Skip to content

Commit 741377e

Browse files
committed
Avoid persisting the resume token unless required
1 parent 9de446c commit 741377e

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

packages/firestore/src/local/local_store.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ export interface LocalWriteResult {
111111
* unrecoverable error (should be caught / reported by the async_queue).
112112
*/
113113
export class LocalStore {
114+
/**
115+
* The maximum time to leave a resume token buffered without writing it
116+
* out.
117+
*/
118+
private static readonly MAX_RESUME_TOKEN_BUFFERING_MICROS = 5 * 60 * 1e6;
119+
114120
/**
115121
* The set of all mutations that have been sent but not yet been applied to
116122
* the backend.
@@ -465,12 +471,22 @@ export class LocalStore {
465471
// any preexisting value.
466472
const resumeToken = change.resumeToken;
467473
if (resumeToken.length > 0) {
474+
const oldQueryData = queryData;
468475
queryData = queryData.copy({
469476
resumeToken,
470477
snapshotVersion: remoteEvent.snapshotVersion
471478
});
472479
this.targetIds[targetId] = queryData;
473-
promises.push(this.queryCache.updateQueryData(txn, queryData));
480+
481+
if (
482+
LocalStore.shouldPersistResumeToken(
483+
oldQueryData,
484+
queryData,
485+
change
486+
)
487+
) {
488+
promises.push(this.queryCache.updateQueryData(txn, queryData));
489+
}
474490
}
475491
}
476492
);
@@ -546,6 +562,42 @@ export class LocalStore {
546562
});
547563
}
548564

565+
/**
566+
* Returns true if the the resume token in newQueryData should be persisted.
567+
*/
568+
private static shouldPersistResumeToken(
569+
oldQueryData: QueryData,
570+
newQueryData: QueryData,
571+
change: TargetChange
572+
): boolean {
573+
// Avoid clearing any existing value
574+
if (newQueryData.resumeToken.length === 0) return false;
575+
576+
// Any resume token is interesting if there isn't one already.
577+
if (oldQueryData.resumeToken.length === 0) return true;
578+
579+
// Don't allow resume token changes to be buffered indefinitely. This
580+
// allows us to be reasonably up-to-date after a crash and avoids needing
581+
// to loop over all active queries on shutdown. Especially in the browser
582+
// we may not get time to do anything interesting while the current tab is
583+
// closing.
584+
const timeDelta =
585+
newQueryData.snapshotVersion.toMicroseconds() -
586+
oldQueryData.snapshotVersion.toMicroseconds();
587+
if (timeDelta >= this.MAX_RESUME_TOKEN_BUFFERING_MICROS) return true;
588+
589+
// Otherwise if the only thing that has changed about a target is its resume
590+
// token it's not worth persisting. Note that the RemoteStore keeps an
591+
// in-memory view of the currently active targets which includes the current
592+
// resume token, so stream failure or user changes will still use an
593+
// up-to-date resume token regardless of what we do here.
594+
const changes =
595+
change.addedDocuments.size +
596+
change.modifiedDocuments.size +
597+
change.removedDocuments.size;
598+
return changes > 0;
599+
}
600+
549601
/**
550602
* Notify local store of the changed views to locally pin documents.
551603
*/

0 commit comments

Comments
 (0)