Skip to content

Commit d5887c6

Browse files
Add ReadTime to MutableDocument
1 parent 2d04af9 commit d5887c6

13 files changed

+156
-211
lines changed

packages/firestore/src/local/indexeddb_remote_document_cache.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import { PersistenceTransaction } from './persistence_transaction';
5353
import { RemoteDocumentCache } from './remote_document_cache';
5454
import { RemoteDocumentChangeBuffer } from './remote_document_change_buffer';
5555
import { IterateOptions, SimpleDbStore } from './simple_db';
56+
import { version } from '../../test/util/helpers';
5657

5758
export interface DocumentSizeEntry {
5859
document: MutableDocument;
@@ -289,7 +290,10 @@ class IndexedDbRemoteDocumentCacheImpl implements IndexedDbRemoteDocumentCache {
289290
return;
290291
}
291292

292-
const document = fromDbRemoteDocument(this.serializer, dbRemoteDoc);
293+
const document = this.maybeDecodeDocument(
294+
DocumentKey.fromSegments(key),
295+
dbRemoteDoc
296+
);
293297
if (!query.path.isPrefixOf(document.key.path)) {
294298
control.done();
295299
} else if (queryMatches(query, document)) {
@@ -334,13 +338,12 @@ class IndexedDbRemoteDocumentCacheImpl implements IndexedDbRemoteDocumentCache {
334338
* Decodes `remoteDoc` and returns the document (or null, if the document
335339
* corresponds to the format used for sentinel deletes).
336340
*/
337-
private maybeDecodeDocument(
341+
maybeDecodeDocument(
338342
documentKey: DocumentKey,
339343
dbRemoteDoc: DbRemoteDocument | null
340344
): MutableDocument {
341345
if (dbRemoteDoc) {
342-
const doc = fromDbRemoteDocument(this.serializer, dbRemoteDoc);
343-
346+
let doc = fromDbRemoteDocument(this.serializer, dbRemoteDoc);
344347
// Whether the document is a sentinel removal and should only be used in the
345348
// `getNewDocumentChanges()`
346349
const isSentinelRemoval =
@@ -392,11 +395,11 @@ export function remoteDocumentCacheGetNewDocumentChanges(
392395
return documentsStore
393396
.iterate(
394397
{ index: DbRemoteDocument.readTimeIndex, range },
395-
(_, dbRemoteDoc) => {
398+
(key, dbRemoteDoc) => {
396399
// Unlike `getEntry()` and others, `getNewDocumentChanges()` parses
397400
// the documents directly since we want to keep sentinel deletes.
398-
const doc = fromDbRemoteDocument(
399-
remoteDocumentCacheImpl.serializer,
401+
const doc = remoteDocumentCacheImpl.maybeDecodeDocument(
402+
DocumentKey.fromSegments(key),
400403
dbRemoteDoc
401404
);
402405
changedDocs = changedDocs.insert(doc.key, doc);
@@ -480,15 +483,14 @@ class IndexedDbRemoteDocumentChangeBuffer extends RemoteDocumentChangeBuffer {
480483
previousSize !== undefined,
481484
`Cannot modify a document that wasn't read (for ${key})`
482485
);
483-
if (documentChange.document.isValidDocument()) {
486+
if (documentChange.isValidDocument()) {
484487
debugAssert(
485-
!this.getReadTime(key).isEqual(SnapshotVersion.min()),
488+
!documentChange.readTime.isEqual(SnapshotVersion.min()),
486489
'Cannot add a document with a read time of zero'
487490
);
488491
const doc = toDbRemoteDocument(
489492
this.documentCache.serializer,
490-
documentChange.document,
491-
this.getReadTime(key)
493+
documentChange
492494
);
493495
collectionParents = collectionParents.add(key.path.popLast());
494496

@@ -504,8 +506,7 @@ class IndexedDbRemoteDocumentChangeBuffer extends RemoteDocumentChangeBuffer {
504506
// preserved in `getNewDocumentChanges()`.
505507
const deletedDoc = toDbRemoteDocument(
506508
this.documentCache.serializer,
507-
MutableDocument.newNoDocument(key, SnapshotVersion.min()),
508-
this.getReadTime(key)
509+
documentChange.convertToNoDocument(SnapshotVersion.min())
509510
);
510511
promises.push(
511512
this.documentCache.addEntry(transaction, key, deletedDoc)

packages/firestore/src/local/local_serializer.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,35 +69,40 @@ export function fromDbRemoteDocument(
6969
localSerializer: LocalSerializer,
7070
remoteDoc: DbRemoteDocument
7171
): MutableDocument {
72+
let doc: MutableDocument;
7273
if (remoteDoc.document) {
73-
return fromDocument(
74+
doc = fromDocument(
7475
localSerializer.remoteSerializer,
7576
remoteDoc.document,
7677
!!remoteDoc.hasCommittedMutations
7778
);
7879
} else if (remoteDoc.noDocument) {
7980
const key = DocumentKey.fromSegments(remoteDoc.noDocument.path);
8081
const version = fromDbTimestamp(remoteDoc.noDocument.readTime);
81-
const document = MutableDocument.newNoDocument(key, version);
82-
return remoteDoc.hasCommittedMutations
83-
? document.setHasCommittedMutations()
84-
: document;
82+
doc = MutableDocument.newNoDocument(key, version);
83+
if (remoteDoc.hasCommittedMutations) {
84+
doc.setHasCommittedMutations();
85+
}
8586
} else if (remoteDoc.unknownDocument) {
8687
const key = DocumentKey.fromSegments(remoteDoc.unknownDocument.path);
8788
const version = fromDbTimestamp(remoteDoc.unknownDocument.version);
88-
return MutableDocument.newUnknownDocument(key, version);
89+
doc = MutableDocument.newUnknownDocument(key, version);
8990
} else {
9091
return fail('Unexpected DbRemoteDocument');
9192
}
93+
94+
if (remoteDoc.readTime) {
95+
doc.setReadTime(fromDbTimestampKey(remoteDoc.readTime));
96+
}
97+
return doc;
9298
}
9399

94100
/** Encodes a document for storage locally. */
95101
export function toDbRemoteDocument(
96102
localSerializer: LocalSerializer,
97-
document: MutableDocument,
98-
readTime: SnapshotVersion
103+
document: MutableDocument
99104
): DbRemoteDocument {
100-
const dbReadTime = toDbTimestampKey(readTime);
105+
const dbReadTime = toDbTimestampKey(document.readTime);
101106
const parentPath = document.key.path.popLast().toArray();
102107
if (document.isFoundDocument()) {
103108
const doc = toDocument(localSerializer.remoteSerializer, document);
@@ -112,11 +117,11 @@ export function toDbRemoteDocument(
112117
);
113118
} else if (document.isNoDocument()) {
114119
const path = document.key.path.toArray();
115-
const readTime = toDbTimestamp(document.version);
120+
const version = toDbTimestamp(document.version);
116121
const hasCommittedMutations = document.hasCommittedMutations;
117122
return new DbRemoteDocument(
118123
/* unknownDocument= */ null,
119-
new DbNoDocument(path, readTime),
124+
new DbNoDocument(path, version),
120125
/* document= */ null,
121126
hasCommittedMutations,
122127
dbReadTime,

packages/firestore/src/local/local_store_impl.ts

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ export function localStoreApplyRemoteEventToLocalCache(
533533
});
534534

535535
let changedDocs = mutableDocumentMap();
536-
remoteEvent.documentUpdates.forEach((key, doc) => {
536+
remoteEvent.documentUpdates.forEach(key => {
537537
if (remoteEvent.resolvedLimboDocuments.has(key)) {
538538
promises.push(
539539
localStoreImpl.persistence.referenceDelegate.updateLimboDocument(
@@ -550,9 +550,7 @@ export function localStoreApplyRemoteEventToLocalCache(
550550
populateDocumentChangeBuffer(
551551
txn,
552552
documentBuffer,
553-
remoteEvent.documentUpdates,
554-
remoteVersion,
555-
undefined
553+
remoteEvent.documentUpdates
556554
).next(result => {
557555
changedDocs = result;
558556
})
@@ -617,19 +615,14 @@ export function localStoreApplyRemoteEventToLocalCache(
617615
function populateDocumentChangeBuffer(
618616
txn: PersistenceTransaction,
619617
documentBuffer: RemoteDocumentChangeBuffer,
620-
documents: MutableDocumentMap,
621-
globalVersion: SnapshotVersion,
622-
// TODO(wuandy): We could add `readTime` to MaybeDocument instead to remove
623-
// this parameter.
624-
documentVersions: DocumentVersionMap | undefined
618+
documents: MutableDocumentMap
625619
): PersistencePromise<MutableDocumentMap> {
626620
let updatedKeys = documentKeySet();
627621
documents.forEach(k => (updatedKeys = updatedKeys.add(k)));
628622
return documentBuffer.getEntries(txn, updatedKeys).next(existingDocs => {
629623
let changedDocs = mutableDocumentMap();
630624
documents.forEach((key, doc) => {
631625
const existingDoc = existingDocs.get(key)!;
632-
const docReadTime = documentVersions?.get(key) || globalVersion;
633626

634627
// Note: The order of the steps below is important, since we want
635628
// to ensure that rejected limbo resolutions (which fabricate
@@ -639,19 +632,15 @@ function populateDocumentChangeBuffer(
639632
// NoDocuments with SnapshotVersion.min() are used in manufactured
640633
// events. We remove these documents from cache since we lost
641634
// access.
642-
documentBuffer.removeEntry(key, docReadTime);
635+
documentBuffer.removeEntry(key, doc.readTime);
643636
changedDocs = changedDocs.insert(key, doc);
644637
} else if (
645638
!existingDoc.isValidDocument() ||
646639
doc.version.compareTo(existingDoc.version) > 0 ||
647640
(doc.version.compareTo(existingDoc.version) === 0 &&
648641
existingDoc.hasPendingWrites)
649642
) {
650-
debugAssert(
651-
!SnapshotVersion.min().isEqual(docReadTime),
652-
'Cannot add a document when the remote version is zero'
653-
);
654-
documentBuffer.addEntry(doc, docReadTime);
643+
documentBuffer.addEntry(doc);
655644
changedDocs = changedDocs.insert(key, doc);
656645
} else {
657646
logDebug(
@@ -1043,7 +1032,8 @@ function applyWriteToRemoteDocuments(
10431032
// We use the commitVersion as the readTime rather than the
10441033
// document's updateTime since the updateTime is not advanced
10451034
// for updates that do not modify the underlying document.
1046-
documentBuffer.addEntry(doc, batchResult.commitVersion);
1035+
doc.setReadTime(batchResult.commitVersion);
1036+
documentBuffer.addEntry(doc);
10471037
}
10481038
}
10491039
});
@@ -1207,20 +1197,16 @@ export async function localStoreApplyBundledDocuments(
12071197
const localStoreImpl = debugCast(localStore, LocalStoreImpl);
12081198
let documentKeys = documentKeySet();
12091199
let documentMap = mutableDocumentMap();
1210-
let versionMap = documentVersionMap();
12111200
for (const bundleDoc of documents) {
12121201
const documentKey = bundleConverter.toDocumentKey(bundleDoc.metadata.name!);
12131202
if (bundleDoc.document) {
12141203
documentKeys = documentKeys.add(documentKey);
12151204
}
1216-
documentMap = documentMap.insert(
1217-
documentKey,
1218-
bundleConverter.toMutableDocument(bundleDoc)
1219-
);
1220-
versionMap = versionMap.insert(
1221-
documentKey,
1205+
const document = bundleConverter.toMutableDocument(bundleDoc);
1206+
document.setReadTime(
12221207
bundleConverter.toSnapshotVersion(bundleDoc.metadata.readTime!)
12231208
);
1209+
documentMap = documentMap.insert(documentKey, document);
12241210
}
12251211

12261212
const documentBuffer = localStoreImpl.remoteDocuments.newChangeBuffer({
@@ -1237,13 +1223,7 @@ export async function localStoreApplyBundledDocuments(
12371223
'Apply bundle documents',
12381224
'readwrite',
12391225
txn => {
1240-
return populateDocumentChangeBuffer(
1241-
txn,
1242-
documentBuffer,
1243-
documentMap,
1244-
SnapshotVersion.min(),
1245-
versionMap
1246-
)
1226+
return populateDocumentChangeBuffer(txn, documentBuffer, documentMap)
12471227
.next(changedDocs => {
12481228
documentBuffer.apply(txn);
12491229
return changedDocs;

packages/firestore/src/local/memory_remote_document_cache.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export type DocumentSizer = (doc: Document) => number;
3939
interface MemoryRemoteDocumentCacheEntry {
4040
document: Document;
4141
size: number;
42-
readTime: SnapshotVersion;
4342
}
4443

4544
type DocumentEntryMap = SortedMap<DocumentKey, MemoryRemoteDocumentCacheEntry>;
@@ -85,11 +84,10 @@ class MemoryRemoteDocumentCacheImpl implements MemoryRemoteDocumentCache {
8584
*/
8685
addEntry(
8786
transaction: PersistenceTransaction,
88-
doc: MutableDocument,
89-
readTime: SnapshotVersion
87+
doc: MutableDocument
9088
): PersistencePromise<void> {
9189
debugAssert(
92-
!readTime.isEqual(SnapshotVersion.min()),
90+
!doc.readTime.isEqual(SnapshotVersion.min()),
9391
'Cannot add a document with a read time of zero'
9492
);
9593

@@ -100,8 +98,7 @@ class MemoryRemoteDocumentCacheImpl implements MemoryRemoteDocumentCache {
10098

10199
this.docs = this.docs.insert(key, {
102100
document: doc.mutableCopy(),
103-
size: currentSize,
104-
readTime
101+
size: currentSize
105102
});
106103

107104
this.size += currentSize - previousSize;
@@ -173,12 +170,12 @@ class MemoryRemoteDocumentCacheImpl implements MemoryRemoteDocumentCache {
173170
while (iterator.hasNext()) {
174171
const {
175172
key,
176-
value: { document, readTime }
173+
value: { document }
177174
} = iterator.getNext();
178175
if (!query.path.isPrefixOf(key.path)) {
179176
break;
180177
}
181-
if (readTime.compareTo(sinceReadTime) <= 0) {
178+
if (document.readTime.compareTo(sinceReadTime) <= 0) {
182179
continue;
183180
}
184181
if (!queryMatches(query, document)) {
@@ -237,14 +234,8 @@ class MemoryRemoteDocumentChangeBuffer extends RemoteDocumentChangeBuffer {
237234
): PersistencePromise<void> {
238235
const promises: Array<PersistencePromise<void>> = [];
239236
this.changes.forEach((key, doc) => {
240-
if (doc.document.isValidDocument()) {
241-
promises.push(
242-
this.documentCache.addEntry(
243-
transaction,
244-
doc.document,
245-
this.getReadTime(key)
246-
)
247-
);
237+
if (doc.isValidDocument()) {
238+
promises.push(this.documentCache.addEntry(transaction, doc));
248239
} else {
249240
this.documentCache.removeEntry(key);
250241
}

0 commit comments

Comments
 (0)