diff options
author | Greg Soltis <gsoltis@google.com> | 2018-03-26 11:57:34 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-26 11:57:34 -0700 |
commit | f77ec68a8862bd03b430deff48022ffb179172b0 (patch) | |
tree | d6e39cc2ac36c1fb7433edc1372ec10a8064e593 /Firestore/Example | |
parent | acc5c456d39a1150bdb8658df60d215feff42f02 (diff) |
Switch LevelDB MutationQueue and RemoteDocumentCache to use transactions (#968)
* Start work on leveldb transactions
* Style
* Working API. Not plumbed in yet
* Move files into correct place
* Wrangling file locations and associations
* Tests pass
* Add some comments
* style
* Fix copyright
* Rewrite iterator internals to handle deletion-while-iterating. Also add tests for same
* Switch to strings instead of slices
* Style
* More style fixes
* Start switching writegroup over
* Swap out write group tracking for transaction usage
* Style
* Response to feedback before updating docs
* Style
* Add comment
* Initialize version_
* Satisfy the linter
* Start switching writegroup over
* Swap out write group tracking for transaction usage
* Style
* Checkpoint before implementing BatchDescription
* Style
* Initial plumbing for leveldb local parts
* Add model::BatchId
* Port leveldb_key.{h,cc}
* Add string StartsWith
* Add leveldb_key_test.cc to the project
* Revert back to using leveldb::Slice for read/describe
These operations universally operate on keys obtained from leveldb so
it's actually unhelpful to force all the callers to make
absl::string_views from them.
* Everything passing
* Drop unused function
* Style
* STart work on reads
* Swap reads in queryCache to use transactions
* Fix up tests of querycache
* Drop commented out code
* Cleanup
* Style
* Fix up for passing tests
* style
* Renaming
* Style
* Start work on ToString for transactions
* Add ToString() method to LevelDbTransaction
* Style
* lint
* Fix includes, drop runTransaction
* current_transaction -> currentTransaction
* LevelDbTransaction::NewIterator now returns a unique_ptr
* Style
* Revert addition of util::StartsWith
* Add log line
* Style
* Add log line
* Style
* Add debug log line for commits, drop unused BatchDescription
* STart work on reads
* Swap reads in queryCache to use transactions
* Start on remote documents
* Transition mutation queue and remote documents to use transactions
* Style
* Make everything pass
* Make everything pass
* Make it compile
* Style
* Style
* Revert name change, use DefaultReadOptions()
* Style
* Handle iterators returning bad statuses
Diffstat (limited to 'Firestore/Example')
4 files changed, 76 insertions, 8 deletions
diff --git a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm index 4f0332e..ad892d8 100644 --- a/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm +++ b/Firestore/Example/Tests/Local/FSTLevelDBMigrationsTests.mm @@ -21,9 +21,8 @@ #import "Firestore/Source/Local/FSTLevelDBKey.h" #import "Firestore/Source/Local/FSTLevelDBMigrations.h" #import "Firestore/Source/Local/FSTLevelDBQueryCache.h" -#include "leveldb/db.h" - #include "Firestore/core/src/firebase/firestore/util/ordered_code.h" +#include "leveldb/db.h" #import "Firestore/Example/Tests/Local/FSTPersistenceTestHelpers.h" diff --git a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm index cad62cf..014adb1 100644 --- a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm +++ b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm @@ -57,22 +57,32 @@ 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]; } - (void)testAcknowledgeBatchID { @@ -114,10 +124,10 @@ NS_ASSUME_NONNULL_BEGIN FSTWriteGroup *group = [self.persistence startGroupWithAction:NSStringFromSelector(_cmd)]; [self.mutationQueue acknowledgeBatch:batch1 streamToken:nil group:group]; [self.mutationQueue removeMutationBatches:@[ batch1 ] group:group]; - [self.persistence commitGroup:group]; XCTAssertEqual([self batchCount], 0); XCTAssertEqual([self.mutationQueue highestAcknowledgedBatchID], batch1.batchID); + [self.persistence commitGroup:group]; } - (void)testHighestAcknowledgedBatchIDNeverExceedsNextBatchID { @@ -166,13 +176,16 @@ NS_ASSUME_NONNULL_BEGIN 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]; XCTAssertNil(notFound); @@ -187,6 +200,7 @@ NS_ASSUME_NONNULL_BEGIN // Even on a nonempty queue searching should not find a non-existent batch notFound = [self.mutationQueue lookupMutationBatch:42]; XCTAssertNil(notFound); + [self.persistence commitGroup:group]; } - (void)testNextMutationBatchAfterBatchID { @@ -198,6 +212,7 @@ NS_ASSUME_NONNULL_BEGIN 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]; @@ -219,22 +234,29 @@ NS_ASSUME_NONNULL_BEGIN FSTMutationBatch *last = batches[batches.count - 1]; FSTMutationBatch *notFound = [self.mutationQueue nextMutationBatchAfterBatchID:last.batchID]; XCTAssertNil(notFound); + [self.persistence commitGroup:group]; } - (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]; } - (void)testAllMutationBatchesThroughBatchID { @@ -245,6 +267,8 @@ NS_ASSUME_NONNULL_BEGIN NSArray<FSTMutationBatch *> *found, *expected; + FSTWriteGroup *group = + [self.persistence startGroupWithAction:@"AllMutationBatchesThroughBatchID"]; found = [self.mutationQueue allMutationBatchesThroughBatchID:batches[0].batchID - 1]; XCTAssertEqualObjects(found, (@[])); @@ -253,6 +277,7 @@ NS_ASSUME_NONNULL_BEGIN expected = [batches subarrayWithRange:NSMakeRange(0, i + 1)]; XCTAssertEqualObjects(found, expected, @"for index %lu", (unsigned long)i); } + [self.persistence commitGroup:group]; } - (void)testAllMutationBatchesAffectingDocumentKey { @@ -283,12 +308,12 @@ NS_ASSUME_NONNULL_BEGIN group:group]; [batches addObject:batch]; } - [self.persistence commitGroup:group]; NSArray<FSTMutationBatch *> *expected = @[ batches[1], batches[2] ]; NSArray<FSTMutationBatch *> *matches = [self.mutationQueue allMutationBatchesAffectingDocumentKey:testutil::Key("foo/bar")]; + [self.persistence commitGroup:group]; XCTAssertEqualObjects(matches, expected); } @@ -320,12 +345,12 @@ NS_ASSUME_NONNULL_BEGIN group:group]; [batches addObject:batch]; } - [self.persistence commitGroup:group]; 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); } @@ -338,48 +363,68 @@ NS_ASSUME_NONNULL_BEGIN [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]; } - (void)testRemoveMutationBatchesEmitsGarbageEvents { @@ -399,29 +444,42 @@ NS_ASSUME_NONNULL_BEGIN ]]; [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]; } - (void)testStreamToken { diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm index 16b7185..4f5595e 100644 --- a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm +++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm @@ -120,6 +120,7 @@ static const int kVersion = 42; [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) ]; @@ -127,6 +128,7 @@ static const int kVersion = 42; for (FSTDocument *doc in expected) { XCTAssertEqualObjects([results objectForKey:doc.key], doc); } + [self.persistence commitGroup:group]; } #pragma mark - Helpers @@ -144,7 +146,10 @@ static const int kVersion = 42; } - (FSTMaybeDocument *_Nullable)readEntryAtPath:(const absl::string_view)path { - return [self.remoteDocumentCache entryForKey:testutil::Key(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 { diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm index 36d3661..d0466f9 100644 --- a/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm +++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentChangeBufferTests.mm @@ -68,8 +68,10 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testReadUnchangedEntry { + FSTWriteGroup *group = [_db startGroupWithAction:@"ReadUnchangedEntry"]; XCTAssertEqualObjects([_remoteDocumentBuffer entryForKey:FSTTestDocKey(@"coll/a")], _kInitialADoc); + [_db commitGroup:group]; } - (void)testAddEntryAndReadItBack { @@ -78,24 +80,28 @@ 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]; } - (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); // Reading directly against the cache should still yield the old result. XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")], _kInitialADoc); + [_db commitGroup:group]; - FSTWriteGroup *group = [_db startGroupWithAction:@"Apply changes"]; + group = [_db startGroupWithAction:@"Apply changes"]; [_remoteDocumentBuffer applyToWriteGroup:group]; - [_db commitGroup:group]; // Reading against the cache should now yield the new result. XCTAssertEqualObjects([_remoteDocumentCache entryForKey:FSTTestDocKey(@"coll/a")], newADoc); + [_db commitGroup:group]; } - (void)testMethodsThrowAfterApply { |