30
30
31
31
#include " Firestore/core/src/firebase/firestore/auth/user.h"
32
32
#include " Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
33
- #include " Firestore/core/src/firebase/firestore/model/document_key.h"
34
33
#include " Firestore/core/src/firebase/firestore/model/resource_path.h"
35
34
#include " Firestore/core/src/firebase/firestore/util/hard_assert.h"
36
35
#include " Firestore/core/src/firebase/firestore/util/string_apple.h"
46
45
using Firestore::StringView;
47
46
using firebase::firestore::auth::User;
48
47
using firebase::firestore::model::DocumentKey;
48
+ using firebase::firestore::model::DocumentKeySet;
49
49
using firebase::firestore::model::ResourcePath;
50
50
using leveldb::DB;
51
51
using leveldb::Iterator;
@@ -396,6 +396,39 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
396
396
return result;
397
397
}
398
398
399
+ - (NSArray <FSTMutationBatch *> *)allMutationBatchesAffectingDocumentKeys :
400
+ (const DocumentKeySet &)documentKeys {
401
+ NSString *userID = self.userID ;
402
+
403
+ // Take a pass through the document keys and collect the set of unique mutation batchIDs that
404
+ // affect them all. Some batches can affect more than one key.
405
+ std::set<FSTBatchID> batchIDs;
406
+
407
+ auto indexIterator = _db.currentTransaction ->NewIterator ();
408
+ FSTLevelDBDocumentMutationKey *rowKey = [[FSTLevelDBDocumentMutationKey alloc ] init ];
409
+ for (const DocumentKey &documentKey : documentKeys) {
410
+ std::string indexPrefix =
411
+ [FSTLevelDBDocumentMutationKey keyPrefixWithUserID: userID resourcePath: documentKey.path ()];
412
+ indexIterator->Seek (indexPrefix);
413
+ for (; indexIterator->Valid (); indexIterator->Next ()) {
414
+ // Only consider rows matching exactly the specific key of interest. Note that because we
415
+ // order by path first, and we order terminators before path separators, we'll encounter all
416
+ // the index rows for documentKey contiguously. In particular, all the rows for documentKey
417
+ // will occur before any rows for documents nested in a subcollection beneath documentKey so
418
+ // we can stop as soon as we hit any such row.
419
+ if (!absl::StartsWith (indexIterator->key (), indexPrefix) ||
420
+ ![rowKey decodeKey: indexIterator->key ()] ||
421
+ DocumentKey{rowKey.documentKey } != documentKey) {
422
+ break ;
423
+ }
424
+
425
+ batchIDs.insert (rowKey.batchID );
426
+ }
427
+ }
428
+
429
+ return [self allMutationBatchesWithBatchIDs: batchIDs];
430
+ }
431
+
399
432
- (NSArray <FSTMutationBatch *> *)allMutationBatchesAffectingQuery : (FSTQuery *)query {
400
433
HARD_ASSERT (![query isDocumentQuery ], " Document queries shouldn't go down this path" );
401
434
NSString *userID = self.userID ;
@@ -417,11 +450,10 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
417
450
// index for more than a single document so the associated batchIDs will be neither necessarily
418
451
// unique nor in order. This means an efficient simultaneous scan isn't possible.
419
452
std::string indexPrefix =
420
- [FSTLevelDBDocumentMutationKey keyPrefixWithUserID: self . userID resourcePath: queryPath];
453
+ [FSTLevelDBDocumentMutationKey keyPrefixWithUserID: userID resourcePath: queryPath];
421
454
auto indexIterator = _db.currentTransaction ->NewIterator ();
422
455
indexIterator->Seek (indexPrefix);
423
456
424
- NSMutableArray *result = [NSMutableArray array ];
425
457
FSTLevelDBDocumentMutationKey *rowKey = [[FSTLevelDBDocumentMutationKey alloc ] init ];
426
458
427
459
// Collect up unique batchIDs encountered during a scan of the index. Use a set<FSTBatchID> to
@@ -430,7 +462,7 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
430
462
// This method is faster than performing lookups of the keys with _db->Get and keeping a hash of
431
463
// batchIDs that have already been looked up. The performance difference is minor for small
432
464
// numbers of keys but > 30% faster for larger numbers of keys.
433
- std::set<FSTBatchID> uniqueBatchIds ;
465
+ std::set<FSTBatchID> uniqueBatchIDs ;
434
466
for (; indexIterator->Valid (); indexIterator->Next ()) {
435
467
if (!absl::StartsWith (indexIterator->key (), indexPrefix) ||
436
468
![rowKey decodeKey: indexIterator->key ()]) {
@@ -444,14 +476,25 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
444
476
continue ;
445
477
}
446
478
447
- uniqueBatchIds .insert (rowKey.batchID );
479
+ uniqueBatchIDs .insert (rowKey.batchID );
448
480
}
449
481
482
+ return [self allMutationBatchesWithBatchIDs: uniqueBatchIDs];
483
+ }
484
+
485
+ /* *
486
+ * Constructs an array of matching batches, sorted by batchID to ensure that multiple mutations
487
+ * affecting the same document key are applied in order.
488
+ */
489
+ - (NSArray <FSTMutationBatch *> *)allMutationBatchesWithBatchIDs :
490
+ (const std::set<FSTBatchID> &)batchIDs {
491
+ NSMutableArray *result = [NSMutableArray array ];
492
+ NSString *userID = self.userID ;
493
+
450
494
// Given an ordered set of unique batchIDs perform a skipping scan over the main table to find
451
495
// the mutation batches.
452
496
auto mutationIterator = _db.currentTransaction ->NewIterator ();
453
-
454
- for (FSTBatchID batchID : uniqueBatchIds) {
497
+ for (FSTBatchID batchID : batchIDs) {
455
498
std::string mutationKey = [FSTLevelDBMutationKey keyWithUserID: userID batchID: batchID];
456
499
mutationIterator->Seek (mutationKey);
457
500
if (!mutationIterator->Valid () || mutationIterator->key () != mutationKey) {
0 commit comments