-
Notifications
You must be signed in to change notification settings - Fork 927
Make getNewDocumentChanges() idempotent #2255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
48642ad
e4cdfe0
d3669b6
10c2f8e
a1e5a00
aee20aa
06f9e83
2dc4170
d6ed20b
7166a3e
9933f56
57f22d8
58b3e41
877a2ca
7f6e989
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ import { ObjectMap } from '../util/obj_map'; | |
import { LocalDocumentsView } from './local_documents_view'; | ||
import { LocalViewChanges } from './local_view_changes'; | ||
import { LruGarbageCollector, LruResults } from './lru_garbage_collector'; | ||
import { IndexedDbRemoteDocumentCache } from './indexeddb_remote_document_cache'; | ||
import { MutationQueue } from './mutation_queue'; | ||
import { Persistence, PersistenceTransaction } from './persistence'; | ||
import { PersistencePromise } from './persistence_promise'; | ||
|
@@ -168,6 +169,13 @@ export class LocalStore { | |
q.canonicalId() | ||
); | ||
|
||
/** | ||
* The read time of the last entry processed by `getNewDocumentChanges()`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh! I see: this refers to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your confusion:) I tried to be to smart about it and reverted back to using getNewDocumentChanges() everywhere, which still makes sense even when a read time is passed (at least I see it that way now). |
||
* | ||
* PORTING NOTE: This is only used for multi-tab synchronization. | ||
*/ | ||
private lastDocumentChangeReadTime = SnapshotVersion.MIN; | ||
|
||
constructor( | ||
/** Manages our in-memory or durable persistence. */ | ||
private persistence: Persistence, | ||
|
@@ -192,6 +200,11 @@ export class LocalStore { | |
this.queryEngine.setLocalDocumentsView(this.localDocuments); | ||
} | ||
|
||
/** Starts the LocalStore. */ | ||
start(): Promise<void> { | ||
return this.synchronizeLastDocumentChangeReadTime(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is equivalent to the previous functionality in RemoteDocumentStore.start(). |
||
} | ||
|
||
/** | ||
* Tells the LocalStore that the currently authenticated user has changed. | ||
* | ||
|
@@ -1006,14 +1019,45 @@ export class LocalStore { | |
} | ||
} | ||
|
||
/** | ||
* Returns the set of documents that have been updated since the last call. | ||
* If this is the first call, returns the set of changes since client | ||
* initialization. Further invocations will return document changes since | ||
* the point of rejection. | ||
*/ | ||
// PORTING NOTE: Multi-tab only. | ||
getNewDocumentChanges(): Promise<MaybeDocumentMap> { | ||
return this.persistence.runTransaction( | ||
'Get new document changes', | ||
'readonly', | ||
txn => { | ||
return this.remoteDocuments.getNewDocumentChanges(txn); | ||
} | ||
); | ||
return this.persistence | ||
.runTransaction('Get new document changes', 'readonly-idempotent', txn => | ||
this.remoteDocuments.getNewDocumentChanges( | ||
txn, | ||
this.lastDocumentChangeReadTime | ||
) | ||
) | ||
.then(({ changedDocs, readTime }) => { | ||
this.lastDocumentChangeReadTime = readTime; | ||
return changedDocs; | ||
}); | ||
} | ||
|
||
/** | ||
* Reads the newest document change from persistence and forwards the internal | ||
* synchronization marker so that calls to `getNewDocumentChanges()` | ||
* only return changes that happened after client initialization. | ||
*/ | ||
// PORTING NOTE: Multi-tab only. | ||
async synchronizeLastDocumentChangeReadTime(): Promise<void> { | ||
if (this.remoteDocuments instanceof IndexedDbRemoteDocumentCache) { | ||
const remoteDocumentCache = this.remoteDocuments; | ||
return this.persistence | ||
.runTransaction( | ||
'Synchronize last document change read time', | ||
'readonly-idempotent', | ||
txn => remoteDocumentCache.getLastDocumentChange(txn) | ||
) | ||
.then(({ readTime }) => { | ||
this.lastDocumentChangeReadTime = readTime; | ||
}); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,15 +83,17 @@ export interface RemoteDocumentCache { | |
): PersistencePromise<DocumentMap>; | ||
|
||
/** | ||
* Returns the set of documents that have been updated since the last call. | ||
* If this is the first call, returns the set of changes since client | ||
* initialization. Further invocations will return document changes since | ||
* the point of rejection. | ||
* Returns the set of documents that have changed since the specified read | ||
* time. | ||
*/ | ||
// PORTING NOTE: This is only used for multi-tab synchronization. | ||
getNewDocumentChanges( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative to making LocalStore aware that it's using IndexedDB persistence would be to leave this method in the interface and allow persistence implementations to throw some kind of unsupported operation error if they're ever called. This would have the effect of making the LocalStore code cleaner. Both would fail if MemoryPersistence was ever used with multi-tab. As is we fail the assertion; the proposed change would throw unsupported operation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added the method back to the interface and am throwing an exception now. I debated between the two approaches, but it probably makes sense to reduce this clutter in LocalStore. I did leave |
||
transaction: PersistenceTransaction | ||
): PersistencePromise<MaybeDocumentMap>; | ||
transaction: PersistenceTransaction, | ||
sinceReadTime: SnapshotVersion | ||
): PersistencePromise<{ | ||
changedDocs: MaybeDocumentMap; | ||
readTime: SnapshotVersion; | ||
}>; | ||
|
||
/** | ||
* Provides access to add or update the contents of the cache. The buffer | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used in the
synchronizeLastProcessedReadTime
version of LocalStore. ThechangedDoc
is never read, but I opted to return it to make the API similar to getDocumentChanges above.