aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore
diff options
context:
space:
mode:
authorGravatar Greg Soltis <gsoltis@google.com>2018-03-30 10:18:25 -0700
committerGravatar GitHub <noreply@github.com>2018-03-30 10:18:25 -0700
commit3f36f5467de4c191fa2903743e5a210420e9d49a (patch)
treee73fa2cd4fa299d6220e4ab04daab515ceeca89a /Firestore
parentea490a2c6492e41e892397e044477f778ce358b8 (diff)
Drop FSTWriteGroup (#986)
* Drop write group from remote document change buffer * Unwind some group dependendencies in local store * Write group dropped from local store * Drop write group from mutation queue tests * Drop write group usage from query cache tests * Drop write groups from remote document cache tests * Drop write groups from remote document change buffer tests * Drop write groups and the write group tracker * Style * Put the action in transaction * Merge master, fix test * Fix some compiler warnings but mostly trigger travis * Responses to feedback
Diffstat (limited to 'Firestore')
-rw-r--r--Firestore/Example/Firestore.xcodeproj/project.pbxproj4
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm8
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm5
-rw-r--r--Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm24
-rw-r--r--Firestore/Example/Tests/Local/FSTMutationQueueTests.mm690
-rw-r--r--Firestore/Example/Tests/Local/FSTQueryCacheTests.mm486
-rw-r--r--Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm101
-rw-r--r--Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm57
-rw-r--r--Firestore/Example/Tests/Local/FSTWriteGroupTests.mm101
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.mm4
-rw-r--r--Firestore/Source/Local/FSTLevelDB.mm23
-rw-r--r--Firestore/Source/Local/FSTLocalStore.mm472
-rw-r--r--Firestore/Source/Local/FSTMemoryPersistence.mm14
-rw-r--r--Firestore/Source/Local/FSTPersistence.h26
-rw-r--r--Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h6
-rw-r--r--Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm2
-rw-r--r--Firestore/Source/Local/FSTWriteGroup.h89
-rw-r--r--Firestore/Source/Local/FSTWriteGroup.mm96
-rw-r--r--Firestore/Source/Local/FSTWriteGroupTracker.h50
-rw-r--r--Firestore/Source/Local/FSTWriteGroupTracker.mm63
-rw-r--r--Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc6
-rw-r--r--Firestore/core/src/firebase/firestore/local/leveldb_transaction.h2
22 files changed, 905 insertions, 1424 deletions
diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
index eb88210..7dbb45d 100644
--- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj
+++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj
@@ -95,7 +95,6 @@
5492E0AD2021552D00B64F25 /* FSTMemoryMutationQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0972021552C00B64F25 /* FSTMemoryMutationQueueTests.mm */; };
5492E0AE2021552D00B64F25 /* FSTLevelDBQueryCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */; };
5492E0AF2021552D00B64F25 /* FSTReferenceSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09A2021552C00B64F25 /* FSTReferenceSetTests.mm */; };
- 5492E0B02021552D00B64F25 /* FSTWriteGroupTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */; };
5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */; };
5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */; };
5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */; };
@@ -311,7 +310,6 @@
5492E0982021552C00B64F25 /* FSTLevelDBQueryCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTLevelDBQueryCacheTests.mm; sourceTree = "<group>"; };
5492E0992021552C00B64F25 /* FSTPersistenceTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTPersistenceTestHelpers.h; sourceTree = "<group>"; };
5492E09A2021552C00B64F25 /* FSTReferenceSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTReferenceSetTests.mm; sourceTree = "<group>"; };
- 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWriteGroupTests.mm; sourceTree = "<group>"; };
5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteDocumentCacheTests.mm; sourceTree = "<group>"; };
5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentKeyTests.mm; sourceTree = "<group>"; };
5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentSetTests.mm; sourceTree = "<group>"; };
@@ -755,7 +753,6 @@
5492E0852021552A00B64F25 /* FSTRemoteDocumentCacheTests.h */,
5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */,
5492E0902021552B00B64F25 /* FSTRemoteDocumentChangeBufferTests.mm */,
- 5492E09B2021552C00B64F25 /* FSTWriteGroupTests.mm */,
5492E0932021552B00B64F25 /* StringViewTests.mm */,
132E36BB104830BD806351AC /* FSTLevelDBTransactionTests.mm */,
);
@@ -1477,7 +1474,6 @@
B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */,
5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */,
5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */,
- 5492E0B02021552D00B64F25 /* FSTWriteGroupTests.mm in Sources */,
5492E058202154AB00B64F25 /* FSTAPIHelpers.mm in Sources */,
AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */,
5492E0A82021552D00B64F25 /* FSTLevelDBLocalStoreTests.mm in Sources */,
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
index ad892d8..14910ce 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm
@@ -60,7 +60,7 @@ using leveldb::Status;
- (void)testAddsTargetGlobal {
FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
XCTAssertNil(metadata, @"Not expecting metadata yet, we should have an empty db");
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testAddsTargetGlobal");
[FSTLevelDBMigrations runMigrationsWithTransaction:&transaction];
transaction.Commit();
metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
@@ -68,7 +68,7 @@ using leveldb::Status;
}
- (void)testSetsVersionNumber {
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testSetsVersionNumber");
FSTLevelDBSchemaVersion initial =
[FSTLevelDBMigrations schemaVersionWithTransaction:&transaction];
XCTAssertEqual(0, initial, "No version should be equivalent to 0");
@@ -83,7 +83,7 @@ using leveldb::Status;
NSUInteger expected = 50;
{
// Setup some targets to be counted in the migration.
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCountsQueries setup");
for (int i = 0; i < expected; i++) {
std::string key = [FSTLevelDBTargetKey keyWithTargetID:i];
transaction.Put(key, "dummy");
@@ -100,7 +100,7 @@ using leveldb::Status;
}
{
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCountsQueries");
[FSTLevelDBMigrations runMigrationsWithTransaction:&transaction];
transaction.Commit();
FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db];
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
index cb03bf2..cd8176e 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBMutationQueueTests.mm
@@ -22,7 +22,6 @@
#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
#import "Firestore/Source/Local/FSTLevelDB.h"
#import "Firestore/Source/Local/FSTLevelDBKey.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
#import "Firestore/Example/Tests/Local/FSTMutationQueueTests.h"
#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
@@ -73,9 +72,7 @@ std::string MutationLikeKey(StringView table, StringView userID, FSTBatchID batc
self.mutationQueue = [_db mutationQueueForUser:User("user")];
self.persistence = _db;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Start MutationQueue"];
- [self.mutationQueue start];
- [self.persistence commitGroup:group];
+ self.persistence.run("Setup", [&]() { [self.mutationQueue start]; });
}
- (void)testLoadNextBatchID_zeroWhenTotallyEmpty {
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
index c959b4f..a32ce9f 100644
--- a/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
+++ b/Firestore/Example/Tests/Local/FSTLevelDBTransactionTests.mm
@@ -58,7 +58,7 @@ using firebase::firestore::local::LevelDbTransaction;
}
- (void)testCreateTransaction {
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCreateTransaction");
std::string key = "key1";
transaction.Put(key, "value");
@@ -83,7 +83,7 @@ using firebase::firestore::local::LevelDbTransaction;
status = _db->Put(writeOptions, committed_key2, committed_value2);
XCTAssertTrue(status.ok());
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCanReadCommittedAndMutations");
const std::string mutation_key1 = "m_key1";
const std::string mutation_value1 = "m_value1";
transaction.Put(mutation_key1, mutation_value1);
@@ -113,7 +113,7 @@ using firebase::firestore::local::LevelDbTransaction;
"value_" + std::to_string(i));
XCTAssertTrue(status.ok());
}
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testDeleteCommitted");
transaction.Put("key_1", "new_value");
std::string value;
Status status = transaction.Get("key_1", &value);
@@ -142,7 +142,7 @@ using firebase::firestore::local::LevelDbTransaction;
XCTAssertTrue(status.ok());
}
std::string value;
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testMutateDeleted");
transaction.Delete("key_1");
Status status = transaction.Get("key_1", &value);
XCTAssertTrue(status.IsNotFound());
@@ -186,7 +186,7 @@ using firebase::firestore::local::LevelDbTransaction;
}
- (void)testProtobufSupport {
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testProtobufSupport");
FSTPBTarget *target = [FSTPBTarget message];
target.targetId = 1;
@@ -206,7 +206,7 @@ using firebase::firestore::local::LevelDbTransaction;
}
- (void)testCanIterateAndDelete {
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCanIterateAndDelete");
for (int i = 0; i < 4; ++i) {
transaction.Put("key_" + std::to_string(i), "value_" + std::to_string(i));
@@ -233,7 +233,7 @@ using firebase::firestore::local::LevelDbTransaction;
}
// Create a transaction, iterate, deleting key_0. Verify we still iterate key_1.
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testCanIterateFromDeletionToCommitted");
auto it = transaction.NewIterator();
it->Seek("key_0");
XCTAssertTrue(it->Valid());
@@ -255,7 +255,7 @@ using firebase::firestore::local::LevelDbTransaction;
}
// Create a transaction, iterate to key_1, delete key_2. Verify we still iterate key_3.
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testDeletingAheadOfAnIterator");
auto it = transaction.NewIterator();
it->Seek("key_0");
XCTAssertTrue(it->Valid());
@@ -277,21 +277,21 @@ using firebase::firestore::local::LevelDbTransaction;
FSTPBWriteBatch *message = [FSTPBWriteBatch message];
message.batchId = 42;
- LevelDbTransaction transaction(_db.get());
+ LevelDbTransaction transaction(_db.get(), "testToString");
std::string description = transaction.ToString();
- XCTAssertEqual(description, "<LevelDbTransaction: 0 changes (0 bytes):>");
+ XCTAssertEqual(description, "<LevelDbTransaction testToString: 0 changes (0 bytes):>");
transaction.Put(key, message);
description = transaction.ToString();
XCTAssertEqual(description,
- "<LevelDbTransaction: 1 changes (2 bytes):\n"
+ "<LevelDbTransaction testToString: 1 changes (2 bytes):\n"
" - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
std::string key2 = LevelDbMutationKey::Key("user1", 43);
transaction.Delete(key2);
description = transaction.ToString();
XCTAssertEqual(description,
- "<LevelDbTransaction: 2 changes (2 bytes):\n"
+ "<LevelDbTransaction testToString: 2 changes (2 bytes):\n"
" - Delete [mutation: user_id=user1 batch_id=43]\n"
" - Put [mutation: user_id=user1 batch_id=42] (2 bytes)>");
}
diff --git a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm
index 465a2cb..b228657 100644
--- a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm
+++ b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm
@@ -21,7 +21,6 @@
#import "Firestore/Source/Local/FSTEagerGarbageCollector.h"
#import "Firestore/Source/Local/FSTMutationQueue.h"
#import "Firestore/Source/Local/FSTPersistence.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
#import "Firestore/Source/Model/FSTMutation.h"
#import "Firestore/Source/Model/FSTMutationBatch.h"
@@ -56,32 +55,24 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testCountBatches {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Count batches"];
- XCTAssertEqual(0, [self batchCount]);
- XCTAssertTrue([self.mutationQueue isEmpty]);
- [self.persistence commitGroup:group];
-
- FSTMutationBatch *batch1 = [self addMutationBatch];
- group = [self.persistence startGroupWithAction:@"Count batches"];
- XCTAssertEqual(1, [self batchCount]);
- XCTAssertFalse([self.mutationQueue isEmpty]);
- [self.persistence commitGroup:group];
-
- FSTMutationBatch *batch2 = [self addMutationBatch];
- group = [self.persistence startGroupWithAction:@"Count batches"];
- XCTAssertEqual(2, [self batchCount]);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batch2 ]];
- group = [self.persistence startGroupWithAction:@"Count batches"];
- XCTAssertEqual(1, [self batchCount]);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batch1 ]];
- group = [self.persistence startGroupWithAction:@"Count batches"];
- XCTAssertEqual(0, [self batchCount]);
- XCTAssertTrue([self.mutationQueue isEmpty]);
- [self.persistence commitGroup:group];
+ self.persistence.run("testCountBatches", [&]() {
+ XCTAssertEqual(0, [self batchCount]);
+ XCTAssertTrue([self.mutationQueue isEmpty]);
+
+ FSTMutationBatch *batch1 = [self addMutationBatch];
+ XCTAssertEqual(1, [self batchCount]);
+ XCTAssertFalse([self.mutationQueue isEmpty]);
+
+ FSTMutationBatch *batch2 = [self addMutationBatch];
+ XCTAssertEqual(2, [self batchCount]);
+
+ [self.mutationQueue removeMutationBatches:@[ batch2 ]];
+ XCTAssertEqual(1, [self batchCount]);
+
+ [self.mutationQueue removeMutationBatches:@[ batch1 ]];
+ XCTAssertEqual(0, [self batchCount]);
+ XCTAssertTrue([self.mutationQueue isEmpty]);
+ });
}
- (void)testAcknowledgeBatchID {
@@ -91,334 +82,327 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
// Adding mutation batches should not change the highest acked batchID.
- FSTMutationBatch *batch1 = [self addMutationBatch];
- FSTMutationBatch *batch2 = [self addMutationBatch];
- FSTMutationBatch *batch3 = [self addMutationBatch];
- XCTAssertGreaterThan(batch1.batchID, kFSTBatchIDUnknown);
- XCTAssertGreaterThan(batch2.batchID, batch1.batchID);
- XCTAssertGreaterThan(batch3.batchID, batch2.batchID);
-
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
-
- [self acknowledgeBatch:batch1];
- [self acknowledgeBatch:batch2];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
-
- [self removeMutationBatches:@[ batch1 ]];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
-
- [self removeMutationBatches:@[ batch2 ]];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
-
- // Batch 3 never acknowledged.
- [self removeMutationBatches:@[ batch3 ]];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+ self.persistence.run("testAcknowledgeBatchID", [&]() {
+ FSTMutationBatch *batch1 = [self addMutationBatch];
+ FSTMutationBatch *batch2 = [self addMutationBatch];
+ FSTMutationBatch *batch3 = [self addMutationBatch];
+ XCTAssertGreaterThan(batch1.batchID, kFSTBatchIDUnknown);
+ XCTAssertGreaterThan(batch2.batchID, batch1.batchID);
+ XCTAssertGreaterThan(batch3.batchID, batch2.batchID);
+
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
+
+ [self.mutationQueue acknowledgeBatch:batch1 streamToken:nil];
+ [self.mutationQueue acknowledgeBatch:batch2 streamToken:nil];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+
+ [self.mutationQueue removeMutationBatches:@[ batch1 ]];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+
+ [self.mutationQueue removeMutationBatches:@[ batch2 ]];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+
+ // Batch 3 never acknowledged.
+ [self.mutationQueue removeMutationBatches:@[ batch3 ]];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+ });
}
- (void)testAcknowledgeThenRemove {
if ([self isTestBaseClass]) return;
- FSTMutationBatch *batch1 = [self addMutationBatch];
+ self.persistence.run("testAcknowledgeThenRemove", [&]() {
+ FSTMutationBatch *batch1 = [self addMutationBatch];
- FSTWriteGroup *group = [self.persistence startGroupWithAction:NSStringFromSelector(_cmd)];
- [self.mutationQueue acknowledgeBatch:batch1 streamToken:nil];
- [self.mutationQueue removeMutationBatches:@[ batch1 ]];
+ [self.mutationQueue acknowledgeBatch:batch1 streamToken:nil];
+ [self.mutationQueue removeMutationBatches:@[ batch1 ]];
- XCTAssertEqual([self batchCount], 0);
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch1.batchID);
- [self.persistence commitGroup:group];
+ XCTAssertEqual([self batchCount], 0);
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch1.batchID);
+ });
}
- (void)testHighestAcknowledgedBatchIDNeverExceedsNextBatchID {
if ([self isTestBaseClass]) return;
- FSTMutationBatch *batch1 = [self addMutationBatch];
- FSTMutationBatch *batch2 = [self addMutationBatch];
- [self acknowledgeBatch:batch1];
- [self acknowledgeBatch:batch2];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+ FSTMutationBatch *batch1 =
+ self.persistence.run("testHighestAcknowledgedBatchIDNeverExceedsNextBatchID batch1",
+ [&]() -> FSTMutationBatch * { return [self addMutationBatch]; });
+ FSTMutationBatch *batch2 =
+ self.persistence.run("testHighestAcknowledgedBatchIDNeverExceedsNextBatchID batch2",
+ [&]() -> FSTMutationBatch * { return [self addMutationBatch]; });
- [self removeMutationBatches:@[ batch1, batch2 ]];
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+ self.persistence.run("testHighestAcknowledgedBatchIDNeverExceedsNextBatchID", [&]() {
+ [self.mutationQueue acknowledgeBatch:batch1 streamToken:nil];
+ [self.mutationQueue acknowledgeBatch:batch2 streamToken:nil];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+
+ [self.mutationQueue removeMutationBatches:@[ batch1, batch2 ]];
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch2.batchID);
+ });
// Restart the queue so that nextBatchID will be reset.
- self.mutationQueue = [self.persistence mutationQueueForUser:User("user")];
+ FSTMutationBatch *batch = self.persistence.run(
+ "testHighestAcknowledgedBatchIDNeverExceedsNextBatchID restart", [&]() -> FSTMutationBatch * {
+ self.mutationQueue = [self.persistence mutationQueueForUser:User("user")];
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Start MutationQueue"];
- [self.mutationQueue start];
- [self.persistence commitGroup:group];
+ [self.mutationQueue start];
- // Verify that on restart with an empty queue, nextBatchID falls to a lower value.
- XCTAssertLessThan(self.mutationQueue.nextBatchID, batch2.batchID);
+ // Verify that on restart with an empty queue, nextBatchID falls to a lower value.
+ XCTAssertLessThan(self.mutationQueue.nextBatchID, batch2.batchID);
- // As a result highestAcknowledgedBatchID must also reset lower.
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
+ // As a result highestAcknowledgedBatchID must also reset lower.
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
- // The mutation queue will reset the next batchID after all mutations are removed so adding
- // another mutation will cause a collision.
- FSTMutationBatch *newBatch = [self addMutationBatch];
- XCTAssertEqual(newBatch.batchID, batch1.batchID);
+ // The mutation queue will reset the next batchID after all mutations are removed so adding
+ // another mutation will cause a collision.
+ FSTMutationBatch *newBatch = [self addMutationBatch];
+ XCTAssertEqual(newBatch.batchID, batch1.batchID);
+ return newBatch;
+ });
+ self.persistence.run("testHighestAcknowledgedBatchIDNeverExceedsNextBatchID restart2", [&]() {
+ // Restart the queue with one unacknowledged batch in it.
+ [self.mutationQueue start];
- // Restart the queue with one unacknowledged batch in it.
- self.persistence.run([&]() { [self.mutationQueue start]; });
+ XCTAssertEqual([self.mutationQueue nextBatchID], batch.batchID + 1);
- XCTAssertEqual([self.mutationQueue nextBatchID], newBatch.batchID + 1);
-
- // highestAcknowledgedBatchID must still be kFSTBatchIDUnknown.
- XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
+ // highestAcknowledgedBatchID must still be kFSTBatchIDUnknown.
+ XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], kFSTBatchIDUnknown);
+ });
}
- (void)testLookupMutationBatch {
if ([self isTestBaseClass]) return;
// Searching on an empty queue should not find a non-existent batch
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"LookupMutationBatch"];
- FSTMutationBatch *notFound = [self.mutationQueue lookupMutationBatch:42];
- [self.persistence commitGroup:group];
- XCTAssertNil(notFound);
-
- NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
- NSArray<FSTMutationBatch *> *removed = [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
-
- // After removing, a batch should not be found
- group = [self.persistence startGroupWithAction:@"LookupMutationBatch"];
- for (NSUInteger i = 0; i < removed.count; i++) {
- notFound = [self.mutationQueue lookupMutationBatch:removed[i].batchID];
+ self.persistence.run("testLookupMutationBatch", [&]() {
+ FSTMutationBatch *notFound = [self.mutationQueue lookupMutationBatch:42];
XCTAssertNil(notFound);
- }
- // Remaining entries should still be found
- for (FSTMutationBatch *batch in batches) {
- FSTMutationBatch *found = [self.mutationQueue lookupMutationBatch:batch.batchID];
- XCTAssertEqual(found.batchID, batch.batchID);
- }
+ NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
+ NSArray<FSTMutationBatch *> *removed = [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
+
+ // After removing, a batch should not be found
+ for (NSUInteger i = 0; i < removed.count; i++) {
+ notFound = [self.mutationQueue lookupMutationBatch:removed[i].batchID];
+ XCTAssertNil(notFound);
+ }
- // Even on a nonempty queue searching should not find a non-existent batch
- notFound = [self.mutationQueue lookupMutationBatch:42];
- XCTAssertNil(notFound);
- [self.persistence commitGroup:group];
+ // Remaining entries should still be found
+ for (FSTMutationBatch *batch in batches) {
+ FSTMutationBatch *found = [self.mutationQueue lookupMutationBatch:batch.batchID];
+ XCTAssertEqual(found.batchID, batch.batchID);
+ }
+
+ // Even on a nonempty queue searching should not find a non-existent batch
+ notFound = [self.mutationQueue lookupMutationBatch:42];
+ XCTAssertNil(notFound);
+ });
}
- (void)testNextMutationBatchAfterBatchID {
if ([self isTestBaseClass]) return;
- NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
-
- // This is an array of successors assuming the removals below will happen:
- NSArray<FSTMutationBatch *> *afters = @[ batches[3], batches[8], batches[8] ];
- NSArray<FSTMutationBatch *> *removed = [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
-
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"NextMutationBatchAfterBatchID"];
- for (NSUInteger i = 0; i < batches.count - 1; i++) {
- FSTMutationBatch *current = batches[i];
- FSTMutationBatch *next = batches[i + 1];
- FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:current.batchID];
- XCTAssertEqual(found.batchID, next.batchID);
- }
-
- for (NSUInteger i = 0; i < removed.count; i++) {
- FSTMutationBatch *current = removed[i];
- FSTMutationBatch *next = afters[i];
- FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:current.batchID];
- XCTAssertEqual(found.batchID, next.batchID);
- }
-
- FSTMutationBatch *first = batches[0];
- FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:first.batchID - 42];
- XCTAssertEqual(found.batchID, first.batchID);
-
- FSTMutationBatch *last = batches[batches.count - 1];
- FSTMutationBatch *notFound = [self.mutationQueue nextMutationBatchAfterBatchID:last.batchID];
- XCTAssertNil(notFound);
- [self.persistence commitGroup:group];
+ self.persistence.run("testNextMutationBatchAfterBatchID", [&]() {
+ NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
+
+ // This is an array of successors assuming the removals below will happen:
+ NSArray<FSTMutationBatch *> *afters = @[ batches[3], batches[8], batches[8] ];
+ NSArray<FSTMutationBatch *> *removed = [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
+
+ for (NSUInteger i = 0; i < batches.count - 1; i++) {
+ FSTMutationBatch *current = batches[i];
+ FSTMutationBatch *next = batches[i + 1];
+ FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:current.batchID];
+ XCTAssertEqual(found.batchID, next.batchID);
+ }
+
+ for (NSUInteger i = 0; i < removed.count; i++) {
+ FSTMutationBatch *current = removed[i];
+ FSTMutationBatch *next = afters[i];
+ FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:current.batchID];
+ XCTAssertEqual(found.batchID, next.batchID);
+ }
+
+ FSTMutationBatch *first = batches[0];
+ FSTMutationBatch *found = [self.mutationQueue nextMutationBatchAfterBatchID:first.batchID - 42];
+ XCTAssertEqual(found.batchID, first.batchID);
+
+ FSTMutationBatch *last = batches[batches.count - 1];
+ FSTMutationBatch *notFound = [self.mutationQueue nextMutationBatchAfterBatchID:last.batchID];
+ XCTAssertNil(notFound);
+ });
}
- (void)testNextMutationBatchAfterBatchIDSkipsAcknowledgedBatches {
if ([self isTestBaseClass]) return;
- NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:3];
- FSTWriteGroup *group = [self.persistence
- startGroupWithAction:@"NextMutationBatchAfterBatchIDSkipsAcknowledgedBatches"];
- XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:kFSTBatchIDUnknown],
- batches[0]);
- [self.persistence commitGroup:group];
-
- [self acknowledgeBatch:batches[0]];
- group = [self.persistence
- startGroupWithAction:@"NextMutationBatchAfterBatchIDSkipsAcknowledgedBatches"];
- XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:kFSTBatchIDUnknown],
- batches[1]);
- XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:batches[0].batchID],
- batches[1]);
- XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:batches[1].batchID],
- batches[2]);
- [self.persistence commitGroup:group];
+ NSMutableArray<FSTMutationBatch *> *batches = self.persistence.run(
+ "testNextMutationBatchAfterBatchIDSkipsAcknowledgedBatches newBatches",
+ [&]() -> NSMutableArray<FSTMutationBatch *> * {
+ NSMutableArray<FSTMutationBatch *> *newBatches = [self createBatches:3];
+ XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:kFSTBatchIDUnknown],
+ newBatches[0]);
+ return newBatches;
+ });
+ self.persistence.run("testNextMutationBatchAfterBatchIDSkipsAcknowledgedBatches", [&]() {
+
+ [self.mutationQueue acknowledgeBatch:batches[0] streamToken:nil];
+ XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:kFSTBatchIDUnknown],
+ batches[1]);
+ XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:batches[0].batchID],
+ batches[1]);
+ XCTAssertEqualObjects([self.mutationQueue nextMutationBatchAfterBatchID:batches[1].batchID],
+ batches[2]);
+ });
}
- (void)testAllMutationBatchesThroughBatchID {
if ([self isTestBaseClass]) return;
- NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
- [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
+ self.persistence.run("testAllMutationBatchesThroughBatchID", [&]() {
+ NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
+ [self makeHoles:@[ @2, @6, @7 ] inBatches:batches];
- NSArray<FSTMutationBatch *> *found, *expected;
+ NSArray<FSTMutationBatch *> *found, *expected;
- FSTWriteGroup *group =
- [self.persistence startGroupWithAction:@"AllMutationBatchesThroughBatchID"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:batches[0].batchID - 1];
- XCTAssertEqualObjects(found, (@[]));
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:batches[0].batchID - 1];
+ XCTAssertEqualObjects(found, (@[]));
- for (NSUInteger i = 0; i < batches.count; i++) {
- found = [self.mutationQueue allMutationBatchesThroughBatchID:batches[i].batchID];
- expected = [batches subarrayWithRange:NSMakeRange(0, i + 1)];
- XCTAssertEqualObjects(found, expected, @"for index %lu", (unsigned long)i);
- }
- [self.persistence commitGroup:group];
+ for (NSUInteger i = 0; i < batches.count; i++) {
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:batches[i].batchID];
+ expected = [batches subarrayWithRange:NSMakeRange(0, i + 1)];
+ XCTAssertEqualObjects(found, expected, @"for index %lu", (unsigned long)i);
+ }
+ });
}
- (void)testAllMutationBatchesAffectingDocumentKey {
if ([self isTestBaseClass]) return;
- NSArray<FSTMutation *> *mutations = @[
- FSTTestSetMutation(@"fob/bar",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"foo/bar",
- @{ @"a" : @1 }),
- FSTTestPatchMutation("foo/bar",
- @{ @"b" : @1 }, {}),
- FSTTestSetMutation(@"foo/bar/suffix/key",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"foo/baz",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"food/bar",
- @{ @"a" : @1 })
- ];
-
- // Store all the mutations.
- NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"New mutation batch"];
- for (FSTMutation *mutation in mutations) {
- FSTMutationBatch *batch =
- [self.mutationQueue addMutationBatchWithWriteTime:[FIRTimestamp timestamp]
- mutations:@[ mutation ]];
- [batches addObject:batch];
- }
-
- NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2] ];
- NSArray<FSTMutationBatch *> *matches =
- [self.mutationQueue allMutationBatchesAffectingDocumentKey:testutil::Key("foo/bar")];
-
- [self.persistence commitGroup:group];
- XCTAssertEqualObjects(matches, expected);
+ self.persistence.run("testAllMutationBatchesAffectingDocumentKey", [&]() {
+ NSArray<FSTMutation *> *mutations = @[
+ FSTTestSetMutation(@"fob/bar",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"foo/bar",
+ @{ @"a" : @1 }),
+ FSTTestPatchMutation("foo/bar",
+ @{ @"b" : @1 }, {}),
+ FSTTestSetMutation(@"foo/bar/suffix/key",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"foo/baz",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"food/bar",
+ @{ @"a" : @1 })
+ ];
+
+ // Store all the mutations.
+ NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
+ for (FSTMutation *mutation in mutations) {
+ FSTMutationBatch *batch =
+ [self.mutationQueue addMutationBatchWithWriteTime:[FIRTimestamp timestamp]
+ mutations:@[ mutation ]];
+ [batches addObject:batch];
+ }
+
+ NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2] ];
+ NSArray<FSTMutationBatch *> *matches =
+ [self.mutationQueue allMutationBatchesAffectingDocumentKey:testutil::Key("foo/bar")];
+
+ XCTAssertEqualObjects(matches, expected);
+ });
}
- (void)testAllMutationBatchesAffectingQuery {
if ([self isTestBaseClass]) return;
- NSArray<FSTMutation *> *mutations = @[
- FSTTestSetMutation(@"fob/bar",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"foo/bar",
- @{ @"a" : @1 }),
- FSTTestPatchMutation("foo/bar",
- @{ @"b" : @1 }, {}),
- FSTTestSetMutation(@"foo/bar/suffix/key",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"foo/baz",
- @{ @"a" : @1 }),
- FSTTestSetMutation(@"food/bar",
- @{ @"a" : @1 })
- ];
-
- // Store all the mutations.
- NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"New mutation batch"];
- for (FSTMutation *mutation in mutations) {
- FSTMutationBatch *batch =
- [self.mutationQueue addMutationBatchWithWriteTime:[FIRTimestamp timestamp]
- mutations:@[ mutation ]];
- [batches addObject:batch];
- }
-
- NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2], batches[4] ];
- FSTQuery *query = FSTTestQuery("foo");
- NSArray<FSTMutationBatch *> *matches =
- [self.mutationQueue allMutationBatchesAffectingQuery:query];
- [self.persistence commitGroup:group];
-
- XCTAssertEqualObjects(matches, expected);
+ self.persistence.run("testAllMutationBatchesAffectingQuery", [&]() {
+ NSArray<FSTMutation *> *mutations = @[
+ FSTTestSetMutation(@"fob/bar",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"foo/bar",
+ @{ @"a" : @1 }),
+ FSTTestPatchMutation("foo/bar",
+ @{ @"b" : @1 }, {}),
+ FSTTestSetMutation(@"foo/bar/suffix/key",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"foo/baz",
+ @{ @"a" : @1 }),
+ FSTTestSetMutation(@"food/bar",
+ @{ @"a" : @1 })
+ ];
+
+ // Store all the mutations.
+ NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
+ for (FSTMutation *mutation in mutations) {
+ FSTMutationBatch *batch =
+ [self.mutationQueue addMutationBatchWithWriteTime:[FIRTimestamp timestamp]
+ mutations:@[ mutation ]];
+ [batches addObject:batch];
+ }
+
+ NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2], batches[4] ];
+ FSTQuery *query = FSTTestQuery("foo");
+ NSArray<FSTMutationBatch *> *matches =
+ [self.mutationQueue allMutationBatchesAffectingQuery:query];
+
+ XCTAssertEqualObjects(matches, expected);
+ });
}
- (void)testRemoveMutationBatches {
if ([self isTestBaseClass]) return;
- NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
- FSTMutationBatch *last = batches[batches.count - 1];
-
- [self removeMutationBatches:@[ batches[0] ]];
- [batches removeObjectAtIndex:0];
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- XCTAssertEqual([self batchCount], 9);
- [self.persistence commitGroup:group];
-
- NSArray<FSTMutationBatch *> *found;
-
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
- XCTAssertEqualObjects(found, batches);
- XCTAssertEqual(found.count, 9);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[0], batches[1], batches[2] ]];
- [batches removeObjectsInRange:NSMakeRange(0, 3)];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- XCTAssertEqual([self batchCount], 6);
- [self.persistence commitGroup:group];
-
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
- XCTAssertEqualObjects(found, batches);
- XCTAssertEqual(found.count, 6);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[batches.count - 1] ]];
- [batches removeObjectAtIndex:batches.count - 1];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- XCTAssertEqual([self batchCount], 5);
- [self.persistence commitGroup:group];
-
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
- XCTAssertEqualObjects(found, batches);
- XCTAssertEqual(found.count, 5);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[3] ]];
- [batches removeObjectAtIndex:3];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- XCTAssertEqual([self batchCount], 4);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[1] ]];
- [batches removeObjectAtIndex:1];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- XCTAssertEqual([self batchCount], 3);
- [self.persistence commitGroup:group];
-
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
- XCTAssertEqualObjects(found, batches);
- XCTAssertEqual(found.count, 3);
- XCTAssertFalse([self.mutationQueue isEmpty]);
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:batches];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatches"];
- found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
- XCTAssertEqualObjects(found, @[]);
- XCTAssertEqual(found.count, 0);
- XCTAssertTrue([self.mutationQueue isEmpty]);
- [self.persistence commitGroup:group];
+ self.persistence.run("testRemoveMutationBatches", [&]() {
+ NSMutableArray<FSTMutationBatch *> *batches = [self createBatches:10];
+
+ [self.mutationQueue removeMutationBatches:@[ batches[0] ]];
+ [batches removeObjectAtIndex:0];
+
+ FSTMutationBatch *last = batches[batches.count - 1];
+ XCTAssertEqual([self batchCount], 9);
+
+ NSArray<FSTMutationBatch *> *found;
+
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
+ XCTAssertEqualObjects(found, batches);
+ XCTAssertEqual(found.count, 9);
+
+ [self.mutationQueue removeMutationBatches:@[ batches[0], batches[1], batches[2] ]];
+ [batches removeObjectsInRange:NSMakeRange(0, 3)];
+ XCTAssertEqual([self batchCount], 6);
+
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
+ XCTAssertEqualObjects(found, batches);
+ XCTAssertEqual(found.count, 6);
+
+ [self.mutationQueue removeMutationBatches:@[ batches[batches.count - 1] ]];
+ [batches removeObjectAtIndex:batches.count - 1];
+ XCTAssertEqual([self batchCount], 5);
+
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
+ XCTAssertEqualObjects(found, batches);
+ XCTAssertEqual(found.count, 5);
+
+ [self.mutationQueue removeMutationBatches:@[ batches[3] ]];
+ [batches removeObjectAtIndex:3];
+ XCTAssertEqual([self batchCount], 4);
+
+ [self.mutationQueue removeMutationBatches:@[ batches[1] ]];
+ [batches removeObjectAtIndex:1];
+ XCTAssertEqual([self batchCount], 3);
+
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
+ XCTAssertEqualObjects(found, batches);
+ XCTAssertEqual(found.count, 3);
+ XCTAssertFalse([self.mutationQueue isEmpty]);
+
+ [self.mutationQueue removeMutationBatches:batches];
+ found = [self.mutationQueue allMutationBatchesThroughBatchID:last.batchID];
+ XCTAssertEqualObjects(found, @[]);
+ XCTAssertEqual(found.count, 0);
+ XCTAssertTrue([self.mutationQueue isEmpty]);
+ });
}
- (void)testRemoveMutationBatchesEmitsGarbageEvents {
@@ -428,52 +412,41 @@ NS_ASSUME_NONNULL_BEGIN
[garbageCollector addGarbageSource:self.mutationQueue];
NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
- [batches addObjectsFromArray:@[
- [self addMutationBatchWithKey:@"foo/bar"],
- [self addMutationBatchWithKey:@"foo/ba"],
- [self addMutationBatchWithKey:@"foo/bar2"],
- [self addMutationBatchWithKey:@"foo/bar"],
- [self addMutationBatchWithKey:@"foo/bar/suffix/baz"],
- [self addMutationBatchWithKey:@"bar/baz"],
- ]];
-
- [self removeMutationBatches:@[ batches[0] ]];
- FSTWriteGroup *group =
- [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- std::set<DocumentKey> garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage, std::set<DocumentKey>({}));
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[1] ]];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("foo/ba")}));
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[5] ]];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("bar/baz")}));
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[2], batches[3] ]];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage,
- std::set<DocumentKey>({testutil::Key("foo/bar"), testutil::Key("foo/bar2")}));
- [self.persistence commitGroup:group];
-
- [batches addObject:[self addMutationBatchWithKey:@"foo/bar/suffix/baz"]];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage, std::set<DocumentKey>({}));
- [self.persistence commitGroup:group];
-
- [self removeMutationBatches:@[ batches[4], batches[6] ]];
- group = [self.persistence startGroupWithAction:@"RemoveMutationBatchesEmitsGarbageEvents"];
- garbage = [garbageCollector collectGarbage];
- XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("foo/bar/suffix/baz")}));
- [self.persistence commitGroup:group];
+ self.persistence.run("testRemoveMutationBatchesEmitsGarbageEvents", [&]() {
+ [batches addObjectsFromArray:@[
+ [self addMutationBatchWithKey:@"foo/bar"],
+ [self addMutationBatchWithKey:@"foo/ba"],
+ [self addMutationBatchWithKey:@"foo/bar2"],
+ [self addMutationBatchWithKey:@"foo/bar"],
+ [self addMutationBatchWithKey:@"foo/bar/suffix/baz"],
+ [self addMutationBatchWithKey:@"bar/baz"],
+ ]];
+
+ [self.mutationQueue removeMutationBatches:@[ batches[0] ]];
+ std::set<DocumentKey> garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage, std::set<DocumentKey>({}));
+
+ [self.mutationQueue removeMutationBatches:@[ batches[1] ]];
+ garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("foo/ba")}));
+
+ [self.mutationQueue removeMutationBatches:@[ batches[5] ]];
+ garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("bar/baz")}));
+
+ [self.mutationQueue removeMutationBatches:@[ batches[2], batches[3] ]];
+ garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage,
+ std::set<DocumentKey>({testutil::Key("foo/bar"), testutil::Key("foo/bar2")}));
+
+ [batches addObject:[self addMutationBatchWithKey:@"foo/bar/suffix/baz"]];
+ garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage, std::set<DocumentKey>({}));
+
+ [self.mutationQueue removeMutationBatches:@[ batches[4], batches[6] ]];
+ garbage = [garbageCollector collectGarbage];
+ XCTAssertEqual(garbage, std::set<DocumentKey>({testutil::Key("foo/bar/suffix/baz")}));
+ });
}
- (void)testStreamToken {
@@ -482,20 +455,22 @@ NS_ASSUME_NONNULL_BEGIN
NSData *streamToken1 = [@"token1" dataUsingEncoding:NSUTF8StringEncoding];
NSData *streamToken2 = [@"token2" dataUsingEncoding:NSUTF8StringEncoding];
- self.persistence.run([&]() { [self.mutationQueue setLastStreamToken:streamToken1]; });
-
- FSTMutationBatch *batch1 = [self addMutationBatch];
- [self addMutationBatch];
+ self.persistence.run("testStreamToken", [&]() {
+ [self.mutationQueue setLastStreamToken:streamToken1];
- XCTAssertEqualObjects([self.mutationQueue lastStreamToken], streamToken1);
+ FSTMutationBatch *batch1 = [self addMutationBatch];
+ [self addMutationBatch];
- self.persistence.run(
- [&]() { [self.mutationQueue acknowledgeBatch:batch1 streamToken:streamToken2]; });
+ XCTAssertEqualObjects([self.mutationQueue lastStreamToken], streamToken1);
- XCTAssertEqual(self.mutationQueue.highestAcknowledgedBatchID, batch1.batchID);
- XCTAssertEqualObjects([self.mutationQueue lastStreamToken], streamToken2);
+ [self.mutationQueue acknowledgeBatch:batch1 streamToken:streamToken2];
+ XCTAssertEqual(self.mutationQueue.highestAcknowledgedBatchID, batch1.batchID);
+ XCTAssertEqualObjects([self.mutationQueue lastStreamToken], streamToken2);
+ });
}
+#pragma mark - Helpers
+
/** Creates a new FSTMutationBatch with the next batch ID and a set of dummy mutations. */
- (FSTMutationBatch *)addMutationBatch {
return [self addMutationBatchWithKey:@"foo/bar"];
@@ -508,11 +483,9 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTMutationBatch *)addMutationBatchWithKey:(NSString *)key {
FSTSetMutation *mutation = FSTTestSetMutation(key, @{ @"a" : @1 });
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"New mutation batch"];
FSTMutationBatch *batch =
[self.mutationQueue addMutationBatchWithWriteTime:[FIRTimestamp timestamp]
mutations:@[ mutation ]];
- [self.persistence commitGroup:group];
return batch;
}
@@ -531,23 +504,6 @@ NS_ASSUME_NONNULL_BEGIN
return batches;
}
-/**
- * Calls -acknowledgeBatch:streamToken:group: on the mutation queue in a new group and commits the
- * the group.
- */
-// TODO(gsoltis): delete this helper, just run it in a transaction directly
-- (void)acknowledgeBatch:(FSTMutationBatch *)batch {
- self.persistence.run([&]() { [self.mutationQueue acknowledgeBatch:batch streamToken:nil]; });
-}
-
-/**
- * Calls -removeMutationBatches:group: on the mutation queue in a new group and commits the group.
- */
-// TODO(gsoltis): delete this helper, just run it in a transaction directly
-- (void)removeMutationBatches:(NSArray<FSTMutationBatch *> *)batches {
- self.persistence.run([&]() { [self.mutationQueue removeMutationBatches:batches]; });
-}
-
/** Returns the number of mutation batches in the mutation queue. */
- (NSUInteger)batchCount {
return [self.mutationQueue allMutationBatches].count;
@@ -567,7 +523,7 @@ NS_ASSUME_NONNULL_BEGIN
for (NSUInteger i = 0; i < holes.count; i++) {
NSUInteger index = holes[i].unsignedIntegerValue - i;
FSTMutationBatch *batch = batches[index];
- [self removeMutationBatches:@[ batch ]];
+ [self.mutationQueue removeMutationBatches:@[ batch ]];
[batches removeObjectAtIndex:index];
[removed addObject:batch];
diff --git a/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm
index b575004..956afa9 100644
--- a/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm
+++ b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm
@@ -21,7 +21,6 @@
#import "Firestore/Source/Local/FSTEagerGarbageCollector.h"
#import "Firestore/Source/Local/FSTPersistence.h"
#import "Firestore/Source/Local/FSTQueryData.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
#import "Firestore/third_party/Immutable/Tests/FSTImmutableSortedSet+Testing.h"
@@ -61,339 +60,344 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testReadQueryNotInCache {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"ReadQueryNotInCache"];
- XCTAssertNil([self.queryCache queryDataForQuery:_queryRooms]);
- [self.persistence commitGroup:group];
+ self.persistence.run("testReadQueryNotInCache",
+ [&]() { XCTAssertNil([self.queryCache queryDataForQuery:_queryRooms]); });
}
- (void)testSetAndReadAQuery {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"SetAndReadQuery"];
- FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
- [self.queryCache addQueryData:queryData];
+ self.persistence.run("testSetAndReadAQuery", [&]() {
+ FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
+ [self.queryCache addQueryData:queryData];
- FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
- XCTAssertEqualObjects(result.query, queryData.query);
- XCTAssertEqual(result.targetID, queryData.targetID);
- XCTAssertEqualObjects(result.resumeToken, queryData.resumeToken);
- [self.persistence commitGroup:group];
+ FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
+ XCTAssertEqualObjects(result.query, queryData.query);
+ XCTAssertEqual(result.targetID, queryData.targetID);
+ XCTAssertEqualObjects(result.resumeToken, queryData.resumeToken);
+ });
}
- (void)testCanonicalIDCollision {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"CanonicalIDCollision"];
- // Type information is currently lost in our canonicalID implementations so this currently an
- // easy way to force colliding canonicalIDs
- FSTQuery *q1 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @(1))];
- FSTQuery *q2 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @"1")];
- XCTAssertEqualObjects(q1.canonicalID, q2.canonicalID);
-
- FSTQueryData *data1 = [self queryDataWithQuery:q1];
- [self.queryCache addQueryData:data1];
-
- // Using the other query should not return the query cache entry despite equal canonicalIDs.
- XCTAssertNil([self.queryCache queryDataForQuery:q2]);
- XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
-
- FSTQueryData *data2 = [self queryDataWithQuery:q2];
- [self.queryCache addQueryData:data2];
- XCTAssertEqual([self.queryCache count], 2);
-
- XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
- XCTAssertEqualObjects([self.queryCache queryDataForQuery:q2], data2);
-
- [self.queryCache removeQueryData:data1];
- XCTAssertNil([self.queryCache queryDataForQuery:q1]);
- XCTAssertEqualObjects([self.queryCache queryDataForQuery:q2], data2);
- XCTAssertEqual([self.queryCache count], 1);
-
- [self.queryCache removeQueryData:data2];
- XCTAssertNil([self.queryCache queryDataForQuery:q1]);
- XCTAssertNil([self.queryCache queryDataForQuery:q2]);
- XCTAssertEqual([self.queryCache count], 0);
- [self.persistence commitGroup:group];
+ self.persistence.run("testCanonicalIDCollision", [&]() {
+ // Type information is currently lost in our canonicalID implementations so this currently an
+ // easy way to force colliding canonicalIDs
+ FSTQuery *q1 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @(1))];
+ FSTQuery *q2 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @"1")];
+ XCTAssertEqualObjects(q1.canonicalID, q2.canonicalID);
+
+ FSTQueryData *data1 = [self queryDataWithQuery:q1];
+ [self.queryCache addQueryData:data1];
+
+ // Using the other query should not return the query cache entry despite equal canonicalIDs.
+ XCTAssertNil([self.queryCache queryDataForQuery:q2]);
+ XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
+
+ FSTQueryData *data2 = [self queryDataWithQuery:q2];
+ [self.queryCache addQueryData:data2];
+ XCTAssertEqual([self.queryCache count], 2);
+
+ XCTAssertEqualObjects([self.queryCache queryDataForQuery:q1], data1);
+ XCTAssertEqualObjects([self.queryCache queryDataForQuery:q2], data2);
+
+ [self.queryCache removeQueryData:data1];
+ XCTAssertNil([self.queryCache queryDataForQuery:q1]);
+ XCTAssertEqualObjects([self.queryCache queryDataForQuery:q2], data2);
+ XCTAssertEqual([self.queryCache count], 1);
+
+ [self.queryCache removeQueryData:data2];
+ XCTAssertNil([self.queryCache queryDataForQuery:q1]);
+ XCTAssertNil([self.queryCache queryDataForQuery:q2]);
+ XCTAssertEqual([self.queryCache count], 0);
+ });
}
- (void)testSetQueryToNewValue {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"SetQueryToNewValue"];
- FSTQueryData *queryData1 =
- [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:1];
- [self.queryCache addQueryData:queryData1];
-
- FSTQueryData *queryData2 =
- [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:2];
- [self.queryCache addQueryData:queryData2];
-
- FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
- XCTAssertNotEqualObjects(queryData2.resumeToken, queryData1.resumeToken);
- XCTAssertNotEqualObjects(queryData2.snapshotVersion, queryData1.snapshotVersion);
- XCTAssertEqualObjects(result.resumeToken, queryData2.resumeToken);
- XCTAssertEqualObjects(result.snapshotVersion, queryData2.snapshotVersion);
- [self.persistence commitGroup:group];
+ self.persistence.run("testSetQueryToNewValue", [&]() {
+ FSTQueryData *queryData1 =
+ [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:1];
+ [self.queryCache addQueryData:queryData1];
+
+ FSTQueryData *queryData2 =
+ [self queryDataWithQuery:_queryRooms targetID:1 listenSequenceNumber:10 version:2];
+ [self.queryCache addQueryData:queryData2];
+
+ FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
+ XCTAssertNotEqualObjects(queryData2.resumeToken, queryData1.resumeToken);
+ XCTAssertNotEqualObjects(queryData2.snapshotVersion, queryData1.snapshotVersion);
+ XCTAssertEqualObjects(result.resumeToken, queryData2.resumeToken);
+ XCTAssertEqualObjects(result.snapshotVersion, queryData2.snapshotVersion);
+ });
}
- (void)testRemoveQuery {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveQuery"];
- FSTQueryData *queryData1 = [self queryDataWithQuery:_queryRooms];
- [self.queryCache addQueryData:queryData1];
+ self.persistence.run("testRemoveQuery", [&]() {
+ FSTQueryData *queryData1 = [self queryDataWithQuery:_queryRooms];
+ [self.queryCache addQueryData:queryData1];
- [self.queryCache removeQueryData:queryData1];
+ [self.queryCache removeQueryData:queryData1];
- FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
- XCTAssertNil(result);
- [self.persistence commitGroup:group];
+ FSTQueryData *result = [self.queryCache queryDataForQuery:_queryRooms];
+ XCTAssertNil(result);
+ });
}
- (void)testRemoveNonExistentQuery {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveNonExistentQuery"];
- FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
+ self.persistence.run("testRemoveNonExistentQuery", [&]() {
+ FSTQueryData *queryData = [self queryDataWithQuery:_queryRooms];
- // no-op, but make sure it doesn't throw.
- XCTAssertNoThrow([self.queryCache removeQueryData:queryData]);
- [self.persistence commitGroup:group];
+ // no-op, but make sure it doesn't throw.
+ XCTAssertNoThrow([self.queryCache removeQueryData:queryData]);
+ });
}
- (void)testRemoveQueryRemovesMatchingKeysToo {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group =
- [self.persistence startGroupWithAction:@"RemoveQueryRemovesMatchingKeysToo"];
- FSTQueryData *rooms = [self queryDataWithQuery:_queryRooms];
- [self.queryCache addQueryData:rooms];
+ self.persistence.run("testRemoveQueryRemovesMatchingKeysToo", [&]() {
+ FSTQueryData *rooms = [self queryDataWithQuery:_queryRooms];
+ [self.queryCache addQueryData:rooms];
- DocumentKey key1 = testutil::Key("rooms/foo");
- DocumentKey key2 = testutil::Key("rooms/bar");
- [self addMatchingKey:key1 forTargetID:rooms.targetID];
- [self addMatchingKey:key2 forTargetID:rooms.targetID];
+ DocumentKey key1 = testutil::Key("rooms/foo");
+ DocumentKey key2 = testutil::Key("rooms/bar");
+ [self addMatchingKey:key1 forTargetID:rooms.targetID];
+ [self addMatchingKey:key2 forTargetID:rooms.targetID];
- XCTAssertTrue([self.queryCache containsKey:key1]);
- XCTAssertTrue([self.queryCache containsKey:key2]);
+ XCTAssertTrue([self.queryCache containsKey:key1]);
+ XCTAssertTrue([self.queryCache containsKey:key2]);
- [self.queryCache removeQueryData:rooms];
- XCTAssertFalse([self.queryCache containsKey:key1]);
- XCTAssertFalse([self.queryCache containsKey:key2]);
- [self.persistence commitGroup:group];
+ [self.queryCache removeQueryData:rooms];
+ XCTAssertFalse([self.queryCache containsKey:key1]);
+ XCTAssertFalse([self.queryCache containsKey:key2]);
+ });
}
- (void)testAddOrRemoveMatchingKeys {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"AddOrRemoveMatchingKeys"];
- DocumentKey key = testutil::Key("foo/bar");
+ self.persistence.run("testAddOrRemoveMatchingKeys", [&]() {
+ DocumentKey key = testutil::Key("foo/bar");
- XCTAssertFalse([self.queryCache containsKey:key]);
+ XCTAssertFalse([self.queryCache containsKey:key]);
- [self addMatchingKey:key forTargetID:1];
- XCTAssertTrue([self.queryCache containsKey:key]);
+ [self addMatchingKey:key forTargetID:1];
+ XCTAssertTrue([self.queryCache containsKey:key]);
- [self addMatchingKey:key forTargetID:2];
- XCTAssertTrue([self.queryCache containsKey:key]);
+ [self addMatchingKey:key forTargetID:2];
+ XCTAssertTrue([self.queryCache containsKey:key]);
- [self removeMatchingKey:key forTargetID:1];
- XCTAssertTrue([self.queryCache containsKey:key]);
+ [self removeMatchingKey:key forTargetID:1];
+ XCTAssertTrue([self.queryCache containsKey:key]);
- [self removeMatchingKey:key forTargetID:2];
- XCTAssertFalse([self.queryCache containsKey:key]);
- [self.persistence commitGroup:group];
+ [self removeMatchingKey:key forTargetID:2];
+ XCTAssertFalse([self.queryCache containsKey:key]);
+ });
}
- (void)testRemoveMatchingKeysForTargetID {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveMatchingKeysForTargetID"];
- DocumentKey key1 = testutil::Key("foo/bar");
- DocumentKey key2 = testutil::Key("foo/baz");
- DocumentKey key3 = testutil::Key("foo/blah");
-
- [self addMatchingKey:key1 forTargetID:1];
- [self addMatchingKey:key2 forTargetID:1];
- [self addMatchingKey:key3 forTargetID:2];
- XCTAssertTrue([self.queryCache containsKey:key1]);
- XCTAssertTrue([self.queryCache containsKey:key2]);
- XCTAssertTrue([self.queryCache containsKey:key3]);
-
- [self.queryCache removeMatchingKeysForTargetID:1];
- XCTAssertFalse([self.queryCache containsKey:key1]);
- XCTAssertFalse([self.queryCache containsKey:key2]);
- XCTAssertTrue([self.queryCache containsKey:key3]);
-
- [self.queryCache removeMatchingKeysForTargetID:2];
- XCTAssertFalse([self.queryCache containsKey:key1]);
- XCTAssertFalse([self.queryCache containsKey:key2]);
- XCTAssertFalse([self.queryCache containsKey:key3]);
- [self.persistence commitGroup:group];
+ self.persistence.run("testRemoveMatchingKeysForTargetID", [&]() {
+ DocumentKey key1 = testutil::Key("foo/bar");
+ DocumentKey key2 = testutil::Key("foo/baz");
+ DocumentKey key3 = testutil::Key("foo/blah");
+
+ [self addMatchingKey:key1 forTargetID:1];
+ [self addMatchingKey:key2 forTargetID:1];
+ [self addMatchingKey:key3 forTargetID:2];
+ XCTAssertTrue([self.queryCache containsKey:key1]);
+ XCTAssertTrue([self.queryCache containsKey:key2]);
+ XCTAssertTrue([self.queryCache containsKey:key3]);
+
+ [self.queryCache removeMatchingKeysForTargetID:1];
+ XCTAssertFalse([self.queryCache containsKey:key1]);
+ XCTAssertFalse([self.queryCache containsKey:key2]);
+ XCTAssertTrue([self.queryCache containsKey:key3]);
+
+ [self.queryCache removeMatchingKeysForTargetID:2];
+ XCTAssertFalse([self.queryCache containsKey:key1]);
+ XCTAssertFalse([self.queryCache containsKey:key2]);
+ XCTAssertFalse([self.queryCache containsKey:key3]);
+ });
}
- (void)testRemoveEmitsGarbageEvents {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveEmitsGarbageEvents"];
- FSTEagerGarbageCollector *garbageCollector = [[FSTEagerGarbageCollector alloc] init];
- [garbageCollector addGarbageSource:self.queryCache];
- XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({}));
+ self.persistence.run("testRemoveEmitsGarbageEvents", [&]() {
+ FSTEagerGarbageCollector *garbageCollector = [[FSTEagerGarbageCollector alloc] init];
+ [garbageCollector addGarbageSource:self.queryCache];
+ XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({}));
- FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery("rooms")];
- DocumentKey room1 = testutil::Key("rooms/bar");
- DocumentKey room2 = testutil::Key("rooms/foo");
- [self.queryCache addQueryData:rooms];
- [self addMatchingKey:room1 forTargetID:rooms.targetID];
- [self addMatchingKey:room2 forTargetID:rooms.targetID];
+ FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery("rooms")];
+ DocumentKey room1 = testutil::Key("rooms/bar");
+ DocumentKey room2 = testutil::Key("rooms/foo");
+ [self.queryCache addQueryData:rooms];
+ [self addMatchingKey:room1 forTargetID:rooms.targetID];
+ [self addMatchingKey:room2 forTargetID:rooms.targetID];
- FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery("halls")];
- DocumentKey hall1 = testutil::Key("halls/bar");
- DocumentKey hall2 = testutil::Key("halls/foo");
- [self.queryCache addQueryData:halls];
- [self addMatchingKey:hall1 forTargetID:halls.targetID];
- [self addMatchingKey:hall2 forTargetID:halls.targetID];
+ FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery("halls")];
+ DocumentKey hall1 = testutil::Key("halls/bar");
+ DocumentKey hall2 = testutil::Key("halls/foo");
+ [self.queryCache addQueryData:halls];
+ [self addMatchingKey:hall1 forTargetID:halls.targetID];
+ [self addMatchingKey:hall2 forTargetID:halls.targetID];
- XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({}));
+ XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({}));
- [self removeMatchingKey:room1 forTargetID:rooms.targetID];
- XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({room1}));
+ [self removeMatchingKey:room1 forTargetID:rooms.targetID];
+ XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({room1}));
- [self.queryCache removeQueryData:rooms];
- XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({room2}));
+ [self.queryCache removeQueryData:rooms];
+ XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({room2}));
- [self.queryCache removeMatchingKeysForTargetID:halls.targetID];
- XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({hall1, hall2}));
- [self.persistence commitGroup:group];
+ [self.queryCache removeMatchingKeysForTargetID:halls.targetID];
+ XCTAssertEqual([garbageCollector collectGarbage], std::set<DocumentKey>({hall1, hall2}));
+ });
}
- (void)testMatchingKeysForTargetID {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"MatchingKeysForTargetID"];
- DocumentKey key1 = testutil::Key("foo/bar");
- DocumentKey key2 = testutil::Key("foo/baz");
- DocumentKey key3 = testutil::Key("foo/blah");
+ self.persistence.run("testMatchingKeysForTargetID", [&]() {
+ DocumentKey key1 = testutil::Key("foo/bar");
+ DocumentKey key2 = testutil::Key("foo/baz");
+ DocumentKey key3 = testutil::Key("foo/blah");
- [self addMatchingKey:key1 forTargetID:1];
- [self addMatchingKey:key2 forTargetID:1];
- [self addMatchingKey:key3 forTargetID:2];
+ [self addMatchingKey:key1 forTargetID:1];
+ [self addMatchingKey:key2 forTargetID:1];
+ [self addMatchingKey:key3 forTargetID:2];
- FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:1], (@[ key1, key2 ]));
- FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:2], @[ key3 ]);
+ FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:1], (@[ key1, key2 ]));
+ FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:2], @[ key3 ]);
- [self addMatchingKey:key1 forTargetID:2];
- FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:1], (@[ key1, key2 ]));
- FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:2], (@[ key1, key3 ]));
- [self.persistence commitGroup:group];
+ [self addMatchingKey:key1 forTargetID:2];
+ FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:1], (@[ key1, key2 ]));
+ FSTAssertEqualSets([self.queryCache matchingKeysForTargetID:2], (@[ key1, key3 ]));
+ });
}
- (void)testHighestListenSequenceNumber {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"HighestListenSequenceNumber"];
- FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms")
- targetID:1
- listenSequenceNumber:10
- purpose:FSTQueryPurposeListen];
- [self.queryCache addQueryData:query1];
- FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls")
- targetID:2
- listenSequenceNumber:20
- purpose:FSTQueryPurposeListen];
- [self.queryCache addQueryData:query2];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
-
- // TargetIDs never come down.
- [self.queryCache removeQueryData:query2];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
-
- // A query with an empty result set still counts.
- FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages")
- targetID:42
- listenSequenceNumber:100
- purpose:FSTQueryPurposeListen];
- [self.queryCache addQueryData:query3];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
-
- [self.queryCache removeQueryData:query1];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
-
- [self.queryCache removeQueryData:query3];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
- [self.persistence commitGroup:group];
+ self.persistence.run("testHighestListenSequenceNumber", [&]() {
+ FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms")
+ targetID:1
+ listenSequenceNumber:10
+ purpose:FSTQueryPurposeListen];
+ [self.queryCache addQueryData:query1];
+ FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls")
+ targetID:2
+ listenSequenceNumber:20
+ purpose:FSTQueryPurposeListen];
+ [self.queryCache addQueryData:query2];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
+
+ // TargetIDs never come down.
+ [self.queryCache removeQueryData:query2];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20);
+
+ // A query with an empty result set still counts.
+ FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages")
+ targetID:42
+ listenSequenceNumber:100
+ purpose:FSTQueryPurposeListen];
+ [self.queryCache addQueryData:query3];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+
+ [self.queryCache removeQueryData:query1];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+
+ [self.queryCache removeQueryData:query3];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+ });
// Verify that the highestTargetID even survives restarts.
- self.queryCache = [self.persistence queryCache];
- [self.queryCache start];
- XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+ self.persistence.run("testHighestListenSequenceNumber restart", [&]() {
+ self.queryCache = [self.persistence queryCache];
+ [self.queryCache start];
+ XCTAssertEqual([self.queryCache highestListenSequenceNumber], 100);
+ });
}
- (void)testHighestTargetID {
if ([self isTestBaseClass]) return;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoveMatchingKeysForTargetID"];
- XCTAssertEqual([self.queryCache highestTargetID], 0);
-
- FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms")
- targetID:1
- listenSequenceNumber:10
- purpose:FSTQueryPurposeListen];
- DocumentKey key1 = testutil::Key("rooms/bar");
- DocumentKey key2 = testutil::Key("rooms/foo");
- [self.queryCache addQueryData:query1];
- [self addMatchingKey:key1 forTargetID:1];
- [self addMatchingKey:key2 forTargetID:1];
-
- FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls")
- targetID:2
- listenSequenceNumber:20
- purpose:FSTQueryPurposeListen];
- DocumentKey key3 = testutil::Key("halls/foo");
- [self.queryCache addQueryData:query2];
- [self addMatchingKey:key3 forTargetID:2];
- XCTAssertEqual([self.queryCache highestTargetID], 2);
-
- // TargetIDs never come down.
- [self.queryCache removeQueryData:query2];
- XCTAssertEqual([self.queryCache highestTargetID], 2);
-
- // A query with an empty result set still counts.
- FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages")
- targetID:42
- listenSequenceNumber:100
- purpose:FSTQueryPurposeListen];
- [self.queryCache addQueryData:query3];
- XCTAssertEqual([self.queryCache highestTargetID], 42);
-
- [self.queryCache removeQueryData:query1];
- XCTAssertEqual([self.queryCache highestTargetID], 42);
-
- [self.queryCache removeQueryData:query3];
- XCTAssertEqual([self.queryCache highestTargetID], 42);
- [self.persistence commitGroup:group];
+ self.persistence.run("testHighestTargetID", [&]() {
+ XCTAssertEqual([self.queryCache highestTargetID], 0);
+
+ FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms")
+ targetID:1
+ listenSequenceNumber:10
+ purpose:FSTQueryPurposeListen];
+ DocumentKey key1 = testutil::Key("rooms/bar");
+ DocumentKey key2 = testutil::Key("rooms/foo");
+ [self.queryCache addQueryData:query1];
+ [self addMatchingKey:key1 forTargetID:1];
+ [self addMatchingKey:key2 forTargetID:1];
+
+ FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls")
+ targetID:2
+ listenSequenceNumber:20
+ purpose:FSTQueryPurposeListen];
+ DocumentKey key3 = testutil::Key("halls/foo");
+ [self.queryCache addQueryData:query2];
+ [self addMatchingKey:key3 forTargetID:2];
+ XCTAssertEqual([self.queryCache highestTargetID], 2);
+
+ // TargetIDs never come down.
+ [self.queryCache removeQueryData:query2];
+ XCTAssertEqual([self.queryCache highestTargetID], 2);
+
+ // A query with an empty result set still counts.
+ FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages")
+ targetID:42
+ listenSequenceNumber:100
+ purpose:FSTQueryPurposeListen];
+ [self.queryCache addQueryData:query3];
+ XCTAssertEqual([self.queryCache highestTargetID], 42);
+
+ [self.queryCache removeQueryData:query1];
+ XCTAssertEqual([self.queryCache highestTargetID], 42);
+
+ [self.queryCache removeQueryData:query3];
+ XCTAssertEqual([self.queryCache highestTargetID], 42);
+ });
+
// Verify that the highestTargetID even survives restarts.
- self.queryCache = [self.persistence queryCache];
- [self.queryCache start];
- XCTAssertEqual([self.queryCache highestTargetID], 42);
+ self.persistence.run("testHighestTargetID restart", [&]() {
+ self.queryCache = [self.persistence queryCache];
+ [self.queryCache start];
+ XCTAssertEqual([self.queryCache highestTargetID], 42);
+ });
}
- (void)testLastRemoteSnapshotVersion {
if ([self isTestBaseClass]) return;
- XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion],
- [FSTSnapshotVersion noVersion]);
+ self.persistence.run("testLastRemoteSnapshotVersion", [&]() {
+ XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion],
+ [FSTSnapshotVersion noVersion]);
- // Can set the snapshot version.
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"setLastRemoteSnapshotVersion"];
- [self.queryCache setLastRemoteSnapshotVersion:FSTTestVersion(42)];
- [self.persistence commitGroup:group];
- XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion], FSTTestVersion(42));
+ // Can set the snapshot version.
+ [self.queryCache setLastRemoteSnapshotVersion:FSTTestVersion(42)];
+ XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion], FSTTestVersion(42));
+ });
// Snapshot version persists restarts.
self.queryCache = [self.persistence queryCache];
- [self.queryCache start];
- XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion], FSTTestVersion(42));
+ self.persistence.run("testLastRemoteSnapshotVersion restart", [&]() {
+ [self.queryCache start];
+ XCTAssertEqualObjects([self.queryCache lastRemoteSnapshotVersion], FSTTestVersion(42));
+ });
}
#pragma mark - Helpers
diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm
index e4c68fe..2e32591 100644
--- a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm
+++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm
@@ -18,7 +18,6 @@
#import "Firestore/Source/Core/FSTQuery.h"
#import "Firestore/Source/Local/FSTPersistence.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
#import "Firestore/Source/Model/FSTDocument.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
#import "Firestore/Source/Model/FSTDocumentSet.h"
@@ -52,14 +51,18 @@ static const int kVersion = 42;
- (void)testReadDocumentNotInCache {
if (!self.remoteDocumentCache) return;
- XCTAssertNil([self readEntryAtPath:kDocPath]);
+ self.persistence.run("testReadDocumentNotInCache", [&]() {
+ XCTAssertNil([self.remoteDocumentCache entryForKey:testutil::Key(kDocPath)]);
+ });
}
// Helper for next two tests.
- (void)setAndReadADocumentAtPath:(const absl::string_view)path {
- FSTDocument *written = [self setTestDocumentAtPath:path];
- FSTMaybeDocument *read = [self readEntryAtPath:path];
- XCTAssertEqualObjects(read, written);
+ self.persistence.run("setAndReadADocumentAtPath", [&]() {
+ FSTDocument *written = [self setTestDocumentAtPath:path];
+ FSTMaybeDocument *read = [self.remoteDocumentCache entryForKey:testutil::Key(path)];
+ XCTAssertEqualObjects(read, written);
+ });
}
- (void)testSetAndReadADocument {
@@ -77,58 +80,67 @@ static const int kVersion = 42;
- (void)testSetAndReadDeletedDocument {
if (!self.remoteDocumentCache) return;
- FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc(kDocPath, kVersion);
- [self addEntry:deletedDoc];
+ self.persistence.run("testSetAndReadDeletedDocument", [&]() {
+ FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc(kDocPath, kVersion);
+ [self.remoteDocumentCache addEntry:deletedDoc];
- XCTAssertEqualObjects([self readEntryAtPath:kDocPath], deletedDoc);
+ XCTAssertEqualObjects([self.remoteDocumentCache entryForKey:testutil::Key(kDocPath)],
+ deletedDoc);
+ });
}
- (void)testSetDocumentToNewValue {
if (!self.remoteDocumentCache) return;
- [self setTestDocumentAtPath:kDocPath];
- FSTDocument *newDoc = FSTTestDoc(kDocPath, kVersion, @{ @"data" : @2 }, NO);
- [self addEntry:newDoc];
- XCTAssertEqualObjects([self readEntryAtPath:kDocPath], newDoc);
+ self.persistence.run("testSetDocumentToNewValue", [&]() {
+ [self setTestDocumentAtPath:kDocPath];
+ FSTDocument *newDoc = FSTTestDoc(kDocPath, kVersion, @{ @"data" : @2 }, NO);
+ [self.remoteDocumentCache addEntry:newDoc];
+ XCTAssertEqualObjects([self.remoteDocumentCache entryForKey:testutil::Key(kDocPath)], newDoc);
+ });
}
- (void)testRemoveDocument {
if (!self.remoteDocumentCache) return;
- [self setTestDocumentAtPath:kDocPath];
- [self removeEntryAtPath:kDocPath];
+ self.persistence.run("testRemoveDocument", [&]() {
+ [self setTestDocumentAtPath:kDocPath];
+ [self.remoteDocumentCache removeEntryForKey:testutil::Key(kDocPath)];
- XCTAssertNil([self readEntryAtPath:kDocPath]);
+ XCTAssertNil([self.remoteDocumentCache entryForKey:testutil::Key(kDocPath)]);
+ });
}
- (void)testRemoveNonExistentDocument {
if (!self.remoteDocumentCache) return;
- // no-op, but make sure it doesn't throw.
- XCTAssertNoThrow([self removeEntryAtPath:kDocPath]);
+ self.persistence.run("testRemoveNonExistentDocument", [&]() {
+ // no-op, but make sure it doesn't throw.
+ XCTAssertNoThrow([self.remoteDocumentCache removeEntryForKey:testutil::Key(kDocPath)]);
+ });
}
// TODO(mikelehen): Write more elaborate tests once we have more elaborate implementations.
- (void)testDocumentsMatchingQuery {
if (!self.remoteDocumentCache) return;
- // TODO(rsgowman): This just verifies that we do a prefix scan against the
- // query path. We'll need more tests once we add index support.
- [self setTestDocumentAtPath:"a/1"];
- [self setTestDocumentAtPath:"b/1"];
- [self setTestDocumentAtPath:"b/2"];
- [self setTestDocumentAtPath:"c/1"];
-
- FSTQuery *query = FSTTestQuery("b");
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"DocumentsMatchingQuery"];
- FSTDocumentDictionary *results = [self.remoteDocumentCache documentsMatchingQuery:query];
- NSArray *expected =
- @[ FSTTestDoc("b/1", kVersion, _kDocData, NO), FSTTestDoc("b/2", kVersion, _kDocData, NO) ];
- XCTAssertEqual([results count], [expected count]);
- for (FSTDocument *doc in expected) {
- XCTAssertEqualObjects([results objectForKey:doc.key], doc);
- }
- [self.persistence commitGroup:group];
+ self.persistence.run("testDocumentsMatchingQuery", [&]() {
+ // TODO(rsgowman): This just verifies that we do a prefix scan against the
+ // query path. We'll need more tests once we add index support.
+ [self setTestDocumentAtPath:"a/1"];
+ [self setTestDocumentAtPath:"b/1"];
+ [self setTestDocumentAtPath:"b/2"];
+ [self setTestDocumentAtPath:"c/1"];
+
+ FSTQuery *query = FSTTestQuery("b");
+ FSTDocumentDictionary *results = [self.remoteDocumentCache documentsMatchingQuery:query];
+ NSArray *expected =
+ @[ FSTTestDoc("b/1", kVersion, _kDocData, NO), FSTTestDoc("b/2", kVersion, _kDocData, NO) ];
+ XCTAssertEqual([results count], [expected count]);
+ for (FSTDocument *doc in expected) {
+ XCTAssertEqualObjects([results objectForKey:doc.key], doc);
+ }
+ });
}
#pragma mark - Helpers
@@ -136,29 +148,10 @@ static const int kVersion = 42;
- (FSTDocument *)setTestDocumentAtPath:(const absl::string_view)path {
FSTDocument *doc = FSTTestDoc(path, kVersion, _kDocData, NO);
- [self addEntry:doc];
+ [self.remoteDocumentCache addEntry:doc];
return doc;
}
-- (void)addEntry:(FSTMaybeDocument *)maybeDoc {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"addEntry"];
- [self.remoteDocumentCache addEntry:maybeDoc];
- [self.persistence commitGroup:group];
-}
-
-- (FSTMaybeDocument *_Nullable)readEntryAtPath:(const absl::string_view)path {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"ReadEntryAtPath"];
- FSTMaybeDocument *result = [self.remoteDocumentCache entryForKey:testutil::Key(path)];
- [self.persistence commitGroup:group];
- return result;
-}
-
-- (void)removeEntryAtPath:(const absl::string_view)path {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"removeEntryAtPath"];
- [self.remoteDocumentCache removeEntryForKey:testutil::Key(path)];
- [self.persistence commitGroup:group];
-}
-
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm
index 59def0f..ae50e3e 100644
--- a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm
+++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm
@@ -46,14 +46,14 @@ NS_ASSUME_NONNULL_BEGIN
_remoteDocumentCache = [_db remoteDocumentCache];
// Add a couple initial items to the cache.
- FSTWriteGroup *group = [_db startGroupWithAction:@"Add initial docs."];
- _kInitialADoc = FSTTestDoc("coll/a", 42, @{@"test" : @"data"}, NO);
- [_remoteDocumentCache addEntry:_kInitialADoc];
+ _db.run("Test setup", [&]() {
+ _kInitialADoc = FSTTestDoc("coll/a", 42, @{@"test" : @"data"}, NO);
+ [_remoteDocumentCache addEntry:_kInitialADoc];
- _kInitialBDoc =
- [FSTDeletedDocument documentWithKey:FSTTestDocKey(@"coll/b") version:FSTTestVersion(314)];
- [_remoteDocumentCache addEntry:_kInitialBDoc];
- [_db commitGroup:group];
+ _kInitialBDoc =
+ [FSTDeletedDocument documentWithKey:FSTTestDocKey(@"coll/b") version:FSTTestVersion(314)];
+ [_remoteDocumentCache addEntry:_kInitialBDoc];
+ });
_remoteDocumentBuffer =
[FSTRemoteDocumentChangeBuffer changeBufferWithCache:_remoteDocumentCache];
@@ -68,10 +68,10 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testReadUnchangedEntry {
- FSTWriteGroup *group = [_db startGroupWithAction:@"ReadUnchangedEntry"];
- XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")],
- _kInitialADoc);
- [_db commitGroup:group];
+ _db.run("testReadUnchangedEntry", [&]() {
+ XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")],
+ _kInitialADoc);
+ });
}
- (void)testAddEntryAndReadItBack {
@@ -80,38 +80,37 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")], newADoc);
// B should still be unchanged.
- FSTWriteGroup *group = [_db startGroupWithAction:@"AddEntryAndReadItBack"];
- XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/b")],
- _kInitialBDoc);
- [_db commitGroup:group];
+ _db.run("testAddEntryAndReadItBack", [&]() {
+ XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/b")],
+ _kInitialBDoc);
+ });
}
- (void)testApplyChanges {
FSTMaybeDocument *newADoc = FSTTestDoc("coll/a", 43, @{@"new" : @"data"}, NO);
[_remoteDocumentBuffer addEntry:newADoc];
- FSTWriteGroup *group = [_db startGroupWithAction:@"Apply Changes"];
- XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")], newADoc);
+ _db.run("testApplyChanges setup", [&]() {
+ XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")], newADoc);
- // Reading directly against the cache should still yield the old result.
- XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")], _kInitialADoc);
- [_db commitGroup:group];
+ // Reading directly against the cache should still yield the old result.
+ XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")],
+ _kInitialADoc);
+ });
- group = [_db startGroupWithAction:@"Apply changes"];
- [_remoteDocumentBuffer applyToWriteGroup:group];
+ _db.run("testApplyChanges", [&]() {
+ [_remoteDocumentBuffer apply];
- // Reading against the cache should now yield the new result.
- XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")], newADoc);
- [_db commitGroup:group];
+ // Reading against the cache should now yield the new result.
+ XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")], newADoc);
+ });
}
- (void)testMethodsThrowAfterApply {
- FSTWriteGroup *group = [_db startGroupWithAction:@"Apply changes"];
- [_remoteDocumentBuffer applyToWriteGroup:group];
- [_db commitGroup:group];
+ _db.run("testMethodsThrowAfterApply", [&]() { [_remoteDocumentBuffer apply]; });
XCTAssertThrows([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")]);
XCTAssertThrows([_remoteDocumentBuffer addEntry:_kInitialADoc]);
- XCTAssertThrows([_remoteDocumentBuffer applyToWriteGroup:group]);
+ XCTAssertThrows([_remoteDocumentBuffer apply]);
}
@end
diff --git a/Firestore/Example/Tests/Local/FSTWriteGroupTests.mm b/Firestore/Example/Tests/Local/FSTWriteGroupTests.mm
deleted file mode 100644
index 871bd99..0000000
--- a/Firestore/Example/Tests/Local/FSTWriteGroupTests.mm
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import "Firestore/Source/Local/FSTWriteGroup.h"
-
-#import <XCTest/XCTest.h>
-#include <leveldb/db.h>
-
-#import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h"
-#import "Firestore/Source/Local/FSTLevelDB.h"
-#import "Firestore/Source/Local/FSTLevelDBKey.h"
-
-#import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h"
-
-using leveldb::ReadOptions;
-using leveldb::Status;
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface FSTWriteGroupTests : XCTestCase
-@end
-
-@implementation FSTWriteGroupTests {
- FSTLevelDB *_db;
-}
-
-- (void)setUp {
- [super setUp];
-
- _db = [FSTPersistenceTestHelpers levelDBPersistence];
-}
-
-- (void)tearDown {
- _db = nil;
-
- [super tearDown];
-}
-
-- (void)testCommit {
- std::string key = [FSTLevelDBMutationKey keyWithUserID:"user1" batchID:42];
- FSTPBWriteBatch *message = [FSTPBWriteBatch message];
- message.batchId = 42;
-
- // This is a test that shows that committing an empty group does not fail. There are no side
- // effects to verify though.
- FSTWriteGroup *group = [_db startGroupWithAction:@"Empty commit"];
- XCTAssertNoThrow([_db commitGroup:group]);
-
- group = [_db startGroupWithAction:@"Put"];
- [group setMessage:message forKey:key];
-
- std::string value;
- Status status = _db.ptr->Get(ReadOptions(), key, &value);
- XCTAssertTrue(status.IsNotFound());
-
- [_db commitGroup:group];
- status = _db.ptr->Get(ReadOptions(), key, &value);
- XCTAssertTrue(status.ok());
-
- group = [_db startGroupWithAction:@"Delete"];
- [group removeMessageForKey:key];
- status = _db.ptr->Get(ReadOptions(), key, &value);
- XCTAssertTrue(status.ok());
-
- [_db commitGroup:group];
- status = _db.ptr->Get(ReadOptions(), key, &value);
- XCTAssertTrue(status.IsNotFound());
-}
-
-- (void)testCommittingWrongGroupThrows {
- // If you don't create the group through persistence, it should throw.
- FSTWriteGroup *group = [FSTWriteGroup groupWithAction:@"group"];
- XCTAssertThrows([_db commitGroup:group]);
-}
-
-- (void)testCommittingTwiceThrows {
- FSTWriteGroup *group = [_db startGroupWithAction:@"group"];
- [_db commitGroup:group];
- XCTAssertThrows([_db commitGroup:group]);
-}
-
-- (void)testNestingGroupsThrows {
- [_db startGroupWithAction:@"group1"];
- XCTAssertThrows([_db startGroupWithAction:@"group2"]);
-}
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm
index d834cc2..673991c 100644
--- a/Firestore/Source/Core/FSTSyncEngine.mm
+++ b/Firestore/Source/Core/FSTSyncEngine.mm
@@ -295,8 +295,8 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
[remoteEvent.targetChanges enumerateKeysAndObjectsUsingBlock:^(
FSTBoxedTargetID *_Nonnull targetID,
FSTTargetChange *_Nonnull targetChange, BOOL *_Nonnull stop) {
- const auto iter = _limboKeysByTarget.find([targetID intValue]);
- if (iter == _limboKeysByTarget.end()) {
+ const auto iter = self->_limboKeysByTarget.find([targetID intValue]);
+ if (iter == self->_limboKeysByTarget.end()) {
return;
}
const DocumentKey &limboKey = iter->second;
diff --git a/Firestore/Source/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm
index 922c5b4..4812228 100644
--- a/Firestore/Source/Local/FSTLevelDB.mm
+++ b/Firestore/Source/Local/FSTLevelDB.mm
@@ -23,8 +23,6 @@
#import "Firestore/Source/Local/FSTLevelDBMutationQueue.h"
#import "Firestore/Source/Local/FSTLevelDBQueryCache.h"
#import "Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
-#import "Firestore/Source/Local/FSTWriteGroupTracker.h"
#import "Firestore/Source/Remote/FSTSerializerBeta.h"
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTLogger.h"
@@ -55,7 +53,6 @@ using leveldb::WriteOptions;
@interface FSTLevelDB ()
@property(nonatomic, copy) NSString *directory;
-@property(nonatomic, strong) FSTWriteGroupTracker *writeGroupTracker;
@property(nonatomic, assign, getter=isStarted) BOOL started;
@property(nonatomic, strong, readonly) FSTLocalSerializer *serializer;
@@ -79,7 +76,6 @@ using leveldb::WriteOptions;
serializer:(FSTLocalSerializer *)serializer {
if (self = [super init]) {
_directory = [directory copy];
- _writeGroupTracker = [FSTWriteGroupTracker tracker];
_serializer = serializer;
_transactionRunner.SetBackingPersistence(self);
}
@@ -148,7 +144,7 @@ using leveldb::WriteOptions;
return NO;
}
_ptr.reset(database);
- LevelDbTransaction transaction(_ptr.get());
+ LevelDbTransaction transaction(_ptr.get(), "Start LevelDB");
[FSTLevelDBMigrations runMigrationsWithTransaction:&transaction];
transaction.Commit();
return YES;
@@ -229,9 +225,9 @@ using leveldb::WriteOptions;
return [[FSTLevelDBRemoteDocumentCache alloc] initWithDB:self serializer:self.serializer];
}
-- (void)startTransaction {
+- (void)startTransaction:(absl::string_view)label {
FSTAssert(_transaction == nullptr, @"Starting a transaction while one is already outstanding");
- _transaction = absl::make_unique<LevelDbTransaction>(_ptr.get());
+ _transaction = absl::make_unique<LevelDbTransaction>(_ptr.get(), label);
}
- (void)commitTransaction {
@@ -240,19 +236,6 @@ using leveldb::WriteOptions;
_transaction.reset();
}
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action {
- FSTAssert(_transaction == nullptr, @"Starting a transaction while one is already outstanding");
- _transaction = absl::make_unique<LevelDbTransaction>(_ptr.get());
- return [self.writeGroupTracker startGroupWithAction:action transaction:_transaction.get()];
-}
-
-- (void)commitGroup:(FSTWriteGroup *)group {
- FSTAssert(_transaction != nullptr, @"Committing a transaction before one is started");
- [self.writeGroupTracker endGroup:group];
- _transaction->Commit();
- _transaction.reset();
-}
-
- (void)shutdown {
FSTAssert(self.isStarted, @"FSTLevelDB shutdown without start!");
self.started = NO;
diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm
index 74eab48..412ade2 100644
--- a/Firestore/Source/Local/FSTLocalStore.mm
+++ b/Firestore/Source/Local/FSTLocalStore.mm
@@ -31,7 +31,6 @@
#import "Firestore/Source/Local/FSTReferenceSet.h"
#import "Firestore/Source/Local/FSTRemoteDocumentCache.h"
#import "Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
#import "Firestore/Source/Model/FSTDocument.h"
#import "Firestore/Source/Model/FSTDocumentDictionary.h"
#import "Firestore/Source/Model/FSTMutation.h"
@@ -132,27 +131,27 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)startMutationQueue {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Start MutationQueue"];
- [self.mutationQueue start];
-
- // If we have any leftover mutation batch results from a prior run, just drop them.
- // TODO(http://b/33446471): We probably need to repopulate heldBatchResults or similar instead,
- // but that is not straightforward since we're not persisting the write ack versions.
- [self.heldBatchResults removeAllObjects];
-
- // TODO(mikelehen): This is the only usage of getAllMutationBatchesThroughBatchId:. Consider
- // removing it in favor of a getAcknowledgedBatches method.
- FSTBatchID highestAck = [self.mutationQueue highestAcknowledgedBatchID];
- if (highestAck != kFSTBatchIDUnknown) {
- NSArray<FSTMutationBatch *> *batches =
- [self.mutationQueue allMutationBatchesThroughBatchID:highestAck];
- if (batches.count > 0) {
- // NOTE: This could be more efficient if we had a removeBatchesThroughBatchID, but this set
- // should be very small and this code should go away eventually.
- [self.mutationQueue removeMutationBatches:batches];
+ self.persistence.run("Start MutationQueue", [&]() {
+ [self.mutationQueue start];
+
+ // If we have any leftover mutation batch results from a prior run, just drop them.
+ // TODO(http://b/33446471): We probably need to repopulate heldBatchResults or similar instead,
+ // but that is not straightforward since we're not persisting the write ack versions.
+ [self.heldBatchResults removeAllObjects];
+
+ // TODO(mikelehen): This is the only usage of getAllMutationBatchesThroughBatchId:. Consider
+ // removing it in favor of a getAcknowledgedBatches method.
+ FSTBatchID highestAck = [self.mutationQueue highestAcknowledgedBatchID];
+ if (highestAck != kFSTBatchIDUnknown) {
+ NSArray<FSTMutationBatch *> *batches =
+ [self.mutationQueue allMutationBatchesThroughBatchID:highestAck];
+ if (batches.count > 0) {
+ // NOTE: This could be more efficient if we had a removeBatchesThroughBatchID, but this set
+ // should be very small and this code should go away eventually.
+ [self.mutationQueue removeMutationBatches:batches];
+ }
}
- }
- [self.persistence commitGroup:group];
+ });
}
- (void)startQueryCache {
@@ -166,9 +165,9 @@ NS_ASSUME_NONNULL_BEGIN
- (FSTMaybeDocumentDictionary *)userDidChange:(const User &)user {
// Swap out the mutation queue, grabbing the pending mutation batches before and after.
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"OldBatches"];
- NSArray<FSTMutationBatch *> *oldBatches = [self.mutationQueue allMutationBatches];
- [self.persistence commitGroup:group];
+ NSArray<FSTMutationBatch *> *oldBatches = self.persistence.run(
+ "OldBatches",
+ [&]() -> NSArray<FSTMutationBatch *> * { return [self.mutationQueue allMutationBatches]; });
[self.garbageCollector removeGarbageSource:self.mutationQueue];
@@ -177,83 +176,79 @@ NS_ASSUME_NONNULL_BEGIN
[self startMutationQueue];
- group = [self.persistence startGroupWithAction:@"NewBatches"];
- NSArray<FSTMutationBatch *> *newBatches = [self.mutationQueue allMutationBatches];
-
- // Recreate our LocalDocumentsView using the new MutationQueue.
- self.localDocuments = [FSTLocalDocumentsView viewWithRemoteDocumentCache:self.remoteDocumentCache
- mutationQueue:self.mutationQueue];
-
- // Union the old/new changed keys.
- FSTDocumentKeySet *changedKeys = [FSTDocumentKeySet keySet];
- for (NSArray<FSTMutationBatch *> *batches in @[ oldBatches, newBatches ]) {
- for (FSTMutationBatch *batch in batches) {
- for (FSTMutation *mutation in batch.mutations) {
- changedKeys = [changedKeys setByAddingObject:mutation.key];
+ return self.persistence.run("NewBatches", [&]() -> FSTMaybeDocumentDictionary * {
+ NSArray<FSTMutationBatch *> *newBatches = [self.mutationQueue allMutationBatches];
+
+ // Recreate our LocalDocumentsView using the new MutationQueue.
+ self.localDocuments =
+ [FSTLocalDocumentsView viewWithRemoteDocumentCache:self.remoteDocumentCache
+ mutationQueue:self.mutationQueue];
+
+ // Union the old/new changed keys.
+ FSTDocumentKeySet *changedKeys = [FSTDocumentKeySet keySet];
+ for (NSArray<FSTMutationBatch *> *batches in @[ oldBatches, newBatches ]) {
+ for (FSTMutationBatch *batch in batches) {
+ for (FSTMutation *mutation in batch.mutations) {
+ changedKeys = [changedKeys setByAddingObject:mutation.key];
+ }
}
}
- }
- // Return the set of all (potentially) changed documents as the result of the user change.
- FSTMaybeDocumentDictionary *result = [self.localDocuments documentsForKeys:changedKeys];
- [self.persistence commitGroup:group];
- return result;
+ // Return the set of all (potentially) changed documents as the result of the user change.
+ return [self.localDocuments documentsForKeys:changedKeys];
+ });
}
- (FSTLocalWriteResult *)locallyWriteMutations:(NSArray<FSTMutation *> *)mutations {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Locally write mutations"];
- FIRTimestamp *localWriteTime = [FIRTimestamp timestamp];
- FSTMutationBatch *batch =
- [self.mutationQueue addMutationBatchWithWriteTime:localWriteTime mutations:mutations];
- FSTDocumentKeySet *keys = [batch keys];
- FSTMaybeDocumentDictionary *changedDocuments = [self.localDocuments documentsForKeys:keys];
- [self.persistence commitGroup:group];
- return [FSTLocalWriteResult resultForBatchID:batch.batchID changes:changedDocuments];
+ return self.persistence.run("Locally write mutations", [&]() -> FSTLocalWriteResult * {
+ FIRTimestamp *localWriteTime = [FIRTimestamp timestamp];
+ FSTMutationBatch *batch =
+ [self.mutationQueue addMutationBatchWithWriteTime:localWriteTime mutations:mutations];
+ FSTDocumentKeySet *keys = [batch keys];
+ FSTMaybeDocumentDictionary *changedDocuments = [self.localDocuments documentsForKeys:keys];
+ return [FSTLocalWriteResult resultForBatchID:batch.batchID changes:changedDocuments];
+ });
}
- (FSTMaybeDocumentDictionary *)acknowledgeBatchWithResult:(FSTMutationBatchResult *)batchResult {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Acknowledge batch"];
- id<FSTMutationQueue> mutationQueue = self.mutationQueue;
+ return self.persistence.run("Acknowledge batch", [&]() -> FSTMaybeDocumentDictionary * {
+ id<FSTMutationQueue> mutationQueue = self.mutationQueue;
- [mutationQueue acknowledgeBatch:batchResult.batch streamToken:batchResult.streamToken];
+ [mutationQueue acknowledgeBatch:batchResult.batch streamToken:batchResult.streamToken];
- FSTDocumentKeySet *affected;
- if ([self shouldHoldBatchResultWithVersion:batchResult.commitVersion]) {
- [self.heldBatchResults addObject:batchResult];
- affected = [FSTDocumentKeySet keySet];
- } else {
- FSTRemoteDocumentChangeBuffer *remoteDocuments =
- [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
+ FSTDocumentKeySet *affected;
+ if ([self shouldHoldBatchResultWithVersion:batchResult.commitVersion]) {
+ [self.heldBatchResults addObject:batchResult];
+ affected = [FSTDocumentKeySet keySet];
+ } else {
+ FSTRemoteDocumentChangeBuffer *remoteDocuments =
+ [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
- affected =
- [self releaseBatchResults:@[ batchResult ] group:group remoteDocuments:remoteDocuments];
+ affected = [self releaseBatchResults:@[ batchResult ] remoteDocuments:remoteDocuments];
- [remoteDocuments applyToWriteGroup:group];
- }
+ [remoteDocuments apply];
+ }
- [self.mutationQueue performConsistencyCheck];
+ [self.mutationQueue performConsistencyCheck];
- FSTMaybeDocumentDictionary *result = [self.localDocuments documentsForKeys:affected];
- [self.persistence commitGroup:group];
- return result;
+ return [self.localDocuments documentsForKeys:affected];
+ });
}
- (FSTMaybeDocumentDictionary *)rejectBatchID:(FSTBatchID)batchID {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Reject batch"];
-
- FSTMutationBatch *toReject = [self.mutationQueue lookupMutationBatch:batchID];
- FSTAssert(toReject, @"Attempt to reject nonexistent batch!");
+ return self.persistence.run("Reject batch", [&]() -> FSTMaybeDocumentDictionary * {
+ FSTMutationBatch *toReject = [self.mutationQueue lookupMutationBatch:batchID];
+ FSTAssert(toReject, @"Attempt to reject nonexistent batch!");
- FSTBatchID lastAcked = [self.mutationQueue highestAcknowledgedBatchID];
- FSTAssert(batchID > lastAcked, @"Acknowledged batches can't be rejected.");
+ FSTBatchID lastAcked = [self.mutationQueue highestAcknowledgedBatchID];
+ FSTAssert(batchID > lastAcked, @"Acknowledged batches can't be rejected.");
- FSTDocumentKeySet *affected = [self removeMutationBatch:toReject group:group];
+ FSTDocumentKeySet *affected = [self removeMutationBatch:toReject];
- [self.mutationQueue performConsistencyCheck];
+ [self.mutationQueue performConsistencyCheck];
- FSTMaybeDocumentDictionary *result = [self.localDocuments documentsForKeys:affected];
- [self.persistence commitGroup:group];
- return result;
+ return [self.localDocuments documentsForKeys:affected];
+ });
}
- (nullable NSData *)lastStreamToken {
@@ -261,10 +256,8 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)setLastStreamToken:(nullable NSData *)streamToken {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Set stream token"];
-
- [self.mutationQueue setLastStreamToken:streamToken];
- [self.persistence commitGroup:group];
+ self.persistence.run("Set stream token",
+ [&]() { [self.mutationQueue setLastStreamToken:streamToken]; });
}
- (FSTSnapshotVersion *)lastRemoteSnapshotVersion {
@@ -272,207 +265,197 @@ NS_ASSUME_NONNULL_BEGIN
}
- (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent {
- id<FSTQueryCache> queryCache = self.queryCache;
-
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Apply remote event"];
- FSTRemoteDocumentChangeBuffer *remoteDocuments =
- [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
+ return self.persistence.run("Apply remote event", [&]() -> FSTMaybeDocumentDictionary * {
+ id<FSTQueryCache> queryCache = self.queryCache;
- [remoteEvent.targetChanges enumerateKeysAndObjectsUsingBlock:^(
- NSNumber *targetIDNumber, FSTTargetChange *change, BOOL *stop) {
- FSTTargetID targetID = targetIDNumber.intValue;
+ FSTRemoteDocumentChangeBuffer *remoteDocuments =
+ [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
- // Do not ref/unref unassigned targetIDs - it may lead to leaks.
- FSTQueryData *queryData = self.targetIDs[targetIDNumber];
- if (!queryData) {
- return;
- }
+ [remoteEvent.targetChanges enumerateKeysAndObjectsUsingBlock:^(
+ NSNumber *targetIDNumber, FSTTargetChange *change, BOOL *stop) {
+ FSTTargetID targetID = targetIDNumber.intValue;
- FSTTargetMapping *mapping = change.mapping;
- if (mapping) {
- // First make sure that all references are deleted.
- if ([mapping isKindOfClass:[FSTResetMapping class]]) {
- FSTResetMapping *reset = (FSTResetMapping *)mapping;
- [queryCache removeMatchingKeysForTargetID:targetID];
- [queryCache addMatchingKeys:reset.documents forTargetID:targetID];
+ // Do not ref/unref unassigned targetIDs - it may lead to leaks.
+ FSTQueryData *queryData = self.targetIDs[targetIDNumber];
+ if (!queryData) {
+ return;
+ }
- } else if ([mapping isKindOfClass:[FSTUpdateMapping class]]) {
- FSTUpdateMapping *update = (FSTUpdateMapping *)mapping;
- [queryCache removeMatchingKeys:update.removedDocuments forTargetID:targetID];
- [queryCache addMatchingKeys:update.addedDocuments forTargetID:targetID];
+ FSTTargetMapping *mapping = change.mapping;
+ if (mapping) {
+ // First make sure that all references are deleted.
+ if ([mapping isKindOfClass:[FSTResetMapping class]]) {
+ FSTResetMapping *reset = (FSTResetMapping *)mapping;
+ [queryCache removeMatchingKeysForTargetID:targetID];
+ [queryCache addMatchingKeys:reset.documents forTargetID:targetID];
+
+ } else if ([mapping isKindOfClass:[FSTUpdateMapping class]]) {
+ FSTUpdateMapping *update = (FSTUpdateMapping *)mapping;
+ [queryCache removeMatchingKeys:update.removedDocuments forTargetID:targetID];
+ [queryCache addMatchingKeys:update.addedDocuments forTargetID:targetID];
+
+ } else {
+ FSTFail(@"Unknown mapping type: %@", mapping);
+ }
+ }
+ // Update the resume token if the change includes one. Don't clear any preexisting value.
+ NSData *resumeToken = change.resumeToken;
+ if (resumeToken.length > 0) {
+ queryData = [queryData queryDataByReplacingSnapshotVersion:change.snapshotVersion
+ resumeToken:resumeToken];
+ self.targetIDs[targetIDNumber] = queryData;
+ [self.queryCache updateQueryData:queryData];
+ }
+ }];
+
+ // TODO(klimt): This could probably be an NSMutableDictionary.
+ FSTDocumentKeySet *changedDocKeys = [FSTDocumentKeySet keySet];
+ for (const auto &kv : remoteEvent.documentUpdates) {
+ const DocumentKey &key = kv.first;
+ FSTMaybeDocument *doc = kv.second;
+ changedDocKeys = [changedDocKeys setByAddingObject:key];
+ FSTMaybeDocument *existingDoc = [remoteDocuments entryForKey:key];
+ // Make sure we don't apply an old document version to the remote cache, though we
+ // make an exception for [SnapshotVersion noVersion] which can happen for manufactured
+ // events (e.g. in the case of a limbo document resolution failing).
+ if (!existingDoc || [doc.version isEqual:[FSTSnapshotVersion noVersion]] ||
+ [doc.version compare:existingDoc.version] != NSOrderedAscending) {
+ [remoteDocuments addEntry:doc];
} else {
- FSTFail(@"Unknown mapping type: %@", mapping);
+ FSTLog(
+ @"FSTLocalStore Ignoring outdated watch update for %s. "
+ "Current version: %@ Watch version: %@",
+ key.ToString().c_str(), existingDoc.version, doc.version);
}
- }
- // Update the resume token if the change includes one. Don't clear any preexisting value.
- NSData *resumeToken = change.resumeToken;
- if (resumeToken.length > 0) {
- queryData = [queryData queryDataByReplacingSnapshotVersion:change.snapshotVersion
- resumeToken:resumeToken];
- self.targetIDs[targetIDNumber] = queryData;
- [self.queryCache updateQueryData:queryData];
+ // The document might be garbage because it was unreferenced by everything.
+ // Make sure to mark it as garbage if it is...
+ [self.garbageCollector addPotentialGarbageKey:key];
}
- }];
- // TODO(klimt): This could probably be an NSMutableDictionary.
- FSTDocumentKeySet *changedDocKeys = [FSTDocumentKeySet keySet];
- for (const auto &kv : remoteEvent.documentUpdates) {
- const DocumentKey &key = kv.first;
- FSTMaybeDocument *doc = kv.second;
- changedDocKeys = [changedDocKeys setByAddingObject:key];
- FSTMaybeDocument *existingDoc = [remoteDocuments entryForKey:key];
- // Make sure we don't apply an old document version to the remote cache, though we
- // make an exception for [SnapshotVersion noVersion] which can happen for manufactured
- // events (e.g. in the case of a limbo document resolution failing).
- if (!existingDoc || [doc.version isEqual:[FSTSnapshotVersion noVersion]] ||
- [doc.version compare:existingDoc.version] != NSOrderedAscending) {
- [remoteDocuments addEntry:doc];
- } else {
- FSTLog(
- @"FSTLocalStore Ignoring outdated watch update for %s. "
- "Current version: %@ Watch version: %@",
- key.ToString().c_str(), existingDoc.version, doc.version);
+ // HACK: The only reason we allow omitting snapshot version is so we can synthesize remote
+ // events when we get permission denied errors while trying to resolve the state of a locally
+ // cached document that is in limbo.
+ FSTSnapshotVersion *lastRemoteVersion = [self.queryCache lastRemoteSnapshotVersion];
+ FSTSnapshotVersion *remoteVersion = remoteEvent.snapshotVersion;
+ if (![remoteVersion isEqual:[FSTSnapshotVersion noVersion]]) {
+ FSTAssert([remoteVersion compare:lastRemoteVersion] != NSOrderedAscending,
+ @"Watch stream reverted to previous snapshot?? (%@ < %@)", remoteVersion,
+ lastRemoteVersion);
+ [self.queryCache setLastRemoteSnapshotVersion:remoteVersion];
}
- // The document might be garbage because it was unreferenced by everything.
- // Make sure to mark it as garbage if it is...
- [self.garbageCollector addPotentialGarbageKey:key];
- }
-
- // HACK: The only reason we allow omitting snapshot version is so we can synthesize remote events
- // when we get permission denied errors while trying to resolve the state of a locally cached
- // document that is in limbo.
- FSTSnapshotVersion *lastRemoteVersion = [self.queryCache lastRemoteSnapshotVersion];
- FSTSnapshotVersion *remoteVersion = remoteEvent.snapshotVersion;
- if (![remoteVersion isEqual:[FSTSnapshotVersion noVersion]]) {
- FSTAssert([remoteVersion compare:lastRemoteVersion] != NSOrderedAscending,
- @"Watch stream reverted to previous snapshot?? (%@ < %@)", remoteVersion,
- lastRemoteVersion);
- [self.queryCache setLastRemoteSnapshotVersion:remoteVersion];
- }
-
- FSTDocumentKeySet *releasedWriteKeys =
- [self releaseHeldBatchResultsWithGroup:group remoteDocuments:remoteDocuments];
+ FSTDocumentKeySet *releasedWriteKeys =
+ [self releaseHeldBatchResultsWithRemoteDocuments:remoteDocuments];
- [remoteDocuments applyToWriteGroup:group];
+ [remoteDocuments apply];
- // Union the two key sets.
- __block FSTDocumentKeySet *keysToRecalc = changedDocKeys;
- [releasedWriteKeys enumerateObjectsUsingBlock:^(FSTDocumentKey *key, BOOL *stop) {
- keysToRecalc = [keysToRecalc setByAddingObject:key];
- }];
+ // Union the two key sets.
+ __block FSTDocumentKeySet *keysToRecalc = changedDocKeys;
+ [releasedWriteKeys enumerateObjectsUsingBlock:^(FSTDocumentKey *key, BOOL *stop) {
+ keysToRecalc = [keysToRecalc setByAddingObject:key];
+ }];
- FSTMaybeDocumentDictionary *result = [self.localDocuments documentsForKeys:keysToRecalc];
- [self.persistence commitGroup:group];
- return result;
+ return [self.localDocuments documentsForKeys:keysToRecalc];
+ });
}
- (void)notifyLocalViewChanges:(NSArray<FSTLocalViewChanges *> *)viewChanges {
- FSTReferenceSet *localViewReferences = self.localViewReferences;
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"NotifyLocalViewChanges"];
- for (FSTLocalViewChanges *view in viewChanges) {
- FSTQueryData *queryData = [self.queryCache queryDataForQuery:view.query];
- FSTAssert(queryData, @"Local view changes contain unallocated query.");
- FSTTargetID targetID = queryData.targetID;
- [localViewReferences addReferencesToKeys:view.addedKeys forID:targetID];
- [localViewReferences removeReferencesToKeys:view.removedKeys forID:targetID];
- }
- [self.persistence commitGroup:group];
+ self.persistence.run("NotifyLocalViewChanges", [&]() {
+ FSTReferenceSet *localViewReferences = self.localViewReferences;
+ for (FSTLocalViewChanges *view in viewChanges) {
+ FSTQueryData *queryData = [self.queryCache queryDataForQuery:view.query];
+ FSTAssert(queryData, @"Local view changes contain unallocated query.");
+ FSTTargetID targetID = queryData.targetID;
+ [localViewReferences addReferencesToKeys:view.addedKeys forID:targetID];
+ [localViewReferences removeReferencesToKeys:view.removedKeys forID:targetID];
+ }
+ });
}
- (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID {
- FSTMutationBatch *result = self.persistence.run([&]() -> FSTMutationBatch * {
- return [self.mutationQueue nextMutationBatchAfterBatchID:batchID];
- });
+ FSTMutationBatch *result =
+ self.persistence.run("NextMutationBatchAfterBatchID", [&]() -> FSTMutationBatch * {
+ return [self.mutationQueue nextMutationBatchAfterBatchID:batchID];
+ });
return result;
}
- (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"ReadDocument"];
- FSTMaybeDocument *result = [self.localDocuments documentForKey:key];
- [self.persistence commitGroup:group];
- return result;
+ return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable {
+ return [self.localDocuments documentForKey:key];
+ });
}
- (FSTQueryData *)allocateQuery:(FSTQuery *)query {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Allocate query"];
- FSTQueryData *cached = [self.queryCache queryDataForQuery:query];
- FSTTargetID targetID;
- FSTListenSequenceNumber sequenceNumber = [self.listenSequence next];
- if (cached) {
- // This query has been listened to previously, so reuse the previous targetID.
- // TODO(mcg): freshen last accessed date?
- targetID = cached.targetID;
- } else {
- targetID = _targetIDGenerator.NextId();
- cached = [[FSTQueryData alloc] initWithQuery:query
- targetID:targetID
- listenSequenceNumber:sequenceNumber
- purpose:FSTQueryPurposeListen];
- [self.queryCache addQueryData:cached];
- }
- [self.persistence commitGroup:group];
+ FSTQueryData *queryData = self.persistence.run("Allocate query", [&]() -> FSTQueryData * {
+ FSTQueryData *cached = [self.queryCache queryDataForQuery:query];
+ // TODO(mcg): freshen last accessed date if cached exists?
+ if (!cached) {
+ cached = [[FSTQueryData alloc] initWithQuery:query
+ targetID:_targetIDGenerator.NextId()
+ listenSequenceNumber:[self.listenSequence next]
+ purpose:FSTQueryPurposeListen];
+ [self.queryCache addQueryData:cached];
+ }
+ return cached;
+ });
// Sanity check to ensure that even when resuming a query it's not currently active.
- FSTBoxedTargetID *boxedTargetID = @(targetID);
+ FSTBoxedTargetID *boxedTargetID = @(queryData.targetID);
FSTAssert(!self.targetIDs[boxedTargetID], @"Tried to allocate an already allocated query: %@",
query);
- self.targetIDs[boxedTargetID] = cached;
- return cached;
+ self.targetIDs[boxedTargetID] = queryData;
+ return queryData;
}
- (void)releaseQuery:(FSTQuery *)query {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Release query"];
-
- FSTQueryData *queryData = [self.queryCache queryDataForQuery:query];
- FSTAssert(queryData, @"Tried to release nonexistent query: %@", query);
-
- [self.localViewReferences removeReferencesForID:queryData.targetID];
- if (self.garbageCollector.isEager) {
- [self.queryCache removeQueryData:queryData];
- }
- [self.targetIDs removeObjectForKey:@(queryData.targetID)];
+ self.persistence.run("Release query", [&]() {
+ FSTQueryData *queryData = [self.queryCache queryDataForQuery:query];
+ FSTAssert(queryData, @"Tried to release nonexistent query: %@", query);
- // If this was the last watch target, then we won't get any more watch snapshots, so we should
- // release any held batch results.
- if ([self.targetIDs count] == 0) {
- FSTRemoteDocumentChangeBuffer *remoteDocuments =
- [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
+ [self.localViewReferences removeReferencesForID:queryData.targetID];
+ if (self.garbageCollector.isEager) {
+ [self.queryCache removeQueryData:queryData];
+ }
+ [self.targetIDs removeObjectForKey:@(queryData.targetID)];
- [self releaseHeldBatchResultsWithGroup:group remoteDocuments:remoteDocuments];
+ // If this was the last watch target, then we won't get any more watch snapshots, so we should
+ // release any held batch results.
+ if ([self.targetIDs count] == 0) {
+ FSTRemoteDocumentChangeBuffer *remoteDocuments =
+ [FSTRemoteDocumentChangeBuffer changeBufferWithCache:self.remoteDocumentCache];
- [remoteDocuments applyToWriteGroup:group];
- }
+ [self releaseHeldBatchResultsWithRemoteDocuments:remoteDocuments];
- [self.persistence commitGroup:group];
+ [remoteDocuments apply];
+ }
+ });
}
- (FSTDocumentDictionary *)executeQuery:(FSTQuery *)query {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"ExecuteQuery"];
- FSTDocumentDictionary *result = [self.localDocuments documentsMatchingQuery:query];
- [self.persistence commitGroup:group];
- return result;
+ return self.persistence.run("ExecuteQuery", [&]() -> FSTDocumentDictionary * {
+ return [self.localDocuments documentsMatchingQuery:query];
+ });
}
- (FSTDocumentKeySet *)remoteDocumentKeysForTarget:(FSTTargetID)targetID {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"RemoteDocumentKeysForTarget"];
- FSTDocumentKeySet *keySet = [self.queryCache matchingKeysForTargetID:targetID];
- [self.persistence commitGroup:group];
- return keySet;
+ return self.persistence.run("RemoteDocumentKeysForTarget", [&]() -> FSTDocumentKeySet * {
+ return [self.queryCache matchingKeysForTargetID:targetID];
+ });
}
- (void)collectGarbage {
- FSTWriteGroup *group = [self.persistence startGroupWithAction:@"Garbage Collection"];
- // Call collectGarbage regardless of whether isGCEnabled so the referenceSet doesn't continue to
- // accumulate the garbage keys.
- std::set<DocumentKey> garbage = [self.garbageCollector collectGarbage];
- if (garbage.size() > 0) {
- for (const DocumentKey &key : garbage) {
- [self.remoteDocumentCache removeEntryForKey:key];
+ self.persistence.run("Garbage Collection", [&]() {
+ // Call collectGarbage regardless of whether isGCEnabled so the referenceSet doesn't continue to
+ // accumulate the garbage keys.
+ std::set<DocumentKey> garbage = [self.garbageCollector collectGarbage];
+ if (garbage.size() > 0) {
+ for (const DocumentKey &key : garbage) {
+ [self.remoteDocumentCache removeEntryForKey:key];
+ }
}
- }
- [self.persistence commitGroup:group];
+ });
}
/**
@@ -481,9 +464,8 @@ NS_ASSUME_NONNULL_BEGIN
*
* @return the set of keys of docs that were modified by those writes.
*/
-- (FSTDocumentKeySet *)releaseHeldBatchResultsWithGroup:(FSTWriteGroup *)group
- remoteDocuments:
- (FSTRemoteDocumentChangeBuffer *)remoteDocuments {
+- (FSTDocumentKeySet *)releaseHeldBatchResultsWithRemoteDocuments:
+ (FSTRemoteDocumentChangeBuffer *)remoteDocuments {
NSMutableArray<FSTMutationBatchResult *> *toRelease = [NSMutableArray array];
for (FSTMutationBatchResult *batchResult in self.heldBatchResults) {
if (![self isRemoteUpToVersion:batchResult.commitVersion]) {
@@ -496,7 +478,7 @@ NS_ASSUME_NONNULL_BEGIN
return [FSTDocumentKeySet keySet];
} else {
[self.heldBatchResults removeObjectsInRange:NSMakeRange(0, toRelease.count)];
- return [self releaseBatchResults:toRelease group:group remoteDocuments:remoteDocuments];
+ return [self releaseBatchResults:toRelease remoteDocuments:remoteDocuments];
}
}
@@ -512,7 +494,6 @@ NS_ASSUME_NONNULL_BEGIN
}
- (FSTDocumentKeySet *)releaseBatchResults:(NSArray<FSTMutationBatchResult *> *)batchResults
- group:(FSTWriteGroup *)group
remoteDocuments:(FSTRemoteDocumentChangeBuffer *)remoteDocuments {
NSMutableArray<FSTMutationBatch *> *batches = [NSMutableArray array];
for (FSTMutationBatchResult *batchResult in batchResults) {
@@ -520,16 +501,15 @@ NS_ASSUME_NONNULL_BEGIN
[batches addObject:batchResult.batch];
}
- return [self removeMutationBatches:batches group:group];
+ return [self removeMutationBatches:batches];
}
-- (FSTDocumentKeySet *)removeMutationBatch:(FSTMutationBatch *)batch group:(FSTWriteGroup *)group {
- return [self removeMutationBatches:@[ batch ] group:group];
+- (FSTDocumentKeySet *)removeMutationBatch:(FSTMutationBatch *)batch {
+ return [self removeMutationBatches:@[ batch ]];
}
/** Removes all the mutation batches named in the given array. */
-- (FSTDocumentKeySet *)removeMutationBatches:(NSArray<FSTMutationBatch *> *)batches
- group:(FSTWriteGroup *)group {
+- (FSTDocumentKeySet *)removeMutationBatches:(NSArray<FSTMutationBatch *> *)batches {
// TODO(klimt): Could this be an NSMutableDictionary?
__block FSTDocumentKeySet *affectedDocs = [FSTDocumentKeySet keySet];
diff --git a/Firestore/Source/Local/FSTMemoryPersistence.mm b/Firestore/Source/Local/FSTMemoryPersistence.mm
index f1f9885..8d74881 100644
--- a/Firestore/Source/Local/FSTMemoryPersistence.mm
+++ b/Firestore/Source/Local/FSTMemoryPersistence.mm
@@ -21,8 +21,6 @@
#import "Firestore/Source/Local/FSTMemoryMutationQueue.h"
#import "Firestore/Source/Local/FSTMemoryQueryCache.h"
#import "Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h"
-#import "Firestore/Source/Local/FSTWriteGroup.h"
-#import "Firestore/Source/Local/FSTWriteGroupTracker.h"
#import "Firestore/Source/Util/FSTAssert.h"
#include "Firestore/core/src/firebase/firestore/auth/user.h"
@@ -33,7 +31,6 @@ using firebase::firestore::auth::User;
NS_ASSUME_NONNULL_BEGIN
@interface FSTMemoryPersistence ()
-@property(nonatomic, strong, nonnull) FSTWriteGroupTracker *writeGroupTracker;
@property(nonatomic, assign, getter=isStarted) BOOL started;
@end
@@ -62,7 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init {
if (self = [super init]) {
- _writeGroupTracker = [FSTWriteGroupTracker tracker];
_queryCache = [[FSTMemoryQueryCache alloc] init];
_remoteDocumentCache = [[FSTMemoryRemoteDocumentCache alloc] init];
}
@@ -103,16 +99,6 @@ NS_ASSUME_NONNULL_BEGIN
return _remoteDocumentCache;
}
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action {
- return [self.writeGroupTracker startGroupWithAction:action];
-}
-
-- (void)commitGroup:(FSTWriteGroup *)group {
- [self.writeGroupTracker endGroup:group];
-
- FSTAssert(group.isEmpty, @"Memory persistence shouldn't use write groups: %@", group.action);
-}
-
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTPersistence.h b/Firestore/Source/Local/FSTPersistence.h
index 1784163..2294ef1 100644
--- a/Firestore/Source/Local/FSTPersistence.h
+++ b/Firestore/Source/Local/FSTPersistence.h
@@ -19,7 +19,6 @@
#import "Firestore/Source/Util/FSTAssert.h"
#include "Firestore/core/src/firebase/firestore/auth/user.h"
-@class FSTWriteGroup;
@protocol FSTMutationQueue;
@protocol FSTQueryCache;
@protocol FSTRemoteDocumentCache;
@@ -86,28 +85,13 @@ struct FSTTransactionRunner;
/** Creates an FSTRemoteDocumentCache representing the persisted cache of remote documents. */
- (id<FSTRemoteDocumentCache>)remoteDocumentCache;
-/**
- * Creates an FSTWriteGroup with the specified action description.
- *
- * @param action A description of the action performed by this group, used for logging.
- * @return The created group.
- */
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action;
-
-/**
- * Commits all accumulated changes in the given group. If there are no changes this is a no-op.
- *
- * @param group The group of changes to write as a unit.
- */
-- (void)commitGroup:(FSTWriteGroup *)group;
-
@property(nonatomic, readonly, assign) const FSTTransactionRunner &run;
@end
@protocol FSTTransactional
-- (void)startTransaction;
+- (void)startTransaction:(absl::string_view)label;
- (void)commitTransaction;
@@ -136,14 +120,14 @@ struct FSTTransactionRunner {
*/
template <typename F>
- auto operator()(F block) const ->
+ auto operator()(absl::string_view label, F block) const ->
typename std::enable_if<std::is_void<decltype(block())>::value, void>::type {
__strong id<FSTTransactional> strongDb = _db;
if (!strongDb && _expect_db) {
FSTCFail(@"Transaction runner accessed without underlying db when it expected one");
}
if (strongDb) {
- [strongDb startTransaction];
+ [strongDb startTransaction:label];
}
block();
if (strongDb) {
@@ -152,7 +136,7 @@ struct FSTTransactionRunner {
}
template <typename F>
- auto operator()(F block) const ->
+ auto operator()(absl::string_view label, F block) const ->
typename std::enable_if<!std::is_void<decltype(block())>::value, decltype(block())>::type {
using ReturnT = decltype(block());
__strong id<FSTTransactional> strongDb = _db;
@@ -160,7 +144,7 @@ struct FSTTransactionRunner {
FSTCFail(@"Transaction runner accessed without underlying db when it expected one");
}
if (strongDb) {
- [strongDb startTransaction];
+ [strongDb startTransaction:label];
}
ReturnT result = block();
if (strongDb) {
diff --git a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h
index cfdf55b..be29a89 100644
--- a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h
+++ b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.h
@@ -22,7 +22,6 @@ NS_ASSUME_NONNULL_BEGIN
@protocol FSTRemoteDocumentCache;
@class FSTMaybeDocument;
-@class FSTWriteGroup;
/**
* An in-memory buffer of entries to be written to an FSTRemoteDocumentCache. It can be used to
@@ -58,10 +57,9 @@ NS_ASSUME_NONNULL_BEGIN
(const firebase::firestore::model::DocumentKey &)documentKey;
/**
- * Applies buffered changes to the underlying FSTRemoteDocumentCache, using the provided
- * FSTWriteGroup.
+ * Applies buffered changes to the underlying FSTRemoteDocumentCache
*/
-- (void)applyToWriteGroup:(FSTWriteGroup *)group;
+- (void)apply;
@end
diff --git a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm
index 0557bce..3812501 100644
--- a/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm
+++ b/Firestore/Source/Local/FSTRemoteDocumentChangeBuffer.mm
@@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
}
}
-- (void)applyToWriteGroup:(FSTWriteGroup *)group {
+- (void)apply {
[self assertValid];
for (const auto &kv : *_changes) {
diff --git a/Firestore/Source/Local/FSTWriteGroup.h b/Firestore/Source/Local/FSTWriteGroup.h
deleted file mode 100644
index a554597..0000000
--- a/Firestore/Source/Local/FSTWriteGroup.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-#include <memory>
-
-#include "Firestore/Source/Local/StringView.h"
-#include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
-#include "leveldb/db.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@class GPBMessage;
-
-/**
- * A group of writes that will be applied together atomically to persistent storage.
- *
- * This class is usable by both Objective-C and Objective-C++ clients. Objective-C clients are able
- * to create a new group and commit it. Objective-C++ clients can additionally add to the group
- * using deleteKey: and putKey:value:.
- *
- * Note that this is a write "group" even though the underlying LevelDB concept is a write "batch"
- * because Firestore already has a concept of mutation batches, which are user-specified groups of
- * changes. This means that an FSTWriteGroup may contain the application of multiple user-specified
- * mutation batches.
- */
-@interface FSTWriteGroup : NSObject
-
-/**
- * Creates a new, empty write group.
- *
- * @param action A description of the action performed by this group, used for logging.
- */
-+ (instancetype)groupWithAction:(NSString *)action;
-
-+ (instancetype)groupWithAction:(NSString *)action
- transaction:(firebase::firestore::local::LevelDbTransaction *)transaction;
-
-- (instancetype)init __attribute__((unavailable("Use a static constructor instead")));
-
-/** The action description assigned to this write group. */
-@property(nonatomic, copy, readonly) NSString *action;
-
-@property(nonatomic, readonly) firebase::firestore::local::LevelDbTransaction *transaction;
-
-/**
- * Marks the given key for deletion.
- *
- * @param key The LevelDB key of the row to delete
- */
-- (void)removeMessageForKey:(Firestore::StringView)key;
-
-/**
- * Sets the row identified by the given key to the value of the given protocol buffer message.
- *
- * @param key The LevelDB Key of the row to set.
- * @param message The protocol buffer message whose serialized contents should be used for the
- * value associated with the key.
- */
-- (void)setMessage:(GPBMessage *)message forKey:(Firestore::StringView)key;
-
-/**
- * Sets the row identified by the given key to the value of the given data bytes.
- *
- * @param key The LevelDB Key of the row to set.
- * @param data The exact value to be associated with the key.
- */
-- (void)setData:(Firestore::StringView)data forKey:(Firestore::StringView)key;
-
-/** Returns YES if the write group has no messages in it. */
-- (BOOL)isEmpty;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTWriteGroup.mm b/Firestore/Source/Local/FSTWriteGroup.mm
deleted file mode 100644
index 9aee31a..0000000
--- a/Firestore/Source/Local/FSTWriteGroup.mm
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import "Firestore/Source/Local/FSTWriteGroup.h"
-
-#include <leveldb/write_batch.h>
-
-#import "Firestore/Source/Local/FSTLevelDBKey.h"
-#import "Firestore/Source/Util/FSTAssert.h"
-
-using firebase::firestore::local::LevelDbTransaction;
-using Firestore::StringView;
-using leveldb::DB;
-using leveldb::Slice;
-using leveldb::Status;
-using leveldb::WriteBatch;
-using leveldb::WriteOptions;
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface FSTWriteGroup ()
-- (instancetype)initWithAction:(NSString *)action NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithAction:(NSString *)action transaction:(LevelDbTransaction *)transaction;
-@end
-
-@implementation FSTWriteGroup {
- int _changes;
-}
-
-+ (instancetype)groupWithAction:(NSString *)action {
- return [[FSTWriteGroup alloc] initWithAction:action];
-}
-
-+ (instancetype)groupWithAction:(NSString *)action
- transaction:(firebase::firestore::local::LevelDbTransaction *)transaction {
- return [[FSTWriteGroup alloc] initWithAction:action transaction:transaction];
-}
-
-- (instancetype)initWithAction:(NSString *)action {
- if (self = [super init]) {
- _action = action;
- _transaction = nullptr;
- }
- return self;
-}
-
-- (instancetype)initWithAction:(NSString *)action transaction:(LevelDbTransaction *)transaction {
- if (self = [self initWithAction:action]) {
- _transaction = transaction;
- }
- return self;
-}
-
-- (void)removeMessageForKey:(StringView)key {
- FSTAssert(_transaction != nullptr, @"Using group without a transaction");
- Slice keySlice = key;
- _transaction->Delete(keySlice.ToString());
- _changes += 1;
-}
-
-- (void)setMessage:(GPBMessage *)message forKey:(StringView)key {
- FSTAssert(_transaction != nullptr, @"Using group without a transaction");
- Slice keySlice = key;
- _transaction->Put(keySlice.ToString(), message);
- _changes += 1;
-}
-
-- (void)setData:(StringView)data forKey:(StringView)key {
- FSTAssert(_transaction != nullptr, @"Using group without a transaction");
- Slice keySlice = key;
- Slice valueSlice = data;
- std::string value = valueSlice.ToString();
- _transaction->Put(keySlice.ToString(), value);
- _changes += 1;
-}
-
-- (BOOL)isEmpty {
- return _changes == 0;
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTWriteGroupTracker.h b/Firestore/Source/Local/FSTWriteGroupTracker.h
deleted file mode 100644
index c4651ab..0000000
--- a/Firestore/Source/Local/FSTWriteGroupTracker.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import <Foundation/Foundation.h>
-#import "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
-
-@class FSTWriteGroup;
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- * Helper class for FSTPersistence implementations to create WriteGroups and verify internal
- * contracts are maintained:
- * 1. Can't create a group when an uncommitted group exists (no nesting).
- * 2. Can't commit a group that differs from the last created one.
- */
-@interface FSTWriteGroupTracker : NSObject
-
-/** Creates and returns an FSTWriteGroupTracker instance. */
-+ (instancetype)tracker;
-
-/**
- * Verifies there's no active group already and then creates a new group and stores it for later
- * validation with `endGroup`.
- */
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action;
-
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action
- transaction:
- (firebase::firestore::local::LevelDbTransaction *)transaction;
-
-/** Ends a group previously started with `startGroupWithAction`. */
-- (void)endGroup:(FSTWriteGroup *)group;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Local/FSTWriteGroupTracker.mm b/Firestore/Source/Local/FSTWriteGroupTracker.mm
deleted file mode 100644
index 2cb10bd..0000000
--- a/Firestore/Source/Local/FSTWriteGroupTracker.mm
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#import "Firestore/Source/Local/FSTWriteGroupTracker.h"
-
-#import "Firestore/Source/Local/FSTWriteGroup.h"
-#import "Firestore/Source/Util/FSTAssert.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface FSTWriteGroupTracker ()
-@property(nonatomic, strong, nullable) FSTWriteGroup *activeGroup;
-@end
-
-@implementation FSTWriteGroupTracker
-
-+ (instancetype)tracker {
- return [[FSTWriteGroupTracker alloc] init];
-}
-
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action {
- // NOTE: We can relax this to allow nesting if/when we find we need it.
- FSTAssert(!self.activeGroup,
- @"Attempt to create write group (%@) while existing write group (%@) still active.",
- action, self.activeGroup.action);
- self.activeGroup = [FSTWriteGroup groupWithAction:action];
- return self.activeGroup;
-}
-
-- (FSTWriteGroup *)startGroupWithAction:(NSString *)action
- transaction:
- (firebase::firestore::local::LevelDbTransaction *)transaction {
- // NOTE: We can relax this to allow nesting if/when we find we need it.
- FSTAssert(!self.activeGroup,
- @"Attempt to create write group (%@) while existing write group (%@) still active.",
- action, self.activeGroup.action);
- self.activeGroup = [FSTWriteGroup groupWithAction:action transaction:transaction];
- return self.activeGroup;
-}
-
-- (void)endGroup:(FSTWriteGroup *)group {
- FSTAssert(self.activeGroup == group,
- @"Attempted to end write group (%@) which is different from active group (%@)",
- group.action, self.activeGroup.action);
- self.activeGroup = nil;
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
index f034b19..d84d441 100644
--- a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
+++ b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.cc
@@ -143,6 +143,7 @@ bool LevelDbTransaction::Iterator::Valid() {
}
LevelDbTransaction::LevelDbTransaction(DB* db,
+ absl::string_view label,
const ReadOptions& read_options,
const WriteOptions& write_options)
: db_(db),
@@ -150,7 +151,8 @@ LevelDbTransaction::LevelDbTransaction(DB* db,
deletions_(),
read_options_(read_options),
write_options_(write_options),
- version_(0) {
+ version_(0),
+ label_(std::string{label}) {
}
const ReadOptions& LevelDbTransaction::DefaultReadOptions() {
@@ -225,7 +227,7 @@ void LevelDbTransaction::Commit() {
}
std::string LevelDbTransaction::ToString() {
- std::string dest("<LevelDbTransaction: ");
+ std::string dest("<LevelDbTransaction " + label_ + ": ");
int64_t changes = deletions_.size() + mutations_.size();
int64_t bytes = 0; // accumulator for size of individual mutations.
dest += std::to_string(changes) + " changes ";
diff --git a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h
index bcc7c91..56a9a77 100644
--- a/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h
+++ b/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h
@@ -126,6 +126,7 @@ class LevelDbTransaction {
explicit LevelDbTransaction(
leveldb::DB* db,
+ absl::string_view label,
const leveldb::ReadOptions& read_options = DefaultReadOptions(),
const leveldb::WriteOptions& write_options = DefaultWriteOptions());
@@ -197,6 +198,7 @@ class LevelDbTransaction {
leveldb::ReadOptions read_options_;
leveldb::WriteOptions write_options_;
int32_t version_;
+ std::string label_;
};
} // namespace local