Skip to content

Commit

Permalink
Allow remote updates from watch to heal a cache with synthesized dele…
Browse files Browse the repository at this point in the history
…tes in it

Port of firebase/firebase-js-sdk#1015

Addresses #1548
  • Loading branch information
wilhuff committed Jul 18, 2018
1 parent 901b90e commit 5ada17a
Showing 1 changed file with 24 additions and 5 deletions.
29 changes: 24 additions & 5 deletions Firestore/Source/Local/FSTLocalStore.mm
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
FSTListenSequenceNumber sequenceNumber = [self.listenSequence next];
id<FSTQueryCache> queryCache = self.queryCache;

DocumentKeySet authoritativeUpdates;
for (const auto &entry : remoteEvent.targetChanges) {
FSTTargetID targetID = entry.first;
FSTBoxedTargetID *boxedTargetID = @(targetID);
Expand All @@ -279,6 +280,21 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
continue;
}

// When a global snapshot contains updates (either add or modify) we can completely trust
// these updates as authoritative and blindly apply them to our cache (as a defensive measure
// to promote self-healing in the unfortunate case that our cache is ever somehow corrupted /
// out-of-sync).
//
// If the document is only updated while removing it from a target then watch isn't obligated
// to send the absolute latest version: it can send the first version that caused the document
// not to match.
for (const DocumentKey& key : change.addedDocuments) {
authoritativeUpdates = authoritativeUpdates.insert(key);
}
for (const DocumentKey& key : change.modifiedDocuments) {
authoritativeUpdates = authoritativeUpdates.insert(key);
}

[queryCache removeMatchingKeys:change.removedDocuments forTargetID:targetID];
[queryCache addMatchingKeys:change.addedDocuments forTargetID:targetID];

Expand All @@ -303,11 +319,14 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
FSTMaybeDocument *doc = kv.second;
changedDocKeys = changedDocKeys.insert(key);
FSTMaybeDocument *existingDoc = [self.remoteDocumentCache entryForKey:key];
// Make sure we don't apply an old document version to the remote cache, though we
// make an exception for SnapshotVersion::None() which can happen for manufactured
// events (e.g. in the case of a limbo document resolution failing).
if (!existingDoc || SnapshotVersion{doc.version} == SnapshotVersion::None() ||
SnapshotVersion{doc.version} >= SnapshotVersion{existingDoc.version}) {

// If a document update isn't authoritative, make sure we don't apply an old document version
// to the remote cache. We make an exception for SnapshotVersion.MIN which can happen for
// manufactured events (e.g. in the case of a limbo document resolution failing).
if (!existingDoc ||
doc.version == SnapshotVersion::None() ||
authoritativeUpdates.contains(doc.key) ||
doc.version >= existingDoc.version) {
[self.remoteDocumentCache addEntry:doc];
} else {
LOG_DEBUG(
Expand Down

0 comments on commit 5ada17a

Please sign in to comment.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy