@@ -55,6 +55,7 @@ import { SortedMap } from '../util/sorted_map';
55
55
import { BATCHID_UNKNOWN } from '../util/types' ;
56
56
57
57
import { BundleCache } from './bundle_cache' ;
58
+ import { DocumentOverlayCache } from './document_overlay_cache' ;
58
59
import { IndexManager } from './index_manager' ;
59
60
import { IndexedDbMutationQueue } from './indexeddb_mutation_queue' ;
60
61
import { IndexedDbPersistence } from './indexeddb_persistence' ;
@@ -125,6 +126,12 @@ class LocalStoreImpl implements LocalStore {
125
126
*/
126
127
mutationQueue ! : MutationQueue ;
127
128
129
+ /**
130
+ * The overlays that can be used to short circuit applying all mutations from
131
+ * mutation queue.
132
+ */
133
+ documentOverlayCache ! : DocumentOverlayCache ;
134
+
128
135
/** The set of all cached remote documents. */
129
136
remoteDocuments : RemoteDocumentCache ;
130
137
@@ -186,6 +193,7 @@ class LocalStoreImpl implements LocalStore {
186
193
initializeUserComponents ( user : User ) : void {
187
194
// TODO(indexing): Add spec tests that test these components change after a
188
195
// user change
196
+ this . documentOverlayCache = this . persistence . getDocumentOverlayCache ( user ) ;
189
197
this . indexManager = this . persistence . getIndexManager ( user ) ;
190
198
this . mutationQueue = this . persistence . getMutationQueue (
191
199
user ,
@@ -194,6 +202,7 @@ class LocalStoreImpl implements LocalStore {
194
202
this . localDocuments = new LocalDocumentsView (
195
203
this . remoteDocuments ,
196
204
this . mutationQueue ,
205
+ this . documentOverlayCache ,
197
206
this . indexManager
198
207
) ;
199
208
this . remoteDocuments . setIndexManager ( this . indexManager ) ;
@@ -209,6 +218,13 @@ class LocalStoreImpl implements LocalStore {
209
218
}
210
219
}
211
220
221
+ class DocumentChangeResult {
222
+ constructor (
223
+ readonly changedDocuments : MutableDocumentMap ,
224
+ readonly existenceChangedKeys : DocumentKeySet
225
+ ) { }
226
+ }
227
+
212
228
export function newLocalStore (
213
229
/** Manages our in-memory or durable persistence. */
214
230
persistence : Persistence ,
@@ -296,6 +312,7 @@ export function localStoreWriteLocally(
296
312
const keys = mutations . reduce ( ( keys , m ) => keys . add ( m . key ) , documentKeySet ( ) ) ;
297
313
298
314
let existingDocs : DocumentMap ;
315
+ let mutationBatch : MutationBatch ;
299
316
300
317
return localStoreImpl . persistence
301
318
. runTransaction ( 'Locally write mutations' , 'readwrite' , txn => {
@@ -340,11 +357,19 @@ export function localStoreWriteLocally(
340
357
baseMutations ,
341
358
mutations
342
359
) ;
360
+ } )
361
+ . next ( batch => {
362
+ mutationBatch = batch ;
363
+ const overlays = batch . applyToLocalDocumentSet ( existingDocs ) ;
364
+ return localStoreImpl . documentOverlayCache . saveOverlays (
365
+ txn ,
366
+ batch . batchId ,
367
+ overlays
368
+ ) ;
343
369
} ) ;
344
370
} )
345
- . then ( batch => {
346
- batch . applyToLocalDocumentSet ( existingDocs ) ;
347
- return { batchId : batch . batchId , changes : existingDocs } ;
371
+ . then ( ( ) => {
372
+ return { batchId : mutationBatch . batchId , changes : existingDocs } ;
348
373
} ) ;
349
374
}
350
375
@@ -383,11 +408,38 @@ export function localStoreAcknowledgeBatch(
383
408
)
384
409
. next ( ( ) => documentBuffer . apply ( txn ) )
385
410
. next ( ( ) => localStoreImpl . mutationQueue . performConsistencyCheck ( txn ) )
411
+ . next ( ( ) =>
412
+ localStoreImpl . documentOverlayCache . removeOverlaysForBatchId (
413
+ txn ,
414
+ affected ,
415
+ batchResult . batch . batchId
416
+ )
417
+ )
418
+ . next ( ( ) =>
419
+ localStoreImpl . localDocuments . recalculateAndSaveOverlaysForDocumentKeys (
420
+ txn ,
421
+ getKeysWithTransformResults ( batchResult )
422
+ )
423
+ )
386
424
. next ( ( ) => localStoreImpl . localDocuments . getDocuments ( txn , affected ) ) ;
387
425
}
388
426
) ;
389
427
}
390
428
429
+ function getKeysWithTransformResults (
430
+ batchResult : MutationBatchResult
431
+ ) : DocumentKeySet {
432
+ let result = documentKeySet ( ) ;
433
+
434
+ for ( let i = 0 ; i < batchResult . mutationResults . length ; ++ i ) {
435
+ const mutationResult = batchResult . mutationResults [ i ] ;
436
+ if ( mutationResult . transformResults . length > 0 ) {
437
+ result = result . add ( batchResult . batch . mutations [ i ] . key ) ;
438
+ }
439
+ }
440
+ return result ;
441
+ }
442
+
391
443
/**
392
444
* Removes mutations from the MutationQueue for the specified batch;
393
445
* LocalDocuments will be recalculated.
@@ -412,6 +464,19 @@ export function localStoreRejectBatch(
412
464
return localStoreImpl . mutationQueue . removeMutationBatch ( txn , batch ) ;
413
465
} )
414
466
. next ( ( ) => localStoreImpl . mutationQueue . performConsistencyCheck ( txn ) )
467
+ . next ( ( ) =>
468
+ localStoreImpl . documentOverlayCache . removeOverlaysForBatchId (
469
+ txn ,
470
+ affectedKeys ,
471
+ batchId
472
+ )
473
+ )
474
+ . next ( ( ) =>
475
+ localStoreImpl . localDocuments . recalculateAndSaveOverlaysForDocumentKeys (
476
+ txn ,
477
+ affectedKeys
478
+ )
479
+ )
415
480
. next ( ( ) =>
416
481
localStoreImpl . localDocuments . getDocuments ( txn , affectedKeys )
417
482
) ;
@@ -530,6 +595,7 @@ export function localStoreApplyRemoteEventToLocalCache(
530
595
} ) ;
531
596
532
597
let changedDocs = mutableDocumentMap ( ) ;
598
+ let existenceChangedKeys = documentKeySet ( ) ;
533
599
remoteEvent . documentUpdates . forEach ( key => {
534
600
if ( remoteEvent . resolvedLimboDocuments . has ( key ) ) {
535
601
promises . push (
@@ -541,15 +607,16 @@ export function localStoreApplyRemoteEventToLocalCache(
541
607
}
542
608
} ) ;
543
609
544
- // Each loop iteration only affects its "own" doc, so it's safe to get all the remote
545
- // documents in advance in a single call.
610
+ // Each loop iteration only affects its "own" doc, so it's safe to get all
611
+ // the remote documents in advance in a single call.
546
612
promises . push (
547
613
populateDocumentChangeBuffer (
548
614
txn ,
549
615
documentBuffer ,
550
616
remoteEvent . documentUpdates
551
617
) . next ( result => {
552
- changedDocs = result ;
618
+ changedDocs = result . changedDocuments ;
619
+ existenceChangedKeys = result . existenceChangedKeys ;
553
620
} )
554
621
) ;
555
622
@@ -580,9 +647,10 @@ export function localStoreApplyRemoteEventToLocalCache(
580
647
return PersistencePromise . waitFor ( promises )
581
648
. next ( ( ) => documentBuffer . apply ( txn ) )
582
649
. next ( ( ) =>
583
- localStoreImpl . localDocuments . applyLocalViewToDocuments (
650
+ localStoreImpl . localDocuments . getLocalViewOfDocuments (
584
651
txn ,
585
- changedDocs
652
+ changedDocs ,
653
+ existenceChangedKeys
586
654
)
587
655
)
588
656
. next ( ( ) => changedDocs ) ;
@@ -595,7 +663,11 @@ export function localStoreApplyRemoteEventToLocalCache(
595
663
596
664
/**
597
665
* Populates document change buffer with documents from backend or a bundle.
598
- * Returns the document changes resulting from applying those documents.
666
+ * Returns the document changes resulting from applying those documents, and
667
+ * also a set of documents whose existence state are changed as a result.
668
+ *
669
+ * Note: this function will use `documentVersions` if it is defined;
670
+ * when it is not defined, resorts to `globalVersion`.
599
671
*
600
672
* @param txn - Transaction to use to read existing documents from storage.
601
673
* @param documentBuffer - Document buffer to collect the resulted changes to be
@@ -605,22 +677,25 @@ export function localStoreApplyRemoteEventToLocalCache(
605
677
* documents have the same read time.
606
678
* @param documentVersions - A DocumentKey-to-SnapshotVersion map if documents
607
679
* have their own read time.
608
- *
609
- * Note: this function will use `documentVersions` if it is defined;
610
- * when it is not defined, resorts to `globalVersion`.
611
680
*/
612
681
function populateDocumentChangeBuffer (
613
682
txn : PersistenceTransaction ,
614
683
documentBuffer : RemoteDocumentChangeBuffer ,
615
684
documents : MutableDocumentMap
616
- ) : PersistencePromise < MutableDocumentMap > {
685
+ ) : PersistencePromise < DocumentChangeResult > {
617
686
let updatedKeys = documentKeySet ( ) ;
687
+ let conditionChanged = documentKeySet ( ) ;
618
688
documents . forEach ( k => ( updatedKeys = updatedKeys . add ( k ) ) ) ;
619
689
return documentBuffer . getEntries ( txn , updatedKeys ) . next ( existingDocs => {
620
690
let changedDocs = mutableDocumentMap ( ) ;
621
691
documents . forEach ( ( key , doc ) => {
622
692
const existingDoc = existingDocs . get ( key ) ! ;
623
693
694
+ // Check if see if there is a existence state change for this document.
695
+ if ( doc . isFoundDocument ( ) !== existingDoc . isFoundDocument ( ) ) {
696
+ conditionChanged = conditionChanged . add ( key ) ;
697
+ }
698
+
624
699
// Note: The order of the steps below is important, since we want
625
700
// to ensure that rejected limbo resolutions (which fabricate
626
701
// NoDocuments with SnapshotVersion.min()) never add documents to
@@ -655,7 +730,7 @@ function populateDocumentChangeBuffer(
655
730
) ;
656
731
}
657
732
} ) ;
658
- return changedDocs ;
733
+ return new DocumentChangeResult ( changedDocs , conditionChanged ) ;
659
734
} ) ;
660
735
}
661
736
@@ -1225,11 +1300,11 @@ export async function localStoreApplyBundledDocuments(
1225
1300
'readwrite' ,
1226
1301
txn => {
1227
1302
return populateDocumentChangeBuffer ( txn , documentBuffer , documentMap )
1228
- . next ( changedDocs => {
1303
+ . next ( documentChangeResult => {
1229
1304
documentBuffer . apply ( txn ) ;
1230
- return changedDocs ;
1305
+ return documentChangeResult ;
1231
1306
} )
1232
- . next ( changedDocs => {
1307
+ . next ( documentChangeResult => {
1233
1308
return localStoreImpl . targetCache
1234
1309
. removeMatchingKeysForTargetId ( txn , umbrellaTargetData . targetId )
1235
1310
. next ( ( ) =>
@@ -1240,12 +1315,13 @@ export async function localStoreApplyBundledDocuments(
1240
1315
)
1241
1316
)
1242
1317
. next ( ( ) =>
1243
- localStoreImpl . localDocuments . applyLocalViewToDocuments (
1318
+ localStoreImpl . localDocuments . getLocalViewOfDocuments (
1244
1319
txn ,
1245
- changedDocs
1320
+ documentChangeResult . changedDocuments ,
1321
+ documentChangeResult . existenceChangedKeys
1246
1322
)
1247
1323
)
1248
- . next ( ( ) => changedDocs ) ;
1324
+ . next ( ( ) => documentChangeResult . changedDocuments ) ;
1249
1325
} ) ;
1250
1326
}
1251
1327
) ;
0 commit comments