From 5ada17a2fefb97a40e0aee9c6407291470681866 Mon Sep 17 00:00:00 2001 From: Marek Gilbert Date: Wed, 18 Jul 2018 14:34:54 -0700 Subject: [PATCH] Allow remote updates from watch to heal a cache with synthesized deletes in it Port of https://github.com/firebase/firebase-js-sdk/pull/1015 Addresses #1548 --- Firestore/Source/Local/FSTLocalStore.mm | 29 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 6aab78e8b6e6..aa3534e29330 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -268,6 +268,7 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { FSTListenSequenceNumber sequenceNumber = [self.listenSequence next]; id queryCache = self.queryCache; + DocumentKeySet authoritativeUpdates; for (const auto &entry : remoteEvent.targetChanges) { FSTTargetID targetID = entry.first; FSTBoxedTargetID *boxedTargetID = @(targetID); @@ -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]; @@ -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( 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