Skip to content

Commit 1455bfa

Browse files
authored
Fix overlay patch mutation bug (#6893)
* Fix overlay patch mutation bug * linting * More fixes * Create stupid-swans-fix.md * Feedback
1 parent 06dc136 commit 1455bfa

File tree

7 files changed

+156
-152
lines changed

7 files changed

+156
-152
lines changed

.changeset/stupid-swans-fix.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/firestore": patch
3+
---
4+
5+
Fix an issue that stops some performance optimization being applied.

packages/firestore/src/local/local_documents_view.ts

+4
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ export class LocalDocumentsView {
242242
overlay.mutation.getFieldMask(),
243243
Timestamp.now()
244244
);
245+
} else {
246+
// no overlay exists
247+
// Using EMPTY to indicate there is no overlay for the document.
248+
mutatedFields.set(doc.key, FieldMask.empty());
245249
}
246250
});
247251

packages/firestore/src/local/overlayed_document.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ export class OverlayedDocument {
2727
readonly overlayedDocument: Document,
2828

2929
/**
30-
* The fields that are locally mutated by patch mutations. If the overlayed
31-
* document is from set or delete mutations, this returns null.
30+
* The fields that are locally mutated by patch mutations.
31+
*
32+
* If the overlayed document is from set or delete mutations, this is `null`.
33+
* If there is no overlay (mutation) for the document, this is an empty `FieldMask`.
3234
*/
3335
readonly mutatedFields: FieldMask | null
3436
) {}

