@@ -268,6 +268,7 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
268
268
FSTListenSequenceNumber sequenceNumber = [self .listenSequence next ];
269
269
id <FSTQueryCache> queryCache = self.queryCache ;
270
270
271
+ DocumentKeySet authoritativeUpdates;
271
272
for (const auto &entry : remoteEvent.targetChanges ) {
272
273
FSTTargetID targetID = entry.first ;
273
274
FSTBoxedTargetID *boxedTargetID = @(targetID);
@@ -279,6 +280,21 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
279
280
continue ;
280
281
}
281
282
283
+ // When a global snapshot contains updates (either add or modify) we can completely trust
284
+ // these updates as authoritative and blindly apply them to our cache (as a defensive measure
285
+ // to promote self-healing in the unfortunate case that our cache is ever somehow corrupted /
286
+ // out-of-sync).
287
+ //
288
+ // If the document is only updated while removing it from a target then watch isn't obligated
289
+ // to send the absolute latest version: it can send the first version that caused the document
290
+ // not to match.
291
+ for (const DocumentKey& key : change.addedDocuments ) {
292
+ authoritativeUpdates = authoritativeUpdates.insert (key);
293
+ }
294
+ for (const DocumentKey& key : change.modifiedDocuments ) {
295
+ authoritativeUpdates = authoritativeUpdates.insert (key);
296
+ }
297
+
282
298
[queryCache removeMatchingKeys: change.removedDocuments forTargetID: targetID];
283
299
[queryCache addMatchingKeys: change.addedDocuments forTargetID: targetID];
284
300
@@ -303,11 +319,14 @@ - (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
303
319
FSTMaybeDocument *doc = kv.second ;
304
320
changedDocKeys = changedDocKeys.insert (key);
305
321
FSTMaybeDocument *existingDoc = [self .remoteDocumentCache entryForKey: key];
306
- // Make sure we don't apply an old document version to the remote cache, though we
307
- // make an exception for SnapshotVersion::None() which can happen for manufactured
308
- // events (e.g. in the case of a limbo document resolution failing).
309
- if (!existingDoc || SnapshotVersion{doc.version } == SnapshotVersion::None () ||
310
- SnapshotVersion{doc.version } >= SnapshotVersion{existingDoc.version }) {
322
+
323
+ // If a document update isn't authoritative, make sure we don't apply an old document version
324
+ // to the remote cache. We make an exception for SnapshotVersion.MIN which can happen for
325
+ // manufactured events (e.g. in the case of a limbo document resolution failing).
326
+ if (!existingDoc ||
327
+ doc.version == SnapshotVersion::None () ||
328
+ authoritativeUpdates.contains (doc.key ) ||
329
+ doc.version >= existingDoc.version ) {
311
330
[self .remoteDocumentCache addEntry: doc];
312
331
} else {
313
332
LOG_DEBUG (
0 commit comments