packages/firestore/src/model/mutation_batch.ts

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ export class MutationBatch {
166166
if (overlay !== null) {
167167
overlays.set(m.key, overlay);
168168
}
169+
169170
if (!mutableDocument.isValidDocument()) {
170171
mutableDocument.convertToNoDocument(SnapshotVersion.min());
171172
}

packages/firestore/test/unit/local/counting_query_engine.ts

+54-101
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,36 @@ import { SnapshotVersion } from '../../../src/core/snapshot_version';
2020
import { DocumentOverlayCache } from '../../../src/local/document_overlay_cache';
2121
import { IndexManager } from '../../../src/local/index_manager';
2222
import { LocalDocumentsView } from '../../../src/local/local_documents_view';
23-
import { MutationQueue } from '../../../src/local/mutation_queue';
2423
import { PersistencePromise } from '../../../src/local/persistence_promise';
2524
import { PersistenceTransaction } from '../../../src/local/persistence_transaction';
2625
import { QueryEngine } from '../../../src/local/query_engine';
2726
import { RemoteDocumentCache } from '../../../src/local/remote_document_cache';
28-
import {
29-
DocumentKeySet,
30-
DocumentMap,
31-
OverlayMap
32-
} from '../../../src/model/collections';
33-
import { DocumentKey } from '../../../src/model/document_key';
34-
import { Overlay } from '../../../src/model/overlay';
35-
import { ResourcePath } from '../../../src/model/path';
27+
import { DocumentKeySet, DocumentMap } from '../../../src/model/collections';
28+
import { MutationType } from '../../../src/model/mutation';
3629

3730
/**
3831
* A test-only query engine that forwards all API calls and exposes the number
3932
* of documents and mutations read.
4033
*/
4134
export class CountingQueryEngine extends QueryEngine {
4235
/**
43-
* The number of mutations returned by the MutationQueue's
44-
* `getAllMutationBatchesAffectingQuery()` API (since the last call to
36+
* The number of overlays returned by the DocumentOverlayCache's
37+
* `getOverlaysByCollection(Group)` API (since the last call to
4538
* `resetCounts()`)
4639
*/
47-
mutationsReadByCollection = 0;
40+
overlaysReadByCollection = 0;
4841

4942
/**
50-
* The number of mutations returned by the MutationQueue's
51-
* `getAllMutationBatchesAffectingDocumentKey()` and
52-
* `getAllMutationBatchesAffectingDocumentKeys()` APIs (since the last call
53-
* to `resetCounts()`)
43+
* The number of overlays returned by the DocumentOverlayCache's
44+
* `getOverlay(s)` APIs (since the last call to `resetCounts()`)
5445
*/
55-
mutationsReadByKey = 0;
46+
overlaysReadByKey = 0;
47+
48+
overlayTypes: { [k: string]: MutationType } = {};
5649

5750
/**
5851
* The number of documents returned by the RemoteDocumentCache's
59-
* `getAll()` API (since the last call to `resetCounts()`)
52+
* `getAll()` API (since the last call to `resetCounts()`).
6053
*/
6154
documentsReadByCollection = 0;
6255

@@ -66,25 +59,12 @@ export class CountingQueryEngine extends QueryEngine {
6659
*/
6760
documentsReadByKey = 0;
6861

69-
/**
70-
* The number of documents returned by the OverlayCache's `getOverlays()`
71-
* API (since the last call to `resetCounts()`)
72-
*/
73-
overlaysReadByCollection = 0;
74-
75-
/**
76-
* The number of documents returned by the OverlayCache's `getOverlay()`
77-
* APIs (since the last call to `resetCounts()`)
78-
*/
79-
overlaysReadByKey = 0;
80-
8162
resetCounts(): void {
82-
this.mutationsReadByCollection = 0;
83-
this.mutationsReadByKey = 0;
84-
this.documentsReadByCollection = 0;
85-
this.documentsReadByKey = 0;
8663
this.overlaysReadByCollection = 0;
8764
this.overlaysReadByKey = 0;
65+
this.overlayTypes = {};
66+
this.documentsReadByCollection = 0;
67+
this.documentsReadByKey = 0;
8868
}
8969

9070
getDocumentsMatchingQuery(
@@ -107,8 +87,8 @@ export class CountingQueryEngine extends QueryEngine {
10787
): void {
10888
const view = new LocalDocumentsView(
10989
this.wrapRemoteDocumentCache(localDocuments.remoteDocumentCache),
110-
this.wrapMutationQueue(localDocuments.mutationQueue),
111-
this.wrapDocumentOverlayCache(localDocuments.documentOverlayCache),
90+
localDocuments.mutationQueue,
91+
this.wrapOverlayCache(localDocuments.documentOverlayCache),
11292
localDocuments.indexManager
11393
);
11494
return super.initialize(view, indexManager);
@@ -168,88 +148,48 @@ export class CountingQueryEngine extends QueryEngine {
168148
};
169149
}
170150

171-
private wrapMutationQueue(subject: MutationQueue): MutationQueue {
151+
private wrapOverlayCache(
152+
subject: DocumentOverlayCache
153+
): DocumentOverlayCache {
172154
return {
173-
addMutationBatch: subject.addMutationBatch,
174-
checkEmpty: subject.checkEmpty,
175-
getAllMutationBatches: transaction => {
176-
return subject.getAllMutationBatches(transaction).next(result => {
177-
this.mutationsReadByKey += result.length;
155+
getOverlay: (transaction, key) => {
156+
return subject.getOverlay(transaction, key).next(result => {
157+
this.overlaysReadByKey += 1;
158+
if (!!result) {
159+
this.overlayTypes[key.toString()] = result.mutation.type;
160+
}
178161
return result;
179162
});
180163
},
181-
getAllMutationBatchesAffectingDocumentKey: (transaction, documentKey) => {
182-
return subject
183-
.getAllMutationBatchesAffectingDocumentKey(transaction, documentKey)
184-
.next(result => {
185-
this.mutationsReadByKey += result.length;
186-
return result;
187-
});
188-
},
189-
getAllMutationBatchesAffectingDocumentKeys: (
190-
transaction,
191-
documentKeys
192-
) => {
193-
return subject
194-
.getAllMutationBatchesAffectingDocumentKeys(transaction, documentKeys)
195-
.next(result => {
196-
this.mutationsReadByKey += result.length;
197-
return result;
198-
});
199-
},
200-
getAllMutationBatchesAffectingQuery: (transaction, query) => {
201-
return subject
202-
.getAllMutationBatchesAffectingQuery(transaction, query)
203-
.next(result => {
204-
this.mutationsReadByCollection += result.length;
205-
return result;
164+
165+
getOverlays: (transaction, keys) => {
166+
return subject.getOverlays(transaction, keys).next(result => {
167+
this.overlaysReadByKey += keys.length;
168+
result.forEach((key, overlay) => {
169+
this.overlayTypes[key.toString()] = overlay.mutation.type;
206170
});
171+
return result;
172+
});
207173
},
208-
getHighestUnacknowledgedBatchId: subject.getHighestUnacknowledgedBatchId,
209-
getNextMutationBatchAfterBatchId:
210-
subject.getNextMutationBatchAfterBatchId,
211-
lookupMutationBatch: subject.lookupMutationBatch,
212-
performConsistencyCheck: subject.performConsistencyCheck,
213-
removeMutationBatch: subject.removeMutationBatch
214-
};
215-
}
216174

217-
private wrapDocumentOverlayCache(
218-
subject: DocumentOverlayCache
219-
): DocumentOverlayCache {
220-
return {
221-
getOverlay: (
222-
transaction: PersistenceTransaction,
223-
key: DocumentKey
224-
): PersistencePromise<Overlay | null> => {
225-
this.overlaysReadByKey++;
226-
return subject.getOverlay(transaction, key);
227-
},
228-
getOverlays: (
229-
transaction: PersistenceTransaction,
230-
keys: DocumentKey[]
231-
): PersistencePromise<OverlayMap> => {
232-
this.overlaysReadByKey += keys.length;
233-
return subject.getOverlays(transaction, keys);
234-
},
235-
getOverlaysForCollection: (
236-
transaction: PersistenceTransaction,
237-
collection: ResourcePath,
238-
sinceBatchId: number
239-
): PersistencePromise<OverlayMap> => {
175+
getOverlaysForCollection: (transaction, collection, sinceBatchId) => {
240176
return subject
241177
.getOverlaysForCollection(transaction, collection, sinceBatchId)
242178
.next(result => {
243179
this.overlaysReadByCollection += result.size();
180+
result.forEach((key, overlay) => {
181+
this.overlayTypes[key.toString()] = overlay.mutation.type;
182+
});
244183
return result;
245184
});
246185
},
186+
247187
getOverlaysForCollectionGroup: (
248188
transaction: PersistenceTransaction,
249189
collectionGroup: string,
250190
sinceBatchId: number,
251191
count: number
252-
): PersistencePromise<OverlayMap> => {
192+
) => {
253193
return subject
254194
.getOverlaysForCollectionGroup(
255195
transaction,
@@ -259,11 +199,24 @@ export class CountingQueryEngine extends QueryEngine {
259199
)
260200
.next(result => {
261201
this.overlaysReadByCollection += result.size();
202+
result.forEach((key, overlay) => {
203+
this.overlayTypes[key.toString()] = overlay.mutation.type;
204+
});
262205
return result;
263206
});
264207
},
265-
removeOverlaysForBatchId: subject.removeOverlaysForBatchId,
266-
saveOverlays: subject.saveOverlays
208+
209+
saveOverlays: (transaction, largestBatchId, overlays) => {
210+
return subject.saveOverlays(transaction, largestBatchId, overlays);
211+
},
212+
213+
removeOverlaysForBatchId: (transaction, documentKeys, batchId) => {
214+
return subject.removeOverlaysForBatchId(
215+
transaction,
216+
documentKeys,
217+
batchId
218+
);
219+
}
267220
};
268221
}
269222
}

0 commit comments

Comments
 (0)