From 76b206b18e6829af06d78c0cfcf3697dae31c4ad Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 17:15:48 -0500 Subject: [PATCH 001/107] Remove extra imports and includes --- Firestore/Source/Remote/FSTRemoteEvent.h | 3 --- Firestore/Source/Remote/FSTRemoteEvent.mm | 3 --- 2 files changed, 6 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index e3a96e4df45..2b4f66e7c34 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -26,10 +26,7 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -@class FSTDocument; -@class FSTExistenceFilter; @class FSTMaybeDocument; -@class FSTWatchChange; @class FSTQueryData; @class FSTDocumentWatchChange; @class FSTWatchTargetChange; diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 2c5fe95fdc6..9d8ecbe839c 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -23,15 +23,12 @@ #include #import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" -#import "Firestore/Source/Remote/FSTRemoteStore.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/log.h" From 7dcb9aec90d19b24d42229aad2dedb4485ad7b4f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 17:39:53 -0500 Subject: [PATCH 002/107] Port --- .../Tests/Remote/FSTRemoteEventTests.mm | 5 +- .../Tests/Remote/FSTWatchChangeTests.mm | 3 +- .../Example/Tests/SpecTests/FSTSpecTests.mm | 3 +- Firestore/Source/Remote/FSTExistenceFilter.h | 31 ----------- Firestore/Source/Remote/FSTExistenceFilter.mm | 53 ------------------- Firestore/Source/Remote/FSTRemoteEvent.mm | 4 +- Firestore/Source/Remote/FSTRemoteStore.mm | 1 - Firestore/Source/Remote/FSTSerializerBeta.mm | 5 +- Firestore/Source/Remote/FSTWatchChange.h | 7 +-- Firestore/Source/Remote/FSTWatchChange.mm | 16 +++--- 10 files changed, 22 insertions(+), 106 deletions(-) delete mode 100644 Firestore/Source/Remote/FSTExistenceFilter.h delete mode 100644 Firestore/Source/Remote/FSTExistenceFilter.mm diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 1e71ba8d144..c01dd8affff 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -21,7 +21,6 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -572,7 +571,7 @@ - (void)testExistenceFilterMismatchClearsTarget { // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. FSTExistenceFilterWatchChange *change4 = - [FSTExistenceFilterWatchChange changeWithFilter:[FSTExistenceFilter filterWithCount:1] + [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{1} targetID:1]; [aggregator handleExistenceFilter:change4]; @@ -611,7 +610,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { // The existence filter mismatch will remove the document from target 1, but not synthesize a // document delete. FSTExistenceFilterWatchChange *existenceFilter = - [FSTExistenceFilterWatchChange changeWithFilter:[FSTExistenceFilter filterWithCount:0] + [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{0} targetID:1]; [aggregator handleExistenceFilter:existenceFilter]; diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm index a00eba6d711..ac258d4439c 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm @@ -19,7 +19,6 @@ #import #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -45,7 +44,7 @@ - (void)testDocumentChange { } - (void)testExistenceFilterChange { - FSTExistenceFilter *filter = [FSTExistenceFilter filterWithCount:7]; + ExistenceFilter filter = ExistenceFilter{7}; FSTExistenceFilterWatchChange *change = [FSTExistenceFilterWatchChange changeWithFilter:filter targetID:5]; XCTAssertEqual(change.filter.count, 7); diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 827051029af..1ac6deb190e 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -28,7 +28,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" @@ -311,7 +310,7 @@ - (void)doWatchFilter:(NSArray *)watchFilter { int keyCount = watchFilter.count == 0 ? 0 : (int)watchFilter.count - 1; // TODO(dimond): extend this with different existence filters over time. - FSTExistenceFilter *filter = [FSTExistenceFilter filterWithCount:keyCount]; + ExistenceFilter filter{keyCount}; FSTExistenceFilterWatchChange *change = [FSTExistenceFilterWatchChange changeWithFilter:filter targetID:targets[0].intValue]; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; diff --git a/Firestore/Source/Remote/FSTExistenceFilter.h b/Firestore/Source/Remote/FSTExistenceFilter.h deleted file mode 100644 index df95950f944..00000000000 --- a/Firestore/Source/Remote/FSTExistenceFilter.h +++ /dev/null @@ -1,31 +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 - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTExistenceFilter : NSObject - -+ (instancetype)filterWithCount:(int32_t)count; - -- (instancetype)init __attribute__((unavailable("Use a static constructor"))); - -@property(nonatomic, assign, readonly) int32_t count; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTExistenceFilter.mm b/Firestore/Source/Remote/FSTExistenceFilter.mm deleted file mode 100644 index d5ec7b3b3fa..00000000000 --- a/Firestore/Source/Remote/FSTExistenceFilter.mm +++ /dev/null @@ -1,53 +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/Remote/FSTExistenceFilter.h" - -@interface FSTExistenceFilter () - -- (instancetype)initWithCount:(int32_t)count NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTExistenceFilter - -+ (instancetype)filterWithCount:(int32_t)count { - return [[FSTExistenceFilter alloc] initWithCount:count]; -} - -- (instancetype)initWithCount:(int32_t)count { - if (self = [super init]) { - _count = count; - } - return self; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isMemberOfClass:[FSTExistenceFilter class]]) { - return NO; - } - - return _count == ((FSTExistenceFilter *)other).count; -} - -- (NSUInteger)hash { - return _count; -} - -@end diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 9d8ecbe839c..c8dee8f6c5a 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -23,9 +23,9 @@ #include #import "Firestore/Source/Core/FSTQuery.h" +#import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" @@ -412,7 +412,7 @@ - (void)removeTarget:(TargetId)targetID { - (void)handleExistenceFilter:(FSTExistenceFilterWatchChange *)existenceFilter { TargetId targetID = existenceFilter.targetID; - int expectedCount = existenceFilter.filter.count; + int expectedCount = existenceFilter.filter.count(); FSTQueryData *queryData = [self queryDataForActiveTarget:targetID]; if (queryData) { diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 88e797df7f0..5fc96f32c79 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -27,7 +27,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTDatastore.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTOnlineStateTracker.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTStream.h" diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 25badaa8fc3..deb392d2fb2 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -39,7 +39,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" @@ -50,6 +49,7 @@ #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" @@ -69,6 +69,7 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; +using firebase::firestore::remote::ExistenceFilter; NS_ASSUME_NONNULL_BEGIN @@ -1192,7 +1193,7 @@ - (FSTDocumentWatchChange *)decodedDocumentRemove:(GCFSDocumentRemove *)change { - (FSTExistenceFilterWatchChange *)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter { // TODO(dimond): implement existence filter parsing - FSTExistenceFilter *existenceFilter = [FSTExistenceFilter filterWithCount:filter.count]; + ExistenceFilter existenceFilter{filter.count}; TargetId targetID = filter.targetId; return [FSTExistenceFilterWatchChange changeWithFilter:existenceFilter targetID:targetID]; } diff --git a/Firestore/Source/Remote/FSTWatchChange.h b/Firestore/Source/Remote/FSTWatchChange.h index 8a7f72b1ae7..474acaa2a24 100644 --- a/Firestore/Source/Remote/FSTWatchChange.h +++ b/Firestore/Source/Remote/FSTWatchChange.h @@ -18,8 +18,8 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" -@class FSTExistenceFilter; @class FSTMaybeDocument; NS_ASSUME_NONNULL_BEGIN @@ -69,12 +69,13 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FSTExistenceFilterWatchChange : FSTWatchChange -+ (instancetype)changeWithFilter:(FSTExistenceFilter *)filter ++ (instancetype)changeWithFilter:(firebase::firestore::remote::ExistenceFilter)filter targetID:(firebase::firestore::model::TargetId)targetID; - (instancetype)init NS_UNAVAILABLE; -@property(nonatomic, strong, readonly) FSTExistenceFilter *filter; +- (const firebase::firestore::remote::ExistenceFilter&) filter; + @property(nonatomic, assign, readonly) firebase::firestore::model::TargetId targetID; @end diff --git a/Firestore/Source/Remote/FSTWatchChange.mm b/Firestore/Source/Remote/FSTWatchChange.mm index 1387b02270e..3e1a982d89a 100644 --- a/Firestore/Source/Remote/FSTWatchChange.mm +++ b/Firestore/Source/Remote/FSTWatchChange.mm @@ -19,12 +19,12 @@ #include #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTExistenceFilter.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::ExistenceFilter; NS_ASSUME_NONNULL_BEGIN @@ -80,18 +80,20 @@ - (NSUInteger)hash { @interface FSTExistenceFilterWatchChange () -- (instancetype)initWithFilter:(FSTExistenceFilter *)filter +- (instancetype)initWithFilter:(ExistenceFilter)filter targetID:(TargetId)targetID NS_DESIGNATED_INITIALIZER; @end -@implementation FSTExistenceFilterWatchChange +@implementation FSTExistenceFilterWatchChange { + ExistenceFilter _filter; +} -+ (instancetype)changeWithFilter:(FSTExistenceFilter *)filter targetID:(TargetId)targetID { ++ (instancetype)changeWithFilter:(ExistenceFilter)filter targetID:(TargetId)targetID { return [[FSTExistenceFilterWatchChange alloc] initWithFilter:filter targetID:targetID]; } -- (instancetype)initWithFilter:(FSTExistenceFilter *)filter targetID:(TargetId)targetID { +- (instancetype)initWithFilter:(ExistenceFilter)filter targetID:(TargetId)targetID { self = [super init]; if (self) { _filter = filter; @@ -109,11 +111,11 @@ - (BOOL)isEqual:(id)other { } FSTExistenceFilterWatchChange *otherChange = (FSTExistenceFilterWatchChange *)other; - return [_filter isEqual:otherChange->_filter] && _targetID == otherChange->_targetID; + return _filter == otherChange->_filter && _targetID == otherChange->_targetID; } - (NSUInteger)hash { - return self.filter.hash; + return _filter.count(); } @end From 88ba1a7bdd6d83ef86db5ed77693843b612ea8cd Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 17:46:02 -0500 Subject: [PATCH 003/107] Forgotten method --- Firestore/Source/Remote/FSTWatchChange.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Firestore/Source/Remote/FSTWatchChange.mm b/Firestore/Source/Remote/FSTWatchChange.mm index 3e1a982d89a..f178340dd1c 100644 --- a/Firestore/Source/Remote/FSTWatchChange.mm +++ b/Firestore/Source/Remote/FSTWatchChange.mm @@ -102,7 +102,11 @@ - (instancetype)initWithFilter:(ExistenceFilter)filter targetID:(TargetId)target return self; } +- (const ExistenceFilter&) filter { + return _filter; +} - (BOOL)isEqual:(id)other { + if (other == self) { return YES; } From 895bf4575d782243b445f43bd88c85a5f3c93960 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 17:48:09 -0500 Subject: [PATCH 004/107] style.sh --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 6 ++---- Firestore/Source/Local/FSTLocalStore.mm | 7 ++++--- Firestore/Source/Remote/FSTWatchChange.h | 2 +- Firestore/Source/Remote/FSTWatchChange.mm | 3 +-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index c01dd8affff..c4fb19f7ec6 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -571,8 +571,7 @@ - (void)testExistenceFilterMismatchClearsTarget { // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. FSTExistenceFilterWatchChange *change4 = - [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{1} - targetID:1]; + [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{1} targetID:1]; [aggregator handleExistenceFilter:change4]; event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(4)]; @@ -610,8 +609,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { // The existence filter mismatch will remove the document from target 1, but not synthesize a // document delete. FSTExistenceFilterWatchChange *existenceFilter = - [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{0} - targetID:1]; + [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{0} targetID:1]; [aggregator handleExistenceFilter:existenceFilter]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 6e2eea6493f..64a0c7698c0 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -375,9 +375,10 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run( + "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { diff --git a/Firestore/Source/Remote/FSTWatchChange.h b/Firestore/Source/Remote/FSTWatchChange.h index 474acaa2a24..f505429d589 100644 --- a/Firestore/Source/Remote/FSTWatchChange.h +++ b/Firestore/Source/Remote/FSTWatchChange.h @@ -74,7 +74,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -- (const firebase::firestore::remote::ExistenceFilter&) filter; +- (const firebase::firestore::remote::ExistenceFilter &)filter; @property(nonatomic, assign, readonly) firebase::firestore::model::TargetId targetID; @end diff --git a/Firestore/Source/Remote/FSTWatchChange.mm b/Firestore/Source/Remote/FSTWatchChange.mm index f178340dd1c..67d6ac2579c 100644 --- a/Firestore/Source/Remote/FSTWatchChange.mm +++ b/Firestore/Source/Remote/FSTWatchChange.mm @@ -102,11 +102,10 @@ - (instancetype)initWithFilter:(ExistenceFilter)filter targetID:(TargetId)target return self; } -- (const ExistenceFilter&) filter { +- (const ExistenceFilter &)filter { return _filter; } - (BOOL)isEqual:(id)other { - if (other == self) { return YES; } From b66c5d2cfd3e2f6a7ca6c9e7cea1d79f138a6f8b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 17:48:39 -0500 Subject: [PATCH 005/107] Forgotten the main part! --- .../firestore/remote/existence_filter.h | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/remote/existence_filter.h diff --git a/Firestore/core/src/firebase/firestore/remote/existence_filter.h b/Firestore/core/src/firebase/firestore/remote/existence_filter.h new file mode 100644 index 00000000000..d84bd531ef4 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/existence_filter.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_EXISTENCE_FILTER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_EXISTENCE_FILTER_H_ + +namespace firebase { +namespace firestore { +namespace remote { + +/** Simplest form of existence filter */ +class ExistenceFilter { + public: + ExistenceFilter() = default; + explicit ExistenceFilter(int count) : count_{count} { + } + + int count() const { + return count_; + } + + private: + int count_ = 0; +}; + +inline bool operator==(const ExistenceFilter& lhs, const ExistenceFilter& rhs) { + return lhs.count() == rhs.count(); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_EXISTENCE_FILTER_H_ From 3f5fdaed6319355edc38650f7c4db94d30c6544a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 15 Jan 2019 18:02:52 -0500 Subject: [PATCH 006/107] Fixup unit tests --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 2 ++ Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm | 8 ++++++-- Firestore/Example/Tests/SpecTests/FSTSpecTests.mm | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index c4fb19f7ec6..0d3a39fb0cc 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -23,6 +23,7 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -33,6 +34,7 @@ using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::remote::ExistenceFilter; NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm index ac258d4439c..28360742ecd 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm @@ -23,6 +23,10 @@ #import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" + +using firebase::firestore::remote::ExistenceFilter; + NS_ASSUME_NONNULL_BEGIN @interface FSTWatchChangeTests : XCTestCase @@ -44,10 +48,10 @@ - (void)testDocumentChange { } - (void)testExistenceFilterChange { - ExistenceFilter filter = ExistenceFilter{7}; + ExistenceFilter filter{7}; FSTExistenceFilterWatchChange *change = [FSTExistenceFilterWatchChange changeWithFilter:filter targetID:5]; - XCTAssertEqual(change.filter.count, 7); + XCTAssertEqual(change.filter.count(), 7); XCTAssertEqual(change.targetID, 5); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 1ac6deb190e..ee92a746a0c 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -39,6 +39,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" @@ -52,6 +53,7 @@ using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::ExistenceFilter; using firebase::firestore::util::TimerId; NS_ASSUME_NONNULL_BEGIN From 5ce04b83cfdd0e6421981451cea180423ddfd60a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 16 Jan 2019 18:42:20 -0500 Subject: [PATCH 007/107] Wip --- Firestore/Source/Remote/FSTSerializerBeta.h | 5 +- Firestore/Source/Remote/FSTSerializerBeta.mm | 44 +++-- .../firebase/firestore/remote/watch_change.cc | 26 +++ .../firebase/firestore/remote/watch_change.h | 173 ++++++++++++++++++ 4 files changed, 224 insertions(+), 24 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/remote/watch_change.cc create mode 100644 Firestore/core/src/firebase/firestore/remote/watch_change.h diff --git a/Firestore/Source/Remote/FSTSerializerBeta.h b/Firestore/Source/Remote/FSTSerializerBeta.h index cd62371f437..46231e18829 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.h +++ b/Firestore/Source/Remote/FSTSerializerBeta.h @@ -16,10 +16,13 @@ #import +#include + #include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTFieldValue; @class FSTMaybeDocument; @@ -98,7 +101,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query; - (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target; -- (FSTWatchChange *)decodedWatchChange:(GCFSListenResponse *)watchChange; +- (std::unique_ptr )decodedWatchChange:(GCFSListenResponse *)watchChange; - (firebase::firestore::model::SnapshotVersion)versionFromListenResponse: (GCFSListenResponse *)watchChange; diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index deb392d2fb2..bf6ae1498e0 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -39,7 +39,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -50,7 +49,9 @@ #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" #include "absl/types/optional.h" @@ -1058,9 +1059,9 @@ - (FSTBound *)decodedBound:(GCFSCursor *)proto { return [FSTBound boundWithPosition:indexComponents isBefore:proto.before]; } -#pragma mark - FSTWatchChange <= GCFSListenResponse proto +#pragma mark - WatchChange <= GCFSListenResponse proto -- (FSTWatchChange *)decodedWatchChange:(GCFSListenResponse *)watchChange { +- (std::unique_ptr)decodedWatchChange:(GCFSListenResponse *)watchChange { switch (watchChange.responseTypeOneOfCase) { case GCFSListenResponse_ResponseType_OneOfCase_TargetChange: return [self decodedTargetChangeFromWatchChange:watchChange.targetChange]; @@ -1095,41 +1096,38 @@ - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { return [self decodedVersion:watchChange.targetChange.readTime]; } -- (FSTWatchTargetChange *)decodedTargetChangeFromWatchChange:(GCFSTargetChange *)change { - FSTWatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType]; - NSMutableArray *targetIDs = - [NSMutableArray arrayWithCapacity:change.targetIdsArray_Count]; +- (std::unique_ptr)decodedTargetChangeFromWatchChange: + (GCFSTargetChange *)change { + WatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType]; + std::vector targetIDs; [change.targetIdsArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { - [targetIDs addObject:@(value)]; + target_ids.push_back(value); }]; - NSError *cause = nil; + std::string resumeToken = util::MakeString(change.resumeToken); + + util::Status cause; if (change.hasCause) { - cause = [NSError errorWithDomain:FIRFirestoreErrorDomain - code:change.cause.code - userInfo:@{NSLocalizedDescriptionKey : change.cause.message}]; + cause = util::Status{code : change.cause.code, change.cause.message}; } - return [[FSTWatchTargetChange alloc] initWithState:state - targetIDs:targetIDs - resumeToken:change.resumeToken - cause:cause]; + return absl::make_unique(state, std::move(targetIDs), std::move(resumeToken), + std::move(cause)); } -- (FSTWatchTargetChangeState)decodedWatchTargetChangeState: - (GCFSTargetChange_TargetChangeType)state { +- (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_TargetChangeType)state { switch (state) { case GCFSTargetChange_TargetChangeType_NoChange: - return FSTWatchTargetChangeStateNoChange; + return WatchTargetChangeState::NoChange; case GCFSTargetChange_TargetChangeType_Add: - return FSTWatchTargetChangeStateAdded; + return WatchTargetChangeState::Added; case GCFSTargetChange_TargetChangeType_Remove: - return FSTWatchTargetChangeStateRemoved; + return WatchTargetChangeState::Removed; case GCFSTargetChange_TargetChangeType_Current: - return FSTWatchTargetChangeStateCurrent; + return WatchTargetChangeState::Current; case GCFSTargetChange_TargetChangeType_Reset: - return FSTWatchTargetChangeStateReset; + return WatchTargetChangeState::Reset; default: HARD_FAIL("Unexpected TargetChange.state: %s", state); } diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.cc b/Firestore/core/src/firebase/firestore/remote/watch_change.cc new file mode 100644 index 00000000000..ef893838029 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.cc @@ -0,0 +1,26 @@ +/* + * Copyright 2019 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" + +namespace firebase { +namespace firestore { +namespace remote { + + +} // namespace remote +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h new file mode 100644 index 00000000000..ec3cf4c2853 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -0,0 +1,173 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ + +#if !defined(__OBJC__) +// TODO(varconst): the only dependency is `FSTMaybeDocument`. +#error "This header only supports Objective-C++" +#endif // !defined(__OBJC__) + +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" + +@class FSTMaybeDocument; + +namespace firebase { +namespace firestore { +namespace remote { + +/** + * `WatchChange` is the internal representation of the watcher API protocol + * buffers. This is an empty abstract class so that all the different kinds of + * changes can have a common base class. + */ +class WatchChange { + public: + virtual ~WatchChange() { + } +}; + +/** + * `DocumentWatchChange` represents a changed document and a list of target ids + * to which this change applies. + * + * If document has been deleted, a `DeletedDocument` will be provided. + */ +class DocumentWatchChange : public WatchChange { + public: + DocumentWatchChange(std::vector&& updated_target_ids, + std::vector&& removed_target_ids, + model::DocumentKey&& document_key, + FSTMaybeDocument* new_document) + : updated_target_ids_{std::move(updated_target_ids)}, + removed_target_ids_{std::move(removed_target_ids)}, + document_key_{std::move(document_key)}, + new_document_{new_document} { + } + + /** The new document applies to all of these targets. */ + const std::vector& updated_target_ids_() const { + return updated_target_ids_; + } + + /** The new document is removed from all of these targets. */ + const std::vector& removed_target_ids_() const { + return removed_target_ids_; + } + + /** + * The new document, or `DeletedDocument` if it was deleted. Is null if the + * document went out of view without the server sending a new document. + */ + FSTMaybeDocument* new_document() const { + return new_document; + } + + /** The key of the document for this change. */ + const model::DocumentKey& document_key() const { + return document_key_; + } + + private: + std::vector updated_target_ids_; + std::vector removed_target_ids_; + model::DocumentKey document_key_; + FSTMaybeDocument* new_document_; +}; + +bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); + +/** + * An `ExistenceFilterWatchChange` applies to the targets and is required to + * verify the current client state against expected state sent from the server. + */ +class ExistenceFilterWatchChange : public WatchChange { + public: + ExistenceFilterWatchChange(ExistenceFilter filter, model::TargetId target_id) + : filter_{filter}, target_id_{target_id} { + } + + private: + ExistenceFilter filter_; + model::TargetId target_id_; +}; + +bool operator==(const ExistenceFilterWatchChange& lhs, + const ExistenceFilterWatchChange& rhs); + +enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; + +class WatchTargetChange : public WatchChange { + public: + WatchTargetChange(WatchTargetChangeState state, + std::vector&& target_ids, + std::string&& resume_token, + util::Status&& cause) + : state_{state}, + target_ids_{std::move(target_ids)}, + resume_token_{std::move(resume_token)}, + cause_{std::move(cause)} { + } + + /** What kind of change occurred to the watch target. */ + WatchTargetChangeState state() const { + return state_; + } + + /** The target IDs that were added/removed/set. */ + const std::vector& target_ids() const { + return target_ids_; + } + + /** + * An opaque, server-assigned token that allows watching a query to be + * resumed after disconnecting without retransmitting all the data that + * matches the query. The resume token essentially identifies a point in + * time from which the server should resume sending results. + */ + const std::string& resume_token() const { + return resume_token_; + } + + /** + * An RPC error indicating why the watch failed. Only valid if + * WatchChangeState == Removed. + */ + const util::Status& status() const { + return status_; + } + + private: + WatchTargetChangeState state_; + std::vector target_ids_; + std::string resume_token_; + util::Status cause_; +}; + +inline bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { +} + +} // namespace remote +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ From 3dc317074d8aad9505c065b2529b63a0e272be81 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 17 Jan 2019 19:08:37 -0500 Subject: [PATCH 008/107] Step back --- Firestore/Source/Local/FSTLocalSerializer.mm | 5 +- Firestore/Source/Local/FSTLocalStore.mm | 9 +- Firestore/Source/Local/FSTQueryData.h | 8 +- Firestore/Source/Local/FSTQueryData.mm | 22 +- Firestore/Source/Remote/FSTDatastore.h | 1 - Firestore/Source/Remote/FSTRemoteEvent.h | 17 +- Firestore/Source/Remote/FSTRemoteEvent.mm | 111 ++-- Firestore/Source/Remote/FSTRemoteStore.mm | 561 +++++++++--------- Firestore/Source/Remote/FSTSerializerBeta.h | 3 +- Firestore/Source/Remote/FSTSerializerBeta.mm | 71 +-- Firestore/Source/Remote/FSTStream.h | 4 +- Firestore/Source/Remote/FSTWatchChange.h | 119 ---- Firestore/Source/Remote/FSTWatchChange.mm | 167 ------ .../firestore/remote/remote_objc_bridge.h | 7 +- .../firebase/firestore/remote/watch_change.h | 63 +- 15 files changed, 461 insertions(+), 707 deletions(-) delete mode 100644 Firestore/Source/Remote/FSTWatchChange.h delete mode 100644 Firestore/Source/Remote/FSTWatchChange.mm diff --git a/Firestore/Source/Local/FSTLocalSerializer.mm b/Firestore/Source/Local/FSTLocalSerializer.mm index 5ad70e43c47..5dc98dcae01 100644 --- a/Firestore/Source/Local/FSTLocalSerializer.mm +++ b/Firestore/Source/Local/FSTLocalSerializer.mm @@ -217,7 +217,7 @@ - (FSTPBTarget *)encodedQueryData:(FSTQueryData *)queryData { proto.targetId = queryData.targetID; proto.lastListenSequenceNumber = queryData.sequenceNumber; proto.snapshotVersion = [remoteSerializer encodedVersion:queryData.snapshotVersion]; - proto.resumeToken = queryData.resumeToken; + proto.resumeToken = [NSData dataWithBytes:queryData.resumeToken.data() length:queryData.resumeToken.size()]; FSTQuery *query = queryData.query; if ([query isDocumentQuery]) { @@ -235,7 +235,8 @@ - (FSTQueryData *)decodedQueryData:(FSTPBTarget *)target { TargetId targetID = target.targetId; ListenSequenceNumber sequenceNumber = target.lastListenSequenceNumber; SnapshotVersion version = [remoteSerializer decodedVersion:target.snapshotVersion]; - NSData *resumeToken = target.resumeToken; + auto tokenData = static_cast(target.resumeToken.bytes); + std::vector resumeToken{tokenData, tokenData + target.resumeToken.length}; FSTQuery *query; switch (target.targetTypeOneOfCase) { diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 64a0c7698c0..4a3b7252a9a 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -247,11 +247,10 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // Update the resume token if the change includes one. Don't clear any preexisting value. // Bump the sequence number as well, so that documents being removed now are ordered later // than documents that were previously removed from this target. - NSData *resumeToken = change.resumeToken; - if (resumeToken.length > 0) { + if (!change.resumeToken.empty()) { FSTQueryData *oldQueryData = queryData; queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshotVersion - resumeToken:resumeToken + resumeToken:change.resumeToken sequenceNumber:sequenceNumber]; self.targetIDs[boxedTargetID] = queryData; @@ -331,10 +330,10 @@ - (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData oldQueryData:(FSTQueryData *)oldQueryData change:(FSTTargetChange *)change { // Avoid clearing any existing value - if (newQueryData.resumeToken.length == 0) return NO; + if (newQueryData.resumeToken.empty()) return NO; // Any resume token is interesting if there isn't one already. - if (oldQueryData.resumeToken.length == 0) return YES; + if (oldQueryData.resumeToken.empty()) return YES; // Don't allow resume token changes to be buffered indefinitely. This allows us to be reasonably // up-to-date after a crash and avoids needing to loop over all active queries on shutdown. diff --git a/Firestore/Source/Local/FSTQueryData.h b/Firestore/Source/Local/FSTQueryData.h index f96f327c6b9..7caf1755b21 100644 --- a/Firestore/Source/Local/FSTQueryData.h +++ b/Firestore/Source/Local/FSTQueryData.h @@ -16,6 +16,8 @@ #import +#include + #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" @@ -43,7 +45,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { listenSequenceNumber:(firebase::firestore::model::ListenSequenceNumber)sequenceNumber purpose:(FSTQueryPurpose)purpose snapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken NS_DESIGNATED_INITIALIZER; + resumeToken:(const std::vector&)resumeToken NS_DESIGNATED_INITIALIZER; /** Convenience initializer for use when creating an FSTQueryData for the first time. */ - (instancetype)initWithQuery:(FSTQuery *)query @@ -59,7 +61,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { */ - (instancetype) queryDataByReplacingSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken + resumeToken:(const std::vector&)resumeToken sequenceNumber: (firebase::firestore::model::ListenSequenceNumber)sequenceNumber; @@ -86,7 +88,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { * without retransmitting all the data that matches the query. The resume token essentially * identifies a point in time from which the server should resume sending results. */ -@property(nonatomic, copy, readonly) NSData *resumeToken; +- (const std::vector&) resumeToken; @end diff --git a/Firestore/Source/Local/FSTQueryData.mm b/Firestore/Source/Local/FSTQueryData.mm index dc174c37ef2..17a3412a9fc 100644 --- a/Firestore/Source/Local/FSTQueryData.mm +++ b/Firestore/Source/Local/FSTQueryData.mm @@ -32,6 +32,7 @@ @implementation FSTQueryData { SnapshotVersion _snapshotVersion; + std::vector _resumeToken; } - (instancetype)initWithQuery:(FSTQuery *)query @@ -39,7 +40,7 @@ - (instancetype)initWithQuery:(FSTQuery *)query listenSequenceNumber:(ListenSequenceNumber)sequenceNumber purpose:(FSTQueryPurpose)purpose snapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken { + resumeToken:(const std::vector&)resumeToken { self = [super init]; if (self) { _query = query; @@ -47,7 +48,7 @@ - (instancetype)initWithQuery:(FSTQuery *)query _sequenceNumber = sequenceNumber; _purpose = purpose; _snapshotVersion = std::move(snapshotVersion); - _resumeToken = [resumeToken copy]; + _resumeToken = resumeToken; } return self; } @@ -61,10 +62,14 @@ - (instancetype)initWithQuery:(FSTQuery *)query listenSequenceNumber:sequenceNumber purpose:purpose snapshotVersion:SnapshotVersion::None() - resumeToken:[NSData data]]; + resumeToken:{}]; } -- (const firebase::firestore::model::SnapshotVersion &)snapshotVersion { +- (const std::vector&) resumeToken { + return _resumeToken; +} + +- (const SnapshotVersion &)snapshotVersion { return _snapshotVersion; } @@ -80,24 +85,25 @@ - (BOOL)isEqual:(id)object { return [self.query isEqual:other.query] && self.targetID == other.targetID && self.sequenceNumber == other.sequenceNumber && self.purpose == other.purpose && self.snapshotVersion == other.snapshotVersion && - [self.resumeToken isEqual:other.resumeToken]; + _resumeToken == other->_resumeToken; } - (NSUInteger)hash { return util::Hash([self.query hash], self.targetID, self.sequenceNumber, static_cast(self.purpose), self.snapshotVersion.Hash(), - [self.resumeToken hash]); + _resumeToken); } - (NSString *)description { + NSData *token = [NSData dataWithBytes:_resumeToken.data() length:_resumeToken.size()]; return [NSString stringWithFormat:@"", self.query, self.targetID, (unsigned long)self.purpose, - self.snapshotVersion.timestamp().ToString().c_str(), self.resumeToken]; + self.snapshotVersion.timestamp().ToString().c_str(), token]; } - (instancetype)queryDataByReplacingSnapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(NSData *)resumeToken + resumeToken:(const std::vector&)resumeToken sequenceNumber:(ListenSequenceNumber)sequenceNumber { return [[FSTQueryData alloc] initWithQuery:self.query targetID:self.targetID diff --git a/Firestore/Source/Remote/FSTDatastore.h b/Firestore/Source/Remote/FSTDatastore.h index 735119fd06d..8a3c5de7127 100644 --- a/Firestore/Source/Remote/FSTDatastore.h +++ b/Firestore/Source/Remote/FSTDatastore.h @@ -36,7 +36,6 @@ @class FSTMutationResult; @class FSTQueryData; @class FSTSerializerBeta; -@class FSTWatchChange; NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 2b4f66e7c34..70595922349 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -25,12 +26,10 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTMaybeDocument; @class FSTQueryData; -@class FSTDocumentWatchChange; -@class FSTWatchTargetChange; -@class FSTExistenceFilterWatchChange; NS_ASSUME_NONNULL_BEGIN @@ -66,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Creates a new target change with the given SnapshotVersion. */ -- (instancetype)initWithResumeToken:(NSData *)resumeToken +- (instancetype)initWithResumeToken:(const std::vector&)resumeToken current:(BOOL)current addedDocuments:(firebase::firestore::model::DocumentKeySet)addedDocuments modifiedDocuments:(firebase::firestore::model::DocumentKeySet)modifiedDocuments @@ -80,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN * disconnecting without retransmitting all the data that matches the query. The resume token * essentially identifies a point in time from which the server should resume sending results. */ -@property(nonatomic, strong, readonly) NSData *resumeToken; +- (const std::vector&) resumeToken; /** * The "current" (synced) status of this target. Note that "current" has special meaning in the RPC @@ -169,11 +168,11 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -/** Processes and adds the FSTDocumentWatchChange to the current set of changes. */ -- (void)handleDocumentChange:(FSTDocumentWatchChange *)documentChange; +/** Processes and adds the DocumentWatchChange to the current set of changes. */ +- (void)handleDocumentChange:(const firebase::firestore::remote::DocumentWatchChange&)documentChange; /** Processes and adds the WatchTargetChange to the current set of changes. */ -- (void)handleTargetChange:(FSTWatchTargetChange *)targetChange; +- (void)handleTargetChange:(const firebase::firestore::remote::WatchTargetChange&)targetChange; /** Removes the in-memory state for the provided target. */ - (void)removeTarget:(firebase::firestore::model::TargetId)targetID; @@ -182,7 +181,7 @@ NS_ASSUME_NONNULL_BEGIN * Handles existence filters and synthesizes deletes for filter mismatches. Targets that are * invalidated by filter mismatches are added to `targetMismatches`. */ -- (void)handleExistenceFilter:(FSTExistenceFilterWatchChange *)existenceFilter; +- (void)handleExistenceFilter:(const firebase::firestore::remote::ExistenceFilterWatchChange&)existenceFilter; /** * Increment the number of acks needed from watch before we can consider the server to be 'in-sync' diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index c8dee8f6c5a..bfefd45bce7 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -26,9 +25,9 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/log.h" @@ -38,6 +37,10 @@ using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::util::Hash; NS_ASSUME_NONNULL_BEGIN @@ -45,18 +48,19 @@ #pragma mark - FSTTargetChange @implementation FSTTargetChange { + std::vector _resumeToken; DocumentKeySet _addedDocuments; DocumentKeySet _modifiedDocuments; DocumentKeySet _removedDocuments; } -- (instancetype)initWithResumeToken:(NSData *)resumeToken +- (instancetype)initWithResumeToken:(const std::vector&)resumeToken current:(BOOL)current addedDocuments:(DocumentKeySet)addedDocuments modifiedDocuments:(DocumentKeySet)modifiedDocuments removedDocuments:(DocumentKeySet)removedDocuments { if (self = [super init]) { - _resumeToken = [resumeToken copy]; + _resumeToken = resumeToken; _current = current; _addedDocuments = std::move(addedDocuments); _modifiedDocuments = std::move(modifiedDocuments); @@ -65,6 +69,10 @@ - (instancetype)initWithResumeToken:(NSData *)resumeToken return self; } +- (const std::vector&) resumeToken { + return _resumeToken; +} + - (const DocumentKeySet &)addedDocuments { return _addedDocuments; } @@ -86,7 +94,7 @@ - (BOOL)isEqual:(id)other { } return [self current] == [other current] && - [[self resumeToken] isEqualToData:[other resumeToken]] && + _resumeToken == static_cast(other)->_resumeToken && [self addedDocuments] == [other addedDocuments] && [self modifiedDocuments] == [other modifiedDocuments] && [self removedDocuments] == [other removedDocuments]; @@ -109,7 +117,7 @@ @interface FSTTargetState : NSObject @property(nonatomic) BOOL current; /** The last resume token sent to us for this target. */ -@property(nonatomic, readonly, strong) NSData *resumeToken; +- (const std::vector&) resumeToken; /** Whether we have modified any state that should trigger a snapshot. */ @property(nonatomic, readonly) BOOL hasPendingChanges; @@ -121,7 +129,7 @@ - (BOOL)isPending; * Applies the resume token to the TargetChange, but only when it has a new value. Empty * resumeTokens are discarded. */ -- (void)updateResumeToken:(NSData *)resumeToken; +- (void)updateResumeToken:(const std::vector&)resumeToken; /** Resets the document changes and sets `hasPendingChanges` to false. */ - (void)clearPendingChanges; @@ -142,6 +150,7 @@ - (void)removeDocumentChangeForKey:(const DocumentKey &)documentKey; @end @implementation FSTTargetState { + std::vector _resumeToken; /** * The number of outstanding responses (adds or removes) that we are waiting on. We only consider * targets active that have no outstanding responses. @@ -159,7 +168,6 @@ @implementation FSTTargetState { - (instancetype)init { if (self = [super init]) { - _resumeToken = [NSData data]; _outstandingResponses = 0; // We initialize to 'true' so that newly-added targets are included in the next RemoteEvent. @@ -172,10 +180,14 @@ - (BOOL)isPending { return _outstandingResponses != 0; } -- (void)updateResumeToken:(NSData *)resumeToken { - if (resumeToken.length > 0) { +- (const std::vector&) resumeToken { + return _resumeToken; +} + +- (void)updateResumeToken:(const std::vector&)resumeToken { + if (!resumeToken.empty()) { _hasPendingChanges = YES; - _resumeToken = [resumeToken copy]; + _resumeToken = resumeToken; } } @@ -318,34 +330,34 @@ - (instancetype)initWithTargetMetadataProvider: return self; } -- (void)handleDocumentChange:(FSTDocumentWatchChange *)documentChange { - for (FSTBoxedTargetID *targetID in documentChange.updatedTargetIDs) { - if ([documentChange.document isKindOfClass:[FSTDocument class]]) { - [self addDocument:documentChange.document toTarget:targetID.intValue]; - } else if ([documentChange.document isKindOfClass:[FSTDeletedDocument class]]) { - [self removeDocument:documentChange.document - withKey:documentChange.documentKey - fromTarget:targetID.intValue]; +- (void)handleDocumentChange:(const DocumentWatchChange&)documentChange { + for (TargetId targetID : documentChange.updated_target_ids()) { + if ([documentChange.new_document() isKindOfClass:[FSTDocument class]]) { + [self addDocument:documentChange.new_document() toTarget:targetID]; + } else if ([documentChange.new_document() isKindOfClass:[FSTDeletedDocument class]]) { + [self removeDocument:documentChange.new_document() + withKey:documentChange.document_key() + fromTarget:targetID]; } } - for (FSTBoxedTargetID *targetID in documentChange.removedTargetIDs) { - [self removeDocument:documentChange.document - withKey:documentChange.documentKey - fromTarget:targetID.intValue]; + for (TargetId targetID : documentChange.removed_target_ids()) { + [self removeDocument:documentChange.new_document() + withKey:documentChange.document_key() + fromTarget:targetID]; } } -- (void)handleTargetChange:(FSTWatchTargetChange *)targetChange { +- (void)handleTargetChange:(const WatchTargetChange&)targetChange { for (TargetId targetID : [self targetIdsForChange:targetChange]) { FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - switch (targetChange.state) { - case FSTWatchTargetChangeStateNoChange: + switch (targetChange.state()) { + case WatchTargetChangeState::NoChange: if ([self isActiveTarget:targetID]) { - [targetState updateResumeToken:targetChange.resumeToken]; + [targetState updateResumeToken:targetChange.resume_token()]; } break; - case FSTWatchTargetChangeStateAdded: + case WatchTargetChangeState::Added: // We need to decrement the number of pending acks needed from watch for this targetId. [targetState recordTargetResponse]; if (!targetState.isPending) { @@ -353,34 +365,34 @@ - (void)handleTargetChange:(FSTWatchTargetChange *)targetChange { // This can happen e.g. when remove and add back a target for existence filter mismatches. [targetState clearPendingChanges]; } - [targetState updateResumeToken:targetChange.resumeToken]; + [targetState updateResumeToken:targetChange.resume_token()]; break; - case FSTWatchTargetChangeStateRemoved: + case WatchTargetChangeState::Removed: // We need to keep track of removed targets to we can post-filter and remove any target // changes. [targetState recordTargetResponse]; if (!targetState.isPending) { [self removeTarget:targetID]; } - HARD_ASSERT(!targetChange.cause, "WatchChangeAggregator does not handle errored targets"); + HARD_ASSERT(targetChange.cause().ok(), "WatchChangeAggregator does not handle errored targets"); break; - case FSTWatchTargetChangeStateCurrent: + case WatchTargetChangeState::Current: if ([self isActiveTarget:targetID]) { [targetState markCurrent]; - [targetState updateResumeToken:targetChange.resumeToken]; + [targetState updateResumeToken:targetChange.resume_token()]; } break; - case FSTWatchTargetChangeStateReset: + case WatchTargetChangeState::Reset: if ([self isActiveTarget:targetID]) { // Reset the target and synthesizes removes for all existing documents. The backend will // re-add any documents that still match the target before it sends the next global // snapshot. [self resetTarget:targetID]; - [targetState updateResumeToken:targetChange.resumeToken]; + [targetState updateResumeToken:targetChange.resume_token()]; } break; default: - HARD_FAIL("Unknown target watch change state: %s", targetChange.state); + HARD_FAIL("Unknown target watch change state: %s", targetChange.state()); } } } @@ -389,20 +401,17 @@ - (void)handleTargetChange:(FSTWatchTargetChange *)targetChange { * Returns all targetIds that the watch change applies to: either the targetIds explicitly listed * in the change or the targetIds of all currently active targets. */ -- (std::vector)targetIdsForChange:(FSTWatchTargetChange *)targetChange { - NSArray *targetIDs = targetChange.targetIDs; +- (std::vector)targetIdsForChange:(const WatchTargetChange&)targetChange { + if (!targetChange.target_ids().empty()) { + return targetChange.target_ids(); + } + std::vector result; - if (targetIDs.count > 0) { - result.reserve(targetIDs.count); - for (NSNumber *targetID in targetIDs) { - result.push_back(targetID.intValue); - } - } else { - result.reserve(_targetStates.size()); - for (const auto &entry : _targetStates) { - result.push_back(entry.first); - } + result.reserve(_targetStates.size()); + for (const auto &entry : _targetStates) { + result.push_back(entry.first); } + return result; } @@ -410,9 +419,9 @@ - (void)removeTarget:(TargetId)targetID { _targetStates.erase(targetID); } -- (void)handleExistenceFilter:(FSTExistenceFilterWatchChange *)existenceFilter { - TargetId targetID = existenceFilter.targetID; - int expectedCount = existenceFilter.filter.count(); +- (void)handleExistenceFilter:(const ExistenceFilterWatchChange&)existenceFilter { + TargetId targetID = existenceFilter.target_id(); + int expectedCount = existenceFilter.filter().count(); FSTQueryData *queryData = [self queryDataForActiveTarget:targetID]; if (queryData) { diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 5fc96f32c79..aa4279784ae 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -18,6 +18,7 @@ #include #include +#include #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Core/FSTTransaction.h" @@ -30,13 +31,13 @@ #import "Firestore/Source/Remote/FSTOnlineStateTracker.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -79,17 +80,6 @@ @interface FSTRemoteStore () #pragma mark Watch Stream -/** - * A mapping of watched targets that the client cares about tracking and the - * user has explicitly called a 'listen' for this target. - * - * These targets may or may not have been sent to or acknowledged by the - * server. On re-establishing the listen stream, these targets should be sent - * to the server. The targets removed with unlistens are removed eagerly - * without waiting for confirmation from the listen stream. */ -@property(nonatomic, strong, readonly) - NSMutableDictionary *listenTargets; - @property(nonatomic, strong, readonly) FSTOnlineStateTracker *onlineStateTracker; @property(nonatomic, strong, nullable) FSTWatchChangeAggregator *watchChangeAggregator; @@ -112,6 +102,16 @@ @interface FSTRemoteStore () @end @implementation FSTRemoteStore { + /** + * A mapping of watched targets that the client cares about tracking and the + * user has explicitly called a 'listen' for this target. + * + * These targets may or may not have been sent to or acknowledged by the + * server. On re-establishing the listen stream, these targets should be sent + * to the server. The targets removed with unlistens are removed eagerly + * without waiting for confirmation from the listen stream. */ + std::unordered_map _listenTargets; + std::shared_ptr _watchStream; std::shared_ptr _writeStream; /** @@ -127,7 +127,6 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore if (self = [super init]) { _localStore = localStore; _datastore = datastore; - _listenTargets = [NSMutableDictionary dictionary]; _writePipeline = [NSMutableArray array]; _onlineStateTracker = [[FSTOnlineStateTracker alloc] initWithWorkerQueue:queue]; @@ -241,11 +240,11 @@ - (void)startWatchStream { } - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { - NSNumber *targetKey = @(queryData.targetID); - HARD_ASSERT(!self.listenTargets[targetKey], "listenToQuery called with duplicate target id: %s", - targetKey); + TargetId targetKey = queryData.targetID; + HARD_ASSERT(_listenTargets.find(targetKey) == _listenTargets.end(), + "listenToQuery called with duplicate target id: %s", targetKey); - self.listenTargets[targetKey] = queryData; + _listenTargets[targetKey] = queryData; if ([self shouldStartWatchStream]) { [self startWatchStream]; @@ -260,15 +259,14 @@ - (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { } - (void)stopListeningToTargetID:(TargetId)targetID { - FSTBoxedTargetID *targetKey = @(targetID); - FSTQueryData *queryData = self.listenTargets[targetKey]; - HARD_ASSERT(queryData, "stopListeningToTargetID: target not currently watched: %s", targetKey); + auto found = _listenTargets.find(targetID); + HARD_ASSERT(found != _listenTargets.end(), "stopListeningToTargetID: target not currently watched: %s", targetID); - [self.listenTargets removeObjectForKey:targetKey]; + _listenTargets.erase(found); if (_watchStream->IsOpen()) { - [self sendUnwatchRequestForTargetID:targetKey]; + [self sendUnwatchRequestForTargetID:targetID]; } - if ([self.listenTargets count] == 0) { + if (_listenTargets.empty()) { if (_watchStream->IsOpen()) { _watchStream->MarkIdle(); } else if ([self canUseNetwork]) { @@ -290,7 +288,7 @@ - (void)sendUnwatchRequestForTargetID:(FSTBoxedTargetID *)targetID { * active watch targets. */ - (BOOL)shouldStartWatchStream { - return [self canUseNetwork] && !_watchStream->IsStarted() && self.listenTargets.count > 0; + return [self canUseNetwork] && !_watchStream->IsStarted() && !_listenTargets.empty(); } - (void)cleanUpWatchStreamState { @@ -299,322 +297,331 @@ - (void)cleanUpWatchStreamState { - (void)watchStreamDidOpen { // Restore any existing watches. - for (FSTQueryData *queryData in [self.listenTargets objectEnumerator]) { - [self sendWatchRequestWithQueryData:queryData]; + for (const auto& kv : _listenTargets) { + [self sendWatchRequestWithQueryData:kv.second]; } } -- (void)watchStreamDidChange:(FSTWatchChange *)change +- (void)watchStreamDidChange:(const WatchChange &)change snapshotVersion:(const SnapshotVersion &)snapshotVersion { // Mark the connection as Online because we got a message from the server. [self.onlineStateTracker updateState:OnlineState::Online]; - if ([change isKindOfClass:[FSTWatchTargetChange class]]) { - FSTWatchTargetChange *watchTargetChange = (FSTWatchTargetChange *)change; - if (watchTargetChange.state == FSTWatchTargetChangeStateRemoved && watchTargetChange.cause) { + if (change.type() == WatchChange::Type::TargetChange) { + const WatchTargetChange &watchTargetChange = static_cast(change); + if (watchTargetChange.state() == WatchTargetChangeState::Removed && + !watchTargetChange.cause().ok()) { // There was an error on a target, don't wait for a consistent snapshot to raise events return [self processTargetErrorForWatchChange:watchTargetChange]; } else { [self.watchChangeAggregator handleTargetChange:watchTargetChange]; } - } else if ([change isKindOfClass:[FSTDocumentWatchChange class]]) { - [self.watchChangeAggregator handleDocumentChange:(FSTDocumentWatchChange *)change]; - } else { - HARD_ASSERT([change isKindOfClass:[FSTExistenceFilterWatchChange class]], - "Expected watchChange to be an instance of FSTExistenceFilterWatchChange"); - [self.watchChangeAggregator handleExistenceFilter:(FSTExistenceFilterWatchChange *)change]; - } + else if (change.type() == WatchChange::Type::Document) { + [self.watchChangeAggregator + handleDocumentChange:static_cast(change)]; + } + else { + HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, + "Expected watchChange to be an instance of ExistenceFilterWatchChange"); + [self.watchChangeAggregator + handleDocumentChange:static_cast(change)]; + } - if (snapshotVersion != SnapshotVersion::None() && - snapshotVersion >= [self.localStore lastRemoteSnapshotVersion]) { - // We have received a target change with a global snapshot if the snapshot version is not equal - // to SnapshotVersion.None(). - [self raiseWatchSnapshotWithSnapshotVersion:snapshotVersion]; + if (snapshotVersion != SnapshotVersion::None() && + snapshotVersion >= [self.localStore lastRemoteSnapshotVersion]) { + // We have received a target change with a global snapshot if the snapshot version is not + // equal to SnapshotVersion.None(). + [self raiseWatchSnapshotWithSnapshotVersion:snapshotVersion]; + } } -} -- (void)watchStreamWasInterruptedWithError:(nullable NSError *)error { - if (!error) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. - HARD_ASSERT(![self shouldStartWatchStream], - "Watch stream was stopped gracefully while still needed."); - } + -(void)watchStreamWasInterruptedWithError : (nullable NSError *)error { + if (!error) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. + HARD_ASSERT(![self shouldStartWatchStream], + "Watch stream was stopped gracefully while still needed."); + } - [self cleanUpWatchStreamState]; + [self cleanUpWatchStreamState]; - // If we still need the watch stream, retry the connection. - if ([self shouldStartWatchStream]) { - [self.onlineStateTracker handleWatchStreamFailure:error]; + // If we still need the watch stream, retry the connection. + if ([self shouldStartWatchStream]) { + [self.onlineStateTracker handleWatchStreamFailure:error]; - [self startWatchStream]; - } else { - // We don't need to restart the watch stream because there are no active targets. The online - // state is set to unknown because there is no active attempt at establishing a connection. - [self.onlineStateTracker updateState:OnlineState::Unknown]; + [self startWatchStream]; + } else { + // We don't need to restart the watch stream because there are no active targets. The online + // state is set to unknown because there is no active attempt at establishing a connection. + [self.onlineStateTracker updateState:OnlineState::Unknown]; + } } -} -/** - * Takes a batch of changes from the Datastore, repackages them as a RemoteEvent, and passes that - * on to the SyncEngine. - */ -- (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotVersion { - HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), - "Can't raise event for unknown SnapshotVersion"); - - FSTRemoteEvent *remoteEvent = - [self.watchChangeAggregator remoteEventAtSnapshotVersion:snapshotVersion]; - - // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when - // applying the completed FSTRemoteEvent. - for (const auto &entry : remoteEvent.targetChanges) { - NSData *resumeToken = entry.second.resumeToken; - if (resumeToken.length > 0) { - FSTBoxedTargetID *targetID = @(entry.first); - FSTQueryData *queryData = _listenTargets[targetID]; - // A watched target might have been removed already. - if (queryData) { - _listenTargets[targetID] = - [queryData queryDataByReplacingSnapshotVersion:snapshotVersion - resumeToken:resumeToken - sequenceNumber:queryData.sequenceNumber]; + /** + * Takes a batch of changes from the Datastore, repackages them as a RemoteEvent, and passes that + * on to the SyncEngine. + */ + -(void)raiseWatchSnapshotWithSnapshotVersion : (const SnapshotVersion &)snapshotVersion { + HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), + "Can't raise event for unknown SnapshotVersion"); + + FSTRemoteEvent *remoteEvent = + [self.watchChangeAggregator remoteEventAtSnapshotVersion:snapshotVersion]; + + // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when + // applying the completed FSTRemoteEvent. + for (const auto &entry : remoteEvent.targetChanges) { + NSData *resumeToken = entry.second.resumeToken; + if (resumeToken.length > 0) { + FSTBoxedTargetID *targetID = @(entry.first); + FSTQueryData *queryData = _listenTargets[targetID]; + // A watched target might have been removed already. + if (queryData) { + _listenTargets[targetID] = + [queryData queryDataByReplacingSnapshotVersion:snapshotVersion + resumeToken:resumeToken + sequenceNumber:queryData.sequenceNumber]; + } } } - } - // Re-establish listens for the targets that have been invalidated by existence filter mismatches. - for (TargetId targetID : remoteEvent.targetMismatches) { - FSTQueryData *queryData = self.listenTargets[@(targetID)]; + // Re-establish listens for the targets that have been invalidated by existence filter + // mismatches. + for (TargetId targetID : remoteEvent.targetMismatches) { + if (_listenTargets.find(targetID) == _listenTargets.end()) { + // A watched target might have been removed already. + continue; + } - if (!queryData) { - // A watched target might have been removed already. - continue; + // Clear the resume token for the query, since we're in a known mismatch state. + queryData = [[FSTQueryData alloc] initWithQuery:queryData.query + targetID:targetID + listenSequenceNumber:queryData.sequenceNumber + purpose:queryData.purpose]; + _listenTargets[targetID] = queryData; + + // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send a + // resume token so that we get a full update. + [self sendUnwatchRequestForTargetID:@(targetID)]; + + // Mark the query we send as being on behalf of an existence filter mismatch, but don't + // actually retain that in _listenTargets. This ensures that we flag the first re-listen this + // way without impacting future listens of this target (that might happen e.g. on reconnect). + FSTQueryData *requestQueryData = + [[FSTQueryData alloc] initWithQuery:queryData.query + targetID:targetID + listenSequenceNumber:queryData.sequenceNumber + purpose:FSTQueryPurposeExistenceFilterMismatch]; + [self sendWatchRequestWithQueryData:requestQueryData]; } - // Clear the resume token for the query, since we're in a known mismatch state. - queryData = [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:queryData.purpose]; - self.listenTargets[@(targetID)] = queryData; - - // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send a - // resume token so that we get a full update. - [self sendUnwatchRequestForTargetID:@(targetID)]; - - // Mark the query we send as being on behalf of an existence filter mismatch, but don't actually - // retain that in listenTargets. This ensures that we flag the first re-listen this way without - // impacting future listens of this target (that might happen e.g. on reconnect). - FSTQueryData *requestQueryData = - [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:FSTQueryPurposeExistenceFilterMismatch]; - [self sendWatchRequestWithQueryData:requestQueryData]; + // Finally handle remote event + [self.syncEngine applyRemoteEvent:remoteEvent]; } - // Finally handle remote event - [self.syncEngine applyRemoteEvent:remoteEvent]; -} - -/** Process a target error and passes the error along to SyncEngine. */ -- (void)processTargetErrorForWatchChange:(FSTWatchTargetChange *)change { - HARD_ASSERT(change.cause, "Handling target error without a cause"); - // Ignore targets that have been removed already. - for (FSTBoxedTargetID *targetID in change.targetIDs) { - if (self.listenTargets[targetID]) { - int unboxedTargetId = targetID.intValue; - [self.listenTargets removeObjectForKey:targetID]; - [self.watchChangeAggregator removeTarget:unboxedTargetId]; - [self.syncEngine rejectListenWithTargetID:unboxedTargetId error:change.cause]; + /** Process a target error and passes the error along to SyncEngine. */ + -(void)processTargetErrorForWatchChange : (const WatchTargetChange &)change { + HARD_ASSERT(!change.cause.ok(), "Handling target error without a cause"); + // Ignore targets that have been removed already. + for (TargetId targetID : change.target_ids()) { + auto found = _listenTargets.find(targetID); + if (found != _listenTargets.end()) { + _listenTargets.erase(found); + [self.watchChangeAggregator removeTarget:targetID]; + [self.syncEngine rejectListenWithTargetID:targetID error:change.cause()]; + } } } -} -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(FSTBoxedTargetID *)targetID { - return [self.syncEngine remoteKeysForTarget:targetID]; -} + -(firebase::firestore::model::DocumentKeySet)remoteKeysForTarget : (FSTBoxedTargetID *)targetID { + return [self.syncEngine remoteKeysForTarget:targetID]; + } -- (nullable FSTQueryData *)queryDataForTarget:(FSTBoxedTargetID *)targetID { - return self.listenTargets[targetID]; -} + -(nullable FSTQueryData *)queryDataForTarget : (TargetId)targetID { + auto found = _listenTargets.find(targetID); + return found != _listenTargets.end() ? found->second : nil; + } #pragma mark Write Stream -/** - * Returns YES if the network is enabled, the write stream has not yet been started and there are - * pending writes. - */ -- (BOOL)shouldStartWriteStream { - return [self canUseNetwork] && !_writeStream->IsStarted() && self.writePipeline.count > 0; -} + /** + * Returns YES if the network is enabled, the write stream has not yet been started and there are + * pending writes. + */ + -(BOOL)shouldStartWriteStream { + return [self canUseNetwork] && !_writeStream->IsStarted() && self.writePipeline.count > 0; + } -- (void)startWriteStream { - HARD_ASSERT([self shouldStartWriteStream], - "startWriteStream: called when shouldStartWriteStream: is false."); - _writeStream->Start(); -} + -(void)startWriteStream { + HARD_ASSERT([self shouldStartWriteStream], + "startWriteStream: called when shouldStartWriteStream: is false."); + _writeStream->Start(); + } -/** - * Attempts to fill our write pipeline with writes from the LocalStore. - * - * Called internally to bootstrap or refill the write pipeline and by SyncEngine whenever there - * are new mutations to process. - * - * Starts the write stream if necessary. - */ -- (void)fillWritePipeline { - BatchId lastBatchIDRetrieved = - self.writePipeline.count == 0 ? kBatchIdUnknown : self.writePipeline.lastObject.batchID; - while ([self canAddToWritePipeline]) { - FSTMutationBatch *batch = [self.localStore nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; - if (!batch) { - if (self.writePipeline.count == 0) { - _writeStream->MarkIdle(); + /** + * Attempts to fill our write pipeline with writes from the LocalStore. + * + * Called internally to bootstrap or refill the write pipeline and by SyncEngine whenever there + * are new mutations to process. + * + * Starts the write stream if necessary. + */ + -(void)fillWritePipeline { + BatchId lastBatchIDRetrieved = + self.writePipeline.count == 0 ? kBatchIdUnknown : self.writePipeline.lastObject.batchID; + while ([self canAddToWritePipeline]) { + FSTMutationBatch *batch = + [self.localStore nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; + if (!batch) { + if (self.writePipeline.count == 0) { + _writeStream->MarkIdle(); + } + break; } - break; + [self addBatchToWritePipeline:batch]; + lastBatchIDRetrieved = batch.batchID; } - [self addBatchToWritePipeline:batch]; - lastBatchIDRetrieved = batch.batchID; - } - if ([self shouldStartWriteStream]) { - [self startWriteStream]; + if ([self shouldStartWriteStream]) { + [self startWriteStream]; + } } -} -/** - * Returns YES if we can add to the write pipeline (i.e. it is not full and the network is enabled). - */ -- (BOOL)canAddToWritePipeline { - return [self canUseNetwork] && self.writePipeline.count < kMaxPendingWrites; -} + /** + * Returns YES if we can add to the write pipeline (i.e. it is not full and the network is + * enabled). + */ + -(BOOL)canAddToWritePipeline { + return [self canUseNetwork] && self.writePipeline.count < kMaxPendingWrites; + } -/** - * Queues additional writes to be sent to the write stream, sending them immediately if the write - * stream is established. - */ -- (void)addBatchToWritePipeline:(FSTMutationBatch *)batch { - HARD_ASSERT([self canAddToWritePipeline], "addBatchToWritePipeline called when pipeline is full"); + /** + * Queues additional writes to be sent to the write stream, sending them immediately if the write + * stream is established. + */ + -(void)addBatchToWritePipeline : (FSTMutationBatch *)batch { + HARD_ASSERT([self canAddToWritePipeline], + "addBatchToWritePipeline called when pipeline is full"); - [self.writePipeline addObject:batch]; + [self.writePipeline addObject:batch]; - if (_writeStream->IsOpen() && _writeStream->handshake_complete()) { - _writeStream->WriteMutations(batch.mutations); + if (_writeStream->IsOpen() && _writeStream->handshake_complete()) { + _writeStream->WriteMutations(batch.mutations); + } } -} -- (void)writeStreamDidOpen { - _writeStream->WriteHandshake(); -} + -(void)writeStreamDidOpen { + _writeStream->WriteHandshake(); + } -/** - * Handles a successful handshake response from the server, which is our cue to send any pending - * writes. - */ -- (void)writeStreamDidCompleteHandshake { - // Record the stream token. - [self.localStore setLastStreamToken:_writeStream->GetLastStreamToken()]; + /** + * Handles a successful handshake response from the server, which is our cue to send any pending + * writes. + */ + -(void)writeStreamDidCompleteHandshake { + // Record the stream token. + [self.localStore setLastStreamToken:_writeStream->GetLastStreamToken()]; - // Send the write pipeline now that the stream is established. - for (FSTMutationBatch *write in self.writePipeline) { - _writeStream->WriteMutations(write.mutations); + // Send the write pipeline now that the stream is established. + for (FSTMutationBatch *write in self.writePipeline) { + _writeStream->WriteMutations(write.mutations); + } } -} - -/** Handles a successful StreamingWriteResponse from the server that contains a mutation result. */ -- (void)writeStreamDidReceiveResponseWithVersion:(const SnapshotVersion &)commitVersion - mutationResults:(NSArray *)results { - // This is a response to a write containing mutations and should be correlated to the first - // write in our write pipeline. - NSMutableArray *writePipeline = self.writePipeline; - FSTMutationBatch *batch = writePipeline[0]; - [writePipeline removeObjectAtIndex:0]; - - FSTMutationBatchResult *batchResult = - [FSTMutationBatchResult resultWithBatch:batch - commitVersion:commitVersion - mutationResults:results - streamToken:_writeStream->GetLastStreamToken()]; - [self.syncEngine applySuccessfulWriteWithResult:batchResult]; - - // It's possible that with the completion of this mutation another slot has freed up. - [self fillWritePipeline]; -} -/** - * Handles the closing of the StreamingWrite RPC, either because of an error or because the RPC - * has been terminated by the client or the server. - */ -- (void)writeStreamWasInterruptedWithError:(nullable NSError *)error { - if (!error) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. - HARD_ASSERT(![self shouldStartWriteStream], - "Write stream was stopped gracefully while still needed."); + /** Handles a successful StreamingWriteResponse from the server that contains a mutation result. + */ + -(void)writeStreamDidReceiveResponseWithVersion + : (const SnapshotVersion &)commitVersion mutationResults + : (NSArray *)results { + // This is a response to a write containing mutations and should be correlated to the first + // write in our write pipeline. + NSMutableArray *writePipeline = self.writePipeline; + FSTMutationBatch *batch = writePipeline[0]; + [writePipeline removeObjectAtIndex:0]; + + FSTMutationBatchResult *batchResult = + [FSTMutationBatchResult resultWithBatch:batch + commitVersion:commitVersion + mutationResults:results + streamToken:_writeStream->GetLastStreamToken()]; + [self.syncEngine applySuccessfulWriteWithResult:batchResult]; + + // It's possible that with the completion of this mutation another slot has freed up. + [self fillWritePipeline]; } - // If the write stream closed due to an error, invoke the error callbacks if there are pending - // writes. - if (error != nil && self.writePipeline.count > 0) { - if (_writeStream->handshake_complete()) { - // This error affects the actual writes. - [self handleWriteError:error]; - } else { - // If there was an error before the handshake finished, it's possible that the server is - // unable to process the stream token we're sending. (Perhaps it's too old?) - [self handleHandshakeError:error]; + /** + * Handles the closing of the StreamingWrite RPC, either because of an error or because the RPC + * has been terminated by the client or the server. + */ + -(void)writeStreamWasInterruptedWithError : (nullable NSError *)error { + if (!error) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. + HARD_ASSERT(![self shouldStartWriteStream], + "Write stream was stopped gracefully while still needed."); } - } - // The write stream might have been started by refilling the write pipeline for failed writes - if ([self shouldStartWriteStream]) { - [self startWriteStream]; - } -} + // If the write stream closed due to an error, invoke the error callbacks if there are pending + // writes. + if (error != nil && self.writePipeline.count > 0) { + if (_writeStream->handshake_complete()) { + // This error affects the actual writes. + [self handleWriteError:error]; + } else { + // If there was an error before the handshake finished, it's possible that the server is + // unable to process the stream token we're sending. (Perhaps it's too old?) + [self handleHandshakeError:error]; + } + } -- (void)handleHandshakeError:(NSError *)error { - HARD_ASSERT(error, "Handling write error with status OK."); - // Reset the token if it's a permanent error, signaling the write stream is - // no longer valid. Note that the handshake does not count as a write: see - // comments on isPermanentWriteError for details. - if ([FSTDatastore isPermanentError:error]) { - NSString *token = [_writeStream->GetLastStreamToken() base64EncodedStringWithOptions:0]; - LOG_DEBUG("FSTRemoteStore %s error before completed handshake; resetting stream token %s: %s", - (__bridge void *)self, token, error); - _writeStream->SetLastStreamToken(nil); - [self.localStore setLastStreamToken:nil]; - } else { - // Some other error, don't reset stream token. Our stream logic will just retry with exponential - // backoff. + // The write stream might have been started by refilling the write pipeline for failed writes + if ([self shouldStartWriteStream]) { + [self startWriteStream]; + } } -} -- (void)handleWriteError:(NSError *)error { - HARD_ASSERT(error, "Handling write error with status OK."); - // Only handle permanent errors here. If it's transient, just let the retry logic kick in. - if (![FSTDatastore isPermanentWriteError:error]) { - return; + -(void)handleHandshakeError : (NSError *)error { + HARD_ASSERT(error, "Handling write error with status OK."); + // Reset the token if it's a permanent error, signaling the write stream is + // no longer valid. Note that the handshake does not count as a write: see + // comments on isPermanentWriteError for details. + if ([FSTDatastore isPermanentError:error]) { + NSString *token = [_writeStream->GetLastStreamToken() base64EncodedStringWithOptions:0]; + LOG_DEBUG("FSTRemoteStore %s error before completed handshake; resetting stream token %s: %s", + (__bridge void *)self, token, error); + _writeStream->SetLastStreamToken(nil); + [self.localStore setLastStreamToken:nil]; + } else { + // Some other error, don't reset stream token. Our stream logic will just retry with + // exponential backoff. + } } - // If this was a permanent error, the request itself was the problem so it's not going to - // succeed if we resend it. - FSTMutationBatch *batch = self.writePipeline[0]; - [self.writePipeline removeObjectAtIndex:0]; + -(void)handleWriteError : (NSError *)error { + HARD_ASSERT(error, "Handling write error with status OK."); + // Only handle permanent errors here. If it's transient, just let the retry logic kick in. + if (![FSTDatastore isPermanentWriteError:error]) { + return; + } - // In this case it's also unlikely that the server itself is melting down--this was just a - // bad request so inhibit backoff on the next restart. - _writeStream->InhibitBackoff(); + // If this was a permanent error, the request itself was the problem so it's not going to + // succeed if we resend it. + FSTMutationBatch *batch = self.writePipeline[0]; + [self.writePipeline removeObjectAtIndex:0]; - [self.syncEngine rejectFailedWriteWithBatchID:batch.batchID error:error]; + // In this case it's also unlikely that the server itself is melting down--this was just a + // bad request so inhibit backoff on the next restart. + _writeStream->InhibitBackoff(); - // It's possible that with the completion of this mutation another slot has freed up. - [self fillWritePipeline]; -} + [self.syncEngine rejectFailedWriteWithBatchID:batch.batchID error:error]; -- (FSTTransaction *)transaction { - return [FSTTransaction transactionWithDatastore:self.datastore]; -} + // It's possible that with the completion of this mutation another slot has freed up. + [self fillWritePipeline]; + } -@end + -(FSTTransaction *)transaction { + return [FSTTransaction transactionWithDatastore:self.datastore]; + } + + @end -NS_ASSUME_NONNULL_END + NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTSerializerBeta.h b/Firestore/Source/Remote/FSTSerializerBeta.h index 46231e18829..f2fb4f51abc 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.h +++ b/Firestore/Source/Remote/FSTSerializerBeta.h @@ -32,7 +32,6 @@ @class FSTObjectValue; @class FSTQuery; @class FSTQueryData; -@class FSTWatchChange; @class GCFSBatchGetDocumentsResponse; @class GCFSDocument; @@ -101,7 +100,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query; - (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target; -- (std::unique_ptr )decodedWatchChange:(GCFSListenResponse *)watchChange; +- (std::unique_ptr )decodedWatchChange:(GCFSListenResponse *)watchChange; - (firebase::firestore::model::SnapshotVersion)versionFromListenResponse: (GCFSListenResponse *)watchChange; diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index bf6ae1498e0..3b1997880d3 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -40,6 +40,7 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/field_mask.h" @@ -58,6 +59,7 @@ namespace util = firebase::firestore::util; using firebase::Timestamp; +using firebase::firestore::FirestoreErrorCode; using firebase::firestore::model::ArrayTransform; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; @@ -70,7 +72,12 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; +using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; NS_ASSUME_NONNULL_BEGIN @@ -731,8 +738,8 @@ - (GCFSTarget *)encodedTarget:(FSTQueryData *)queryData { } result.targetId = queryData.targetID; - if (queryData.resumeToken.length > 0) { - result.resumeToken = queryData.resumeToken; + if (!queryData.resumeToken.empty()) { + result.resumeToken = [NSData dataWithBytes: queryData.resumeToken.data() length: queryData.resumeToken.size()]; } return result; @@ -1096,20 +1103,20 @@ - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { return [self decodedVersion:watchChange.targetChange.readTime]; } -- (std::unique_ptr)decodedTargetChangeFromWatchChange: - (GCFSTargetChange *)change { +- (std::unique_ptr)decodedTargetChangeFromWatchChange:(GCFSTargetChange *)change { WatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType]; - std::vector targetIDs; + __block std::vector targetIDs; [change.targetIdsArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { - target_ids.push_back(value); + targetIDs.push_back(value); }]; - std::string resumeToken = util::MakeString(change.resumeToken); + auto tokenData = static_cast([change.resumeToken bytes]); + std::vector resumeToken{tokenData, tokenData + [change.resumeToken length]}; util::Status cause; if (change.hasCause) { - cause = util::Status{code : change.cause.code, change.cause.message}; + cause = util::Status{static_cast(change.cause.code), util::MakeString(change.cause.message)}; } return absl::make_unique(state, std::move(targetIDs), std::move(resumeToken), @@ -1133,17 +1140,17 @@ - (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_Target } } -- (NSArray *)decodedIntegerArray:(GPBInt32Array *)values { - NSMutableArray *result = [NSMutableArray arrayWithCapacity:values.count]; +- (std::vector)decodedIntegerArray:(GPBInt32Array *)values { + __block std::vector result; [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { - [result addObject:@(value)]; + result.push_back(value); }]; return result; } -- (FSTDocumentWatchChange *)decodedDocumentChange:(GCFSDocumentChange *)change { +- (std::unique_ptr)decodedDocumentChange:(GCFSDocumentChange *)change { FSTObjectValue *value = [self decodedFields:change.document.fields]; - const DocumentKey key = [self decodedDocumentKey:change.document.name]; + DocumentKey key = [self decodedDocumentKey:change.document.name]; SnapshotVersion version = [self decodedVersion:change.document.updateTime]; HARD_ASSERT(version != SnapshotVersion::None(), "Got a document change with no snapshot version"); // The document may soon be re-serialized back to protos in order to store it in local @@ -1154,46 +1161,40 @@ - (FSTDocumentWatchChange *)decodedDocumentChange:(GCFSDocumentChange *)change { state:FSTDocumentStateSynced proto:change.document]; - NSArray *updatedTargetIds = [self decodedIntegerArray:change.targetIdsArray]; - NSArray *removedTargetIds = [self decodedIntegerArray:change.removedTargetIdsArray]; + std::vector updatedTargetIDs = [self decodedIntegerArray:change.targetIdsArray]; + std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - return [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:updatedTargetIds - removedTargetIDs:removedTargetIds - documentKey:document.key - document:document]; + return absl::make_unique( + std::move(updatedTargetIDs), std::move(removedTargetIDs), std::move(key), document); } -- (FSTDocumentWatchChange *)decodedDocumentDelete:(GCFSDocumentDelete *)change { - const DocumentKey key = [self decodedDocumentKey:change.document]; +- (std::unique_ptr)decodedDocumentDelete:(GCFSDocumentDelete *)change { + DocumentKey key = [self decodedDocumentKey:change.document]; // Note that version might be unset in which case we use SnapshotVersion::None() SnapshotVersion version = [self decodedVersion:change.readTime]; FSTMaybeDocument *document = [FSTDeletedDocument documentWithKey:key version:version hasCommittedMutations:NO]; - NSArray *removedTargetIds = [self decodedIntegerArray:change.removedTargetIdsArray]; + std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - return [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:removedTargetIds - documentKey:document.key - document:document]; + return absl::make_unique( + std::vector{}, std::move(removedTargetIDs), std::move(key), document); } -- (FSTDocumentWatchChange *)decodedDocumentRemove:(GCFSDocumentRemove *)change { - const DocumentKey key = [self decodedDocumentKey:change.document]; - NSArray *removedTargetIds = [self decodedIntegerArray:change.removedTargetIdsArray]; +- (std::unique_ptr)decodedDocumentRemove:(GCFSDocumentRemove *)change { + DocumentKey key = [self decodedDocumentKey:change.document]; + std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - return [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:removedTargetIds - documentKey:key - document:nil]; + return absl::make_unique( + std::vector{}, std::move(removedTargetIDs), std::move(key), nil); } -- (FSTExistenceFilterWatchChange *)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter { +- (std::unique_ptr)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter { // TODO(dimond): implement existence filter parsing ExistenceFilter existenceFilter{filter.count}; TargetId targetID = filter.targetId; - return [FSTExistenceFilterWatchChange changeWithFilter:existenceFilter targetID:targetID]; + return absl::make_unique(existenceFilter, targetID); } @end diff --git a/Firestore/Source/Remote/FSTStream.h b/Firestore/Source/Remote/FSTStream.h index 00dcab37f7f..e47dbb2a71c 100644 --- a/Firestore/Source/Remote/FSTStream.h +++ b/Firestore/Source/Remote/FSTStream.h @@ -17,9 +17,9 @@ #import #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTMutationResult; -@class FSTWatchChange; NS_ASSUME_NONNULL_BEGIN @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN * Called by the FSTWatchStream with changes and the snapshot versions included in in the * WatchChange responses sent back by the server. */ -- (void)watchStreamDidChange:(FSTWatchChange *)change +- (void)watchStreamDidChange:(const firebase::firestore::remote::WatchChange&)change snapshotVersion:(const firebase::firestore::model::SnapshotVersion &)snapshotVersion; /** diff --git a/Firestore/Source/Remote/FSTWatchChange.h b/Firestore/Source/Remote/FSTWatchChange.h deleted file mode 100644 index f505429d589..00000000000 --- a/Firestore/Source/Remote/FSTWatchChange.h +++ /dev/null @@ -1,119 +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 - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" - -@class FSTMaybeDocument; - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTWatchChange is the internal representation of the watcher API protocol buffers. - * This is an empty abstract class so that all the different kinds of changes can have a common - * base class. - */ -@interface FSTWatchChange : NSObject -@end - -/** - * FSTDocumentWatchChange represents a changed document and a list of target ids to which this - * change applies. If the document has been deleted, the deleted document will be provided. - */ -@interface FSTDocumentWatchChange : FSTWatchChange - -- (instancetype)initWithUpdatedTargetIDs:(NSArray *)updatedTargetIDs - removedTargetIDs:(NSArray *)removedTargetIDs - documentKey:(firebase::firestore::model::DocumentKey)documentKey - document:(nullable FSTMaybeDocument *)document - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** The key of the document for this change. */ -- (const firebase::firestore::model::DocumentKey &)documentKey; - -/** The new document applies to all of these targets. */ -@property(nonatomic, strong, readonly) NSArray *updatedTargetIDs; - -/** The new document is removed from all of these targets. */ -@property(nonatomic, strong, readonly) NSArray *removedTargetIDs; - -/** - * The new document or DeletedDocument if it was deleted. Is null if the document went out of - * view without the server sending a new document. - */ -@property(nonatomic, strong, readonly, nullable) FSTMaybeDocument *document; - -@end - -/** - * An ExistenceFilterWatchChange applies to the targets and is required to verify the current client - * state against expected state sent from the server. - */ -@interface FSTExistenceFilterWatchChange : FSTWatchChange - -+ (instancetype)changeWithFilter:(firebase::firestore::remote::ExistenceFilter)filter - targetID:(firebase::firestore::model::TargetId)targetID; - -- (instancetype)init NS_UNAVAILABLE; - -- (const firebase::firestore::remote::ExistenceFilter &)filter; - -@property(nonatomic, assign, readonly) firebase::firestore::model::TargetId targetID; -@end - -/** FSTWatchTargetChangeState is the kind of change that happened to the watch target. */ -typedef NS_ENUM(NSInteger, FSTWatchTargetChangeState) { - FSTWatchTargetChangeStateNoChange, - FSTWatchTargetChangeStateAdded, - FSTWatchTargetChangeStateRemoved, - FSTWatchTargetChangeStateCurrent, - FSTWatchTargetChangeStateReset, -}; - -/** FSTWatchTargetChange is a change to a watch target. */ -@interface FSTWatchTargetChange : FSTWatchChange - -- (instancetype)initWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - resumeToken:(NSData *)resumeToken - cause:(nullable NSError *)cause NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** What kind of change occurred to the watch target. */ -@property(nonatomic, assign, readonly) FSTWatchTargetChangeState state; - -/** The target IDs that were added/removed/set. */ -@property(nonatomic, strong, readonly) NSArray *targetIDs; - -/** - * An opaque, server-assigned token that allows watching a query to be resumed after disconnecting - * without retransmitting all the data that matches the query. The resume token essentially - * identifies a point in time from which the server should resume sending results. - */ -@property(nonatomic, strong, readonly) NSData *resumeToken; - -/** An RPC error indicating why the watch failed. */ -@property(nonatomic, strong, readonly, nullable) NSError *cause; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTWatchChange.mm b/Firestore/Source/Remote/FSTWatchChange.mm deleted file mode 100644 index 67d6ac2579c..00000000000 --- a/Firestore/Source/Remote/FSTWatchChange.mm +++ /dev/null @@ -1,167 +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/Remote/FSTWatchChange.h" - -#include - -#import "Firestore/Source/Model/FSTDocument.h" - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" - -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::TargetId; -using firebase::firestore::remote::ExistenceFilter; - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTWatchChange -@end - -@implementation FSTDocumentWatchChange { - DocumentKey _documentKey; -} - -- (instancetype)initWithUpdatedTargetIDs:(NSArray *)updatedTargetIDs - removedTargetIDs:(NSArray *)removedTargetIDs - documentKey:(DocumentKey)documentKey - document:(nullable FSTMaybeDocument *)document { - self = [super init]; - if (self) { - _updatedTargetIDs = updatedTargetIDs; - _removedTargetIDs = removedTargetIDs; - _documentKey = std::move(documentKey); - _document = document; - } - return self; -} - -- (const firebase::firestore::model::DocumentKey &)documentKey { - return _documentKey; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isMemberOfClass:[FSTDocumentWatchChange class]]) { - return NO; - } - - FSTDocumentWatchChange *otherChange = (FSTDocumentWatchChange *)other; - return [_updatedTargetIDs isEqual:otherChange.updatedTargetIDs] && - [_removedTargetIDs isEqual:otherChange.removedTargetIDs] && - _documentKey == otherChange.documentKey && - (_document == otherChange.document || [_document isEqual:otherChange.document]); -} - -- (NSUInteger)hash { - NSUInteger hash = self.updatedTargetIDs.hash; - hash = hash * 31 + self.removedTargetIDs.hash; - hash = hash * 31 + self.documentKey.Hash(); - hash = hash * 31 + self.document.hash; - return hash; -} - -@end - -@interface FSTExistenceFilterWatchChange () - -- (instancetype)initWithFilter:(ExistenceFilter)filter - targetID:(TargetId)targetID NS_DESIGNATED_INITIALIZER; - -@end - -@implementation FSTExistenceFilterWatchChange { - ExistenceFilter _filter; -} - -+ (instancetype)changeWithFilter:(ExistenceFilter)filter targetID:(TargetId)targetID { - return [[FSTExistenceFilterWatchChange alloc] initWithFilter:filter targetID:targetID]; -} - -- (instancetype)initWithFilter:(ExistenceFilter)filter targetID:(TargetId)targetID { - self = [super init]; - if (self) { - _filter = filter; - _targetID = targetID; - } - return self; -} - -- (const ExistenceFilter &)filter { - return _filter; -} -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isMemberOfClass:[FSTExistenceFilterWatchChange class]]) { - return NO; - } - - FSTExistenceFilterWatchChange *otherChange = (FSTExistenceFilterWatchChange *)other; - return _filter == otherChange->_filter && _targetID == otherChange->_targetID; -} - -- (NSUInteger)hash { - return _filter.count(); -} - -@end - -@implementation FSTWatchTargetChange - -- (instancetype)initWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - resumeToken:(NSData *)resumeToken - cause:(nullable NSError *)cause { - self = [super init]; - if (self) { - _state = state; - _targetIDs = targetIDs; - _resumeToken = [resumeToken copy]; - _cause = cause; - } - return self; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isMemberOfClass:[FSTWatchTargetChange class]]) { - return NO; - } - - FSTWatchTargetChange *otherChange = (FSTWatchTargetChange *)other; - return _state == otherChange->_state && [_targetIDs isEqual:otherChange->_targetIDs] && - [_resumeToken isEqual:otherChange->_resumeToken] && - (_cause == otherChange->_cause || [_cause isEqual:otherChange->_cause]); -} - -- (NSUInteger)hash { - NSUInteger hash = (NSUInteger)self.state; - - hash = hash * 31 + self.targetIDs.hash; - hash = hash * 31 + self.resumeToken.hash; - hash = hash * 31 + self.cause.hash; - return hash; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h index 0349f04a8ff..049aaf98a8d 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h @@ -23,11 +23,13 @@ #import +#include #include #include #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "grpcpp/support/byte_buffer.h" @@ -37,7 +39,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" namespace firebase { namespace firestore { @@ -78,7 +79,7 @@ class WatchStreamSerializer { */ GCFSListenResponse* ParseResponse(const grpc::ByteBuffer& message, util::Status* out_status) const; - FSTWatchChange* ToWatchChange(GCFSListenResponse* proto) const; + std::unique_ptr ToWatchChange(GCFSListenResponse* proto) const; model::SnapshotVersion ToSnapshotVersion(GCFSListenResponse* proto) const; /** Creates a pretty-printed description of the proto for debugging. */ @@ -180,7 +181,7 @@ class WatchStreamDelegate { } void NotifyDelegateOnOpen(); - void NotifyDelegateOnChange(FSTWatchChange* change, + void NotifyDelegateOnChange(const WatchChange& change, const model::SnapshotVersion& snapshot_version); void NotifyDelegateOnClose(const util::Status& status); diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index ec3cf4c2853..5fce0d0bf9a 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -18,10 +18,13 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_WATCH_CHANGE_H_ #if !defined(__OBJC__) -// TODO(varconst): the only dependency is `FSTMaybeDocument`. +// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` +// (the latter is used to represent the resume token). #error "This header only supports Objective-C++" #endif // !defined(__OBJC__) +#import + #include #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -42,8 +45,19 @@ namespace remote { */ class WatchChange { public: + enum class Type { + Document, + ExistenceFilter, + TargetChange, + }; + + explicit WatchChange(Type type) : type_{type} {} virtual ~WatchChange() { } + + Type type() const { return type_; } + + const Type type_; }; /** @@ -54,23 +68,24 @@ class WatchChange { */ class DocumentWatchChange : public WatchChange { public: - DocumentWatchChange(std::vector&& updated_target_ids, - std::vector&& removed_target_ids, + DocumentWatchChange(std::vector&& updated_target_ids, + std::vector&& removed_target_ids, model::DocumentKey&& document_key, FSTMaybeDocument* new_document) - : updated_target_ids_{std::move(updated_target_ids)}, + : WatchChange{Type::Document}, + updated_target_ids_{std::move(updated_target_ids)}, removed_target_ids_{std::move(removed_target_ids)}, document_key_{std::move(document_key)}, new_document_{new_document} { } /** The new document applies to all of these targets. */ - const std::vector& updated_target_ids_() const { + const std::vector& updated_target_ids() const { return updated_target_ids_; } /** The new document is removed from all of these targets. */ - const std::vector& removed_target_ids_() const { + const std::vector& removed_target_ids() const { return removed_target_ids_; } @@ -79,7 +94,7 @@ class DocumentWatchChange : public WatchChange { * document went out of view without the server sending a new document. */ FSTMaybeDocument* new_document() const { - return new_document; + return new_document_; } /** The key of the document for this change. */ @@ -88,8 +103,8 @@ class DocumentWatchChange : public WatchChange { } private: - std::vector updated_target_ids_; - std::vector removed_target_ids_; + std::vector updated_target_ids_; + std::vector removed_target_ids_; model::DocumentKey document_key_; FSTMaybeDocument* new_document_; }; @@ -103,9 +118,13 @@ bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); class ExistenceFilterWatchChange : public WatchChange { public: ExistenceFilterWatchChange(ExistenceFilter filter, model::TargetId target_id) - : filter_{filter}, target_id_{target_id} { + : WatchChange{Type::ExistenceFilter}, + filter_{filter}, target_id_{target_id} { } + const ExistenceFilter& filter() const { return filter_; } + model::TargetId target_id() const { return target_id_; } + private: ExistenceFilter filter_; model::TargetId target_id_; @@ -119,12 +138,13 @@ enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; class WatchTargetChange : public WatchChange { public: WatchTargetChange(WatchTargetChangeState state, - std::vector&& target_ids, - std::string&& resume_token, + std::vector&& target_ids, + NSData* resume_token, util::Status&& cause) - : state_{state}, + : WatchChange{Type::ExistenceFilter}, + state_{state}, target_ids_{std::move(target_ids)}, - resume_token_{std::move(resume_token)}, + resume_token_{resume_token}, cause_{std::move(cause)} { } @@ -134,7 +154,7 @@ class WatchTargetChange : public WatchChange { } /** The target IDs that were added/removed/set. */ - const std::vector& target_ids() const { + const std::vector& target_ids() const { return target_ids_; } @@ -144,7 +164,7 @@ class WatchTargetChange : public WatchChange { * matches the query. The resume token essentially identifies a point in * time from which the server should resume sending results. */ - const std::string& resume_token() const { + NSData* resume_token() const { return resume_token_; } @@ -152,20 +172,17 @@ class WatchTargetChange : public WatchChange { * An RPC error indicating why the watch failed. Only valid if * WatchChangeState == Removed. */ - const util::Status& status() const { - return status_; + const util::Status& cause() const { + return cause_; } private: WatchTargetChangeState state_; - std::vector target_ids_; - std::string resume_token_; + std::vector target_ids_; + std::vector resume_token_; util::Status cause_; }; -inline bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { -} - } // namespace remote } // namespace firestore } // namespace firebase From 9d1f9312fe66c838925860d68a0a5b6e72a6d998 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 17 Jan 2019 19:32:56 -0500 Subject: [PATCH 009/107] Core compiles --- Firestore/Source/Local/FSTLocalSerializer.mm | 5 ++-- Firestore/Source/Local/FSTLocalStore.mm | 6 ++-- Firestore/Source/Local/FSTQueryData.h | 8 ++--- Firestore/Source/Local/FSTQueryData.mm | 22 +++++--------- Firestore/Source/Remote/FSTRemoteEvent.h | 7 ++--- Firestore/Source/Remote/FSTRemoteEvent.mm | 29 +++++++------------ Firestore/Source/Remote/FSTRemoteStore.mm | 24 ++++++++++----- Firestore/Source/Remote/FSTSerializerBeta.mm | 9 +++--- .../firestore/remote/remote_objc_bridge.mm | 4 +-- .../firebase/firestore/remote/watch_change.cc | 2 +- .../firebase/firestore/remote/watch_change.h | 2 +- .../firebase/firestore/remote/watch_stream.mm | 2 +- 12 files changed, 55 insertions(+), 65 deletions(-) diff --git a/Firestore/Source/Local/FSTLocalSerializer.mm b/Firestore/Source/Local/FSTLocalSerializer.mm index 5dc98dcae01..5ad70e43c47 100644 --- a/Firestore/Source/Local/FSTLocalSerializer.mm +++ b/Firestore/Source/Local/FSTLocalSerializer.mm @@ -217,7 +217,7 @@ - (FSTPBTarget *)encodedQueryData:(FSTQueryData *)queryData { proto.targetId = queryData.targetID; proto.lastListenSequenceNumber = queryData.sequenceNumber; proto.snapshotVersion = [remoteSerializer encodedVersion:queryData.snapshotVersion]; - proto.resumeToken = [NSData dataWithBytes:queryData.resumeToken.data() length:queryData.resumeToken.size()]; + proto.resumeToken = queryData.resumeToken; FSTQuery *query = queryData.query; if ([query isDocumentQuery]) { @@ -235,8 +235,7 @@ - (FSTQueryData *)decodedQueryData:(FSTPBTarget *)target { TargetId targetID = target.targetId; ListenSequenceNumber sequenceNumber = target.lastListenSequenceNumber; SnapshotVersion version = [remoteSerializer decodedVersion:target.snapshotVersion]; - auto tokenData = static_cast(target.resumeToken.bytes); - std::vector resumeToken{tokenData, tokenData + target.resumeToken.length}; + NSData *resumeToken = target.resumeToken; FSTQuery *query; switch (target.targetTypeOneOfCase) { diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 4a3b7252a9a..e04a54c1fa8 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -247,7 +247,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // Update the resume token if the change includes one. Don't clear any preexisting value. // Bump the sequence number as well, so that documents being removed now are ordered later // than documents that were previously removed from this target. - if (!change.resumeToken.empty()) { + if (change.resumeToken.length > 0) { FSTQueryData *oldQueryData = queryData; queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshotVersion resumeToken:change.resumeToken @@ -330,10 +330,10 @@ - (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData oldQueryData:(FSTQueryData *)oldQueryData change:(FSTTargetChange *)change { // Avoid clearing any existing value - if (newQueryData.resumeToken.empty()) return NO; + if (newQueryData.resumeToken.length == 0) return NO; // Any resume token is interesting if there isn't one already. - if (oldQueryData.resumeToken.empty()) return YES; + if (oldQueryData.resumeToken.length == 0) return YES; // Don't allow resume token changes to be buffered indefinitely. This allows us to be reasonably // up-to-date after a crash and avoids needing to loop over all active queries on shutdown. diff --git a/Firestore/Source/Local/FSTQueryData.h b/Firestore/Source/Local/FSTQueryData.h index 7caf1755b21..f96f327c6b9 100644 --- a/Firestore/Source/Local/FSTQueryData.h +++ b/Firestore/Source/Local/FSTQueryData.h @@ -16,8 +16,6 @@ #import -#include - #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" @@ -45,7 +43,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { listenSequenceNumber:(firebase::firestore::model::ListenSequenceNumber)sequenceNumber purpose:(FSTQueryPurpose)purpose snapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(const std::vector&)resumeToken NS_DESIGNATED_INITIALIZER; + resumeToken:(NSData *)resumeToken NS_DESIGNATED_INITIALIZER; /** Convenience initializer for use when creating an FSTQueryData for the first time. */ - (instancetype)initWithQuery:(FSTQuery *)query @@ -61,7 +59,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { */ - (instancetype) queryDataByReplacingSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - resumeToken:(const std::vector&)resumeToken + resumeToken:(NSData *)resumeToken sequenceNumber: (firebase::firestore::model::ListenSequenceNumber)sequenceNumber; @@ -88,7 +86,7 @@ typedef NS_ENUM(NSInteger, FSTQueryPurpose) { * without retransmitting all the data that matches the query. The resume token essentially * identifies a point in time from which the server should resume sending results. */ -- (const std::vector&) resumeToken; +@property(nonatomic, copy, readonly) NSData *resumeToken; @end diff --git a/Firestore/Source/Local/FSTQueryData.mm b/Firestore/Source/Local/FSTQueryData.mm index 17a3412a9fc..dc174c37ef2 100644 --- a/Firestore/Source/Local/FSTQueryData.mm +++ b/Firestore/Source/Local/FSTQueryData.mm @@ -32,7 +32,6 @@ @implementation FSTQueryData { SnapshotVersion _snapshotVersion; - std::vector _resumeToken; } - (instancetype)initWithQuery:(FSTQuery *)query @@ -40,7 +39,7 @@ - (instancetype)initWithQuery:(FSTQuery *)query listenSequenceNumber:(ListenSequenceNumber)sequenceNumber purpose:(FSTQueryPurpose)purpose snapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(const std::vector&)resumeToken { + resumeToken:(NSData *)resumeToken { self = [super init]; if (self) { _query = query; @@ -48,7 +47,7 @@ - (instancetype)initWithQuery:(FSTQuery *)query _sequenceNumber = sequenceNumber; _purpose = purpose; _snapshotVersion = std::move(snapshotVersion); - _resumeToken = resumeToken; + _resumeToken = [resumeToken copy]; } return self; } @@ -62,14 +61,10 @@ - (instancetype)initWithQuery:(FSTQuery *)query listenSequenceNumber:sequenceNumber purpose:purpose snapshotVersion:SnapshotVersion::None() - resumeToken:{}]; + resumeToken:[NSData data]]; } -- (const std::vector&) resumeToken { - return _resumeToken; -} - -- (const SnapshotVersion &)snapshotVersion { +- (const firebase::firestore::model::SnapshotVersion &)snapshotVersion { return _snapshotVersion; } @@ -85,25 +80,24 @@ - (BOOL)isEqual:(id)object { return [self.query isEqual:other.query] && self.targetID == other.targetID && self.sequenceNumber == other.sequenceNumber && self.purpose == other.purpose && self.snapshotVersion == other.snapshotVersion && - _resumeToken == other->_resumeToken; + [self.resumeToken isEqual:other.resumeToken]; } - (NSUInteger)hash { return util::Hash([self.query hash], self.targetID, self.sequenceNumber, static_cast(self.purpose), self.snapshotVersion.Hash(), - _resumeToken); + [self.resumeToken hash]); } - (NSString *)description { - NSData *token = [NSData dataWithBytes:_resumeToken.data() length:_resumeToken.size()]; return [NSString stringWithFormat:@"", self.query, self.targetID, (unsigned long)self.purpose, - self.snapshotVersion.timestamp().ToString().c_str(), token]; + self.snapshotVersion.timestamp().ToString().c_str(), self.resumeToken]; } - (instancetype)queryDataByReplacingSnapshotVersion:(SnapshotVersion)snapshotVersion - resumeToken:(const std::vector&)resumeToken + resumeToken:(NSData *)resumeToken sequenceNumber:(ListenSequenceNumber)sequenceNumber { return [[FSTQueryData alloc] initWithQuery:self.query targetID:self.targetID diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 70595922349..2c3e51b7706 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -46,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Returns the FSTQueryData for an active target ID or 'null' if this query has become inactive */ -- (nullable FSTQueryData *)queryDataForTarget:(FSTBoxedTargetID *)targetID; +- (nullable FSTQueryData *)queryDataForTarget:(firebase::firestore::model::TargetId)targetID; @end @@ -65,7 +64,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Creates a new target change with the given SnapshotVersion. */ -- (instancetype)initWithResumeToken:(const std::vector&)resumeToken +- (instancetype)initWithResumeToken:(NSData *)resumeToken current:(BOOL)current addedDocuments:(firebase::firestore::model::DocumentKeySet)addedDocuments modifiedDocuments:(firebase::firestore::model::DocumentKeySet)modifiedDocuments @@ -79,7 +78,7 @@ NS_ASSUME_NONNULL_BEGIN * disconnecting without retransmitting all the data that matches the query. The resume token * essentially identifies a point in time from which the server should resume sending results. */ -- (const std::vector&) resumeToken; +@property(nonatomic, strong, readonly) NSData *resumeToken; /** * The "current" (synced) status of this target. Note that "current" has special meaning in the RPC diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index bfefd45bce7..31b80e8122e 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -48,19 +48,18 @@ #pragma mark - FSTTargetChange @implementation FSTTargetChange { - std::vector _resumeToken; DocumentKeySet _addedDocuments; DocumentKeySet _modifiedDocuments; DocumentKeySet _removedDocuments; } -- (instancetype)initWithResumeToken:(const std::vector&)resumeToken +- (instancetype)initWithResumeToken:(NSData *)resumeToken current:(BOOL)current addedDocuments:(DocumentKeySet)addedDocuments modifiedDocuments:(DocumentKeySet)modifiedDocuments removedDocuments:(DocumentKeySet)removedDocuments { if (self = [super init]) { - _resumeToken = resumeToken; + _resumeToken = [resumeToken copy]; _current = current; _addedDocuments = std::move(addedDocuments); _modifiedDocuments = std::move(modifiedDocuments); @@ -69,10 +68,6 @@ - (instancetype)initWithResumeToken:(const std::vector&)resumeTok return self; } -- (const std::vector&) resumeToken { - return _resumeToken; -} - - (const DocumentKeySet &)addedDocuments { return _addedDocuments; } @@ -94,7 +89,7 @@ - (BOOL)isEqual:(id)other { } return [self current] == [other current] && - _resumeToken == static_cast(other)->_resumeToken && + [[self resumeToken] isEqualToData:[other resumeToken]] && [self addedDocuments] == [other addedDocuments] && [self modifiedDocuments] == [other modifiedDocuments] && [self removedDocuments] == [other removedDocuments]; @@ -117,7 +112,7 @@ @interface FSTTargetState : NSObject @property(nonatomic) BOOL current; /** The last resume token sent to us for this target. */ -- (const std::vector&) resumeToken; +@property(nonatomic, readonly, strong) NSData *resumeToken; /** Whether we have modified any state that should trigger a snapshot. */ @property(nonatomic, readonly) BOOL hasPendingChanges; @@ -129,7 +124,7 @@ - (BOOL)isPending; * Applies the resume token to the TargetChange, but only when it has a new value. Empty * resumeTokens are discarded. */ -- (void)updateResumeToken:(const std::vector&)resumeToken; +- (void)updateResumeToken:(NSData *)resumeToken; /** Resets the document changes and sets `hasPendingChanges` to false. */ - (void)clearPendingChanges; @@ -150,7 +145,6 @@ - (void)removeDocumentChangeForKey:(const DocumentKey &)documentKey; @end @implementation FSTTargetState { - std::vector _resumeToken; /** * The number of outstanding responses (adds or removes) that we are waiting on. We only consider * targets active that have no outstanding responses. @@ -168,6 +162,7 @@ @implementation FSTTargetState { - (instancetype)init { if (self = [super init]) { + _resumeToken = [NSData data]; _outstandingResponses = 0; // We initialize to 'true' so that newly-added targets are included in the next RemoteEvent. @@ -180,14 +175,10 @@ - (BOOL)isPending { return _outstandingResponses != 0; } -- (const std::vector&) resumeToken { - return _resumeToken; -} - -- (void)updateResumeToken:(const std::vector&)resumeToken { - if (!resumeToken.empty()) { +- (void)updateResumeToken:(NSData *)resumeToken { + if (resumeToken.length > 0) { _hasPendingChanges = YES; - _resumeToken = resumeToken; + _resumeToken = [resumeToken copy]; } } @@ -562,7 +553,7 @@ - (nullable FSTQueryData *)queryDataForActiveTarget:(TargetId)targetID { auto targetState = _targetStates.find(targetID); return targetState != _targetStates.end() && targetState->second.isPending ? nil - : [_targetMetadataProvider queryDataForTarget:@(targetID)]; + : [_targetMetadataProvider queryDataForTarget:targetID]; } - (FSTRemoteEvent *)remoteEventAtSnapshotVersion:(const SnapshotVersion &)snapshotVersion { diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index aa4279784ae..6dec2268e4d 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -38,6 +38,7 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -55,6 +56,11 @@ using firebase::firestore::model::TargetId; using firebase::firestore::remote::WatchStream; using firebase::firestore::remote::WriteStream; +using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; using util::AsyncQueue; NS_ASSUME_NONNULL_BEGIN @@ -264,7 +270,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { _listenTargets.erase(found); if (_watchStream->IsOpen()) { - [self sendUnwatchRequestForTargetID:targetID]; + [self sendUnwatchRequestForTargetID:@(targetID)]; } if (_listenTargets.empty()) { if (_watchStream->IsOpen()) { @@ -316,6 +322,7 @@ - (void)watchStreamDidChange:(const WatchChange &)change } else { [self.watchChangeAggregator handleTargetChange:watchTargetChange]; } + } else if (change.type() == WatchChange::Type::Document) { [self.watchChangeAggregator handleDocumentChange:static_cast(change)]; @@ -324,7 +331,7 @@ - (void)watchStreamDidChange:(const WatchChange &)change HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, "Expected watchChange to be an instance of ExistenceFilterWatchChange"); [self.watchChangeAggregator - handleDocumentChange:static_cast(change)]; + handleExistenceFilter:static_cast(change)]; } if (snapshotVersion != SnapshotVersion::None() && @@ -372,8 +379,9 @@ -(void)raiseWatchSnapshotWithSnapshotVersion : (const SnapshotVersion &)snapshot for (const auto &entry : remoteEvent.targetChanges) { NSData *resumeToken = entry.second.resumeToken; if (resumeToken.length > 0) { - FSTBoxedTargetID *targetID = @(entry.first); - FSTQueryData *queryData = _listenTargets[targetID]; + TargetId targetID = entry.first; + auto found = _listenTargets.find(targetID); + FSTQueryData *queryData = found != _listenTargets.end() ? found->second : nil; // A watched target might have been removed already. if (queryData) { _listenTargets[targetID] = @@ -387,10 +395,12 @@ -(void)raiseWatchSnapshotWithSnapshotVersion : (const SnapshotVersion &)snapshot // Re-establish listens for the targets that have been invalidated by existence filter // mismatches. for (TargetId targetID : remoteEvent.targetMismatches) { - if (_listenTargets.find(targetID) == _listenTargets.end()) { + auto found = _listenTargets.find(targetID); + if (found == _listenTargets.end()) { // A watched target might have been removed already. continue; } + FSTQueryData* queryData = found->second; // Clear the resume token for the query, since we're in a known mismatch state. queryData = [[FSTQueryData alloc] initWithQuery:queryData.query @@ -420,14 +430,14 @@ -(void)raiseWatchSnapshotWithSnapshotVersion : (const SnapshotVersion &)snapshot /** Process a target error and passes the error along to SyncEngine. */ -(void)processTargetErrorForWatchChange : (const WatchTargetChange &)change { - HARD_ASSERT(!change.cause.ok(), "Handling target error without a cause"); + HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); // Ignore targets that have been removed already. for (TargetId targetID : change.target_ids()) { auto found = _listenTargets.find(targetID); if (found != _listenTargets.end()) { _listenTargets.erase(found); [self.watchChangeAggregator removeTarget:targetID]; - [self.syncEngine rejectListenWithTargetID:targetID error:change.cause()]; + [self.syncEngine rejectListenWithTargetID:targetID error:util::MakeNSError(change.cause())]; } } } diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 3b1997880d3..71d43e99595 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -738,8 +738,8 @@ - (GCFSTarget *)encodedTarget:(FSTQueryData *)queryData { } result.targetId = queryData.targetID; - if (!queryData.resumeToken.empty()) { - result.resumeToken = [NSData dataWithBytes: queryData.resumeToken.data() length: queryData.resumeToken.size()]; + if (queryData.resumeToken.length > 0) { + result.resumeToken = queryData.resumeToken; } return result; @@ -1111,15 +1111,14 @@ - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { targetIDs.push_back(value); }]; - auto tokenData = static_cast([change.resumeToken bytes]); - std::vector resumeToken{tokenData, tokenData + [change.resumeToken length]}; + NSData *resumeToken = change.resumeToken; util::Status cause; if (change.hasCause) { cause = util::Status{static_cast(change.cause.code), util::MakeString(change.cause.message)}; } - return absl::make_unique(state, std::move(targetIDs), std::move(resumeToken), + return absl::make_unique(state, std::move(targetIDs), resumeToken, std::move(cause)); } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm index 5d5bebf8447..654674acc35 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm @@ -146,7 +146,7 @@ bool IsLoggingEnabled() { return ToProto(message, out_status); } -FSTWatchChange* WatchStreamSerializer::ToWatchChange( +std::unique_ptr WatchStreamSerializer::ToWatchChange( GCFSListenResponse* proto) const { return [serializer_ decodedWatchChange:proto]; } @@ -301,7 +301,7 @@ bool IsLoggingEnabled() { } void WatchStreamDelegate::NotifyDelegateOnChange( - FSTWatchChange* change, const model::SnapshotVersion& snapshot_version) { + const WatchChange& change, const SnapshotVersion& snapshot_version) { [delegate_ watchStreamDidChange:change snapshotVersion:snapshot_version]; } diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.cc b/Firestore/core/src/firebase/firestore/remote/watch_change.cc index ef893838029..33364f593ee 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.cc +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +//#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" namespace firebase { namespace firestore { diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index 5fce0d0bf9a..3c9d152ae41 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -179,7 +179,7 @@ class WatchTargetChange : public WatchChange { private: WatchTargetChangeState state_; std::vector target_ids_; - std::vector resume_token_; + NSData* resume_token_; util::Status cause_; }; diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm index 3e248e53f02..7a487d75664 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm @@ -93,7 +93,7 @@ backoff_.Reset(); delegate_bridge_.NotifyDelegateOnChange( - serializer_bridge_.ToWatchChange(response), + *serializer_bridge_.ToWatchChange(response), serializer_bridge_.ToSnapshotVersion(response)); return Status::OK(); } From 84842be918f9351b5e56d2b1d420959915c11c6d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 15:43:52 -0500 Subject: [PATCH 010/107] quick fix --- Firestore/Example/Tests/Util/FSTHelpers.mm | 1 - Firestore/Source/Remote/FSTRemoteStore.mm | 2 -- 2 files changed, 3 deletions(-) diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 406f237a9ba..10b33cf6f67 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -39,7 +39,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index de334dbb3f3..d7fe65902b6 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -133,7 +133,6 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore if (self = [super init]) { _localStore = localStore; _datastore = std::move(datastore); - _listenTargets = [NSMutableDictionary dictionary]; _writePipeline = [NSMutableArray array]; _onlineStateTracker = [[FSTOnlineStateTracker alloc] initWithWorkerQueue:queue]; @@ -442,7 +441,6 @@ - (void)processTargetErrorForWatchChange:(const WatchTargetChange &)change { } } } -} - (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(FSTBoxedTargetID *)targetID { return [self.syncEngine remoteKeysForTarget:targetID]; From e5132be5c5623bb7737050cf610965cfb0e31790 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 16:04:59 -0500 Subject: [PATCH 011/107] Test helpers --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 1 - Firestore/Example/Tests/Util/FSTHelpers.h | 42 ++++++----- Firestore/Example/Tests/Util/FSTHelpers.mm | 69 +++++++++---------- .../firebase/firestore/remote/watch_change.h | 38 ++++++---- 4 files changed, 82 insertions(+), 68 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 98635767d38..dc348ff0ad0 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -28,7 +28,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Example/Tests/Local/FSTLocalStoreTests.h" diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index 679b59196f9..e0db83be66a 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -147,12 +147,17 @@ inline NSString *FSTRemoveExceptionPrefix(NSString *exception) { * the documentKey and that the provided targets will be returned as active from the * `queryDataForTarget` target. */ -+ (instancetype)providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey - targets:(NSArray *)targets; - -+ (instancetype)providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey - listenTargets:(NSArray *)listenTargets - limboTargets:(NSArray *)limboTargets; ++ (instancetype) + providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey + targets: + (const std::vector &)targets; + ++ (instancetype) + providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey + listenTargets: + (const std::vector&)listenTargets + limboTargets: + (const std::vector&)limboTargets; /** * Creates an FSTTestTargetMetadataProvider that behaves as if there's an established listen for @@ -162,8 +167,10 @@ inline NSString *FSTRemoveExceptionPrefix(NSString *exception) { * empty set of document keys and that the provided targets will be returned as active from the * `queryDataForTarget` target. */ -+ (instancetype)providerWithEmptyResultForKey:(firebase::firestore::model::DocumentKey)documentKey - targets:(NSArray *)targets; ++ (instancetype) + providerWithEmptyResultForKey:(firebase::firestore::model::DocumentKey)documentKey + targets: + (const std::vector &)targets; /** Sets or replaces the local state for the provided query data. */ - (void)setSyncedKeys:(firebase::firestore::model::DocumentKeySet)keys @@ -276,18 +283,21 @@ FSTDeleteMutation *FSTTestDeleteMutation(NSString *path); firebase::firestore::model::MaybeDocumentMap FSTTestDocUpdates(NSArray *docs); /** Creates a remote event that inserts a new document. */ -FSTRemoteEvent *FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, NSArray *addedToTargets); +FSTRemoteEvent *FSTTestAddedRemoteEvent( + FSTMaybeDocument *doc, const std::vector &addedToTargets); /** Creates a remote event with changes to a document. */ -FSTRemoteEvent *FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, - NSArray *updatedInTargets, - NSArray *removedFromTargets); +FSTRemoteEvent *FSTTestUpdateRemoteEvent( + FSTMaybeDocument *doc, + const std::vector &updatedInTargets, + const std::vector &removedFromTargets); /** Creates a remote event with changes to a document. Allows for identifying limbo targets */ -FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets(FSTMaybeDocument *doc, - NSArray *updatedInTargets, - NSArray *removedFromTargets, - NSArray *limboTargets); +FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( + FSTMaybeDocument *doc, + const std::vector& updatedInTargets, + const std::vector& removedFromTargets, + const std::vector& limboTargets); /** Creates a test view changes. */ FSTLocalViewChanges *FSTTestViewChanges(firebase::firestore::model::TargetId targetID, diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 10b33cf6f67..98af5835b70 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -49,6 +49,7 @@ #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" #include "absl/memory/memory.h" @@ -70,6 +71,7 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; +using firebase::firestore::remote::DocumentWatchChange; NS_ASSUME_NONNULL_BEGIN @@ -307,21 +309,21 @@ @implementation FSTTestTargetMetadataProvider { } + (instancetype)providerWithSingleResultForKey:(DocumentKey)documentKey - listenTargets:(NSArray *)listenTargets - limboTargets:(NSArray *)limboTargets { + listenTargets:(const std::vector &)listenTargets + limboTargets:(const std::vector &)limboTargets { FSTTestTargetMetadataProvider *metadataProvider = [FSTTestTargetMetadataProvider new]; FSTQuery *query = [FSTQuery queryWithPath:documentKey.path()]; - for (FSTBoxedTargetID *targetID in listenTargets) { + for (TargetId targetID : listenTargets) { FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID.intValue + targetID:targetID listenSequenceNumber:0 purpose:FSTQueryPurposeListen]; [metadataProvider setSyncedKeys:DocumentKeySet{documentKey} forQueryData:queryData]; } - for (FSTBoxedTargetID *targetID in limboTargets) { + for (TargetId targetID : limboTargets) { FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID.intValue + targetID:targetID listenSequenceNumber:0 purpose:FSTQueryPurposeLimboResolution]; [metadataProvider setSyncedKeys:DocumentKeySet{documentKey} forQueryData:queryData]; @@ -331,18 +333,18 @@ + (instancetype)providerWithSingleResultForKey:(DocumentKey)documentKey } + (instancetype)providerWithSingleResultForKey:(DocumentKey)documentKey - targets:(NSArray *)targets { - return [self providerWithSingleResultForKey:documentKey listenTargets:targets limboTargets:@[]]; + targets:(const std::vector &)targets { + return [self providerWithSingleResultForKey:documentKey listenTargets:targets limboTargets:{}]; } + (instancetype)providerWithEmptyResultForKey:(DocumentKey)documentKey - targets:(NSArray *)targets { + targets:(const std::vector &)targets { FSTTestTargetMetadataProvider *metadataProvider = [FSTTestTargetMetadataProvider new]; FSTQuery *query = [FSTQuery queryWithPath:documentKey.path()]; - for (FSTBoxedTargetID *targetID in targets) { + for (TargetId targetID : targets) { FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID.intValue + targetID:targetID listenSequenceNumber:0 purpose:FSTQueryPurposeListen]; [metadataProvider setSyncedKeys:DocumentKeySet {} forQueryData:queryData]; @@ -356,29 +358,25 @@ - (void)setSyncedKeys:(DocumentKeySet)keys forQueryData:(FSTQueryData *)queryDat _queryData[queryData.targetID] = queryData; } -- (DocumentKeySet)remoteKeysForTarget:(FSTBoxedTargetID *)targetID { - auto it = _syncedKeys.find(targetID.intValue); - HARD_ASSERT(it != _syncedKeys.end(), "Cannot process unknown target %s", targetID.intValue); +- (DocumentKeySet)remoteKeysForTarget:(TargetId)targetID { + auto it = _syncedKeys.find(targetID); + HARD_ASSERT(it != _syncedKeys.end(), "Cannot process unknown target %s", targetID); return it->second; } -- (nullable FSTQueryData *)queryDataForTarget:(FSTBoxedTargetID *)targetID { - auto it = _queryData.find(targetID.intValue); - HARD_ASSERT(it != _queryData.end(), "Cannot process unknown target %s", targetID.intValue); +- (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { + auto it = _queryData.find(targetID); + HARD_ASSERT(it != _queryData.end(), "Cannot process unknown target %s", targetID); return it->second; } @end FSTRemoteEvent *FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, - NSArray *addedToTargets) { + const std::vector &addedToTargets) { HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); - FSTDocumentWatchChange *change = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:addedToTargets - removedTargetIDs:{} - documentKey:doc.key - document:doc]; + DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithEmptyResultForKey:doc.key @@ -417,18 +415,17 @@ - (nullable FSTQueryData *)queryDataForTarget:(FSTBoxedTargetID *)targetID { FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( FSTMaybeDocument *doc, - NSArray *updatedInTargets, - NSArray *removedFromTargets, - NSArray *limboTargets) { + const std::vector &updatedInTargets, + const std::vector &removedFromTargets, + const std::vector &limboTargets) { HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); - FSTDocumentWatchChange *change = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:updatedInTargets - removedTargetIDs:removedFromTargets - documentKey:doc.key - document:doc]; - NSArray *listens = - [updatedInTargets arrayByAddingObjectsFromArray:removedFromTargets]; + DocumentWatchChange change{updatedInTargets, removedFromTargets, doc.key, doc}; + + std::vector listens = updatedInTargets; + listens.insert(listens.end(), removedFromTargets.begin(), + removedFromTargets.end()); + FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithSingleResultForKey:doc.key @@ -439,9 +436,9 @@ - (nullable FSTQueryData *)queryDataForTarget:(FSTBoxedTargetID *)targetID { } FSTRemoteEvent *FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, - NSArray *updatedInTargets, - NSArray *removedFromTargets) { - return FSTTestUpdateRemoteEventWithLimboTargets(doc, updatedInTargets, removedFromTargets, @[]); + const std::vector &updatedInTargets, + const std::vector &removedFromTargets) { + return FSTTestUpdateRemoteEventWithLimboTargets(doc, updatedInTargets, removedFromTargets, {}); } /** Creates a resume token to match the given snapshot version. */ diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index 3c9d152ae41..fb1b758df6b 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -51,11 +51,14 @@ class WatchChange { TargetChange, }; - explicit WatchChange(Type type) : type_{type} {} + explicit WatchChange(Type type) : type_{type} { + } virtual ~WatchChange() { } - Type type() const { return type_; } + Type type() const { + return type_; + } const Type type_; }; @@ -68,12 +71,12 @@ class WatchChange { */ class DocumentWatchChange : public WatchChange { public: - DocumentWatchChange(std::vector&& updated_target_ids, - std::vector&& removed_target_ids, - model::DocumentKey&& document_key, + DocumentWatchChange(std::vector updated_target_ids, + std::vector removed_target_ids, + model::DocumentKey document_key, FSTMaybeDocument* new_document) : WatchChange{Type::Document}, - updated_target_ids_{std::move(updated_target_ids)}, + updated_target_ids_{std::move(updated_target_ids)}, removed_target_ids_{std::move(removed_target_ids)}, document_key_{std::move(document_key)}, new_document_{new_document} { @@ -109,7 +112,7 @@ class DocumentWatchChange : public WatchChange { FSTMaybeDocument* new_document_; }; -bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); +// bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); /** * An `ExistenceFilterWatchChange` applies to the targets and is required to @@ -119,30 +122,35 @@ class ExistenceFilterWatchChange : public WatchChange { public: ExistenceFilterWatchChange(ExistenceFilter filter, model::TargetId target_id) : WatchChange{Type::ExistenceFilter}, - filter_{filter}, target_id_{target_id} { + filter_{filter}, + target_id_{target_id} { } - const ExistenceFilter& filter() const { return filter_; } - model::TargetId target_id() const { return target_id_; } + const ExistenceFilter& filter() const { + return filter_; + } + model::TargetId target_id() const { + return target_id_; + } private: ExistenceFilter filter_; model::TargetId target_id_; }; -bool operator==(const ExistenceFilterWatchChange& lhs, - const ExistenceFilterWatchChange& rhs); +// bool operator==(const ExistenceFilterWatchChange& lhs, +// const ExistenceFilterWatchChange& rhs); enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; class WatchTargetChange : public WatchChange { public: WatchTargetChange(WatchTargetChangeState state, - std::vector&& target_ids, + std::vector target_ids, NSData* resume_token, - util::Status&& cause) + util::Status cause) : WatchChange{Type::ExistenceFilter}, - state_{state}, + state_{state}, target_ids_{std::move(target_ids)}, resume_token_{resume_token}, cause_{std::move(cause)} { From 6c850904a3188b0257134353e77dce451d0172e1 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 16:43:17 -0500 Subject: [PATCH 012/107] MockDatastore --- .../Firestore.xcodeproj/project.pbxproj | 6 --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 1 - .../Tests/Remote/FSTWatchChange+Testing.h | 39 -------------- .../Tests/Remote/FSTWatchChange+Testing.mm | 54 ------------------- .../Tests/SpecTests/FSTMockDatastore.h | 5 +- .../Tests/SpecTests/FSTMockDatastore.mm | 38 ++++++------- .../Example/Tests/SpecTests/FSTSpecTests.mm | 32 ++++++----- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 8 +-- .../SpecTests/FSTSyncEngineTestDriver.mm | 14 +++-- 9 files changed, 57 insertions(+), 140 deletions(-) delete mode 100644 Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h delete mode 100644 Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index b36bb7ec332..9a1f20b141e 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -109,7 +109,6 @@ 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */; }; 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B72021555100B64F25 /* FSTMutationTests.mm */; }; 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */; }; - 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */; }; 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */; }; 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */; }; 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */; }; @@ -401,10 +400,8 @@ 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentTests.mm; sourceTree = ""; }; 5492E0B72021555100B64F25 /* FSTMutationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMutationTests.mm; sourceTree = ""; }; 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTFieldValueTests.mm; sourceTree = ""; }; - 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "FSTWatchChange+Testing.mm"; sourceTree = ""; }; 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSerializerBetaTests.mm; sourceTree = ""; }; 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteEventTests.mm; sourceTree = ""; }; - 5492E0C42021557E00B64F25 /* FSTWatchChange+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FSTWatchChange+Testing.h"; sourceTree = ""; }; 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWatchChangeTests.mm; sourceTree = ""; }; 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodableGeoPointTests.swift; sourceTree = ""; }; 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_key_test.cc; sourceTree = ""; }; @@ -1275,8 +1272,6 @@ children = ( 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */, 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */, - 5492E0C42021557E00B64F25 /* FSTWatchChange+Testing.h */, - 5492E0C02021557E00B64F25 /* FSTWatchChange+Testing.mm */, 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */, ); path = Remote; @@ -2025,7 +2020,6 @@ DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */, 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */, 5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */, - 5492E0C62021557E00B64F25 /* FSTWatchChange+Testing.mm in Sources */, 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */, 5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */, 618BBEAF20B89AAC00B5BCE7 /* annotations.pb.cc in Sources */, diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index dc348ff0ad0..b88604b8c69 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -31,7 +31,6 @@ #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Example/Tests/Local/FSTLocalStoreTests.h" -#import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #import "Firestore/third_party/Immutable/Tests/FSTImmutableSortedDictionary+Testing.h" #import "Firestore/third_party/Immutable/Tests/FSTImmutableSortedSet+Testing.h" diff --git a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h b/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h deleted file mode 100644 index 6fce91b09bf..00000000000 --- a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h +++ /dev/null @@ -1,39 +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 - -#import "Firestore/Source/Remote/FSTWatchChange.h" - -NS_ASSUME_NONNULL_BEGIN - -/** FSTWatchTargetChange is a change to a watch target. */ -@interface FSTWatchTargetChange (Testing) - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs; - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - cause:(nullable NSError *)cause; - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - resumeToken:(nullable NSData *)resumeToken; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm b/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm deleted file mode 100644 index 6bb314da223..00000000000 --- a/Firestore/Example/Tests/Remote/FSTWatchChange+Testing.mm +++ /dev/null @@ -1,54 +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/Example/Tests/Remote/FSTWatchChange+Testing.h" - -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTWatchTargetChange (Testing) - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs { - return [[FSTWatchTargetChange alloc] initWithState:state - targetIDs:targetIDs - resumeToken:[NSData data] - cause:nil]; -} - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - cause:(nullable NSError *)cause { - return [[FSTWatchTargetChange alloc] initWithState:state - targetIDs:targetIDs - resumeToken:[NSData data] - cause:cause]; -} - -+ (instancetype)changeWithState:(FSTWatchTargetChangeState)state - targetIDs:(NSArray *)targetIDs - resumeToken:(nullable NSData *)resumeToken { - return [[FSTWatchTargetChange alloc] initWithState:state - targetIDs:targetIDs - resumeToken:resumeToken - cause:nil]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h index 4781f223ba7..9d58e3416bb 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h @@ -17,6 +17,7 @@ #import #include +#include #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" @@ -64,12 +65,12 @@ class MockDatastore : public Datastore { } /** Injects a WatchChange as though it had come from the backend. */ - void WriteWatchChange(FSTWatchChange* change, const model::SnapshotVersion& snap); + void WriteWatchChange(const WatchChange& change, const model::SnapshotVersion& snap); /** Injects a stream failure as though it had come from the backend. */ void FailWatchStream(const util::Status& error); /** Returns the set of active targets on the watch stream. */ - NSDictionary* ActiveTargets() const; + const std::unordered_map& ActiveTargets() const; /** Helper method to expose watch stream state to verify in tests. */ bool IsWatchStreamOpen() const; diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index 63ac440f432..f8b6a2d6f87 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -27,8 +27,6 @@ #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Source/Remote/FSTStream.h" -#import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" - #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" @@ -54,7 +52,9 @@ using firebase::firestore::model::TargetId; using firebase::firestore::remote::ConnectivityMonitor; using firebase::firestore::remote::GrpcConnection; +using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchStream; +using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WriteStream; using firebase::firestore::util::AsyncQueue; using firebase::firestore::util::CreateNoOpConnectivityMonitor; @@ -75,11 +75,10 @@ : WatchStream{worker_queue, credentials_provider, serializer, grpc_connection, delegate}, datastore_{datastore}, delegate_{delegate} { - active_targets_ = [NSMutableDictionary dictionary]; } - NSDictionary* ActiveTargets() const { - return [active_targets_ copy]; + const std::unordered_map& ActiveTargets() const { + return active_targets_; } void Start() override { @@ -91,7 +90,7 @@ void Start() override { void Stop() override { WatchStream::Stop(); open_ = false; - [active_targets_ removeAllObjects]; + active_targets_.clear(); } bool IsStarted() const override { @@ -109,12 +108,12 @@ void WatchQuery(FSTQueryData* query) override { resumeToken:query.resumeToken sequenceNumber:query.sequenceNumber]; datastore_->IncrementWatchStreamRequests(); - active_targets_[@(query.targetID)] = sentQueryData; + active_targets_[query.targetID] = sentQueryData; } void UnwatchTargetId(model::TargetId target_id) override { LOG_DEBUG("UnwatchTargetId: %s", target_id); - [active_targets_ removeObjectForKey:@(target_id)]; + active_targets_.erase(target_id); } void FailStream(const Status& error) { @@ -122,23 +121,24 @@ void FailStream(const Status& error) { [delegate_ watchStreamWasInterruptedWithError:error]; } - void WriteWatchChange(FSTWatchChange* change, SnapshotVersion snap) { - if ([change isKindOfClass:[FSTWatchTargetChange class]]) { - FSTWatchTargetChange* targetChange = (FSTWatchTargetChange*)change; - if (targetChange.cause) { - for (NSNumber* target_id in targetChange.targetIDs) { - if (!active_targets_[target_id]) { + void WriteWatchChange(const WatchChange& change, SnapshotVersion snap) { + if (change.type() == WatchChange::Type::TargetChange) { + const auto& targetChange = static_cast(change); + if (!targetChange.cause().ok()) { + for (TargetId target_id : targetChange.target_ids()) { + auto found = active_targets_.find(target_id); + if (found == active_targets_.end()) { // Technically removing an unknown target is valid (e.g. it could race with a // server-side removal), but we want to pay extra careful attention in tests // that we only remove targets we listened to. HARD_FAIL("Removing a non-active target"); } - [active_targets_ removeObjectForKey:target_id]; + active_targets_.erase(found); } } - if ([targetChange.targetIDs count] != 0) { + if (!targetChange.target_ids().empty()) { // If the list of target IDs is not empty, we reset the snapshot version to NONE as // done in `FSTSerializerBeta.versionFromListenResponse:`. snap = SnapshotVersion::None(); @@ -150,7 +150,7 @@ void WriteWatchChange(FSTWatchChange* change, SnapshotVersion snap) { private: bool open_ = false; - NSMutableDictionary* active_targets_ = nullptr; + std::unordered_map active_targets_; MockDatastore* datastore_ = nullptr; id delegate_ = nullptr; }; @@ -266,7 +266,7 @@ int sent_mutations_count() const { return write_stream_; } -void MockDatastore::WriteWatchChange(FSTWatchChange* change, const SnapshotVersion& snap) { +void MockDatastore::WriteWatchChange(const WatchChange& change, const SnapshotVersion& snap) { watch_stream_->WriteWatchChange(change, snap); } @@ -274,7 +274,7 @@ int sent_mutations_count() const { watch_stream_->FailStream(error); } -NSDictionary* MockDatastore::ActiveTargets() const { +const std::unordered_map& MockDatastore::ActiveTargets() const { return watch_stream_->ActiveTargets(); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 04a2553fb05..184e0b78176 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -19,6 +19,7 @@ #import #include +#include #include #import "Firestore/Source/Core/FSTEventManager.h" @@ -39,6 +40,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -583,7 +585,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { [self.driver setExpectedLimboDocuments:std::move(expectedLimboDocuments)]; } if (expected[@"activeTargets"]) { - NSMutableDictionary *expectedActiveTargets = [NSMutableDictionary dictionary]; + std::unordered_map expectedActiveTargets; [expected[@"activeTargets"] enumerateKeysAndObjectsUsingBlock:^(NSString *targetIDString, NSDictionary *queryData, BOOL *stop) { @@ -593,7 +595,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { // TODO(mcg): populate the purpose of the target once it's possible to encode that in the // spec tests. For now, hard-code that it's a listen despite the fact that it's not always // the right value. - expectedActiveTargets[@(targetID)] = + expectedActiveTargets[targetID] = [[FSTQueryData alloc] initWithQuery:query targetID:targetID listenSequenceNumber:0 @@ -601,7 +603,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { snapshotVersion:SnapshotVersion::None() resumeToken:resumeToken]; }]; - self.driver.expectedActiveTargets = expectedActiveTargets; + self.driver.setExpectedActiveTargets:expectedActiveTargets; } } @@ -634,7 +636,7 @@ - (void)validateLimboDocuments { // Validate that each limbo doc has an expected active target for (const auto &kv : actualLimboDocs) { - XCTAssertNotNil(self.driver.expectedActiveTargets[@(kv.second)], + XCTAssertNotNil([self.driver expectedActiveTargets][kv.second], @"Found limbo doc without an expected active target"); } @@ -654,12 +656,11 @@ - (void)validateActiveTargets { } // Create a copy so we can modify it in tests - NSMutableDictionary *actualTargets = - [NSMutableDictionary dictionaryWithDictionary:self.driver.activeTargets]; + std::unordered_map actualTargets = [self.driver activeTargets]; - [self.driver.expectedActiveTargets enumerateKeysAndObjectsUsingBlock:^(FSTBoxedTargetID *targetID, - FSTQueryData *queryData, - BOOL *stop) { + for (const auto& kv : [self.driver activeTargets]) { + TargetId targetID = kv.first; + FSTQueryData* queryData = kv.second; XCTAssertNotNil(actualTargets[targetID], @"Expected active target not found: %@", queryData); // TODO(mcg): validate the purpose of the target once it's possible to encode that in the @@ -675,9 +676,16 @@ - (void)validateActiveTargets { XCTAssertEqualObjects(Describe(actual.resumeToken), Describe(queryData.resumeToken)); } - [actualTargets removeObjectForKey:targetID]; - }]; - XCTAssertTrue(actualTargets.count == 0, "Unexpected active targets: %@", actualTargets); + actualTargets.erase(targetID); + } + + if (!actualTargets.empty()) { + NSMutableDictionary *actualTargetsDictionary = [NSMutableDictionary dictionary]; + for (const auto& kv : actualTargets) { + actualTargetsDictionary[@(kv.first)] = kv.second; + } + XCTAssertTrue(actualTargets.empty(), "Unexpected active targets: %@", [actualTargetsDictionary description]); + } } - (void)runSpecTestSteps:(NSArray *)steps config:(NSDictionary *)config { diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 1e54f1e8471..4a50cc20c07 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -294,12 +294,12 @@ typedef std::unordered_map *activeTargets; +- (const std::unordered_map &)activeTargets; /** The expected set of active targets, keyed by target ID. */ -@property(nonatomic, strong, readwrite) - NSDictionary *expectedActiveTargets; +- (const std::unordered_map &)expectedActiveTargets; + +- (void)setExpectedActiveTargets:(const std::unordered_map &)targets; @end diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 229fb77b374..d15f87ed6fa 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -111,6 +111,8 @@ @interface FSTSyncEngineTestDriver () @implementation FSTSyncEngineTestDriver { std::unique_ptr _workerQueue; + std::unordered_map _expectedActiveTargets; + // ivar is declared as mutable. std::unordered_map *, HashUser> _outstandingWrites; DocumentKeySet _expectedLimboDocuments; @@ -171,8 +173,6 @@ - (instancetype)initWithPersistence:(id)persistence _queryListeners = [NSMutableDictionary dictionary]; - _expectedActiveTargets = [NSDictionary dictionary]; - _currentUser = initialUser; _acknowledgedDocs = [NSMutableArray array]; @@ -395,10 +395,18 @@ - (void)receiveWatchStreamError:(int)errorCode userInfo:(NSDictionary *)activeTargets { +- (const std::unordered_map&)activeTargets { return _datastore->ActiveTargets(); } +- (const std::unordered_map&)expectedActiveTargets { + return _expectedActiveTargets; +} + +- (void)setExpectedActiveTargets:(const std::unordered_map&)targets { + _expectedActiveTargets = targets; +} + #pragma mark - Helper Methods - (NSMutableArray *)currentOutstandingWrites { From f7a90b5e61ff3691354041db85a347edeb72ab5d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 16:55:20 -0500 Subject: [PATCH 013/107] FSTLocalStoreTests --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index b88604b8c69..7613e1c5e4c 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -37,6 +37,8 @@ #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" namespace testutil = firebase::firestore::testutil; @@ -48,6 +50,9 @@ using firebase::firestore::model::MaybeDocumentMap; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::util::Status; static NSArray *docMapToArray(const DocumentMap &docs) { NSMutableArray *result = [NSMutableArray array]; @@ -255,7 +260,7 @@ - (void)testHandlesSetMutationThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations)); @@ -298,7 +303,7 @@ - (void)testHandlesAckThenRejectThenRemoteEvent { [self applyRemoteEvent:FSTTestAddedRemoteEvent(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced), - @[ @(targetID) ])]; + {targetID})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced)); FSTAssertNotContains(@"bar/baz"); @@ -311,7 +316,7 @@ - (void)testHandlesDeletedDocumentThenSetMutationThenAck { TargetId targetID = [self allocateQuery:query]; [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); // Under eager GC, there is no longer a reference for the document, and it should be // deleted. @@ -350,7 +355,7 @@ - (void)testHandlesSetMutationThenDeletedDocument { @[ FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations)); @@ -365,7 +370,7 @@ - (void)testHandlesDocumentThenSetMutationThenAckThenDocument { [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/bar", 2, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ])]; + {targetID})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 2, @{@"it" : @"base"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"it" : @"base"}, FSTDocumentStateSynced)); @@ -383,7 +388,7 @@ - (void)testHandlesDocumentThenSetMutationThenAckThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced)); } @@ -416,7 +421,7 @@ - (void)testHandlesPatchMutationThenDocumentThenAck { [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ])]; + {targetID})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar", @"it" : @"base"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar", @"it" : @"base"}, @@ -433,7 +438,7 @@ - (void)testHandlesPatchMutationThenDocumentThenAck { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar", @"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar", @"it" : @"base"}, FSTDocumentStateSynced) ]); @@ -463,7 +468,7 @@ - (void)testHandlesPatchMutationThenAckThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced)); } @@ -491,7 +496,7 @@ - (void)testHandlesDocumentThenDeleteMutationThenAck { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced)); @@ -523,7 +528,7 @@ - (void)testHandlesDeleteMutationThenDocumentThenAck { // Add the document to a target so it will remain in persistence even when ack'd [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertContains(FSTTestDeletedDoc("foo/bar", 0, NO)); @@ -547,12 +552,12 @@ - (void)testHandlesDocumentThenDeletedDocumentThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced)); [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); if (![self gcIsEager]) { FSTAssertContains(FSTTestDeletedDoc("foo/bar", 2, NO)); @@ -560,7 +565,7 @@ - (void)testHandlesDocumentThenDeletedDocumentThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced)); } @@ -583,7 +588,7 @@ - (void)testHandlesSetMutationThenPatchMutationThenDocumentThenAckThenAck { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations)); @@ -683,12 +688,12 @@ - (void)testCollectsGarbageAfterChangeBatchWithNoTargetIDs { if (![self gcIsEager]) return; [self applyRemoteEvent:FSTTestUpdateRemoteEventWithLimboTargets( - FSTTestDeletedDoc("foo/bar", 2, NO), @[], @[], @[ @1 ])]; + FSTTestDeletedDoc("foo/bar", 2, NO), {}, {}, {1})]; FSTAssertNotContains(@"foo/bar"); [self applyRemoteEvent:FSTTestUpdateRemoteEventWithLimboTargets( FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateSynced), - @[], @[], @[ @1 ])]; + {}, {}, {1})]; FSTAssertNotContains(@"foo/bar"); } @@ -701,12 +706,12 @@ - (void)testCollectsGarbageAfterChangeBatch { [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateSynced), - @[ @(targetID) ])]; + {targetID})]; FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateSynced)); [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 2, @{@"foo" : @"baz"}, FSTDocumentStateSynced), - @[], @[ @(targetID) ])]; + {}, {targetID})]; FSTAssertNotContains(@"foo/bar"); } @@ -720,7 +725,7 @@ - (void)testCollectsGarbageAfterAcknowledgedMutation { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 0, @{@"foo" : @"old"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; // Release the query so that our target count goes back to 0 and we are considered up-to-date. [self.localStore releaseQuery:query]; @@ -756,7 +761,7 @@ - (void)testCollectsGarbageAfterRejectedMutation { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 0, @{@"foo" : @"old"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; // Release the query so that our target count goes back to 0 and we are considered up-to-date. [self.localStore releaseQuery:query]; @@ -792,7 +797,7 @@ - (void)testPinsDocumentsInTheLocalView { [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateSynced), - @[ @(targetID) ])]; + {targetID})]; [self writeMutation:FSTTestSetMutation(@"foo/baz", @{@"foo" : @"baz"})]; FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateSynced)); FSTAssertContains(FSTTestDoc("foo/baz", 0, @{@"foo" : @"baz"}, FSTDocumentStateLocalMutations)); @@ -801,10 +806,10 @@ - (void)testPinsDocumentsInTheLocalView { FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateSynced)); [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 1, @{@"foo" : @"bar"}, FSTDocumentStateSynced), - @[], @[ @(targetID) ])]; + {}, {targetID})]; [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/baz", 2, @{@"foo" : @"baz"}, FSTDocumentStateSynced), - @[ @(targetID) ], @[])]; + {targetID}, {})]; FSTAssertContains(FSTTestDoc("foo/baz", 2, @{@"foo" : @"baz"}, FSTDocumentStateLocalMutations)); [self acknowledgeMutationWithVersion:2]; FSTAssertContains(FSTTestDoc("foo/baz", 2, @{@"foo" : @"baz"}, FSTDocumentStateSynced)); @@ -824,8 +829,8 @@ - (void)testThrowsAwayDocumentsWithUnknownTargetIDsImmediately { TargetId targetID = 321; [self applyRemoteEvent:FSTTestUpdateRemoteEventWithLimboTargets( - FSTTestDoc("foo/bar", 1, @{}, FSTDocumentStateSynced), @[], @[], - @[ @(targetID) ])]; + FSTTestDoc("foo/bar", 1, @{}, FSTDocumentStateSynced), {}, {}, + {targetID})]; FSTAssertNotContains(@"foo/bar"); } @@ -872,10 +877,10 @@ - (void)testCanExecuteMixedCollectionQueries { [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), - @[ @2 ], @[])]; + {2}, {})]; [self applyRemoteEvent:FSTTestUpdateRemoteEvent( FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), - @[ @2 ], @[])]; + {2}, {})]; [self.localStore locallyWriteMutations:@[ FSTTestSetMutation(@"foo/bonk", @{@"a" : @"b"}) ]]; @@ -895,20 +900,14 @@ - (void)testPersistsResumeTokens { FSTQuery *query = FSTTestQuery("foo/bar"); FSTQueryData *queryData = [self.localStore allocateQuery:query]; ListenSequenceNumber initialSequenceNumber = queryData.sequenceNumber; - FSTBoxedTargetID *targetID = @(queryData.targetID); + TargetId targetID = queryData.targetID; NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); - FSTWatchTargetChange *watchChange = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ targetID ] - resumeToken:resumeToken]; - NSMutableDictionary *listens = - [NSMutableDictionary dictionary]; - listens[targetID] = queryData; + WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken, Status::OK()}; FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithSingleResultForKey:testutil::Key("foo/bar") - targets:@[ targetID ]]]; + targets:{targetID}]]; [aggregator handleTargetChange:watchChange]; FSTRemoteEvent *remoteEvent = [aggregator remoteEventAtSnapshotVersion:testutil::Version(1000)]; [self applyRemoteEvent:remoteEvent]; @@ -934,10 +933,10 @@ - (void)testRemoteDocumentKeysForTarget { [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), - @[ @2 ])]; + {2})]; [self applyRemoteEvent:FSTTestAddedRemoteEvent( FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), - @[ @2 ])]; + {2})]; [self.localStore locallyWriteMutations:@[ FSTTestSetMutation(@"foo/bonk", @{@"a" : @"b"}) ]]; From 267963ff8b07cb7b2fdb217aee99e9a11e6f7220 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 16:59:48 -0500 Subject: [PATCH 014/107] wip --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 3 +-- Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm | 2 +- Firestore/Source/Remote/FSTRemoteEvent.h | 2 +- Firestore/Source/Remote/FSTRemoteEvent.mm | 6 +++--- Firestore/Source/Remote/FSTRemoteStore.mm | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 0d3a39fb0cc..2f0f36992fc 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -21,11 +21,10 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -#import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 5c3e7d3a853..0d298302fc3 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -42,7 +42,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -51,6 +50,7 @@ #include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 2c3e51b7706..d74a0d3e3c1 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -40,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Returns the set of remote document keys for the given target ID as of the last raised snapshot. */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(FSTBoxedTargetID *)targetID; +- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(firebase::firestore::model::TargetId)targetID; /** * Returns the FSTQueryData for an active target ID or 'null' if this query has become inactive diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 31b80e8122e..1effe4444e7 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -448,7 +448,7 @@ - (void)handleExistenceFilter:(const ExistenceFilterWatchChange&)existenceFilter - (int)currentDocumentCountForTarget:(TargetId)targetID { FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; FSTTargetChange *targetChange = [targetState toTargetChange]; - return ([_targetMetadataProvider remoteKeysForTarget:@(targetID)].size() + + return ([_targetMetadataProvider remoteKeysForTarget:targetID].size() + targetChange.addedDocuments.size() - targetChange.removedDocuments.size()); } @@ -465,7 +465,7 @@ - (void)resetTarget:(TargetId)targetID { // Trigger removal for any documents currently mapped to this target. These removals will be part // of the initial snapshot if Watch does not resend these documents. - DocumentKeySet existingKeys = [_targetMetadataProvider remoteKeysForTarget:@(targetID)]; + DocumentKeySet existingKeys = [_targetMetadataProvider remoteKeysForTarget:targetID]; for (const DocumentKey &key : existingKeys) { [self removeDocument:nil withKey:key fromTarget:targetID]; @@ -525,7 +525,7 @@ - (void)removeDocument:(FSTMaybeDocument *_Nullable)document * Returns whether the LocalStore considers the document to be part of the specified target. */ - (BOOL)containsDocument:(const DocumentKey &)key inTarget:(TargetId)targetID { - const DocumentKeySet &existingKeys = [_targetMetadataProvider remoteKeysForTarget:@(targetID)]; + const DocumentKeySet &existingKeys = [_targetMetadataProvider remoteKeysForTarget:targetID]; return existingKeys.contains(key); } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index d7fe65902b6..4fca5705853 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -442,8 +442,8 @@ - (void)processTargetErrorForWatchChange:(const WatchTargetChange &)change { } } -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(FSTBoxedTargetID *)targetID { - return [self.syncEngine remoteKeysForTarget:targetID]; +- (DocumentKeySet)remoteKeysForTarget:(TargetId)targetID { + return [self.syncEngine remoteKeysForTarget:@(targetID)]; } - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { From 60a5726aa02f78da786e39ceffd67918ed5c9247 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 17:53:51 -0500 Subject: [PATCH 015/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 4 +- .../Tests/Remote/FSTSerializerBetaTests.mm | 19 +++-- .../Example/Tests/SpecTests/FSTSpecTests.mm | 80 +++++++++---------- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 4 +- .../SpecTests/FSTSyncEngineTestDriver.mm | 3 +- .../firebase/firestore/remote/watch_change.h | 19 ++++- 6 files changed, 74 insertions(+), 55 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 2f0f36992fc..5b8118b36e1 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -89,7 +89,7 @@ - (void)setUp { } /** - * Creates an aggregator initialized with the set of provided FSTWatchChanges. Tests can add further + * Creates an aggregator initialized with the set of provided `WatchChange`s. Tests can add further * changes via `handleDocumentChange`, `handleTargetChange` and `handleExistenceFilterChange`. * * @param targetMap A map of query data for all active targets. The map must include an entry for @@ -100,7 +100,7 @@ - (void)setUp { * part of a previous listen. To modify this set during test execution, invoke * `[_targetMetadataProvider setSyncedKeys:forQueryData:]`. * @param watchChanges The watch changes to apply before returning the aggregator. Supported - * changes are FSTDocumentWatchChange and FSTWatchTargetChange. + * changes are `DocumentWatchChange` and `WatchTargetChange`. */ - (FSTWatchChangeAggregator *) aggregatorWithTargetMap:(NSDictionary *)targetMap diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 0d298302fc3..34c4886fbf0 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -51,6 +51,7 @@ #include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -62,6 +63,11 @@ using firebase::firestore::model::FieldTransform; using firebase::firestore::model::Precondition; using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::util::Status; NS_ASSUME_NONNULL_BEGIN @@ -766,21 +772,20 @@ - (void)assertRoundTripForQueryData:(FSTQueryData *)queryData proto:(GCFSTarget } - (void)testConvertsTargetChangeWithAdded { - FSTWatchChange *expected = - [[FSTWatchTargetChange alloc] initWithState:FSTWatchTargetChangeStateAdded - targetIDs:@[ @1, @4 ] - resumeToken:[NSData data] - cause:nil]; + WatchTargetChange expected{WatchTargetChangeState::Added, {1, 4}}; GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.targetChange.targetChangeType = GCFSTargetChange_TargetChangeType_Add; [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actual->type(), WatchChange::Type::TargetChange); + XCTAssertEqual(static_cast*actual, expected); } - (void)testConvertsTargetChangeWithRemoved { + WatchTargetChange expected{WatchTargetChangeState::Removed, {1, 4}}; + FSTWatchChange *expected = [[FSTWatchTargetChange alloc] initWithState:FSTWatchTargetChangeStateRemoved targetIDs:@[ @1, @4 ] diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 184e0b78176..3b86100ae2b 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -29,10 +29,8 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -42,9 +40,11 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -56,6 +56,11 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::util::Status; using firebase::firestore::util::TimerId; NS_ASSUME_NONNULL_BEGIN @@ -84,10 +89,22 @@ NSString *const kDurablePersistence = @"durable-persistence"; -static NSString *Describe(NSData *data) { +namespace { + +NSString *Describe(NSData *data) { return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } +std::vector ConvertTargetsArray(NSArray* from) { + std::vector result; + for (NSNumber* targetID in from) { + result.push_back(targetID.intValue); + } + return result; +} + +} // namespace + @interface FSTSpecTests () @property(nonatomic, strong) FSTSyncEngineTestDriver *driver; @@ -223,20 +240,14 @@ - (void)doDelete:(NSString *)key { } - (void)doWatchAck:(NSArray *)ackedTargets { - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded - targetIDs:ackedTargets - cause:nil]; + WatchTargetChange change{WatchTargetChangeState::Added, ConvertTargetsArray(ackedTargets)}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } - (void)doWatchCurrent:(NSArray *)currentSpec { NSArray *currentTargets = currentSpec[0]; NSData *resumeToken = [currentSpec[1] dataUsingEncoding:NSUTF8StringEncoding]; - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:currentTargets - resumeToken:resumeToken]; + WatchTargetChange change{WatchTargetChangeState::Current, ConvertTargetsArray(currentTargets), resumeToken}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } @@ -250,10 +261,7 @@ - (void)doWatchRemove:(NSDictionary *)watchRemoveSpec { }; error = [NSError errorWithDomain:FIRFirestoreErrorDomain code:code userInfo:userInfo]; } - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved - targetIDs:watchRemoveSpec[@"targetIds"] - cause:error]; + WatchTargetChange change{WatchTargetChangeState::Removed, ConvertTargetsArray(watchRemoveSpec[@"targetIds"]), error}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; // Unlike web, the FSTMockDatastore detects a watch removal with cause and will remove active // targets @@ -288,19 +296,13 @@ - (void)doWatchEntity:(NSDictionary *)watchEntity { : [FSTDeletedDocument documentWithKey:key version:std::move(version) hasCommittedMutations:NO]; - FSTWatchChange *change = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:watchEntity[@"targets"] - removedTargetIDs:watchEntity[@"removedTargets"] - documentKey:doc.key - document:doc]; + DocumentWatchChange change{ConvertTargetsArray(watchEntity[@"targets"]), ConvertTargetsArray(watchEntity[@"removedTargets"]), doc.key, + doc}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } else if (watchEntity[@"key"]) { DocumentKey docKey = FSTTestDocKey(watchEntity[@"key"]); - FSTWatchChange *change = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:watchEntity[@"removedTargets"] - documentKey:docKey - document:nil]; + DocumentWatchChange change{{}, ConvertTargetsArray(watchEntity[@"removedTargets"]), doc.key, + nil}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } else { HARD_FAIL("Either key, doc or docs must be set."); @@ -314,16 +316,12 @@ - (void)doWatchFilter:(NSArray *)watchFilter { int keyCount = watchFilter.count == 0 ? 0 : (int)watchFilter.count - 1; ExistenceFilter filter{keyCount}; - FSTExistenceFilterWatchChange *change = - [FSTExistenceFilterWatchChange changeWithFilter:filter targetID:targets[0].intValue]; + ExistenceFilterWatchChange change{filter, targets[0]}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } - (void)doWatchReset:(NSArray *)watchReset { - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset - targetIDs:watchReset - cause:nil]; + WatchTargetChange change{WatchTargetChangeState::Reset, ConvertTargetsArray(watchReset)}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } @@ -333,10 +331,7 @@ - (void)doWatchSnapshot:(NSDictionary *)watchSnapshot { NSArray *targetIDs = watchSnapshot[@"targetIds"] ? watchSnapshot[@"targetIds"] : [NSArray array]; NSData *resumeToken = [watchSnapshot[@"resumeToken"] dataUsingEncoding:NSUTF8StringEncoding]; - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange - targetIDs:targetIDs - resumeToken:resumeToken]; + WatchTargetChange change{WatchTargetChangeState::NoChange, ConvertTargetsArray(targetIDs), resumeToken}; [self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot[@"version"]]]; } @@ -585,7 +580,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { [self.driver setExpectedLimboDocuments:std::move(expectedLimboDocuments)]; } if (expected[@"activeTargets"]) { - std::unordered_map expectedActiveTargets; + std::unordered_map expectedActiveTargets; [expected[@"activeTargets"] enumerateKeysAndObjectsUsingBlock:^(NSString *targetIDString, NSDictionary *queryData, BOOL *stop) { @@ -603,7 +598,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { snapshotVersion:SnapshotVersion::None() resumeToken:resumeToken]; }]; - self.driver.setExpectedActiveTargets:expectedActiveTargets; + self.driver.setExpectedActiveTargets : expectedActiveTargets; } } @@ -656,11 +651,11 @@ - (void)validateActiveTargets { } // Create a copy so we can modify it in tests - std::unordered_map actualTargets = [self.driver activeTargets]; + std::unordered_map actualTargets = [self.driver activeTargets]; - for (const auto& kv : [self.driver activeTargets]) { + for (const auto &kv : [self.driver activeTargets]) { TargetId targetID = kv.first; - FSTQueryData* queryData = kv.second; + FSTQueryData *queryData = kv.second; XCTAssertNotNil(actualTargets[targetID], @"Expected active target not found: %@", queryData); // TODO(mcg): validate the purpose of the target once it's possible to encode that in the @@ -681,10 +676,11 @@ - (void)validateActiveTargets { if (!actualTargets.empty()) { NSMutableDictionary *actualTargetsDictionary = [NSMutableDictionary dictionary]; - for (const auto& kv : actualTargets) { + for (const auto &kv : actualTargets) { actualTargetsDictionary[@(kv.first)] = kv.second; } - XCTAssertTrue(actualTargets.empty(), "Unexpected active targets: %@", [actualTargetsDictionary description]); + XCTAssertTrue(actualTargets.empty(), "Unexpected active targets: %@", + [actualTargetsDictionary description]); } } diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 4a50cc20c07..3045b506773 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -26,6 +26,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" @class FSTDocumentKey; @@ -34,7 +35,6 @@ @class FSTQuery; @class FSTQueryData; @class FSTViewSnapshot; -@class FSTWatchChange; @protocol FSTPersistence; NS_ASSUME_NONNULL_BEGIN @@ -147,7 +147,7 @@ typedef std::unordered_mapEnqueueBlocking([&] { _datastore->WriteWatchChange(change, snapshot); }); } diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index fb1b758df6b..bb3e5c61cf2 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -145,11 +145,28 @@ enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; class WatchTargetChange : public WatchChange { public: + WatchTargetChange(WatchTargetChangeState state, + std::vector target_ids) + : WatchTargetChange{state, std::move(target_ids), [NSData data], util::Status::OK()} { + } + + WatchTargetChange(WatchTargetChangeState state, + std::vector target_ids, + NSData* resume_token) + : WatchTargetChange{state, std::move(target_ids), resume_token, util::Status::OK()} { + } + + WatchTargetChange(WatchTargetChangeState state, + std::vector target_ids, + util::Status cause) + : WatchTargetChange{state, std::move(target_ids), [NSData data], cause} { + } + WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, NSData* resume_token, util::Status cause) - : WatchChange{Type::ExistenceFilter}, + : WatchChange{Type::TargetChange}, state_{state}, target_ids_{std::move(target_ids)}, resume_token_{resume_token}, From dd9d98d9e9a694d1f0367ee7af38476032576f55 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 18:57:08 -0500 Subject: [PATCH 016/107] FSTRemoveEventTests --- .../Tests/Remote/FSTRemoteEventTests.mm | 417 +++++++----------- Firestore/Source/Remote/FSTRemoteEvent.h | 2 +- 2 files changed, 171 insertions(+), 248 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 5b8118b36e1..ceafd07dad0 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -18,22 +18,32 @@ #import +#include +#include +#include +#include + #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" + #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +#include "absl/memory/memory.h" namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::model::TargetId; using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::WatchChange; NS_ASSUME_NONNULL_BEGIN @@ -103,49 +113,53 @@ - (void)setUp { * changes are `DocumentWatchChange` and `WatchTargetChange`. */ - (FSTWatchChangeAggregator *) - aggregatorWithTargetMap:(NSDictionary *)targetMap + aggregatorWithTargetMap:(const std::unordered_map &)targetMap outstandingResponses: (nullable NSDictionary *)outstandingResponses existingKeys:(DocumentKeySet)existingKeys - changes:(NSArray *)watchChanges { + changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:_targetMetadataProvider]; - NSMutableArray *targetIDs = [NSMutableArray array]; - [targetMap enumerateKeysAndObjectsUsingBlock:^(FSTBoxedTargetID *targetID, - FSTQueryData *queryData, BOOL *stop) { - [targetIDs addObject:targetID]; + std::vector targetIDs; + for (const auto &kv : targetMap) { + TargetId targetID = kv.first; + FSTQueryData *queryData = kv.second; + + targetIDs.push_back(targetID); [_targetMetadataProvider setSyncedKeys:existingKeys forQueryData:queryData]; - }]; + }; [outstandingResponses enumerateKeysAndObjectsUsingBlock:^(FSTBoxedTargetID *targetID, NSNumber *count, BOOL *stop) { for (int i = 0; i < count.intValue; ++i) { - [aggregator recordTargetRequest:targetID]; + [aggregator recordTargetRequest:@(targetID)]; } }]; - for (FSTWatchChange *change in watchChanges) { - if ([change isKindOfClass:[FSTDocumentWatchChange class]]) { - [aggregator handleDocumentChange:(FSTDocumentWatchChange *)change]; - } else if ([change isKindOfClass:[FSTWatchTargetChange class]]) { - [aggregator handleTargetChange:(FSTWatchTargetChange *)change]; - } else { - HARD_ASSERT("Encountered unexpected type of FSTWatchChange"); + for (const std::unique_ptr &change : watchChanges) { + switch (change->type()) { + case WatchChange::Type::Document: { + [aggregator handleDocumentChange:*static_cast(change.get())]; + break; + } + case WatchChange::Type::WatchTargetChange: { + [aggregator handleDocumentChange:*static_cast(change.get())]; + break; + } + default: + HARD_ASSERT("Encountered unexpected type of WatchChange"); } } - [aggregator handleTargetChange:[[FSTWatchTargetChange alloc] - initWithState:FSTWatchTargetChangeStateNoChange - targetIDs:targetIDs - resumeToken:_resumeToken1 - cause:nil]]; + [aggregator handleTargetChange:WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, + _resumeToken1}] - return aggregator; + return aggregator; } /** - * Creates a single remote event that includes target changes for all provided FSTWatchChanges. + * Creates a single remote event that includes target changes for all provided `WatchChange`s. * * @param snapshotVersion The version at which to create the remote event. This corresponds to the * snapshot version provided by the NO_CHANGE event. @@ -156,7 +170,7 @@ - (void)setUp { * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. * @param watchChanges The watch changes to apply before creating the remote event. Supported - * changes are FSTDocumentWatchChange and FSTWatchTargetChange. + * changes are `DocumentWatchChange` and `WatchTargetChange`. */ - (FSTRemoteEvent *) remoteEventAtSnapshotVersion:(FSTTestSnapshotVersion)snapshotVersion @@ -164,7 +178,7 @@ - (void)setUp { outstandingResponses: (nullable NSDictionary *)outstandingResponses existingKeys:(DocumentKeySet)existingKeys - changes:(NSArray *)watchChanges { + changes:(const std::vector>&)watchChanges { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:outstandingResponses existingKeys:existingKeys @@ -173,22 +187,21 @@ - (void)setUp { } - (void)testWillAccumulateDocumentAddedAndRemovedEvents { - // The target map that contains an entry for every target in this test. If a target ID is omitted, - // the target is considered inactive and FSTTestTargetMetadataProvider will fail on access. + // The target map that contains an entry for every target in this test. If a target ID is + // omitted, the target is considered inactive and FSTTestTargetMetadataProvider will fail on + // access. NSDictionary *targetMap = [self queryDataForTargets:@[ @1, @2, @3, @4, @5, @6 ]]; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @2, @3 ] - removedTargetIDs:@[ @4, @5, @6 ] - documentKey:existingDoc.key - document:existingDoc]; + auto change1 = absl::make_unique({1, 2, 3}, {4, 5, 6}, existingDoc.key, existingDoc); FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @4 ] - removedTargetIDs:@[ @2, @6 ] - documentKey:newDoc.key - document:newDoc]; + auto change2 = absl::make_unique({1, 4}, {2, 6}, newDoc.key, newDoc); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); // Create a remote event that includes both `change1` and `change2` as well as a NO_CHANGE event // with the default resume token (`_resumeToken1`). @@ -198,7 +211,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{existingDoc.key} - changes:@[ change1, change2 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); XCTAssertEqualObjects(event.documentUpdates.at(existingDoc.key), existingDoc); @@ -238,24 +251,17 @@ - (void)testWillIgnoreEventsForPendingTargets { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; - - FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved - targetIDs:@[ @1 ] - cause:nil]; - - FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded - targetIDs:@[ @1 ] - cause:nil]; - + auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Removed, {1}); + auto change3 = absl::make_unique(WatchTargetChangeState::Added, {1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change4 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc2.key - document:doc2]; + auto change4 = absl::make_unique({1}, {}, doc2.key, doc2); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); + changes.push_back(std::move(change3)); + changes.push_back(std::move(change4)); // We're waiting for the unwatch and watch ack NSDictionary *outstandingResponses = @{@1 : @2}; @@ -265,7 +271,7 @@ - (void)testWillIgnoreEventsForPendingTargets { targetMap:targetMap outstandingResponses:outstandingResponses existingKeys:DocumentKeySet {} - changes:@[ change1, change2, change3, change4 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); // doc1 is ignored because it was part of an inactive target, but doc2 is in the changes // because it become active. @@ -279,14 +285,12 @@ - (void)testWillIgnoreEventsForRemovedTargets { NSDictionary *targetMap = [self queryDataForTargets:@[]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; + auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Removed, {1}); - FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved - targetIDs:@[ @1 ] - cause:nil]; + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); // We're waiting for the unwatch ack NSDictionary *outstandingResponses = @{@1 : @1}; @@ -295,7 +299,7 @@ - (void)testWillIgnoreEventsForRemovedTargets { targetMap:targetMap outstandingResponses:outstandingResponses existingKeys:DocumentKeySet {} - changes:@[ change1, change2 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); // doc1 is ignored because it was part of an inactive target XCTAssertEqual(event.documentUpdates.size(), 0); @@ -308,39 +312,34 @@ - (void)testWillKeepResetMappingEvenWithUpdates { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; + auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + // Reset stream, ignoring doc1 - FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset - targetIDs:@[ @1 ] - cause:nil]; + auto change2 = absl::make_unique(WatchTargetChangeState::Reset, {1}); // Add doc2, doc3 FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change3 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc2.key - document:doc2]; + auto change3 = absl::make_unique({1}, {}, doc2.key, doc2); FSTDocument *doc3 = FSTTestDoc("docs/3", 3, @{@"value" : @3}, FSTDocumentStateSynced); - FSTWatchChange *change4 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc3.key - document:doc3]; + auto change4 = absl::make_unique({1}, {}, doc3.key, doc3); // Remove doc2 again, should not show up in reset mapping - FSTWatchChange *change5 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1 ] - documentKey:doc2.key - document:doc2]; + auto change5 = absl::make_unique({}, {1}, doc2.key, doc2); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); + changes.push_back(std::move(change3)); + changes.push_back(std::move(change4)); + changes.push_back(std::move(change5)); + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1.key} - changes:@[ change1, change2, change3, change4, change5 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 3); XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); @@ -359,15 +358,12 @@ - (void)testWillHandleSingleReset { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; // Reset target - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset - targetIDs:@[ @1 ] - cause:nil]; + WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[]]; + changes:{}]; [aggregator handleTargetChange:change]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -387,22 +383,20 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { [self queryDataForTargets:@[ @1, @2 ]]; FSTDocument *doc1a = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[ @2 ] - documentKey:doc1a.key - document:doc1a]; + auto change1 = absl::make_unique({1}, {2}, doc1a.key, doc1a); FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @2 ] - removedTargetIDs:@[ @1 ] - documentKey:doc1b.key - document:doc1b]; + auto change2 = absl::make_unique({2}, {1}, doc1b.key, doc1b); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1a.key} - changes:@[ change1, change2 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 1); XCTAssertEqualObjects(event.documentUpdates.at(doc1b.key), doc1b); @@ -421,14 +415,15 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; - FSTWatchChange *change = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + auto change = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); + std::vector changes; + changes.push_back(std::move(change)); + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[ change ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 0); @@ -444,32 +439,21 @@ - (void)testTargetAddedChangeWillResetPreviousState { [self queryDataForTargets:@[ @1, @3 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @3 ] - removedTargetIDs:@[ @2 ] - documentKey:doc1.key - document:doc1]; - - FSTWatchChange *change2 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1, @2, @3 ] - resumeToken:_resumeToken1]; - - FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved - targetIDs:@[ @1 ] - cause:nil]; - - FSTWatchChange *change4 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateRemoved - targetIDs:@[ @2 ] - cause:nil]; - - FSTWatchChange *change5 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateAdded - targetIDs:@[ @1 ] - cause:nil]; - + auto change1 = absl::make_unique({1, 3}, {2}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Current, {1, 2, 3}, _resumeToken1); + auto change3 = absl::make_unique(WatchTargetChangeState::Removed, {1}); + auto change4 = absl::make_unique(WatchTargetChangeState::Removed, {2}); + auto change5 = absl::make_unique(WatchTargetChangeState::Added, {1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change6 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[ @3 ] - documentKey:doc2.key - document:doc2]; + auto change6 = absl::make_unique({1}, {3}, doc2.key, doc2); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); + changes.push_back(std::move(change3)); + changes.push_back(std::move(change4)); + changes.push_back(std::move(change5)); + changes.push_back(std::move(change6)); NSDictionary *outstandingResponses = @{@1 : @2, @2 : @1}; @@ -478,7 +462,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { targetMap:targetMap outstandingResponses:outstandingResponses existingKeys:DocumentKeySet{doc2.key} - changes:@[ change1, change2, change3, change4, change5, change6 ]]; + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); @@ -509,10 +493,7 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { existingKeys:DocumentKeySet {} changes:@[]]; - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + WatchTargetChange change{WatchTargetChangeState::NoChange, {1}, _resumeToken1}; [aggregator handleTargetChange:change]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -531,26 +512,21 @@ - (void)testExistenceFilterMismatchClearsTarget { [self queryDataForTargets:@[ @1, @2 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; - + auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc2.key - document:doc2]; + auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); + auto change3 = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); - FSTWatchChange *change3 = [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); + changes.push_back(std::move(change3)); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1.key, doc2.key} - changes:@[ change1, change2, change3 ]]; + changes:changes]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -571,8 +547,7 @@ - (void)testExistenceFilterMismatchClearsTarget { // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. - FSTExistenceFilterWatchChange *change4 = - [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{1} targetID:1]; + ExistenceFilterWatchChange change4{ExistenceFilter{1}, 1}; [aggregator handleExistenceFilter:change4]; event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(4)]; @@ -594,23 +569,16 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { existingKeys:DocumentKeySet {} changes:@[]]; - FSTWatchTargetChange *markCurrent = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + WatchTargetChange markCurrent{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:markCurrent]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTDocumentWatchChange *addDoc = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; + DocumentWatchChange addDoc{{1}, {}, doc1.key, doc1}; [aggregator handleDocumentChange:addDoc]; // The existence filter mismatch will remove the document from target 1, but not synthesize a // document delete. - FSTExistenceFilterWatchChange *existenceFilter = - [FSTExistenceFilterWatchChange changeWithFilter:ExistenceFilter{0} targetID:1]; + ExistenceFilterWatchChange existenceFilter{ExistenceFilter{0}, 1}; [aggregator handleExistenceFilter:existenceFilter]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -631,21 +599,18 @@ - (void)testDocumentUpdate { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - FSTWatchChange *change1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; - + auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - FSTWatchChange *change2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc2.key - document:doc2]; + auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); + + std::vector changes; + changes.push_back(std::move(change1)); + changes.push_back(std::move(change2)); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[ change1, change2 ]]; + changes:changes]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -660,27 +625,15 @@ - (void)testDocumentUpdate { FSTDeletedDocument *deletedDoc1 = [FSTDeletedDocument documentWithKey:doc1.key version:testutil::Version(3) hasCommittedMutations:NO]; - FSTDocumentWatchChange *change3 = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1 ] - documentKey:deletedDoc1.key - document:deletedDoc1]; + DocumentWatchChange change3{{}, {1}, deletedDoc1.key, deletedDoc1}; [aggregator handleDocumentChange:change3]; FSTDocument *updatedDoc2 = FSTTestDoc("docs/2", 3, @{@"value" : @2}, FSTDocumentStateSynced); - FSTDocumentWatchChange *change4 = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:updatedDoc2.key - document:updatedDoc2]; + DocumentWatchChange change4{{1}, {}, updatedDoc2.key, updatedDoc2}; [aggregator handleDocumentChange:change4]; FSTDocument *doc3 = FSTTestDoc("docs/3", 3, @{@"value" : @3}, FSTDocumentStateSynced); - FSTDocumentWatchChange *change5 = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc3.key - document:doc3]; + DocumentWatchChange change5{{1}, {}, doc3.key, doc3}; [aggregator handleDocumentChange:change5]; event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -712,17 +665,11 @@ - (void)testResumeTokensHandledPerTarget { existingKeys:DocumentKeySet {} changes:@[]]; - FSTWatchTargetChange *change1 = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:change1]; NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding]; - FSTWatchTargetChange *change2 = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @2 ] - resumeToken:resumeToken2]; + WatchTargetChange change2{WatchTargetChangeState::Current, {2}, resumeToken2}; [aggregator handleTargetChange:change2]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -746,24 +693,15 @@ - (void)testLastResumeTokenWins { existingKeys:DocumentKeySet {} changes:@[]]; - FSTWatchTargetChange *change1 = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent - targetIDs:@[ @1 ] - resumeToken:_resumeToken1]; + WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:change1]; NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding]; - FSTWatchTargetChange *change2 = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange - targetIDs:@[ @1 ] - resumeToken:resumeToken2]; + WatchTargetChange change2{WatchTargetChangeState::NoChange, {1}, resumeToken2}; [aggregator handleTargetChange:change2]; NSData *resumeToken3 = [@"resume3" dataUsingEncoding:NSUTF8StringEncoding]; - FSTWatchTargetChange *change3 = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange - targetIDs:@[ @2 ] - resumeToken:resumeToken3]; + WatchTargetChange change3{WatchTargetChangeState::NoChange, {2}, resumeToken3}; [aggregator handleTargetChange:change3]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -784,14 +722,15 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); - FSTWatchChange *resolveLimboTarget = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent targetIDs:@[ @1 ]]; + auto resolveLimboTarget = absl::make_unique(WatchTargetChangeState::Current, {1}); + std::vector changes; + changes.push_back(std::move(resolveLimboTarget)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[ resolveLimboTarget ]]; + changes:changes]; FSTDeletedDocument *expected = [FSTDeletedDocument documentWithKey:limboKey version:event.snapshotVersion @@ -804,14 +743,15 @@ - (void)testDoesntSynthesizeDeletesForWrongState { NSDictionary *targetMap = [self queryDataForLimboTargets:@[ @1 ]]; - FSTWatchChange *wrongState = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateNoChange targetIDs:@[ @1 ]]; + auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, {1}); + std::vector changes; + changes.push_back(std::move(wrongState)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[ wrongState ]]; + changes:changes]; XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.limboDocumentChanges.size(), 0); @@ -821,15 +761,16 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { NSDictionary *targetMap = [self queryDataForLimboTargets:@[ @3 ]]; - FSTWatchChange *hasDocument = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent targetIDs:@[ @3 ]]; + auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, {3}); + std::vector changes; + changes.push_back(std::move(hasDocument)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{FSTTestDocKey(@"coll/limbo")} - changes:@[ hasDocument ]]; + changes:changes]; XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.limboDocumentChanges.size(), 0); @@ -840,41 +781,30 @@ - (void)testSeparatesDocumentUpdates { [self queryDataForLimboTargets:@[ @1 ]]; FSTDocument *newDoc = FSTTestDoc("docs/new", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); - FSTWatchChange *newDocChange = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:newDoc.key - document:newDoc]; + auto newDocChange = absl::make_unique({1}, {}, newDoc.key, newDoc); FSTDocument *existingDoc = FSTTestDoc("docs/existing", 1, @{@"some" : @"data"}, FSTDocumentStateSynced); - FSTWatchChange *existingDocChange = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:existingDoc.key - document:existingDoc]; + auto existingDocChange = absl::make_unique({1}, {}, existingDoc.key, existingDoc); FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc("docs/deleted", 1, NO); - FSTWatchChange *deletedDocChange = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1 ] - documentKey:deletedDoc.key - document:deletedDoc]; + auto deletedDocChange = absl::make_unique({}, {1}, deletedDoc.key, deletedDoc); FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); - FSTWatchChange *missingDocChange = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1 ] - documentKey:missingDoc.key - document:missingDoc]; + auto missingDocChange = absl::make_unique({}, {1}, missingDoc.key, missingDoc); + + std::vector changes; + changes.push_back(std::move(newDocChange)); + changes.push_back(std::move(existingDocChange)); + changes.push_back(std::move(deletedDocChange)); + changes.push_back(std::move(missingDocChange)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} - changes:@[ - newDocChange, existingDocChange, deletedDocChange, missingDocChange - ]]; + changes:changes]; FSTTargetChange *targetChange = FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, @@ -895,30 +825,23 @@ - (void)testTracksLimboDocuments { FSTDocument *doc3 = FSTTestDoc("docs/3", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); // Target 2 is a limbo target - FSTWatchChange *docChange1 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @2 ] - removedTargetIDs:@[] - documentKey:doc1.key - document:doc1]; - - FSTWatchChange *docChange2 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @2 ] - removedTargetIDs:@[] - documentKey:doc2.key - document:doc2]; - - FSTWatchChange *docChange3 = [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1 ] - removedTargetIDs:@[] - documentKey:doc3.key - document:doc3]; + auto docChange1 = absl::make_unique({1, 2}, {}, doc1.key, doc1); + auto docChange2 = absl::make_unique({2}, {}, doc2.key, doc2); + auto docChange3 = absl::make_unique({1}, {}, doc3.key, doc3); + auto targetsChange = absl::make_unique(WatchTargetChangeState::Current, {1, 2}); - FSTWatchChange *targetsChange = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateCurrent targetIDs:@[ @1, @2 ]]; + std::vector changes; + changes.push_back(std::move(docChange1)); + changes.push_back(std::move(docChange2)); + changes.push_back(std::move(docChange3)); + changes.push_back(std::move(targetsChange)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} - changes:@[ docChange1, docChange2, docChange3, targetsChange ]]; + changes:changes]; DocumentKeySet limboDocChanges = event.limboDocumentChanges; // Doc1 is in both limbo and non-limbo targets, therefore not tracked as limbo diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index d74a0d3e3c1..502040864a6 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -186,7 +186,7 @@ NS_ASSUME_NONNULL_BEGIN * Increment the number of acks needed from watch before we can consider the server to be 'in-sync' * with the client's active targets. */ -- (void)recordTargetRequest:(FSTBoxedTargetID *)targetID; +- (void)recordTargetRequest:(firebase::firestore::model::TargetId)targetID; /** * Converts the current state into a remote event with the snapshot version taken from the From aec3f54b5b0692842f2e6b790f4f810e69ad28da Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 19:14:43 -0500 Subject: [PATCH 017/107] FSTSerializerBetaTests --- .../Tests/Remote/FSTSerializerBetaTests.mm | 125 ++++++++++-------- .../firebase/firestore/remote/watch_change.h | 33 +++-- 2 files changed, 98 insertions(+), 60 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 34c4886fbf0..787b6629d7b 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -51,6 +51,7 @@ #include "Firestore/core/src/firebase/firestore/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -69,6 +70,31 @@ using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::util::Status; +namespace { + +template +bool Equals(const WatchChange &lhs, const WatchChange &rhs) { + return *static_cast(lhs) == *static_cast(rhs); +} + +bool operator==(const WatchChange &lhs, const WatchChange &rhs) { + if (lhs.type() != rhs.type()) { + return false; + } + + switch (lhs.type()) { + case WatchChange::Type::Document: + return Equals(lhs, rhs); + case WatchChange::Type::ExistenceFilter: + return Equals(lhs, rhs); + case WatchChange::Type::TargetChange: + return Equals(lhs, rhs); + } + UNREACHABLE(); +} + +} // namespace + NS_ASSUME_NONNULL_BEGIN @interface FSTSerializerBeta (Test) @@ -778,23 +804,18 @@ - (void)testConvertsTargetChangeWithAdded { [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actual->type(), WatchChange::Type::TargetChange); - XCTAssertEqual(static_cast*actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsTargetChangeWithRemoved { - WatchTargetChange expected{WatchTargetChangeState::Removed, {1, 4}}; - - FSTWatchChange *expected = [[FSTWatchTargetChange alloc] - initWithState:FSTWatchTargetChangeStateRemoved - targetIDs:@[ @1, @4 ] - resumeToken:FSTTestData(0, 1, 2, -1) - cause:[NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodePermissionDenied - userInfo:@{ - NSLocalizedDescriptionKey : @"Error message", - }]]; + WatchTargetChange expected{WatchTargetChangeState::Removed, + {1, 4}, + FSTTestData(0, 1, 2, -1), + Status{FirestoreErrorCode::PermissionDenied, "Error message"}}; + GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.targetChange.targetChangeType = GCFSTargetChange_TargetChangeType_Remove; listenResponse.targetChange.cause.code = FIRFirestoreErrorCodePermissionDenied; @@ -802,33 +823,31 @@ - (void)testConvertsTargetChangeWithRemoved { listenResponse.targetChange.resumeToken = FSTTestData(0, 1, 2, -1); [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsTargetChangeWithNoChange { - FSTWatchChange *expected = - [[FSTWatchTargetChange alloc] initWithState:FSTWatchTargetChangeStateNoChange - targetIDs:@[ @1, @4 ] - resumeToken:[NSData data] - cause:nil]; + WatchTargetChange expected{WatchTargetChangeState::NoChange, {1, 4}}; GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.targetChange.targetChangeType = GCFSTargetChange_TargetChangeType_NoChange; [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsDocumentChangeWithTargetIds { - FSTWatchChange *expected = [[FSTDocumentWatchChange alloc] - initWithUpdatedTargetIDs:@[ @1, @2 ] - removedTargetIDs:@[] - documentKey:FSTTestDocKey(@"coll/1") - document:FSTTestDoc("coll/1", 5, @{@"foo" : @"bar"}, FSTDocumentStateSynced)]; - GCFSListenResponse *listenResponse = [GCFSListenResponse message]; + DocumentWatchChange expected { + {1, 2}, {}, FSTTestDocKey(@"coll/1"), + FSTTestDoc("coll/1", 5, @{@"foo" : @"bar"}, FSTDocumentStateSynced) + }; listenResponse.documentChange.document.name = @"projects/p/databases/d/documents/coll/1"; listenResponse.documentChange.document.updateTime.nanos = 5000; GCFSValue *fooValue = [GCFSValue message]; @@ -836,17 +855,19 @@ - (void)testConvertsDocumentChangeWithTargetIds { [listenResponse.documentChange.document.fields setObject:fooValue forKey:@"foo"]; [listenResponse.documentChange.targetIdsArray addValue:1]; [listenResponse.documentChange.targetIdsArray addValue:2]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsDocumentChangeWithRemovedTargetIds { - FSTWatchChange *expected = [[FSTDocumentWatchChange alloc] - initWithUpdatedTargetIDs:@[ @2 ] - removedTargetIDs:@[ @1 ] - documentKey:FSTTestDocKey(@"coll/1") - document:FSTTestDoc("coll/1", 5, @{@"foo" : @"bar"}, FSTDocumentStateSynced)]; + DocumentWatchChange expected { + {2}, {1}, FSTTestDocKey(@"coll/1"), + FSTTestDoc("coll/1", 5, @{@"foo" : @"bar"}, FSTDocumentStateSynced) + }; + GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentChange.document.name = @"projects/p/databases/d/documents/coll/1"; listenResponse.documentChange.document.updateTime.nanos = 5000; @@ -855,40 +876,40 @@ - (void)testConvertsDocumentChangeWithRemovedTargetIds { [listenResponse.documentChange.document.fields setObject:fooValue forKey:@"foo"]; [listenResponse.documentChange.removedTargetIdsArray addValue:1]; [listenResponse.documentChange.targetIdsArray addValue:2]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsDocumentChangeWithDeletions { - FSTWatchChange *expected = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1, @2 ] - documentKey:FSTTestDocKey(@"coll/1") - document:FSTTestDeletedDoc("coll/1", 5, NO)]; + DocumentWatchChange expected{{}, {1, 2}, FSTTestDocKey(@"coll/1"), FSTTestDoc("coll/1", 5, NO)}; + GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentDelete.document = @"projects/p/databases/d/documents/coll/1"; listenResponse.documentDelete.readTime.nanos = 5000; [listenResponse.documentDelete.removedTargetIdsArray addValue:1]; [listenResponse.documentDelete.removedTargetIdsArray addValue:2]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } - (void)testConvertsDocumentChangeWithRemoves { - FSTWatchChange *expected = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[] - removedTargetIDs:@[ @1, @2 ] - documentKey:FSTTestDocKey(@"coll/1") - document:nil]; + DocumentWatchChange expected{{}, {1, 2}, FSTTestDocKey(@"coll/1"), nil}; + GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentRemove.document = @"projects/p/databases/d/documents/coll/1"; [listenResponse.documentRemove.removedTargetIdsArray addValue:1]; [listenResponse.documentRemove.removedTargetIdsArray addValue:2]; - FSTWatchChange *actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqualObjects(actual, expected); + std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; + XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); + auto actual = static_cast(actualBase.get()); + XCTAssertTrue(*actual == expected); } @end diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index bb3e5c61cf2..25c4c2afb94 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -112,7 +112,13 @@ class DocumentWatchChange : public WatchChange { FSTMaybeDocument* new_document_; }; -// bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); +inline bool operator==(const DocumentWatchChange& lhs, + const DocumentWatchChange& rhs) { + return lhs.updated_target_ids() == rhs.updated_target_ids() && + lhs.removed_target_ids() == rhs.removed_target_ids() && + lhs.document_key() == rhs.document_key() && + [lhs.new_document_ isEqual:rhs.new_document_]; +} /** * An `ExistenceFilterWatchChange` applies to the targets and is required to @@ -138,8 +144,10 @@ class ExistenceFilterWatchChange : public WatchChange { model::TargetId target_id_; }; -// bool operator==(const ExistenceFilterWatchChange& lhs, -// const ExistenceFilterWatchChange& rhs); +inline bool operator==(const ExistenceFilterWatchChange& lhs, + const ExistenceFilterWatchChange& rhs) { + return lhs.filter_ == rhs.filter_ && lhs.target_id_ == rhs.target_is_; +} enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; @@ -147,20 +155,22 @@ class WatchTargetChange : public WatchChange { public: WatchTargetChange(WatchTargetChangeState state, std::vector target_ids) - : WatchTargetChange{state, std::move(target_ids), [NSData data], util::Status::OK()} { - } + : WatchTargetChange{state, std::move(target_ids), [NSData data], + util::Status::OK()} { + } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, NSData* resume_token) - : WatchTargetChange{state, std::move(target_ids), resume_token, util::Status::OK()} { - } + : WatchTargetChange{state, std::move(target_ids), resume_token, + util::Status::OK()} { + } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, util::Status cause) : WatchTargetChange{state, std::move(target_ids), [NSData data], cause} { - } + } WatchTargetChange(WatchTargetChangeState state, std::vector target_ids, @@ -208,6 +218,13 @@ class WatchTargetChange : public WatchChange { util::Status cause_; }; +inline bool operator==(const WatchTargetChangeState& lhs, + const WatchTargetChangeState& rhs) { + return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && + [lhs.resume_token() isEqual:rhs.resume_token()] && + lhs.cause() == rhs.cause(); +} + } // namespace remote } // namespace firestore } // namespace firebase From b012929f7fa488f409406622f9f64c05cb9001e0 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 18 Jan 2019 19:30:26 -0500 Subject: [PATCH 018/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 38 ++++++++------- Firestore/Source/Remote/FSTRemoteEvent.mm | 4 +- Firestore/Source/Remote/FSTRemoteStore.mm | 4 +- .../firebase/firestore/remote/watch_change.h | 23 +++------ .../firebase/firestore/remote/watch_change.mm | 48 +++++++++++++++++++ 5 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/remote/watch_change.mm diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index ceafd07dad0..9879db684b7 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -43,7 +43,9 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchTargetChange; NS_ASSUME_NONNULL_BEGIN @@ -133,7 +135,7 @@ - (void)setUp { [outstandingResponses enumerateKeysAndObjectsUsingBlock:^(FSTBoxedTargetID *targetID, NSNumber *count, BOOL *stop) { for (int i = 0; i < count.intValue; ++i) { - [aggregator recordTargetRequest:@(targetID)]; + [aggregator recordTargetRequest:targetID.intValue]; } }]; @@ -143,8 +145,8 @@ - (void)setUp { [aggregator handleDocumentChange:*static_cast(change.get())]; break; } - case WatchChange::Type::WatchTargetChange: { - [aggregator handleDocumentChange:*static_cast(change.get())]; + case WatchChange::Type::TargetChange: { + [aggregator handleTargetChange:*static_cast(change.get())]; break; } default: @@ -153,7 +155,7 @@ - (void)setUp { } [aggregator handleTargetChange:WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, - _resumeToken1}] + _resumeToken1}]; return aggregator; } @@ -199,7 +201,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique({1, 4}, {2, 6}, newDoc.key, newDoc); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); @@ -257,7 +259,7 @@ - (void)testWillIgnoreEventsForPendingTargets { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change4 = absl::make_unique({1}, {}, doc2.key, doc2); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); changes.push_back(std::move(change3)); @@ -288,7 +290,7 @@ - (void)testWillIgnoreEventsForRemovedTargets { auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); auto change2 = absl::make_unique(WatchTargetChangeState::Removed, {1}); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); @@ -327,7 +329,7 @@ - (void)testWillKeepResetMappingEvenWithUpdates { // Remove doc2 again, should not show up in reset mapping auto change5 = absl::make_unique({}, {1}, doc2.key, doc2); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); changes.push_back(std::move(change3)); @@ -388,7 +390,7 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique({2}, {1}, doc1b.key, doc1b); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); @@ -416,7 +418,7 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; auto change = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -447,7 +449,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change6 = absl::make_unique({1}, {3}, doc2.key, doc2); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); changes.push_back(std::move(change3)); @@ -517,7 +519,7 @@ - (void)testExistenceFilterMismatchClearsTarget { auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); auto change3 = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); changes.push_back(std::move(change3)); @@ -603,7 +605,7 @@ - (void)testDocumentUpdate { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); - std::vector changes; + std::vector> changes; changes.push_back(std::move(change1)); changes.push_back(std::move(change2)); @@ -723,7 +725,7 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); auto resolveLimboTarget = absl::make_unique(WatchTargetChangeState::Current, {1}); - std::vector changes; + std::vector> changes; changes.push_back(std::move(resolveLimboTarget)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -744,7 +746,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { [self queryDataForLimboTargets:@[ @1 ]]; auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, {1}); - std::vector changes; + std::vector> changes; changes.push_back(std::move(wrongState)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -762,7 +764,7 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { [self queryDataForLimboTargets:@[ @3 ]]; auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, {3}); - std::vector changes; + std::vector> changes; changes.push_back(std::move(hasDocument)); FSTRemoteEvent *event = @@ -793,7 +795,7 @@ - (void)testSeparatesDocumentUpdates { FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); auto missingDocChange = absl::make_unique({}, {1}, missingDoc.key, missingDoc); - std::vector changes; + std::vector> changes; changes.push_back(std::move(newDocChange)); changes.push_back(std::move(existingDocChange)); changes.push_back(std::move(deletedDocChange)); @@ -830,7 +832,7 @@ - (void)testTracksLimboDocuments { auto docChange3 = absl::make_unique({1}, {}, doc3.key, doc3); auto targetsChange = absl::make_unique(WatchTargetChangeState::Current, {1, 2}); - std::vector changes; + std::vector> changes; changes.push_back(std::move(docChange1)); changes.push_back(std::move(docChange2)); changes.push_back(std::move(docChange3)); diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 1effe4444e7..61b6f085373 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -624,9 +624,9 @@ - (FSTRemoteEvent *)remoteEventAtSnapshotVersion:(const SnapshotVersion &)snapsh return remoteEvent; } -- (void)recordTargetRequest:(FSTBoxedTargetID *)targetID { +- (void)recordTargetRequest:(TargetId)targetID { // For each request we get we need to record we need a response for it. - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID.intValue]; + FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; [targetState recordTargetRequest]; } @end diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 4fca5705853..417c8b18132 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -261,7 +261,7 @@ - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { } - (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { - [self.watchChangeAggregator recordTargetRequest:@(queryData.targetID)]; + [self.watchChangeAggregator recordTargetRequest:queryData.targetID]; _watchStream->WatchQuery(queryData); } @@ -287,7 +287,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { } - (void)sendUnwatchRequestForTargetID:(FSTBoxedTargetID *)targetID { - [self.watchChangeAggregator recordTargetRequest:targetID]; + [self.watchChangeAggregator recordTargetRequest:targetID.intValue]; _watchStream->UnwatchTargetId([targetID intValue]); } diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index 25c4c2afb94..eded4257528 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -112,13 +112,8 @@ class DocumentWatchChange : public WatchChange { FSTMaybeDocument* new_document_; }; -inline bool operator==(const DocumentWatchChange& lhs, - const DocumentWatchChange& rhs) { - return lhs.updated_target_ids() == rhs.updated_target_ids() && - lhs.removed_target_ids() == rhs.removed_target_ids() && - lhs.document_key() == rhs.document_key() && - [lhs.new_document_ isEqual:rhs.new_document_]; -} +bool operator==(const DocumentWatchChange& lhs, + const DocumentWatchChange& rhs); /** * An `ExistenceFilterWatchChange` applies to the targets and is required to @@ -144,10 +139,8 @@ class ExistenceFilterWatchChange : public WatchChange { model::TargetId target_id_; }; -inline bool operator==(const ExistenceFilterWatchChange& lhs, - const ExistenceFilterWatchChange& rhs) { - return lhs.filter_ == rhs.filter_ && lhs.target_id_ == rhs.target_is_; -} +bool operator==(const ExistenceFilterWatchChange& lhs, + const ExistenceFilterWatchChange& rhs); enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; @@ -218,12 +211,8 @@ class WatchTargetChange : public WatchChange { util::Status cause_; }; -inline bool operator==(const WatchTargetChangeState& lhs, - const WatchTargetChangeState& rhs) { - return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && - [lhs.resume_token() isEqual:rhs.resume_token()] && - lhs.cause() == rhs.cause(); -} +bool operator==(const WatchTargetChange& lhs, + const WatchTargetChange& rhs); } // namespace remote } // namespace firestore diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.mm b/Firestore/core/src/firebase/firestore/remote/watch_change.mm new file mode 100644 index 00000000000..6b229ee9752 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.mm @@ -0,0 +1,48 @@ +/* + * Copyright 2019 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" + +#import "Firestore/Source/Model/FSTDocument.h" + +namespace firebase { +namespace firestore { +namespace remote { + +bool operator==(const DocumentWatchChange& lhs, + const DocumentWatchChange& rhs) { + return lhs.updated_target_ids() == rhs.updated_target_ids() && + lhs.removed_target_ids() == rhs.removed_target_ids() && + lhs.document_key() == rhs.document_key() && + [lhs.new_document() isEqual:rhs.new_document()]; +} + +bool operator==(const ExistenceFilterWatchChange& lhs, + const ExistenceFilterWatchChange& rhs) { + return lhs.filter() == rhs.filter() && lhs.target_id() == rhs.target_id(); +} + +bool operator==(const WatchTargetChange& lhs, + const WatchTargetChange& rhs) { + return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && + [lhs.resume_token() isEqual:rhs.resume_token()] && + lhs.cause() == rhs.cause(); +} + + +} // namespace remote +} // namespace firestore +} // namespace firebase From 1da067243c35f5d0a0de0c53d3775500af5f6ca8 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 13:43:34 -0500 Subject: [PATCH 019/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 149 ++++++++++-------- .../Tests/Remote/FSTSerializerBetaTests.mm | 8 +- 2 files changed, 85 insertions(+), 72 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 9879db684b7..44012e43c8c 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -46,6 +46,10 @@ using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; +// `make_unique` cannot deduce that the template parameter is intended to +// resolve to a vector of target ids when given an initialization list (e.g., +// {1, 2}). The type alias is deliberately very short to minimize boilderplate. +using ids = std::vector; NS_ASSUME_NONNULL_BEGIN @@ -157,7 +161,7 @@ - (void)setUp { [aggregator handleTargetChange:WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, _resumeToken1}]; - return aggregator; + return aggregator; } /** @@ -180,7 +184,7 @@ - (void)setUp { outstandingResponses: (nullable NSDictionary *)outstandingResponses existingKeys:(DocumentKeySet)existingKeys - changes:(const std::vector>&)watchChanges { + changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:outstandingResponses existingKeys:existingKeys @@ -196,10 +200,11 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { [self queryDataForTargets:@[ @1, @2, @3, @4, @5, @6 ]]; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1, 2, 3}, {4, 5, 6}, existingDoc.key, existingDoc); + auto change1 = absl::make_unique(ids{1, 2, 3}, ids{4, 5, 6}, existingDoc.key, + existingDoc); FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique({1, 4}, {2, 6}, newDoc.key, newDoc); + auto change2 = absl::make_unique(ids{1, 4}, ids{2, 6}, newDoc.key, newDoc); std::vector> changes; changes.push_back(std::move(change1)); @@ -253,11 +258,11 @@ - (void)testWillIgnoreEventsForPendingTargets { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Removed, {1}); - auto change3 = absl::make_unique(WatchTargetChangeState::Added, {1}); + auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); + auto change3 = absl::make_unique(WatchTargetChangeState::Added, ids{1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change4 = absl::make_unique({1}, {}, doc2.key, doc2); + auto change4 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); std::vector> changes; changes.push_back(std::move(change1)); @@ -268,12 +273,11 @@ - (void)testWillIgnoreEventsForPendingTargets { // We're waiting for the unwatch and watch ack NSDictionary *outstandingResponses = @{@1 : @2}; - FSTRemoteEvent *event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:outstandingResponses + existingKeys:DocumentKeySet {} + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); // doc1 is ignored because it was part of an inactive target, but doc2 is in the changes // because it become active. @@ -287,8 +291,8 @@ - (void)testWillIgnoreEventsForRemovedTargets { NSDictionary *targetMap = [self queryDataForTargets:@[]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Removed, {1}); + auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); std::vector> changes; changes.push_back(std::move(change1)); @@ -314,20 +318,20 @@ - (void)testWillKeepResetMappingEvenWithUpdates { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); // Reset stream, ignoring doc1 - auto change2 = absl::make_unique(WatchTargetChangeState::Reset, {1}); + auto change2 = absl::make_unique(WatchTargetChangeState::Reset, ids{1}); // Add doc2, doc3 FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change3 = absl::make_unique({1}, {}, doc2.key, doc2); + auto change3 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); FSTDocument *doc3 = FSTTestDoc("docs/3", 3, @{@"value" : @3}, FSTDocumentStateSynced); - auto change4 = absl::make_unique({1}, {}, doc3.key, doc3); + auto change4 = absl::make_unique(ids{1}, ids{}, doc3.key, doc3); // Remove doc2 again, should not show up in reset mapping - auto change5 = absl::make_unique({}, {1}, doc2.key, doc2); + auto change5 = absl::make_unique(ids{}, ids{1}, doc2.key, doc2); std::vector> changes; changes.push_back(std::move(change1)); @@ -336,12 +340,11 @@ - (void)testWillKeepResetMappingEvenWithUpdates { changes.push_back(std::move(change4)); changes.push_back(std::move(change5)); - FSTRemoteEvent *event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet{doc1.key} - changes:changes]; + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet{doc1.key} + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 3); XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); @@ -385,10 +388,10 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { [self queryDataForTargets:@[ @1, @2 ]]; FSTDocument *doc1a = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {2}, doc1a.key, doc1a); + auto change1 = absl::make_unique(ids{1}, ids{2}, doc1a.key, doc1a); FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique({2}, {1}, doc1b.key, doc1b); + auto change2 = absl::make_unique(ids{2}, ids{1}, doc1b.key, doc1b); std::vector> changes; changes.push_back(std::move(change1)); @@ -417,7 +420,8 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; - auto change = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); + auto change = + absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); std::vector> changes; changes.push_back(std::move(change)); @@ -441,13 +445,14 @@ - (void)testTargetAddedChangeWillResetPreviousState { [self queryDataForTargets:@[ @1, @3 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1, 3}, {2}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Current, {1, 2, 3}, _resumeToken1); - auto change3 = absl::make_unique(WatchTargetChangeState::Removed, {1}); - auto change4 = absl::make_unique(WatchTargetChangeState::Removed, {2}); - auto change5 = absl::make_unique(WatchTargetChangeState::Added, {1}); + auto change1 = absl::make_unique(ids{1, 3}, ids{2}, doc1.key, doc1); + auto change2 = absl::make_unique(WatchTargetChangeState::Current, ids{1, 2, 3}, + _resumeToken1); + auto change3 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); + auto change4 = absl::make_unique(WatchTargetChangeState::Removed, ids{2}); + auto change5 = absl::make_unique(WatchTargetChangeState::Added, ids{1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change6 = absl::make_unique({1}, {3}, doc2.key, doc2); + auto change6 = absl::make_unique(ids{1}, ids{3}, doc2.key, doc2); std::vector> changes; changes.push_back(std::move(change1)); @@ -459,12 +464,11 @@ - (void)testTargetAddedChangeWillResetPreviousState { NSDictionary *outstandingResponses = @{@1 : @2, @2 : @1}; - FSTRemoteEvent *event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:DocumentKeySet{doc2.key} - changes:changes]; + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:outstandingResponses + existingKeys:DocumentKeySet{doc2.key} + changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); @@ -514,10 +518,11 @@ - (void)testExistenceFilterMismatchClearsTarget { [self queryDataForTargets:@[ @1, @2 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); - auto change3 = absl::make_unique(WatchTargetChangeState::Current, {1}, _resumeToken1); + auto change2 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); + auto change3 = + absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); std::vector> changes; changes.push_back(std::move(change1)); @@ -601,9 +606,9 @@ - (void)testDocumentUpdate { NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique({1}, {}, doc1.key, doc1); + auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique({1}, {}, doc2.key, doc2); + auto change2 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); std::vector> changes; changes.push_back(std::move(change1)); @@ -724,7 +729,8 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); - auto resolveLimboTarget = absl::make_unique(WatchTargetChangeState::Current, {1}); + auto resolveLimboTarget = + absl::make_unique(WatchTargetChangeState::Current, ids{1}); std::vector> changes; changes.push_back(std::move(resolveLimboTarget)); @@ -745,7 +751,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { NSDictionary *targetMap = [self queryDataForLimboTargets:@[ @1 ]]; - auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, {1}); + auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, ids{1}); std::vector> changes; changes.push_back(std::move(wrongState)); @@ -763,7 +769,7 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { NSDictionary *targetMap = [self queryDataForLimboTargets:@[ @3 ]]; - auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, {3}); + auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, ids{3}); std::vector> changes; changes.push_back(std::move(hasDocument)); @@ -783,17 +789,20 @@ - (void)testSeparatesDocumentUpdates { [self queryDataForLimboTargets:@[ @1 ]]; FSTDocument *newDoc = FSTTestDoc("docs/new", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); - auto newDocChange = absl::make_unique({1}, {}, newDoc.key, newDoc); + auto newDocChange = absl::make_unique(ids{1}, ids{}, newDoc.key, newDoc); FSTDocument *existingDoc = FSTTestDoc("docs/existing", 1, @{@"some" : @"data"}, FSTDocumentStateSynced); - auto existingDocChange = absl::make_unique({1}, {}, existingDoc.key, existingDoc); + auto existingDocChange = + absl::make_unique(ids{1}, ids{}, existingDoc.key, existingDoc); FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc("docs/deleted", 1, NO); - auto deletedDocChange = absl::make_unique({}, {1}, deletedDoc.key, deletedDoc); + auto deletedDocChange = + absl::make_unique(ids{}, ids{1}, deletedDoc.key, deletedDoc); FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); - auto missingDocChange = absl::make_unique({}, {1}, missingDoc.key, missingDoc); + auto missingDocChange = + absl::make_unique(ids{}, ids{1}, missingDoc.key, missingDoc); std::vector> changes; changes.push_back(std::move(newDocChange)); @@ -801,12 +810,12 @@ - (void)testSeparatesDocumentUpdates { changes.push_back(std::move(deletedDocChange)); changes.push_back(std::move(missingDocChange)); - FSTRemoteEvent *event = [self - remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} + changes:changes]; FSTTargetChange *targetChange = FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, @@ -827,10 +836,11 @@ - (void)testTracksLimboDocuments { FSTDocument *doc3 = FSTTestDoc("docs/3", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); // Target 2 is a limbo target - auto docChange1 = absl::make_unique({1, 2}, {}, doc1.key, doc1); - auto docChange2 = absl::make_unique({2}, {}, doc2.key, doc2); - auto docChange3 = absl::make_unique({1}, {}, doc3.key, doc3); - auto targetsChange = absl::make_unique(WatchTargetChangeState::Current, {1, 2}); + auto docChange1 = absl::make_unique(ids{1, 2}, ids{}, doc1.key, doc1); + auto docChange2 = absl::make_unique(ids{2}, ids{}, doc2.key, doc2); + auto docChange3 = absl::make_unique(ids{1}, ids{}, doc3.key, doc3); + auto targetsChange = + absl::make_unique(WatchTargetChangeState::Current, ids{1, 2}); std::vector> changes; changes.push_back(std::move(docChange1)); @@ -838,12 +848,11 @@ - (void)testTracksLimboDocuments { changes.push_back(std::move(docChange3)); changes.push_back(std::move(targetsChange)); - FSTRemoteEvent *event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:changes]; DocumentKeySet limboDocChanges = event.limboDocumentChanges; // Doc1 is in both limbo and non-limbo targets, therefore not tracked as limbo diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 787b6629d7b..aa67a5b693f 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -46,6 +46,7 @@ #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_transform.h" @@ -59,12 +60,14 @@ namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; using firebase::Timestamp; +using firebase::firestore::FirestoreErrorCode; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldTransform; using firebase::firestore::model::Precondition; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; @@ -74,7 +77,7 @@ template bool Equals(const WatchChange &lhs, const WatchChange &rhs) { - return *static_cast(lhs) == *static_cast(rhs); + return static_cast(lhs) == static_cast(rhs); } bool operator==(const WatchChange &lhs, const WatchChange &rhs) { @@ -848,6 +851,7 @@ - (void)testConvertsDocumentChangeWithTargetIds { {1, 2}, {}, FSTTestDocKey(@"coll/1"), FSTTestDoc("coll/1", 5, @{@"foo" : @"bar"}, FSTDocumentStateSynced) }; + GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentChange.document.name = @"projects/p/databases/d/documents/coll/1"; listenResponse.documentChange.document.updateTime.nanos = 5000; GCFSValue *fooValue = [GCFSValue message]; @@ -884,7 +888,7 @@ - (void)testConvertsDocumentChangeWithRemovedTargetIds { } - (void)testConvertsDocumentChangeWithDeletions { - DocumentWatchChange expected{{}, {1, 2}, FSTTestDocKey(@"coll/1"), FSTTestDoc("coll/1", 5, NO)}; + DocumentWatchChange expected{{}, {1, 2}, FSTTestDocKey(@"coll/1"), FSTTestDeletedDoc("coll/1", 5, NO)}; GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentDelete.document = @"projects/p/databases/d/documents/coll/1"; From e0f77f2d67386b7e9b54af480ffc0eb1f0dc91c3 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 14:10:24 -0500 Subject: [PATCH 020/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 187 ++++++++++-------- 1 file changed, 109 insertions(+), 78 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 44012e43c8c..4fbcc97a586 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -46,6 +46,7 @@ using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; // `make_unique` cannot deduce that the template parameter is intended to // resolve to a vector of target ids when given an initialization list (e.g., // {1, 2}). The type alias is deliberately very short to minimize boilderplate. @@ -53,18 +54,24 @@ NS_ASSUME_NONNULL_BEGIN +namespace { + +std::unordered_map NoOutstandingResponses() { + return {}; +} + +} // namespace + @interface FSTRemoteEventTests : XCTestCase @end @implementation FSTRemoteEventTests { NSData *_resumeToken1; - NSMutableDictionary *_noOutstandingResponses; FSTTestTargetMetadataProvider *_targetMetadataProvider; } - (void)setUp { _resumeToken1 = [@"resume1" dataUsingEncoding:NSUTF8StringEncoding]; - _noOutstandingResponses = [NSMutableDictionary dictionary]; _targetMetadataProvider = [FSTTestTargetMetadataProvider new]; } @@ -72,11 +79,10 @@ - (void)setUp { * Creates a map with query data for the provided target IDs. All targets are considered active * and query a collection named "coll". */ -- (NSDictionary *)queryDataForTargets: - (NSArray *)targetIDs { - NSMutableDictionary *targets = - [NSMutableDictionary dictionary]; - for (FSTBoxedTargetID *targetID in targetIDs) { +- (std::unordered_map)queryDataForTargets: + (std::initializer_list)targetIDs { + std::unordered_map targets; + for (TargetId targetID : targetIDs) { FSTQuery *query = FSTTestQuery("coll"); targets[targetID] = [[FSTQueryData alloc] initWithQuery:query targetID:targetID.intValue @@ -90,11 +96,10 @@ - (void)setUp { * Creates a map with query data for the provided target IDs. All targets are marked as limbo * queries for the document at "coll/limbo". */ -- (NSDictionary *)queryDataForLimboTargets: - (NSArray *)targetIDs { - NSMutableDictionary *targets = - [NSMutableDictionary dictionary]; - for (FSTBoxedTargetID *targetID in targetIDs) { +- (std::unordered_map)queryDataForLimboTargets: + (std::initializer_list)targetIDs { + std::unordered_map targets; + for (TargetId targetID : targetIDs) { FSTQuery *query = FSTTestQuery("coll/limbo"); targets[targetID] = [[FSTQueryData alloc] initWithQuery:query targetID:targetID.intValue @@ -111,7 +116,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or `_noOutstandingResponses` if all targets are already active. + * considered active, or `NoOutstandingResponses` if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. To modify this set during test execution, invoke * `[_targetMetadataProvider setSyncedKeys:forQueryData:]`. @@ -120,8 +125,7 @@ - (void)setUp { */ - (FSTWatchChangeAggregator *) aggregatorWithTargetMap:(const std::unordered_map &)targetMap - outstandingResponses: - (nullable NSDictionary *)outstandingResponses + outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = @@ -136,21 +140,22 @@ - (void)setUp { [_targetMetadataProvider setSyncedKeys:existingKeys forQueryData:queryData]; }; - [outstandingResponses - enumerateKeysAndObjectsUsingBlock:^(FSTBoxedTargetID *targetID, NSNumber *count, BOOL *stop) { - for (int i = 0; i < count.intValue; ++i) { - [aggregator recordTargetRequest:targetID.intValue]; - } - }]; + for (const auto &kv : outstandingResponses) { + TargetId targetID = kv.first; + int count = kv.second; + for (int i = 0; i < count; ++i) { + [aggregator recordTargetRequest:targetID]; + } + } for (const std::unique_ptr &change : watchChanges) { switch (change->type()) { case WatchChange::Type::Document: { - [aggregator handleDocumentChange:*static_cast(change.get())]; + [aggregator handleDocumentChange:*static_cast(change.get())]; break; } case WatchChange::Type::TargetChange: { - [aggregator handleTargetChange:*static_cast(change.get())]; + [aggregator handleTargetChange:*static_cast(change.get())]; break; } default: @@ -172,7 +177,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or `_noOutstandingResponses` if all targets are already active. + * considered active, or `NoOutstandingResponses` if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. * @param watchChanges The watch changes to apply before creating the remote event. Supported @@ -180,9 +185,8 @@ - (void)setUp { */ - (FSTRemoteEvent *) remoteEventAtSnapshotVersion:(FSTTestSnapshotVersion)snapshotVersion - targetMap:(NSDictionary *)targetMap - outstandingResponses: - (nullable NSDictionary *)outstandingResponses + targetMap:(std::unordered_map)targetMap + outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap @@ -196,8 +200,9 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // The target map that contains an entry for every target in this test. If a target ID is // omitted, the target is considered inactive and FSTTestTargetMetadataProvider will fail on // access. - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @2, @3, @4, @5, @6 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 2, 3, 4, 5, 6}] + }; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1, 2, 3}, ids{4, 5, 6}, existingDoc.key, @@ -216,7 +221,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // as modifications rather than adds. FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{existingDoc.key} changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); @@ -255,7 +260,9 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { } - (void)testWillIgnoreEventsForPendingTargets { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -271,7 +278,7 @@ - (void)testWillIgnoreEventsForPendingTargets { changes.push_back(std::move(change4)); // We're waiting for the unwatch and watch ack - NSDictionary *outstandingResponses = @{@1 : @2}; + std::unordered_map outstandingResponses{{1, 2}}; FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -288,7 +295,9 @@ - (void)testWillIgnoreEventsForPendingTargets { } - (void)testWillIgnoreEventsForRemovedTargets { - NSDictionary *targetMap = [self queryDataForTargets:@[]]; + std::unordered_map targetMap { + [self queryDataForTargets:{}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -299,7 +308,7 @@ - (void)testWillIgnoreEventsForRemovedTargets { changes.push_back(std::move(change2)); // We're waiting for the unwatch ack - NSDictionary *outstandingResponses = @{@1 : @1}; + std::unordered_map outstandingResponses{{1, 1}}; FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -315,7 +324,9 @@ - (void)testWillIgnoreEventsForRemovedTargets { } - (void)testWillKeepResetMappingEvenWithUpdates { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -342,7 +353,7 @@ - (void)testWillKeepResetMappingEvenWithUpdates { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{doc1.key} changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); @@ -360,13 +371,15 @@ - (void)testWillKeepResetMappingEvenWithUpdates { } - (void)testWillHandleSingleReset { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; // Reset target WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:{}]; [aggregator handleTargetChange:change]; @@ -384,8 +397,9 @@ - (void)testWillHandleSingleReset { } - (void)testWillHandleTargetAddAndRemovalInSameBatch { - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @2 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 2}] + }; FSTDocument *doc1a = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{2}, doc1a.key, doc1a); @@ -399,7 +413,7 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{doc1a.key} changes:changes]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); @@ -418,7 +432,9 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { } - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1]} + }; auto change = absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); @@ -427,7 +443,7 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:changes]; @@ -441,8 +457,9 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { } - (void)testTargetAddedChangeWillResetPreviousState { - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @3 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 3}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1, 3}, ids{2}, doc1.key, doc1); @@ -462,7 +479,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { changes.push_back(std::move(change5)); changes.push_back(std::move(change6)); - NSDictionary *outstandingResponses = @{@1 : @2, @2 : @1}; + std::unordered_map outstandingResponses{{1, 2}, {2, 1}}; FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -492,10 +509,12 @@ - (void)testTargetAddedChangeWillResetPreviousState { } - (void)testNoChangeWillStillMarkTheAffectedTargets { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:@[]]; @@ -514,8 +533,9 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { } - (void)testExistenceFilterMismatchClearsTarget { - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @2 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 2}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -531,7 +551,7 @@ - (void)testExistenceFilterMismatchClearsTarget { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{doc1.key, doc2.key} changes:changes]; @@ -569,10 +589,12 @@ - (void)testExistenceFilterMismatchClearsTarget { } - (void)testExistenceFilterMismatchRemovesCurrentChanges { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:@[]]; @@ -603,7 +625,9 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { } - (void)testDocumentUpdate { - NSDictionary *targetMap = [self queryDataForTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -615,7 +639,7 @@ - (void)testDocumentUpdate { changes.push_back(std::move(change2)); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:changes]; @@ -664,11 +688,12 @@ - (void)testDocumentUpdate { } - (void)testResumeTokensHandledPerTarget { - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @2 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 2}] + }; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:@[]]; @@ -692,11 +717,12 @@ - (void)testResumeTokensHandledPerTarget { } - (void)testLastResumeTokenWins { - NSDictionary *targetMap = - [self queryDataForTargets:@[ @1, @2 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1, 2}] + }; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:@[]]; @@ -724,8 +750,9 @@ - (void)testLastResumeTokenWins { } - (void)testSynthesizeDeletes { - NSDictionary *targetMap = - [self queryDataForLimboTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; DocumentKey limboKey = testutil::Key("coll/limbo"); @@ -736,7 +763,7 @@ - (void)testSynthesizeDeletes { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:changes]; @@ -748,8 +775,9 @@ - (void)testSynthesizeDeletes { } - (void)testDoesntSynthesizeDeletesForWrongState { - NSDictionary *targetMap = - [self queryDataForLimboTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{1}] + }; auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, ids{1}); std::vector> changes; @@ -757,7 +785,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:changes]; @@ -766,8 +794,9 @@ - (void)testDoesntSynthesizeDeletesForWrongState { } - (void)testDoesntSynthesizeDeletesForExistingDoc { - NSDictionary *targetMap = - [self queryDataForLimboTargets:@[ @3 ]]; + std::unordered_map targetMap { + [self queryDataForTargets:{3}] + }; auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, ids{3}); std::vector> changes; @@ -776,7 +805,7 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{FSTTestDocKey(@"coll/limbo")} changes:changes]; @@ -785,8 +814,9 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { } - (void)testSeparatesDocumentUpdates { - NSDictionary *targetMap = - [self queryDataForLimboTargets:@[ @1 ]]; + std::unordered_map targetMap { + [self queryDataForLimboTargets:{1}] + }; FSTDocument *newDoc = FSTTestDoc("docs/new", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); auto newDocChange = absl::make_unique(ids{1}, ids{}, newDoc.key, newDoc); @@ -813,7 +843,7 @@ - (void)testSeparatesDocumentUpdates { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} changes:changes]; @@ -825,10 +855,11 @@ - (void)testSeparatesDocumentUpdates { } - (void)testTracksLimboDocuments { - NSMutableDictionary *targetMap = - [NSMutableDictionary dictionary]; - [targetMap addEntriesFromDictionary:[self queryDataForTargets:@[ @1 ]]]; - [targetMap addEntriesFromDictionary:[self queryDataForLimboTargets:@[ @2 ]]]; + std::unordered_map targetMap; + auto additionalTargets = [self queryDataForTargets:{1}]; + auto additionalLimboTargets = [self queryDataForLimboTargets:{2}]; + targetMap.insert(targetMap.end(), additionalTargets.begin(), additionalTargets.end()); + targetMap.insert(targetMap.end(), additionalLimboTargets.begin(), additionalLimboTargets.end()); // Add 3 docs: 1 is limbo and non-limbo, 2 is limbo-only, 3 is non-limbo FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); @@ -850,7 +881,7 @@ - (void)testTracksLimboDocuments { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:_noOutstandingResponses + outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} changes:changes]; From df5cd00bb97135c287075e9e0362105a8073e92b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 14:19:23 -0500 Subject: [PATCH 021/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 115 ++++++++---------- .../Tests/Remote/FSTWatchChangeTests.mm | 4 +- 2 files changed, 51 insertions(+), 68 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 4fbcc97a586..dbd3c8e3c52 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -42,8 +42,9 @@ using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; -using firebase::firestore::remote::ExistenceFilter; using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; @@ -60,6 +61,24 @@ return {}; } +void AddChanges(std::vector> *result) { +} + +template +void AddChanges(std::vector> *result, + std::unique_ptr head, + Args... tail) { + result->push_back(std::move(head)); + AddChanges(result, tail); +} + +template +std::vector> Changes(Args... args) { + std::vector> result; + AddChanges(&result, args...); + return result; +} + } // namespace @interface FSTRemoteEventTests : XCTestCase @@ -85,7 +104,7 @@ - (void)setUp { for (TargetId targetID : targetIDs) { FSTQuery *query = FSTTestQuery("coll"); targets[targetID] = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID.intValue + targetID:targetID listenSequenceNumber:0 purpose:FSTQueryPurposeListen]; } @@ -102,7 +121,7 @@ - (void)setUp { for (TargetId targetID : targetIDs) { FSTQuery *query = FSTTestQuery("coll/limbo"); targets[targetID] = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID.intValue + targetID:targetID listenSequenceNumber:0 purpose:FSTQueryPurposeLimboResolution]; } @@ -200,9 +219,8 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // The target map that contains an entry for every target in this test. If a target ID is // omitted, the target is considered inactive and FSTTestTargetMetadataProvider will fail on // access. - std::unordered_map targetMap { - [self queryDataForTargets:{1, 2, 3, 4, 5, 6}] - }; + std::unordered_map targetMap{ + [self queryDataForTargets:{1, 2, 3, 4, 5, 6}]}; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1, 2, 3}, ids{4, 5, 6}, existingDoc.key, @@ -211,19 +229,20 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique(ids{1, 4}, ids{2, 6}, newDoc.key, newDoc); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); + // std::vector> changes; + // changes.push_back(std::move(change1)); + // changes.push_back(std::move(change2)); // Create a remote event that includes both `change1` and `change2` as well as a NO_CHANGE event // with the default resume token (`_resumeToken1`). // As `existingDoc` is provided as an existing key, any updates to this document will be treated // as modifications rather than adds. - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet{existingDoc.key} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet{existingDoc.key} + changes:Changes(std::move(change1), std::move(change2))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); XCTAssertEqualObjects(event.documentUpdates.at(existingDoc.key), existingDoc); @@ -260,9 +279,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { } - (void)testWillIgnoreEventsForPendingTargets { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -295,9 +312,7 @@ - (void)testWillIgnoreEventsForPendingTargets { } - (void)testWillIgnoreEventsForRemovedTargets { - std::unordered_map targetMap { - [self queryDataForTargets:{}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -324,9 +339,7 @@ - (void)testWillIgnoreEventsForRemovedTargets { } - (void)testWillKeepResetMappingEvenWithUpdates { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -371,9 +384,7 @@ - (void)testWillKeepResetMappingEvenWithUpdates { } - (void)testWillHandleSingleReset { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; // Reset target WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; @@ -397,9 +408,7 @@ - (void)testWillHandleSingleReset { } - (void)testWillHandleTargetAddAndRemovalInSameBatch { - std::unordered_map targetMap { - [self queryDataForTargets:{1, 2}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTDocument *doc1a = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{2}, doc1a.key, doc1a); @@ -432,9 +441,7 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { } - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { - std::unordered_map targetMap { - [self queryDataForTargets:{1]} - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; auto change = absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); @@ -457,9 +464,7 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { } - (void)testTargetAddedChangeWillResetPreviousState { - std::unordered_map targetMap { - [self queryDataForTargets:{1, 3}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1, 3}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1, 3}, ids{2}, doc1.key, doc1); @@ -509,9 +514,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { } - (void)testNoChangeWillStillMarkTheAffectedTargets { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() @@ -533,9 +536,7 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { } - (void)testExistenceFilterMismatchClearsTarget { - std::unordered_map targetMap { - [self queryDataForTargets:{1, 2}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -589,9 +590,7 @@ - (void)testExistenceFilterMismatchClearsTarget { } - (void)testExistenceFilterMismatchRemovesCurrentChanges { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() @@ -625,9 +624,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { } - (void)testDocumentUpdate { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); @@ -688,9 +685,7 @@ - (void)testDocumentUpdate { } - (void)testResumeTokensHandledPerTarget { - std::unordered_map targetMap { - [self queryDataForTargets:{1, 2}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() @@ -717,9 +712,7 @@ - (void)testResumeTokensHandledPerTarget { } - (void)testLastResumeTokenWins { - std::unordered_map targetMap { - [self queryDataForTargets:{1, 2}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() @@ -750,9 +743,7 @@ - (void)testLastResumeTokenWins { } - (void)testSynthesizeDeletes { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; DocumentKey limboKey = testutil::Key("coll/limbo"); @@ -775,9 +766,7 @@ - (void)testSynthesizeDeletes { } - (void)testDoesntSynthesizeDeletesForWrongState { - std::unordered_map targetMap { - [self queryDataForTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{1}]}; auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, ids{1}); std::vector> changes; @@ -794,9 +783,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { } - (void)testDoesntSynthesizeDeletesForExistingDoc { - std::unordered_map targetMap { - [self queryDataForTargets:{3}] - }; + std::unordered_map targetMap{[self queryDataForTargets:{3}]}; auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, ids{3}); std::vector> changes; @@ -814,9 +801,7 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { } - (void)testSeparatesDocumentUpdates { - std::unordered_map targetMap { - [self queryDataForLimboTargets:{1}] - }; + std::unordered_map targetMap{[self queryDataForLimboTargets:{1}]}; FSTDocument *newDoc = FSTTestDoc("docs/new", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); auto newDocChange = absl::make_unique(ids{1}, ids{}, newDoc.key, newDoc); diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm index 28360742ecd..8de72107162 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm @@ -14,16 +14,14 @@ * limitations under the License. */ -#import "Firestore/Source/Remote/FSTWatchChange.h" - #import #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Example/Tests/Remote/FSTWatchChange+Testing.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" using firebase::firestore::remote::ExistenceFilter; From 5d3313afcdb6a656dc69b054eed84541450f45e6 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 15:10:54 -0500 Subject: [PATCH 022/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 2 +- .../Tests/Remote/FSTWatchChangeTests.mm | 33 +++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index dbd3c8e3c52..e1112937f70 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -69,7 +69,7 @@ void AddChanges(std::vector> *result, std::unique_ptr head, Args... tail) { result->push_back(std::move(head)); - AddChanges(result, tail); + AddChanges(result, tail...); } template diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm index 8de72107162..d554f0506e8 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm @@ -23,7 +23,11 @@ #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilter; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; NS_ASSUME_NONNULL_BEGIN @@ -34,32 +38,25 @@ @implementation FSTWatchChangeTests - (void)testDocumentChange { FSTMaybeDocument *doc = FSTTestDoc("a/b", 1, @{}, FSTDocumentStateSynced); - FSTDocumentWatchChange *change = - [[FSTDocumentWatchChange alloc] initWithUpdatedTargetIDs:@[ @1, @2, @3 ] - removedTargetIDs:@[ @4, @5 ] - documentKey:doc.key - document:doc]; - XCTAssertEqual(change.updatedTargetIDs.count, 3); - XCTAssertEqual(change.removedTargetIDs.count, 2); + DocumentWatchChange change{{1, 2, 3}, {4, 5}, doc.key, doc}; + + XCTAssertEqual(change.updated_target_ids().size(), 3); + XCTAssertEqual(change.removed_target_ids().size(), 2); // Testing object identity here is fine. - XCTAssertEqual(change.document, doc); + XCTAssertEqual(change.new_document(), doc); } - (void)testExistenceFilterChange { ExistenceFilter filter{7}; - FSTExistenceFilterWatchChange *change = [FSTExistenceFilterWatchChange changeWithFilter:filter - targetID:5]; - XCTAssertEqual(change.filter.count(), 7); - XCTAssertEqual(change.targetID, 5); + ExistenceFilterWatchChange change{filter, 5}; + XCTAssertEqual(change.filter().count(), 7); + XCTAssertEqual(change.target_id(), 5); } - (void)testWatchTargetChange { - FSTWatchTargetChange *change = - [FSTWatchTargetChange changeWithState:FSTWatchTargetChangeStateReset - targetIDs:@[ @1, @2 ] - cause:nil]; - XCTAssertEqual(change.state, FSTWatchTargetChangeStateReset); - XCTAssertEqual(change.targetIDs.count, 2); + WatchTargetChange change{WatchTargetChangeState::Reset, {1, 2,}}; + XCTAssertEqual(change.state(), WatchTargetChangeState::Reset); + XCTAssertEqual(change.target_ids().size(), 2); } @end From 31e5f3d36af0e3953445a19a9cc489218b4d3b0e Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 15:17:43 -0500 Subject: [PATCH 023/107] wip --- .../Tests/Remote/FSTRemoteEventTests.mm | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index e1112937f70..b7973174d48 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -64,18 +64,18 @@ void AddChanges(std::vector> *result) { } -template +template void AddChanges(std::vector> *result, - std::unique_ptr head, - Args... tail) { + Head head, + Tail... tail) { result->push_back(std::move(head)); - AddChanges(result, tail...); + AddChanges(result, std::move(tail)...); } template std::vector> Changes(Args... args) { std::vector> result; - AddChanges(&result, args...); + AddChanges(&result, std::move(args)...); return result; } @@ -519,7 +519,7 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:@[]]; + changes:{}]; WatchTargetChange change{WatchTargetChangeState::NoChange, {1}, _resumeToken1}; [aggregator handleTargetChange:change]; @@ -595,7 +595,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:@[]]; + changes:{}]; WatchTargetChange markCurrent{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:markCurrent]; @@ -648,7 +648,7 @@ - (void)testDocumentUpdate { XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); [_targetMetadataProvider setSyncedKeys:DocumentKeySet{doc1.key, doc2.key} - forQueryData:targetMap[@1]]; + forQueryData:targetMap[1]]; FSTDeletedDocument *deletedDoc1 = [FSTDeletedDocument documentWithKey:doc1.key version:testutil::Version(3) @@ -690,7 +690,7 @@ - (void)testResumeTokensHandledPerTarget { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:@[]]; + changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:change1]; @@ -717,7 +717,7 @@ - (void)testLastResumeTokenWins { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:@[]]; + changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; [aggregator handleTargetChange:change1]; @@ -840,11 +840,9 @@ - (void)testSeparatesDocumentUpdates { } - (void)testTracksLimboDocuments { - std::unordered_map targetMap; - auto additionalTargets = [self queryDataForTargets:{1}]; - auto additionalLimboTargets = [self queryDataForLimboTargets:{2}]; - targetMap.insert(targetMap.end(), additionalTargets.begin(), additionalTargets.end()); - targetMap.insert(targetMap.end(), additionalLimboTargets.begin(), additionalLimboTargets.end()); + std::unordered_map targetMap = [self queryDataForTargets:{1}]; + auto additionalTargets = [self queryDataForLimboTargets:{2}]; + targetMap.insert(additionalTargets.begin(), additionalTargets.end()); // Add 3 docs: 1 is limbo and non-limbo, 2 is limbo-only, 3 is non-limbo FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); From 063724396c0e307d8e182d798fb740fb98dffe91 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 15:34:40 -0500 Subject: [PATCH 024/107] Ship it! --- .../Tests/Remote/FSTRemoteEventTests.mm | 2 + .../Example/Tests/SpecTests/FSTSpecTests.mm | 39 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b7973174d48..f781aac9047 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -48,6 +48,8 @@ using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::util::MakeString; +using firebase::firestore::util::Status; // `make_unique` cannot deduce that the template parameter is intended to // resolve to a vector of target ids when given an initialization list (e.g., // {1, 2}). The type alias is deliberately very short to minimize boilderplate. diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 3b86100ae2b..721203bc9d9 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -34,6 +34,7 @@ #import "Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" @@ -50,6 +51,7 @@ namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; +using firebase::firestore::FirestoreErrorCode; using firebase::firestore::auth::User; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; @@ -60,6 +62,7 @@ using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::util::MakeString; using firebase::firestore::util::Status; using firebase::firestore::util::TimerId; @@ -95,15 +98,15 @@ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } -std::vector ConvertTargetsArray(NSArray* from) { +std::vector ConvertTargetsArray(NSArray *from) { std::vector result; - for (NSNumber* targetID in from) { + for (NSNumber *targetID in from) { result.push_back(targetID.intValue); } return result; } -} // namespace +} // namespace @interface FSTSpecTests () @property(nonatomic, strong) FSTSyncEngineTestDriver *driver; @@ -247,21 +250,23 @@ - (void)doWatchAck:(NSArray *)ackedTargets { - (void)doWatchCurrent:(NSArray *)currentSpec { NSArray *currentTargets = currentSpec[0]; NSData *resumeToken = [currentSpec[1] dataUsingEncoding:NSUTF8StringEncoding]; - WatchTargetChange change{WatchTargetChangeState::Current, ConvertTargetsArray(currentTargets), resumeToken}; + WatchTargetChange change{WatchTargetChangeState::Current, ConvertTargetsArray(currentTargets), + resumeToken}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } - (void)doWatchRemove:(NSDictionary *)watchRemoveSpec { - NSError *error = nil; + Status error; NSDictionary *cause = watchRemoveSpec[@"cause"]; if (cause) { int code = ((NSNumber *)cause[@"code"]).intValue; NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"Error from watchRemove.", }; - error = [NSError errorWithDomain:FIRFirestoreErrorDomain code:code userInfo:userInfo]; + error = Status{static_cast(code), MakeString([userInfo description])}; } - WatchTargetChange change{WatchTargetChangeState::Removed, ConvertTargetsArray(watchRemoveSpec[@"targetIds"]), error}; + WatchTargetChange change{WatchTargetChangeState::Removed, + ConvertTargetsArray(watchRemoveSpec[@"targetIds"]), error}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; // Unlike web, the FSTMockDatastore detects a watch removal with cause and will remove active // targets @@ -296,13 +301,13 @@ - (void)doWatchEntity:(NSDictionary *)watchEntity { : [FSTDeletedDocument documentWithKey:key version:std::move(version) hasCommittedMutations:NO]; - DocumentWatchChange change{ConvertTargetsArray(watchEntity[@"targets"]), ConvertTargetsArray(watchEntity[@"removedTargets"]), doc.key, - doc}; + DocumentWatchChange change{ConvertTargetsArray(watchEntity[@"targets"]), + ConvertTargetsArray(watchEntity[@"removedTargets"]), doc.key, doc}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } else if (watchEntity[@"key"]) { DocumentKey docKey = FSTTestDocKey(watchEntity[@"key"]); - DocumentWatchChange change{{}, ConvertTargetsArray(watchEntity[@"removedTargets"]), doc.key, - nil}; + DocumentWatchChange change{ + {}, ConvertTargetsArray(watchEntity[@"removedTargets"]), docKey, nil}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } else { HARD_FAIL("Either key, doc or docs must be set."); @@ -316,7 +321,7 @@ - (void)doWatchFilter:(NSArray *)watchFilter { int keyCount = watchFilter.count == 0 ? 0 : (int)watchFilter.count - 1; ExistenceFilter filter{keyCount}; - ExistenceFilterWatchChange change{filter, targets[0]}; + ExistenceFilterWatchChange change{filter, targets[0].intValue}; [self.driver receiveWatchChange:change snapshotVersion:SnapshotVersion::None()]; } @@ -331,7 +336,8 @@ - (void)doWatchSnapshot:(NSDictionary *)watchSnapshot { NSArray *targetIDs = watchSnapshot[@"targetIds"] ? watchSnapshot[@"targetIds"] : [NSArray array]; NSData *resumeToken = [watchSnapshot[@"resumeToken"] dataUsingEncoding:NSUTF8StringEncoding]; - WatchTargetChange change{WatchTargetChangeState::NoChange, ConvertTargetsArray(targetIDs), resumeToken}; + WatchTargetChange change{WatchTargetChangeState::NoChange, ConvertTargetsArray(targetIDs), + resumeToken}; [self.driver receiveWatchChange:change snapshotVersion:[self parseVersion:watchSnapshot[@"version"]]]; } @@ -580,7 +586,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { [self.driver setExpectedLimboDocuments:std::move(expectedLimboDocuments)]; } if (expected[@"activeTargets"]) { - std::unordered_map expectedActiveTargets; + __block std::unordered_map expectedActiveTargets; [expected[@"activeTargets"] enumerateKeysAndObjectsUsingBlock:^(NSString *targetIDString, NSDictionary *queryData, BOOL *stop) { @@ -598,7 +604,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { snapshotVersion:SnapshotVersion::None() resumeToken:resumeToken]; }]; - self.driver.setExpectedActiveTargets : expectedActiveTargets; + [self.driver setExpectedActiveTargets: expectedActiveTargets]; } } @@ -631,7 +637,8 @@ - (void)validateLimboDocuments { // Validate that each limbo doc has an expected active target for (const auto &kv : actualLimboDocs) { - XCTAssertNotNil([self.driver expectedActiveTargets][kv.second], + const auto& expected = [self.driver expectedActiveTargets]; + XCTAssertTrue(expected.find(kv.second) != expected.end(), @"Found limbo doc without an expected active target"); } From 26b39c7f26e7fe3cae02a342005406d543e88c8b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 15:39:44 -0500 Subject: [PATCH 025/107] use changes --- .../Tests/Remote/FSTRemoteEventTests.mm | 190 +++++++----------- 1 file changed, 71 insertions(+), 119 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index f781aac9047..26094fbde0c 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -67,9 +67,7 @@ void AddChanges(std::vector> *result) { } template -void AddChanges(std::vector> *result, - Head head, - Tail... tail) { +void AddChanges(std::vector> *result, Head head, Tail... tail) { result->push_back(std::move(head)); AddChanges(result, std::move(tail)...); } @@ -148,8 +146,7 @@ - (void)setUp { aggregatorWithTargetMap:(const std::unordered_map &)targetMap outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys - changes:(const std::vector> &)watchChanges { - FSTWatchChangeAggregator *aggregator = + changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:_targetMetadataProvider]; std::vector targetIDs; @@ -290,20 +287,16 @@ - (void)testWillIgnoreEventsForPendingTargets { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change4 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - changes.push_back(std::move(change3)); - changes.push_back(std::move(change4)); - // We're waiting for the unwatch and watch ack std::unordered_map outstandingResponses{{1, 2}}; - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:outstandingResponses + existingKeys:DocumentKeySet {} + changes:Changes(std::move(change1), std::move(change2), + std::move(change3), std::move(change4))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); // doc1 is ignored because it was part of an inactive target, but doc2 is in the changes // because it become active. @@ -320,18 +313,15 @@ - (void)testWillIgnoreEventsForRemovedTargets { auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); auto change2 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - // We're waiting for the unwatch ack std::unordered_map outstandingResponses{{1, 1}}; - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:outstandingResponses + existingKeys:DocumentKeySet {} + changes:Changes(std::move(change1), std::move(change2))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); // doc1 is ignored because it was part of an inactive target XCTAssertEqual(event.documentUpdates.size(), 0); @@ -359,18 +349,14 @@ - (void)testWillKeepResetMappingEvenWithUpdates { // Remove doc2 again, should not show up in reset mapping auto change5 = absl::make_unique(ids{}, ids{1}, doc2.key, doc2); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - changes.push_back(std::move(change3)); - changes.push_back(std::move(change4)); - changes.push_back(std::move(change5)); - - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet{doc1.key} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet{doc1.key} + changes:Changes(std::move(change1), std::move(change2), + std::move(change3), std::move(change4), + std::move(change5))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 3); XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); @@ -418,15 +404,12 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique(ids{2}, ids{1}, doc1b.key, doc1b); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet{doc1a.key} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet{doc1a.key} + changes:Changes(std::move(change1), std::move(change2))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 1); XCTAssertEqualObjects(event.documentUpdates.at(doc1b.key), doc1b); @@ -447,14 +430,12 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { auto change = absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); - std::vector> changes; - changes.push_back(std::move(change)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:changes]; + changes:Changes(std::move(change))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 0); @@ -478,21 +459,16 @@ - (void)testTargetAddedChangeWillResetPreviousState { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change6 = absl::make_unique(ids{1}, ids{3}, doc2.key, doc2); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - changes.push_back(std::move(change3)); - changes.push_back(std::move(change4)); - changes.push_back(std::move(change5)); - changes.push_back(std::move(change6)); - std::unordered_map outstandingResponses{{1, 2}, {2, 1}}; - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:DocumentKeySet{doc2.key} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:outstandingResponses + existingKeys:DocumentKeySet{doc2.key} + changes:Changes(std::move(change1), std::move(change2), + std::move(change3), std::move(change4), + std::move(change5), std::move(change6))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); @@ -547,16 +523,11 @@ - (void)testExistenceFilterMismatchClearsTarget { auto change3 = absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - changes.push_back(std::move(change3)); - - FSTWatchChangeAggregator *aggregator = - [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet{doc1.key, doc2.key} - changes:changes]; + FSTWatchChangeAggregator *aggregator = [self + aggregatorWithTargetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet{doc1.key, doc2.key} + changes:Changes(std::move(change1), std::move(change2), std::move(change3))]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -633,14 +604,11 @@ - (void)testDocumentUpdate { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); - std::vector> changes; - changes.push_back(std::move(change1)); - changes.push_back(std::move(change2)); - - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet {} - changes:changes]; + FSTWatchChangeAggregator *aggregator = + [self aggregatorWithTargetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet {} + changes:Changes(std::move(change1), std::move(change2))]; FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; @@ -749,16 +717,12 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); - auto resolveLimboTarget = - absl::make_unique(WatchTargetChangeState::Current, ids{1}); - std::vector> changes; - changes.push_back(std::move(resolveLimboTarget)); - - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet {} + changes:Changes(std::move(resolveLimboTarget))]; FSTDeletedDocument *expected = [FSTDeletedDocument documentWithKey:limboKey version:event.snapshotVersion @@ -771,14 +735,12 @@ - (void)testDoesntSynthesizeDeletesForWrongState { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, ids{1}); - std::vector> changes; - changes.push_back(std::move(wrongState)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet {} - changes:changes]; + changes:Changes(std::move(wrongState))]; XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.limboDocumentChanges.size(), 0); @@ -788,15 +750,13 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { std::unordered_map targetMap{[self queryDataForTargets:{3}]}; auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, ids{3}); - std::vector> changes; - changes.push_back(std::move(hasDocument)); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:NoOutstandingResponses() existingKeys:DocumentKeySet{FSTTestDocKey(@"coll/limbo")} - changes:changes]; + changes:Changes(std::move(hasDocument))]; XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.limboDocumentChanges.size(), 0); @@ -821,18 +781,14 @@ - (void)testSeparatesDocumentUpdates { auto missingDocChange = absl::make_unique(ids{}, ids{1}, missingDoc.key, missingDoc); - std::vector> changes; - changes.push_back(std::move(newDocChange)); - changes.push_back(std::move(existingDocChange)); - changes.push_back(std::move(deletedDocChange)); - changes.push_back(std::move(missingDocChange)); - - FSTRemoteEvent *event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} - changes:changes]; + FSTRemoteEvent *event = [self + remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} + changes:Changes(std::move(newDocChange), std::move(existingDocChange), + std::move(deletedDocChange), + std::move(missingDocChange))]; FSTTargetChange *targetChange = FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, @@ -858,17 +814,13 @@ - (void)testTracksLimboDocuments { auto targetsChange = absl::make_unique(WatchTargetChangeState::Current, ids{1, 2}); - std::vector> changes; - changes.push_back(std::move(docChange1)); - changes.push_back(std::move(docChange2)); - changes.push_back(std::move(docChange3)); - changes.push_back(std::move(targetsChange)); - - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:NoOutstandingResponses() - existingKeys:DocumentKeySet {} - changes:changes]; + FSTRemoteEvent *event = + [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:NoOutstandingResponses() + existingKeys:DocumentKeySet {} + changes:Changes(std::move(docChange1), std::move(docChange2), + std::move(docChange3), std::move(targetsChange))]; DocumentKeySet limboDocChanges = event.limboDocumentChanges; // Doc1 is in both limbo and non-limbo targets, therefore not tracked as limbo From 2cab650062425cb6c9c69d9201f844cf7ce5eba4 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 15:41:30 -0500 Subject: [PATCH 026/107] quick fix --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 26094fbde0c..c55f4478f97 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -717,6 +717,8 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); + auto resolveLimboTarget = + absl::make_unique(WatchTargetChangeState::Current, ids{1}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap From ca88d8c4b26db4871c71fc42d8a477fe538e66aa Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 16:48:29 -0500 Subject: [PATCH 027/107] Unit tests pass --- .../Example/Tests/Remote/FSTRemoteEventTests.mm | 3 +-- .../src/firebase/firestore/remote/watch_change.mm | 13 +++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index c55f4478f97..d1eb85c623e 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -713,8 +713,7 @@ - (void)testLastResumeTokenWins { } - (void)testSynthesizeDeletes { - std::unordered_map targetMap{[self queryDataForTargets:{1}]}; - + std::unordered_map targetMap{[self queryDataForLimboTargets:{1}]}; DocumentKey limboKey = testutil::Key("coll/limbo"); auto resolveLimboTarget = diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.mm b/Firestore/core/src/firebase/firestore/remote/watch_change.mm index 6b229ee9752..277a7e32834 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.mm @@ -23,26 +23,27 @@ namespace remote { bool operator==(const DocumentWatchChange& lhs, - const DocumentWatchChange& rhs) { + const DocumentWatchChange& rhs) { + auto docs_equal = [](FSTMaybeDocument* lhs, FSTMaybeDocument* rhs) { + return (lhs == nil && rhs == nil) || [lhs isEqual:rhs]; + }; return lhs.updated_target_ids() == rhs.updated_target_ids() && lhs.removed_target_ids() == rhs.removed_target_ids() && lhs.document_key() == rhs.document_key() && - [lhs.new_document() isEqual:rhs.new_document()]; + docs_equal(lhs.new_document(), rhs.new_document()); } bool operator==(const ExistenceFilterWatchChange& lhs, - const ExistenceFilterWatchChange& rhs) { + const ExistenceFilterWatchChange& rhs) { return lhs.filter() == rhs.filter() && lhs.target_id() == rhs.target_id(); } -bool operator==(const WatchTargetChange& lhs, - const WatchTargetChange& rhs) { +bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && [lhs.resume_token() isEqual:rhs.resume_token()] && lhs.cause() == rhs.cause(); } - } // namespace remote } // namespace firestore } // namespace firebase From 2c0a7ef40b178766cc4f0c23df686df25dd884ac Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 16:56:30 -0500 Subject: [PATCH 028/107] style.sh --- .../Example/App/GoogleService-Info.plist | 42 +++++++++++------- .../Example/Tests/Local/FSTLocalStoreTests.mm | 43 ++++++++++--------- .../Tests/Remote/FSTRemoteEventTests.mm | 3 +- .../Tests/Remote/FSTSerializerBetaTests.mm | 6 ++- .../Tests/Remote/FSTWatchChangeTests.mm | 6 ++- .../Example/Tests/SpecTests/FSTSpecTests.mm | 7 +-- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 8 ++-- .../SpecTests/FSTSyncEngineTestDriver.mm | 8 ++-- Firestore/Example/Tests/Util/FSTHelpers.h | 10 ++--- Firestore/Example/Tests/Util/FSTHelpers.mm | 3 +- Firestore/Source/Remote/FSTRemoteEvent.h | 11 +++-- Firestore/Source/Remote/FSTRemoteEvent.mm | 11 ++--- Firestore/Source/Remote/FSTRemoteStore.mm | 1 + Firestore/Source/Remote/FSTSerializerBeta.h | 3 +- Firestore/Source/Remote/FSTSerializerBeta.mm | 7 +-- Firestore/Source/Remote/FSTStream.h | 2 +- .../firebase/firestore/remote/watch_change.h | 9 ++-- 17 files changed, 104 insertions(+), 76 deletions(-) diff --git a/Firestore/Example/App/GoogleService-Info.plist b/Firestore/Example/App/GoogleService-Info.plist index 3f7547fb48d..0e35ab4a3d9 100644 --- a/Firestore/Example/App/GoogleService-Info.plist +++ b/Firestore/Example/App/GoogleService-Info.plist @@ -2,27 +2,39 @@ - API_KEY - correct_api_key - TRACKING_ID - correct_tracking_id + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 CLIENT_ID - correct_client_id + 174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11.apps.googleusercontent.com REVERSED_CLIENT_ID - correct_reversed_client_id - GOOGLE_APP_ID - 1:123:ios:123abc + com.googleusercontent.apps.174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11 + API_KEY + AIzaSyB_QJO1AARQzdvEgzb-o8wQ9eag5V8ZVCI GCM_SENDER_ID - correct_gcm_sender_id + 174583568604 PLIST_VERSION 1 BUNDLE_ID - com.google.FirebaseSDKTests + com.firebase.FirestoreExample PROJECT_ID - abc-xyz-123 - DATABASE_URL - https://abc-xyz-123.firebaseio.com + varconst-9 STORAGE_BUCKET - project-id-123.storage.firebase.com + varconst-9.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:174583568604:ios:0459a01df1082630 + DATABASE_URL + https://varconst-9.firebaseio.com - + \ No newline at end of file diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 7613e1c5e4c..f2089b20d69 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -260,7 +260,7 @@ - (void)testHandlesSetMutationThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced), - {targetID}, {})]; + {targetID}, {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations)); @@ -303,7 +303,7 @@ - (void)testHandlesAckThenRejectThenRemoteEvent { [self applyRemoteEvent:FSTTestAddedRemoteEvent(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced), - {targetID})]; + {targetID})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 2, @{@"it" : @"changed"}, FSTDocumentStateSynced)); FSTAssertNotContains(@"bar/baz"); @@ -315,8 +315,8 @@ - (void)testHandlesDeletedDocumentThenSetMutationThenAck { FSTQuery *query = FSTTestQuery("foo"); TargetId targetID = [self allocateQuery:query]; - [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - {targetID}, {})]; + [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), {targetID}, + {})]; FSTAssertRemoved(@[ @"foo/bar" ]); // Under eager GC, there is no longer a reference for the document, and it should be // deleted. @@ -354,8 +354,8 @@ - (void)testHandlesSetMutationThenDeletedDocument { FSTAssertChanged( @[ FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); - [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - {targetID}, {})]; + [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), {targetID}, + {})]; FSTAssertChanged( @[ FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations) ]); FSTAssertContains(FSTTestDoc("foo/bar", 0, @{@"foo" : @"bar"}, FSTDocumentStateLocalMutations)); @@ -388,7 +388,7 @@ - (void)testHandlesDocumentThenSetMutationThenAckThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced), - {targetID}, {})]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced)); } @@ -556,8 +556,8 @@ - (void)testHandlesDocumentThenDeletedDocumentThenDocument { FSTAssertChanged(@[ FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 1, @{@"it" : @"base"}, FSTDocumentStateSynced)); - [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), - {targetID}, {})]; + [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDeletedDoc("foo/bar", 2, NO), {targetID}, + {})]; FSTAssertRemoved(@[ @"foo/bar" ]); if (![self gcIsEager]) { FSTAssertContains(FSTTestDeletedDoc("foo/bar", 2, NO)); @@ -565,7 +565,7 @@ - (void)testHandlesDocumentThenDeletedDocumentThenDocument { [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced), - {targetID}, {})]; + {targetID}, {})]; FSTAssertChanged(@[ FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced) ]); FSTAssertContains(FSTTestDoc("foo/bar", 3, @{@"it" : @"changed"}, FSTDocumentStateSynced)); } @@ -876,11 +876,11 @@ - (void)testCanExecuteMixedCollectionQueries { FSTAssertTargetID(2); [self applyRemoteEvent:FSTTestUpdateRemoteEvent( - FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), - {2}, {})]; + FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), {2}, + {})]; [self applyRemoteEvent:FSTTestUpdateRemoteEvent( - FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), - {2}, {})]; + FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), {2}, + {})]; [self.localStore locallyWriteMutations:@[ FSTTestSetMutation(@"foo/bonk", @{@"a" : @"b"}) ]]; @@ -903,7 +903,8 @@ - (void)testPersistsResumeTokens { TargetId targetID = queryData.targetID; NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); - WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken, Status::OK()}; + WatchTargetChange watchChange{ + WatchTargetChangeState::Current, {targetID}, resumeToken, Status::OK()}; FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithSingleResultForKey:testutil::Key("foo/bar") @@ -931,12 +932,12 @@ - (void)testRemoteDocumentKeysForTarget { [self allocateQuery:query]; FSTAssertTargetID(2); - [self applyRemoteEvent:FSTTestAddedRemoteEvent( - FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), - {2})]; - [self applyRemoteEvent:FSTTestAddedRemoteEvent( - FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), - {2})]; + [self + applyRemoteEvent:FSTTestAddedRemoteEvent( + FSTTestDoc("foo/baz", 10, @{@"a" : @"b"}, FSTDocumentStateSynced), {2})]; + [self + applyRemoteEvent:FSTTestAddedRemoteEvent( + FSTTestDoc("foo/bar", 20, @{@"a" : @"b"}, FSTDocumentStateSynced), {2})]; [self.localStore locallyWriteMutations:@[ FSTTestSetMutation(@"foo/bonk", @{@"a" : @"b"}) ]]; diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index d1eb85c623e..d8073b5dbf3 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -146,7 +146,8 @@ - (void)setUp { aggregatorWithTargetMap:(const std::unordered_map &)targetMap outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys - changes:(const std::vector> &)watchChanges { FSTWatchChangeAggregator *aggregator = + changes:(const std::vector> &)watchChanges { + FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:_targetMetadataProvider]; std::vector targetIDs; diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index aa67a5b693f..5b6258261e8 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -23,6 +23,7 @@ #import #import +#include #include #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" @@ -77,7 +78,7 @@ template bool Equals(const WatchChange &lhs, const WatchChange &rhs) { - return static_cast(lhs) == static_cast(rhs); + return static_cast(lhs) == static_cast(rhs); } bool operator==(const WatchChange &lhs, const WatchChange &rhs) { @@ -888,7 +889,8 @@ - (void)testConvertsDocumentChangeWithRemovedTargetIds { } - (void)testConvertsDocumentChangeWithDeletions { - DocumentWatchChange expected{{}, {1, 2}, FSTTestDocKey(@"coll/1"), FSTTestDeletedDoc("coll/1", 5, NO)}; + DocumentWatchChange expected{ + {}, {1, 2}, FSTTestDocKey(@"coll/1"), FSTTestDeletedDoc("coll/1", 5, NO)}; GCFSListenResponse *listenResponse = [GCFSListenResponse message]; listenResponse.documentDelete.document = @"projects/p/databases/d/documents/coll/1"; diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm index d554f0506e8..ed8537f67c3 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm @@ -54,7 +54,11 @@ - (void)testExistenceFilterChange { } - (void)testWatchTargetChange { - WatchTargetChange change{WatchTargetChangeState::Reset, {1, 2,}}; + WatchTargetChange change{WatchTargetChangeState::Reset, + { + 1, + 2, + }}; XCTAssertEqual(change.state(), WatchTargetChangeState::Reset); XCTAssertEqual(change.target_ids().size(), 2); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 721203bc9d9..fd254cbd106 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -21,6 +21,7 @@ #include #include #include +#include #import "Firestore/Source/Core/FSTEventManager.h" #import "Firestore/Source/Core/FSTQuery.h" @@ -604,7 +605,7 @@ - (void)validateStateExpectations:(nullable NSDictionary *)expected { snapshotVersion:SnapshotVersion::None() resumeToken:resumeToken]; }]; - [self.driver setExpectedActiveTargets: expectedActiveTargets]; + [self.driver setExpectedActiveTargets:expectedActiveTargets]; } } @@ -637,9 +638,9 @@ - (void)validateLimboDocuments { // Validate that each limbo doc has an expected active target for (const auto &kv : actualLimboDocs) { - const auto& expected = [self.driver expectedActiveTargets]; + const auto &expected = [self.driver expectedActiveTargets]; XCTAssertTrue(expected.find(kv.second) != expected.end(), - @"Found limbo doc without an expected active target"); + @"Found limbo doc without an expected active target"); } for (const DocumentKey &expectedLimboDoc : self.driver.expectedLimboDocuments) { diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 3045b506773..0622aa4290e 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -147,7 +147,7 @@ typedef std::unordered_map &)activeTargets; /** The expected set of active targets, keyed by target ID. */ -- (const std::unordered_map &)expectedActiveTargets; +- (const std::unordered_map &) + expectedActiveTargets; -- (void)setExpectedActiveTargets:(const std::unordered_map &)targets; +- (void)setExpectedActiveTargets: + (const std::unordered_map &)targets; @end diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 49f6ba5abde..e34349e716a 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -375,7 +375,7 @@ - (void)writeUserMutation:(FSTMutation *)mutation { }); } -- (void)receiveWatchChange:(const WatchChange&)change +- (void)receiveWatchChange:(const WatchChange &)change snapshotVersion:(const SnapshotVersion &)snapshot { _workerQueue->EnqueueBlocking([&] { _datastore->WriteWatchChange(change, snapshot); }); } @@ -396,15 +396,15 @@ - (void)receiveWatchStreamError:(int)errorCode userInfo:(NSDictionary&)activeTargets { +- (const std::unordered_map &)activeTargets { return _datastore->ActiveTargets(); } -- (const std::unordered_map&)expectedActiveTargets { +- (const std::unordered_map &)expectedActiveTargets { return _expectedActiveTargets; } -- (void)setExpectedActiveTargets:(const std::unordered_map&)targets { +- (void)setExpectedActiveTargets:(const std::unordered_map &)targets { _expectedActiveTargets = targets; } diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index e0db83be66a..a276ef4900b 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -155,9 +155,9 @@ inline NSString *FSTRemoveExceptionPrefix(NSString *exception) { + (instancetype) providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey listenTargets: - (const std::vector&)listenTargets + (const std::vector &)listenTargets limboTargets: - (const std::vector&)limboTargets; + (const std::vector &)limboTargets; /** * Creates an FSTTestTargetMetadataProvider that behaves as if there's an established listen for @@ -295,9 +295,9 @@ FSTRemoteEvent *FSTTestUpdateRemoteEvent( /** Creates a remote event with changes to a document. Allows for identifying limbo targets */ FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( FSTMaybeDocument *doc, - const std::vector& updatedInTargets, - const std::vector& removedFromTargets, - const std::vector& limboTargets); + const std::vector &updatedInTargets, + const std::vector &removedFromTargets, + const std::vector &limboTargets); /** Creates a test view changes. */ FSTLocalViewChanges *FSTTestViewChanges(firebase::firestore::model::TargetId targetID, diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 98af5835b70..2d02c5902f7 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -423,8 +423,7 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { DocumentWatchChange change{updatedInTargets, removedFromTargets, doc.key, doc}; std::vector listens = updatedInTargets; - listens.insert(listens.end(), removedFromTargets.begin(), - removedFromTargets.end()); + listens.insert(listens.end(), removedFromTargets.begin(), removedFromTargets.end()); FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 502040864a6..e5c5d602686 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -40,7 +40,8 @@ NS_ASSUME_NONNULL_BEGIN /** * Returns the set of remote document keys for the given target ID as of the last raised snapshot. */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget:(firebase::firestore::model::TargetId)targetID; +- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: + (firebase::firestore::model::TargetId)targetID; /** * Returns the FSTQueryData for an active target ID or 'null' if this query has become inactive @@ -168,10 +169,11 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; /** Processes and adds the DocumentWatchChange to the current set of changes. */ -- (void)handleDocumentChange:(const firebase::firestore::remote::DocumentWatchChange&)documentChange; +- (void)handleDocumentChange: + (const firebase::firestore::remote::DocumentWatchChange &)documentChange; /** Processes and adds the WatchTargetChange to the current set of changes. */ -- (void)handleTargetChange:(const firebase::firestore::remote::WatchTargetChange&)targetChange; +- (void)handleTargetChange:(const firebase::firestore::remote::WatchTargetChange &)targetChange; /** Removes the in-memory state for the provided target. */ - (void)removeTarget:(firebase::firestore::model::TargetId)targetID; @@ -180,7 +182,8 @@ NS_ASSUME_NONNULL_BEGIN * Handles existence filters and synthesizes deletes for filter mismatches. Targets that are * invalidated by filter mismatches are added to `targetMismatches`. */ -- (void)handleExistenceFilter:(const firebase::firestore::remote::ExistenceFilterWatchChange&)existenceFilter; +- (void)handleExistenceFilter: + (const firebase::firestore::remote::ExistenceFilterWatchChange &)existenceFilter; /** * Increment the number of acks needed from watch before we can consider the server to be 'in-sync' diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 61b6f085373..70e22a7bac1 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -321,7 +321,7 @@ - (instancetype)initWithTargetMetadataProvider: return self; } -- (void)handleDocumentChange:(const DocumentWatchChange&)documentChange { +- (void)handleDocumentChange:(const DocumentWatchChange &)documentChange { for (TargetId targetID : documentChange.updated_target_ids()) { if ([documentChange.new_document() isKindOfClass:[FSTDocument class]]) { [self addDocument:documentChange.new_document() toTarget:targetID]; @@ -339,7 +339,7 @@ - (void)handleDocumentChange:(const DocumentWatchChange&)documentChange { } } -- (void)handleTargetChange:(const WatchTargetChange&)targetChange { +- (void)handleTargetChange:(const WatchTargetChange &)targetChange { for (TargetId targetID : [self targetIdsForChange:targetChange]) { FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; switch (targetChange.state()) { @@ -365,7 +365,8 @@ - (void)handleTargetChange:(const WatchTargetChange&)targetChange { if (!targetState.isPending) { [self removeTarget:targetID]; } - HARD_ASSERT(targetChange.cause().ok(), "WatchChangeAggregator does not handle errored targets"); + HARD_ASSERT(targetChange.cause().ok(), + "WatchChangeAggregator does not handle errored targets"); break; case WatchTargetChangeState::Current: if ([self isActiveTarget:targetID]) { @@ -392,7 +393,7 @@ - (void)handleTargetChange:(const WatchTargetChange&)targetChange { * Returns all targetIds that the watch change applies to: either the targetIds explicitly listed * in the change or the targetIds of all currently active targets. */ -- (std::vector)targetIdsForChange:(const WatchTargetChange&)targetChange { +- (std::vector)targetIdsForChange:(const WatchTargetChange &)targetChange { if (!targetChange.target_ids().empty()) { return targetChange.target_ids(); } @@ -410,7 +411,7 @@ - (void)removeTarget:(TargetId)targetID { _targetStates.erase(targetID); } -- (void)handleExistenceFilter:(const ExistenceFilterWatchChange&)existenceFilter { +- (void)handleExistenceFilter:(const ExistenceFilterWatchChange &)existenceFilter { TargetId targetID = existenceFilter.target_id(); int expectedCount = existenceFilter.filter().count(); diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 417c8b18132..78829e8bae4 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -18,6 +18,7 @@ #include #include +#include #include #import "Firestore/Source/Core/FSTQuery.h" diff --git a/Firestore/Source/Remote/FSTSerializerBeta.h b/Firestore/Source/Remote/FSTSerializerBeta.h index f2fb4f51abc..4b6c0876ba7 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.h +++ b/Firestore/Source/Remote/FSTSerializerBeta.h @@ -100,7 +100,8 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query; - (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target; -- (std::unique_ptr )decodedWatchChange:(GCFSListenResponse *)watchChange; +- (std::unique_ptr)decodedWatchChange: + (GCFSListenResponse *)watchChange; - (firebase::firestore::model::SnapshotVersion)versionFromListenResponse: (GCFSListenResponse *)watchChange; diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index d8e23d72af9..73b328998df 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -1115,7 +1115,8 @@ - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { util::Status cause; if (change.hasCause) { - cause = util::Status{static_cast(change.cause.code), util::MakeString(change.cause.message)}; + cause = util::Status{static_cast(change.cause.code), + util::MakeString(change.cause.message)}; } return absl::make_unique(state, std::move(targetIDs), resumeToken, @@ -1185,8 +1186,8 @@ - (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_Target DocumentKey key = [self decodedDocumentKey:change.document]; std::vector removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray]; - return absl::make_unique( - std::vector{}, std::move(removedTargetIDs), std::move(key), nil); + return absl::make_unique(std::vector{}, + std::move(removedTargetIDs), std::move(key), nil); } - (std::unique_ptr)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter { diff --git a/Firestore/Source/Remote/FSTStream.h b/Firestore/Source/Remote/FSTStream.h index 4c041080a32..d4183379329 100644 --- a/Firestore/Source/Remote/FSTStream.h +++ b/Firestore/Source/Remote/FSTStream.h @@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN * Called by the FSTWatchStream with changes and the snapshot versions included in in the * WatchChange responses sent back by the server. */ -- (void)watchStreamDidChange:(const firebase::firestore::remote::WatchChange&)change +- (void)watchStreamDidChange:(const firebase::firestore::remote::WatchChange &)change snapshotVersion:(const firebase::firestore::model::SnapshotVersion &)snapshotVersion; /** diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index eded4257528..67f8f93923c 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -26,6 +26,7 @@ #import #include +#include #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/types.h" @@ -112,8 +113,7 @@ class DocumentWatchChange : public WatchChange { FSTMaybeDocument* new_document_; }; -bool operator==(const DocumentWatchChange& lhs, - const DocumentWatchChange& rhs); +bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); /** * An `ExistenceFilterWatchChange` applies to the targets and is required to @@ -140,7 +140,7 @@ class ExistenceFilterWatchChange : public WatchChange { }; bool operator==(const ExistenceFilterWatchChange& lhs, - const ExistenceFilterWatchChange& rhs); + const ExistenceFilterWatchChange& rhs); enum class WatchTargetChangeState { NoChange, Added, Removed, Current, Reset }; @@ -211,8 +211,7 @@ class WatchTargetChange : public WatchChange { util::Status cause_; }; -bool operator==(const WatchTargetChange& lhs, - const WatchTargetChange& rhs); +bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs); } // namespace remote } // namespace firestore From 52b131de6097cf7ad54f604d80a58028f03ecabf Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 17:20:00 -0500 Subject: [PATCH 029/107] Small fixes --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 2 +- .../Tests/Remote/FSTRemoteEventTests.mm | 19 +++++++++++++------ Firestore/Source/Remote/FSTSerializerBeta.mm | 3 ++- .../firebase/firestore/remote/watch_change.mm | 13 ++++++++----- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index f2089b20d69..7d7a3ddb2d7 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -904,7 +904,7 @@ - (void)testPersistsResumeTokens { NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); WatchTargetChange watchChange{ - WatchTargetChangeState::Current, {targetID}, resumeToken, Status::OK()}; + WatchTargetChangeState::Current, {targetID}, resumeToken}; FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithSingleResultForKey:testutil::Key("foo/bar") diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index d8073b5dbf3..e1a631b0f19 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -63,6 +63,7 @@ return {}; } +// Degenerate case to end recursion. void AddChanges(std::vector> *result) { } @@ -72,6 +73,16 @@ void AddChanges(std::vector> *result, Head head, Ta AddChanges(result, std::move(tail)...); } +// Works around the fact that move-only types (in this case, `unique_ptr`) don't work with `initialzer_list`. +// Desired (doesn't work): +// +// std::unique_ptr x, y; +// std::vector> foo{std::move(x), std::move(y)}; +// +// Actual: +// +// std::unique_ptr x, y; +// std::vector> foo = Changes(std::move(x), std::move(y)); template std::vector> Changes(Args... args) { std::vector> result; @@ -135,7 +146,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or `NoOutstandingResponses` if all targets are already active. + * considered active, or an empty map if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. To modify this set during test execution, invoke * `[_targetMetadataProvider setSyncedKeys:forQueryData:]`. @@ -196,7 +207,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or `NoOutstandingResponses` if all targets are already active. + * considered active, or an empty map if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. * @param watchChanges The watch changes to apply before creating the remote event. Supported @@ -229,10 +240,6 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = absl::make_unique(ids{1, 4}, ids{2, 6}, newDoc.key, newDoc); - // std::vector> changes; - // changes.push_back(std::move(change1)); - // changes.push_back(std::move(change2)); - // Create a remote event that includes both `change1` and `change2` as well as a NO_CHANGE event // with the default resume token (`_resumeToken1`). // As `existingDoc` is provided as an existing key, any updates to this document will be treated diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 73b328998df..93e6f115035 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -1105,7 +1105,7 @@ - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange { - (std::unique_ptr)decodedTargetChangeFromWatchChange:(GCFSTargetChange *)change { WatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType]; - __block std::vector targetIDs; + __block std::vector targetIDs; [change.targetIdsArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { targetIDs.push_back(value); @@ -1142,6 +1142,7 @@ - (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_Target - (std::vector)decodedIntegerArray:(GPBInt32Array *)values { __block std::vector result; + result.reserve(values.count); [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { result.push_back(value); }]; diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.mm b/Firestore/core/src/firebase/firestore/remote/watch_change.mm index 277a7e32834..1f293c180b0 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.mm @@ -22,15 +22,18 @@ namespace firestore { namespace remote { +template +bool objc_equals(T* lhs, T* rhs) { + // `isEqual:` will return false if both objects are nil. + return (lhs == nil && rhs == nil) || [lhs isEqual:rhs]; +} + bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs) { - auto docs_equal = [](FSTMaybeDocument* lhs, FSTMaybeDocument* rhs) { - return (lhs == nil && rhs == nil) || [lhs isEqual:rhs]; - }; return lhs.updated_target_ids() == rhs.updated_target_ids() && lhs.removed_target_ids() == rhs.removed_target_ids() && lhs.document_key() == rhs.document_key() && - docs_equal(lhs.new_document(), rhs.new_document()); + objc_equal(lhs.new_document(), rhs.new_document()); } bool operator==(const ExistenceFilterWatchChange& lhs, @@ -40,7 +43,7 @@ bool operator==(const WatchTargetChange& lhs, const WatchTargetChange& rhs) { return lhs.state() == rhs.state() && lhs.target_ids() == rhs.target_ids() && - [lhs.resume_token() isEqual:rhs.resume_token()] && + objc_equals(lhs.resume_token(), rhs.resume_token()) && lhs.cause() == rhs.cause(); } From 35ce8cc667a908894ff0f7b0499d18e0a6b3c39d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 17:26:42 -0500 Subject: [PATCH 030/107] Get rid of ids alias --- .../Tests/Remote/FSTRemoteEventTests.mm | 97 ++++++++++--------- .../firebase/firestore/remote/watch_change.mm | 2 +- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index e1a631b0f19..e580f61293f 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -50,10 +50,19 @@ using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::util::MakeString; using firebase::firestore::util::Status; -// `make_unique` cannot deduce that the template parameter is intended to -// resolve to a vector of target ids when given an initialization list (e.g., -// {1, 2}). The type alias is deliberately very short to minimize boilderplate. -using ids = std::vector; + +std::unique_ptr MakeDocChange(std::vector updated, + std::vector removed, + DocumentKey key, + FSTMaybeDocument *doc) { + return absl::make_unique(std::move(updated), std::move(removed), + std::move(key), existingDoc); +} + +std::unique_ptr MakeTargetChange(WatchTargetChangeState state, + std::vector target_ids) { + return MakeTargetChange(state, std::move(target_ids)); +} NS_ASSUME_NONNULL_BEGIN @@ -73,8 +82,8 @@ void AddChanges(std::vector> *result, Head head, Ta AddChanges(result, std::move(tail)...); } -// Works around the fact that move-only types (in this case, `unique_ptr`) don't work with `initialzer_list`. -// Desired (doesn't work): +// Works around the fact that move-only types (in this case, `unique_ptr`) don't work with +// `initialzer_list`. Desired (doesn't work): // // std::unique_ptr x, y; // std::vector> foo{std::move(x), std::move(y)}; @@ -234,11 +243,11 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { [self queryDataForTargets:{1, 2, 3, 4, 5, 6}]}; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1, 2, 3}, ids{4, 5, 6}, existingDoc.key, + auto change1 = MakeDocChange({1, 2, 3}, {4, 5, 6}, existingDoc.key, existingDoc); FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique(ids{1, 4}, ids{2, 6}, newDoc.key, newDoc); + auto change2 = MakeDocChange({1, 4}, {2, 6}, newDoc.key, newDoc); // Create a remote event that includes both `change1` and `change2` as well as a NO_CHANGE event // with the default resume token (`_resumeToken1`). @@ -289,11 +298,11 @@ - (void)testWillIgnoreEventsForPendingTargets { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); - auto change3 = absl::make_unique(WatchTargetChangeState::Added, ids{1}); + auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); + auto change2 = MakeTargetChange(WatchTargetChangeState::Removed, {1}); + auto change3 = MakeTargetChange(WatchTargetChangeState::Added, {1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change4 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); + auto change4 = MakeDocChange({1}, {}, doc2.key, doc2); // We're waiting for the unwatch and watch ack std::unordered_map outstandingResponses{{1, 2}}; @@ -318,8 +327,8 @@ - (void)testWillIgnoreEventsForRemovedTargets { std::unordered_map targetMap{[self queryDataForTargets:{}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); + auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); + auto change2 = MakeTargetChange(WatchTargetChangeState::Removed, {1}); // We're waiting for the unwatch ack std::unordered_map outstandingResponses{{1, 1}}; @@ -342,20 +351,20 @@ - (void)testWillKeepResetMappingEvenWithUpdates { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); + auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); // Reset stream, ignoring doc1 - auto change2 = absl::make_unique(WatchTargetChangeState::Reset, ids{1}); + auto change2 = MakeTargetChange(WatchTargetChangeState::Reset, {1}); // Add doc2, doc3 FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change3 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); + auto change3 = MakeDocChange({1}, {}, doc2.key, doc2); FSTDocument *doc3 = FSTTestDoc("docs/3", 3, @{@"value" : @3}, FSTDocumentStateSynced); - auto change4 = absl::make_unique(ids{1}, ids{}, doc3.key, doc3); + auto change4 = MakeDocChange({1}, {}, doc3.key, doc3); // Remove doc2 again, should not show up in reset mapping - auto change5 = absl::make_unique(ids{}, ids{1}, doc2.key, doc2); + auto change5 = MakeDocChange({}, {1}, doc2.key, doc2); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -407,10 +416,10 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTDocument *doc1a = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{2}, doc1a.key, doc1a); + auto change1 = MakeDocChange({1}, {2}, doc1a.key, doc1a); FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique(ids{2}, ids{1}, doc1b.key, doc1b); + auto change2 = MakeDocChange({2}, {1}, doc1b.key, doc1b); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -437,7 +446,7 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; auto change = - absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); + MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -458,14 +467,14 @@ - (void)testTargetAddedChangeWillResetPreviousState { std::unordered_map targetMap{[self queryDataForTargets:{1, 3}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1, 3}, ids{2}, doc1.key, doc1); - auto change2 = absl::make_unique(WatchTargetChangeState::Current, ids{1, 2, 3}, + auto change1 = MakeDocChange({1, 3}, {2}, doc1.key, doc1); + auto change2 = MakeTargetChange(WatchTargetChangeState::Current, {1, 2, 3}, _resumeToken1); - auto change3 = absl::make_unique(WatchTargetChangeState::Removed, ids{1}); - auto change4 = absl::make_unique(WatchTargetChangeState::Removed, ids{2}); - auto change5 = absl::make_unique(WatchTargetChangeState::Added, ids{1}); + auto change3 = MakeTargetChange(WatchTargetChangeState::Removed, {1}); + auto change4 = MakeTargetChange(WatchTargetChangeState::Removed, {2}); + auto change5 = MakeTargetChange(WatchTargetChangeState::Added, {1}); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change6 = absl::make_unique(ids{1}, ids{3}, doc2.key, doc2); + auto change6 = MakeDocChange({1}, {3}, doc2.key, doc2); std::unordered_map outstandingResponses{{1, 2}, {2, 1}}; @@ -525,11 +534,11 @@ - (void)testExistenceFilterMismatchClearsTarget { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); + auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); + auto change2 = MakeDocChange({1}, {}, doc2.key, doc2); auto change3 = - absl::make_unique(WatchTargetChangeState::Current, ids{1}, _resumeToken1); + MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap @@ -608,9 +617,9 @@ - (void)testDocumentUpdate { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = absl::make_unique(ids{1}, ids{}, doc1.key, doc1); + auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); - auto change2 = absl::make_unique(ids{1}, ids{}, doc2.key, doc2); + auto change2 = MakeDocChange({1}, {}, doc2.key, doc2); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap @@ -725,7 +734,7 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); auto resolveLimboTarget = - absl::make_unique(WatchTargetChangeState::Current, ids{1}); + MakeTargetChange(WatchTargetChangeState::Current, {1}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -743,7 +752,7 @@ - (void)testSynthesizeDeletes { - (void)testDoesntSynthesizeDeletesForWrongState { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; - auto wrongState = absl::make_unique(WatchTargetChangeState::NoChange, ids{1}); + auto wrongState = MakeTargetChange(WatchTargetChangeState::NoChange, {1}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -758,7 +767,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { - (void)testDoesntSynthesizeDeletesForExistingDoc { std::unordered_map targetMap{[self queryDataForTargets:{3}]}; - auto hasDocument = absl::make_unique(WatchTargetChangeState::Current, ids{3}); + auto hasDocument = MakeTargetChange(WatchTargetChangeState::Current, {3}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -775,20 +784,20 @@ - (void)testSeparatesDocumentUpdates { std::unordered_map targetMap{[self queryDataForLimboTargets:{1}]}; FSTDocument *newDoc = FSTTestDoc("docs/new", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); - auto newDocChange = absl::make_unique(ids{1}, ids{}, newDoc.key, newDoc); + auto newDocChange = MakeDocChange({1}, {}, newDoc.key, newDoc); FSTDocument *existingDoc = FSTTestDoc("docs/existing", 1, @{@"some" : @"data"}, FSTDocumentStateSynced); auto existingDocChange = - absl::make_unique(ids{1}, ids{}, existingDoc.key, existingDoc); + MakeDocChange({1}, {}, existingDoc.key, existingDoc); FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc("docs/deleted", 1, NO); auto deletedDocChange = - absl::make_unique(ids{}, ids{1}, deletedDoc.key, deletedDoc); + MakeDocChange({}, {1}, deletedDoc.key, deletedDoc); FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); auto missingDocChange = - absl::make_unique(ids{}, ids{1}, missingDoc.key, missingDoc); + MakeDocChange({}, {1}, missingDoc.key, missingDoc); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -817,11 +826,11 @@ - (void)testTracksLimboDocuments { FSTDocument *doc3 = FSTTestDoc("docs/3", 1, @{@"key" : @"value"}, FSTDocumentStateSynced); // Target 2 is a limbo target - auto docChange1 = absl::make_unique(ids{1, 2}, ids{}, doc1.key, doc1); - auto docChange2 = absl::make_unique(ids{2}, ids{}, doc2.key, doc2); - auto docChange3 = absl::make_unique(ids{1}, ids{}, doc3.key, doc3); + auto docChange1 = MakeDocChange({1, 2}, {}, doc1.key, doc1); + auto docChange2 = MakeDocChange({2}, {}, doc2.key, doc2); + auto docChange3 = MakeDocChange({1}, {}, doc3.key, doc3); auto targetsChange = - absl::make_unique(WatchTargetChangeState::Current, ids{1, 2}); + MakeTargetChange(WatchTargetChangeState::Current, {1, 2}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.mm b/Firestore/core/src/firebase/firestore/remote/watch_change.mm index 1f293c180b0..56fccad0b4e 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.mm @@ -33,7 +33,7 @@ bool objc_equals(T* lhs, T* rhs) { return lhs.updated_target_ids() == rhs.updated_target_ids() && lhs.removed_target_ids() == rhs.removed_target_ids() && lhs.document_key() == rhs.document_key() && - objc_equal(lhs.new_document(), rhs.new_document()); + objc_equals(lhs.new_document(), rhs.new_document()); } bool operator==(const ExistenceFilterWatchChange& lhs, From 8230fbb713e753420e08784d05ede49c8de18702 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 17:28:00 -0500 Subject: [PATCH 031/107] Fixes --- .../Example/App/GoogleService-Info.plist | 42 +++++++------------ .../Example/Tests/Local/FSTLocalStoreTests.mm | 3 +- .../Tests/Remote/FSTRemoteEventTests.mm | 29 +++++-------- 3 files changed, 26 insertions(+), 48 deletions(-) diff --git a/Firestore/Example/App/GoogleService-Info.plist b/Firestore/Example/App/GoogleService-Info.plist index 0e35ab4a3d9..3f7547fb48d 100644 --- a/Firestore/Example/App/GoogleService-Info.plist +++ b/Firestore/Example/App/GoogleService-Info.plist @@ -2,39 +2,27 @@ - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-3940256099942544/2934735716 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-3940256099942544/4411468910 + API_KEY + correct_api_key + TRACKING_ID + correct_tracking_id CLIENT_ID - 174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11.apps.googleusercontent.com + correct_client_id REVERSED_CLIENT_ID - com.googleusercontent.apps.174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11 - API_KEY - AIzaSyB_QJO1AARQzdvEgzb-o8wQ9eag5V8ZVCI + correct_reversed_client_id + GOOGLE_APP_ID + 1:123:ios:123abc GCM_SENDER_ID - 174583568604 + correct_gcm_sender_id PLIST_VERSION 1 BUNDLE_ID - com.firebase.FirestoreExample + com.google.FirebaseSDKTests PROJECT_ID - varconst-9 - STORAGE_BUCKET - varconst-9.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:174583568604:ios:0459a01df1082630 + abc-xyz-123 DATABASE_URL - https://varconst-9.firebaseio.com + https://abc-xyz-123.firebaseio.com + STORAGE_BUCKET + project-id-123.storage.firebase.com - \ No newline at end of file + diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 7d7a3ddb2d7..3c4042579fb 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -903,8 +903,7 @@ - (void)testPersistsResumeTokens { TargetId targetID = queryData.targetID; NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); - WatchTargetChange watchChange{ - WatchTargetChangeState::Current, {targetID}, resumeToken}; + WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken}; FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider providerWithSingleResultForKey:testutil::Key("foo/bar") diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index e580f61293f..9fe4d35c4d2 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -60,7 +60,7 @@ } std::unique_ptr MakeTargetChange(WatchTargetChangeState state, - std::vector target_ids) { + std::vector target_ids) { return MakeTargetChange(state, std::move(target_ids)); } @@ -243,8 +243,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { [self queryDataForTargets:{1, 2, 3, 4, 5, 6}]}; FSTDocument *existingDoc = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); - auto change1 = MakeDocChange({1, 2, 3}, {4, 5, 6}, existingDoc.key, - existingDoc); + auto change1 = MakeDocChange({1, 2, 3}, {4, 5, 6}, existingDoc.key, existingDoc); FSTDocument *newDoc = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = MakeDocChange({1, 4}, {2, 6}, newDoc.key, newDoc); @@ -445,8 +444,7 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; - auto change = - MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); + auto change = MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -468,8 +466,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); auto change1 = MakeDocChange({1, 3}, {2}, doc1.key, doc1); - auto change2 = MakeTargetChange(WatchTargetChangeState::Current, {1, 2, 3}, - _resumeToken1); + auto change2 = MakeTargetChange(WatchTargetChangeState::Current, {1, 2, 3}, _resumeToken1); auto change3 = MakeTargetChange(WatchTargetChangeState::Removed, {1}); auto change4 = MakeTargetChange(WatchTargetChangeState::Removed, {2}); auto change5 = MakeTargetChange(WatchTargetChangeState::Added, {1}); @@ -537,8 +534,7 @@ - (void)testExistenceFilterMismatchClearsTarget { auto change1 = MakeDocChange({1}, {}, doc1.key, doc1); FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = MakeDocChange({1}, {}, doc2.key, doc2); - auto change3 = - MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); + auto change3 = MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap @@ -733,8 +729,7 @@ - (void)testSynthesizeDeletes { std::unordered_map targetMap{[self queryDataForLimboTargets:{1}]}; DocumentKey limboKey = testutil::Key("coll/limbo"); - auto resolveLimboTarget = - MakeTargetChange(WatchTargetChangeState::Current, {1}); + auto resolveLimboTarget = MakeTargetChange(WatchTargetChangeState::Current, {1}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap @@ -788,16 +783,13 @@ - (void)testSeparatesDocumentUpdates { FSTDocument *existingDoc = FSTTestDoc("docs/existing", 1, @{@"some" : @"data"}, FSTDocumentStateSynced); - auto existingDocChange = - MakeDocChange({1}, {}, existingDoc.key, existingDoc); + auto existingDocChange = MakeDocChange({1}, {}, existingDoc.key, existingDoc); FSTDeletedDocument *deletedDoc = FSTTestDeletedDoc("docs/deleted", 1, NO); - auto deletedDocChange = - MakeDocChange({}, {1}, deletedDoc.key, deletedDoc); + auto deletedDocChange = MakeDocChange({}, {1}, deletedDoc.key, deletedDoc); FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); - auto missingDocChange = - MakeDocChange({}, {1}, missingDoc.key, missingDoc); + auto missingDocChange = MakeDocChange({}, {1}, missingDoc.key, missingDoc); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 @@ -829,8 +821,7 @@ - (void)testTracksLimboDocuments { auto docChange1 = MakeDocChange({1, 2}, {}, doc1.key, doc1); auto docChange2 = MakeDocChange({2}, {}, doc2.key, doc2); auto docChange3 = MakeDocChange({1}, {}, doc3.key, doc3); - auto targetsChange = - MakeTargetChange(WatchTargetChangeState::Current, {1, 2}); + auto targetsChange = MakeTargetChange(WatchTargetChangeState::Current, {1, 2}); FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 From ceb3bee64208331b96aa1301c8c2d4826d94280b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 17:59:03 -0500 Subject: [PATCH 032/107] Move the test --- .../Firestore.xcodeproj/project.pbxproj | 8 ++--- .../Tests/Remote/FSTRemoteEventTests.mm | 10 ++++-- .../Tests/Remote/FSTSerializerBetaTests.mm | 28 ++++----------- .../Example/Tests/SpecTests/FSTSpecTests.mm | 2 ++ Firestore/Source/Local/FSTLocalStore.mm | 12 +++---- .../firestore/remote/watch_change_test.mm} | 36 +++++++++---------- 6 files changed, 45 insertions(+), 51 deletions(-) rename Firestore/{Example/Tests/Remote/FSTWatchChangeTests.mm => core/test/firebase/firestore/remote/watch_change_test.mm} (70%) diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 9a1f20b141e..29a0ab8dd64 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -111,7 +111,6 @@ 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */; }; 5492E0C72021557E00B64F25 /* FSTSerializerBetaTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */; }; 5492E0C92021557E00B64F25 /* FSTRemoteEventTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */; }; - 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */; }; 5495EB032040E90200EBA509 /* CodableGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */; }; 54995F6F205B6E12004EFFA0 /* leveldb_key_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */; }; 549CCA5020A36DBC00BCEB75 /* sorted_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */; }; @@ -202,6 +201,7 @@ B67BF449216EB43000CA9097 /* create_noop_connectivity_monitor.cc in Sources */ = {isa = PBXBuildFile; fileRef = B67BF448216EB43000CA9097 /* create_noop_connectivity_monitor.cc */; }; B686F2AF2023DDEE0028D6BE /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; }; B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2B02024FFD70028D6BE /* resource_path_test.cc */; }; + B68FC0E521F6848700A7055C /* watch_change_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B68FC0E421F6848700A7055C /* watch_change_test.mm */; }; B6BBE43121262CF400C6A53E /* grpc_stream_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6BBE42F21262CF400C6A53E /* grpc_stream_test.cc */; }; B6D1B68520E2AB1B00B35856 /* exponential_backoff_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D1B68420E2AB1A00B35856 /* exponential_backoff_test.cc */; }; B6D9649121544D4F00EB9CFB /* grpc_connection_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D9649021544D4F00EB9CFB /* grpc_connection_test.cc */; }; @@ -402,7 +402,6 @@ 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTFieldValueTests.mm; sourceTree = ""; }; 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTSerializerBetaTests.mm; sourceTree = ""; }; 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteEventTests.mm; sourceTree = ""; }; - 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTWatchChangeTests.mm; sourceTree = ""; }; 5495EB022040E90200EBA509 /* CodableGeoPointTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodableGeoPointTests.swift; sourceTree = ""; }; 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_key_test.cc; sourceTree = ""; }; 549CCA4C20A36DBB00BCEB75 /* sorted_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sorted_set_test.cc; sourceTree = ""; }; @@ -523,6 +522,7 @@ B67BF448216EB43000CA9097 /* create_noop_connectivity_monitor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = create_noop_connectivity_monitor.cc; sourceTree = ""; }; B686F2AD2023DDB20028D6BE /* field_path_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field_path_test.cc; sourceTree = ""; }; B686F2B02024FFD70028D6BE /* resource_path_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resource_path_test.cc; sourceTree = ""; }; + B68FC0E421F6848700A7055C /* watch_change_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = watch_change_test.mm; sourceTree = ""; }; B69CF05A219B9105004C434D /* FIRFirestore+Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FIRFirestore+Testing.h"; sourceTree = ""; }; B6BBE42F21262CF400C6A53E /* grpc_stream_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = grpc_stream_test.cc; sourceTree = ""; }; B6D1B68420E2AB1A00B35856 /* exponential_backoff_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exponential_backoff_test.cc; sourceTree = ""; }; @@ -701,6 +701,7 @@ 546854A720A3681B004BDBD5 /* remote */ = { isa = PBXGroup; children = ( + B68FC0E421F6848700A7055C /* watch_change_test.mm */, 546854A820A36867004BDBD5 /* datastore_test.mm */, B6D1B68420E2AB1A00B35856 /* exponential_backoff_test.cc */, B6D9649021544D4F00EB9CFB /* grpc_connection_test.cc */, @@ -1272,7 +1273,6 @@ children = ( 5492E0C32021557E00B64F25 /* FSTRemoteEventTests.mm */, 5492E0C12021557E00B64F25 /* FSTSerializerBetaTests.mm */, - 5492E0C52021557E00B64F25 /* FSTWatchChangeTests.mm */, ); path = Remote; sourceTree = ""; @@ -1981,6 +1981,7 @@ 5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */, 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */, 5492E03E2021401F00B64F25 /* FSTEventAccumulator.mm in Sources */, + B68FC0E521F6848700A7055C /* watch_change_test.mm in Sources */, 5492E067202154B900B64F25 /* FSTEventManagerTests.mm in Sources */, 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */, 54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */, @@ -2020,7 +2021,6 @@ DE2EF0881F3D0B6E003D0CDC /* FSTTreeSortedDictionaryTests.m in Sources */, 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */, 5492E065202154B900B64F25 /* FSTViewTests.mm in Sources */, - 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */, 5492E03C2021401F00B64F25 /* XCTestCase+Await.mm in Sources */, 618BBEAF20B89AAC00B5BCE7 /* annotations.pb.cc in Sources */, 5467FB08203E6A44009C9584 /* app_testing.mm in Sources */, diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 9fe4d35c4d2..b8a4e909636 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -56,12 +56,18 @@ DocumentKey key, FSTMaybeDocument *doc) { return absl::make_unique(std::move(updated), std::move(removed), - std::move(key), existingDoc); + std::move(key), doc); } std::unique_ptr MakeTargetChange(WatchTargetChangeState state, std::vector target_ids) { - return MakeTargetChange(state, std::move(target_ids)); + return absl::make_unique(state, std::move(target_ids)); +} + +std::unique_ptr MakeTargetChange(WatchTargetChangeState state, + std::vector target_ids, + NSData *token) { + return absl::make_unique(state, std::move(target_ids), token); } NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 5b6258261e8..c6a3c8099d9 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -808,9 +808,7 @@ - (void)testConvertsTargetChangeWithAdded { [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -828,9 +826,7 @@ - (void)testConvertsTargetChangeWithRemoved { [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -841,9 +837,7 @@ - (void)testConvertsTargetChangeWithNoChange { [listenResponse.targetChange.targetIdsArray addValue:1]; [listenResponse.targetChange.targetIdsArray addValue:4]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::TargetChange); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -861,9 +855,7 @@ - (void)testConvertsDocumentChangeWithTargetIds { [listenResponse.documentChange.targetIdsArray addValue:1]; [listenResponse.documentChange.targetIdsArray addValue:2]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -882,9 +874,7 @@ - (void)testConvertsDocumentChangeWithRemovedTargetIds { [listenResponse.documentChange.removedTargetIdsArray addValue:1]; [listenResponse.documentChange.targetIdsArray addValue:2]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -898,9 +888,7 @@ - (void)testConvertsDocumentChangeWithDeletions { [listenResponse.documentDelete.removedTargetIdsArray addValue:1]; [listenResponse.documentDelete.removedTargetIdsArray addValue:2]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } @@ -912,9 +900,7 @@ - (void)testConvertsDocumentChangeWithRemoves { [listenResponse.documentRemove.removedTargetIdsArray addValue:1]; [listenResponse.documentRemove.removedTargetIdsArray addValue:2]; - std::unique_ptr actualBase = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertEqual(actualBase->type(), WatchChange::Type::Document); - auto actual = static_cast(actualBase.get()); + std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; XCTAssertTrue(*actual == expected); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index fd254cbd106..ec780c8383c 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -683,6 +683,8 @@ - (void)validateActiveTargets { } if (!actualTargets.empty()) { + // Converting to an Objective-C class is a quick-and-dirty way to get + // a readable debug description of the context of the map. NSMutableDictionary *actualTargetsDictionary = [NSMutableDictionary dictionary]; for (const auto &kv : actualTargets) { actualTargetsDictionary[@(kv.first)] = kv.second; diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index e04a54c1fa8..6e2eea6493f 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -247,10 +247,11 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // Update the resume token if the change includes one. Don't clear any preexisting value. // Bump the sequence number as well, so that documents being removed now are ordered later // than documents that were previously removed from this target. - if (change.resumeToken.length > 0) { + NSData *resumeToken = change.resumeToken; + if (resumeToken.length > 0) { FSTQueryData *oldQueryData = queryData; queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshotVersion - resumeToken:change.resumeToken + resumeToken:resumeToken sequenceNumber:sequenceNumber]; self.targetIDs[boxedTargetID] = queryData; @@ -374,10 +375,9 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run( - "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { diff --git a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm b/Firestore/core/test/firebase/firestore/remote/watch_change_test.mm similarity index 70% rename from Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm rename to Firestore/core/test/firebase/firestore/remote/watch_change_test.mm index ed8537f67c3..3d02523dd68 100644 --- a/Firestore/Example/Tests/Remote/FSTWatchChangeTests.mm +++ b/Firestore/core/test/firebase/firestore/remote/watch_change_test.mm @@ -1,5 +1,5 @@ /* - * Copyright 2017 Google + * Copyright 2019 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,13 @@ * limitations under the License. */ -#import - #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "gtest/gtest.h" using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilter; @@ -31,38 +30,39 @@ NS_ASSUME_NONNULL_BEGIN -@interface FSTWatchChangeTests : XCTestCase -@end - -@implementation FSTWatchChangeTests +namespace firebase { +namespace firestore { +namespace remote { -- (void)testDocumentChange { +TEST(WatchChangeTest, CanCreateDocumentWatchChange) { FSTMaybeDocument *doc = FSTTestDoc("a/b", 1, @{}, FSTDocumentStateSynced); DocumentWatchChange change{{1, 2, 3}, {4, 5}, doc.key, doc}; - XCTAssertEqual(change.updated_target_ids().size(), 3); - XCTAssertEqual(change.removed_target_ids().size(), 2); + EXPECT_EQ(change.updated_target_ids().size(), 3); + EXPECT_EQ(change.removed_target_ids().size(), 2); // Testing object identity here is fine. - XCTAssertEqual(change.new_document(), doc); + EXPECT_EQ(change.new_document(), doc); } -- (void)testExistenceFilterChange { +TEST(WatchChangeTest, CanCreateExistenceFilterWatchChange) { ExistenceFilter filter{7}; ExistenceFilterWatchChange change{filter, 5}; - XCTAssertEqual(change.filter().count(), 7); - XCTAssertEqual(change.target_id(), 5); + EXPECT_EQ(change.filter().count(), 7); + EXPECT_EQ(change.target_id(), 5); } -- (void)testWatchTargetChange { +TEST(WatchChangeTest, CanCreateWatchTargetChange) { WatchTargetChange change{WatchTargetChangeState::Reset, { 1, 2, }}; - XCTAssertEqual(change.state(), WatchTargetChangeState::Reset); - XCTAssertEqual(change.target_ids().size(), 2); + EXPECT_EQ(change.state(), WatchTargetChangeState::Reset); + EXPECT_EQ(change.target_ids().size(), 2); } -@end +} // namespace remote +} // namespace firestore +} // namespace firebase NS_ASSUME_NONNULL_END From dd617dea2fac1c099fa1dbe791c935c518e4f420 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 18:03:05 -0500 Subject: [PATCH 033/107] Restore nooutstandingresponses variable --- .../Tests/Remote/FSTRemoteEventTests.mm | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b8a4e909636..7a3a5f33651 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -51,33 +51,10 @@ using firebase::firestore::util::MakeString; using firebase::firestore::util::Status; -std::unique_ptr MakeDocChange(std::vector updated, - std::vector removed, - DocumentKey key, - FSTMaybeDocument *doc) { - return absl::make_unique(std::move(updated), std::move(removed), - std::move(key), doc); -} - -std::unique_ptr MakeTargetChange(WatchTargetChangeState state, - std::vector target_ids) { - return absl::make_unique(state, std::move(target_ids)); -} - -std::unique_ptr MakeTargetChange(WatchTargetChangeState state, - std::vector target_ids, - NSData *token) { - return absl::make_unique(state, std::move(target_ids), token); -} - NS_ASSUME_NONNULL_BEGIN namespace { -std::unordered_map NoOutstandingResponses() { - return {}; -} - // Degenerate case to end recursion. void AddChanges(std::vector> *result) { } @@ -105,6 +82,28 @@ void AddChanges(std::vector> *result, Head head, Ta return result; } +// These helpers work around the fact that `make_unique` cannot deduce the +// desired type (`vector` in this case) from an initialization list +// (e.g., `{1,2}`). +std::unique_ptr MakeDocChange(std::vector updated, + std::vector removed, + DocumentKey key, + FSTMaybeDocument *doc) { + return absl::make_unique(std::move(updated), std::move(removed), + std::move(key), doc); +} + +std::unique_ptr MakeTargetChange(WatchTargetChangeState state, + std::vector target_ids) { + return absl::make_unique(state, std::move(target_ids)); +} + +std::unique_ptr MakeTargetChange(WatchTargetChangeState state, + std::vector target_ids, + NSData *token) { + return absl::make_unique(state, std::move(target_ids), token); +} + } // namespace @interface FSTRemoteEventTests : XCTestCase @@ -113,6 +112,7 @@ @interface FSTRemoteEventTests : XCTestCase @implementation FSTRemoteEventTests { NSData *_resumeToken1; FSTTestTargetMetadataProvider *_targetMetadataProvider; + std::unordered_map _noOutstandingResponses; } - (void)setUp { @@ -261,7 +261,7 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{existingDoc.key} changes:Changes(std::move(change1), std::move(change2))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); @@ -374,7 +374,7 @@ - (void)testWillKeepResetMappingEvenWithUpdates { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1.key} changes:Changes(std::move(change1), std::move(change2), std::move(change3), std::move(change4), @@ -400,7 +400,7 @@ - (void)testWillHandleSingleReset { WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; [aggregator handleTargetChange:change]; @@ -429,7 +429,7 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1a.key} changes:Changes(std::move(change1), std::move(change2))]; XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); @@ -454,7 +454,7 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change))]; @@ -515,7 +515,7 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; @@ -544,7 +544,7 @@ - (void)testExistenceFilterMismatchClearsTarget { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1.key, doc2.key} changes:Changes(std::move(change1), std::move(change2), std::move(change3))]; @@ -585,7 +585,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; @@ -625,7 +625,7 @@ - (void)testDocumentUpdate { FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change1), std::move(change2))]; @@ -677,7 +677,7 @@ - (void)testResumeTokensHandledPerTarget { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; @@ -704,7 +704,7 @@ - (void)testLastResumeTokenWins { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; @@ -739,7 +739,7 @@ - (void)testSynthesizeDeletes { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(resolveLimboTarget))]; @@ -757,7 +757,7 @@ - (void)testDoesntSynthesizeDeletesForWrongState { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(wrongState))]; @@ -773,7 +773,7 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{FSTTestDocKey(@"coll/limbo")} changes:Changes(std::move(hasDocument))]; @@ -800,7 +800,7 @@ - (void)testSeparatesDocumentUpdates { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{existingDoc.key, deletedDoc.key} changes:Changes(std::move(newDocChange), std::move(existingDocChange), std::move(deletedDocChange), @@ -832,7 +832,7 @@ - (void)testTracksLimboDocuments { FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap - outstandingResponses:NoOutstandingResponses() + outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(docChange1), std::move(docChange2), std::move(docChange3), std::move(targetsChange))]; From 9d80eea41ce8b27cce41218c6d655e5a93c0b4a3 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 18:19:50 -0500 Subject: [PATCH 034/107] Small fixes --- .../Tests/Remote/FSTRemoteEventTests.mm | 4 ++-- .../firebase/firestore/remote/watch_change.h | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 7a3a5f33651..b898fa312f6 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -161,7 +161,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or an empty map if all targets are already active. + * considered active, or `_noOutstandingResponses` if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. To modify this set during test execution, invoke * `[_targetMetadataProvider setSyncedKeys:forQueryData:]`. @@ -222,7 +222,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or an empty map if all targets are already active. + * considered active, or an `_noOutstandingResponses` all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. * @param watchChanges The watch changes to apply before creating the remote event. Supported diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index 67f8f93923c..68938600e26 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -46,22 +46,18 @@ namespace remote { */ class WatchChange { public: + // PORTING NOTE: `WatchChange` is expected to be downcast, but on C++ we can't + // rely on RTTI to be available. enum class Type { Document, ExistenceFilter, TargetChange, }; - explicit WatchChange(Type type) : type_{type} { - } virtual ~WatchChange() { } - Type type() const { - return type_; - } - - const Type type_; + virtual Type type() const = 0; }; /** @@ -76,13 +72,15 @@ class DocumentWatchChange : public WatchChange { std::vector removed_target_ids, model::DocumentKey document_key, FSTMaybeDocument* new_document) - : WatchChange{Type::Document}, + : updated_target_ids_{std::move(updated_target_ids)}, removed_target_ids_{std::move(removed_target_ids)}, document_key_{std::move(document_key)}, new_document_{new_document} { } + Type type() const override { return Type::Document; } + /** The new document applies to all of these targets. */ const std::vector& updated_target_ids() const { return updated_target_ids_; @@ -122,11 +120,12 @@ bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); class ExistenceFilterWatchChange : public WatchChange { public: ExistenceFilterWatchChange(ExistenceFilter filter, model::TargetId target_id) - : WatchChange{Type::ExistenceFilter}, - filter_{filter}, + : filter_{filter}, target_id_{target_id} { } + Type type() const override { return Type::ExistenceFilter; } + const ExistenceFilter& filter() const { return filter_; } @@ -169,13 +168,14 @@ class WatchTargetChange : public WatchChange { std::vector target_ids, NSData* resume_token, util::Status cause) - : WatchChange{Type::TargetChange}, - state_{state}, + : state_{state}, target_ids_{std::move(target_ids)}, resume_token_{resume_token}, cause_{std::move(cause)} { } + Type type() const override { return Type::TargetChange; } + /** What kind of change occurred to the watch target. */ WatchTargetChangeState state() const { return state_; From 836d4de03e62ec87cd101e903f76fa1008f23466 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 21 Jan 2019 18:20:54 -0500 Subject: [PATCH 035/107] style.sh --- .../firebase/firestore/remote/watch_change.h | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/watch_change.h b/Firestore/core/src/firebase/firestore/remote/watch_change.h index 68938600e26..885110c12c9 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_change.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_change.h @@ -72,14 +72,15 @@ class DocumentWatchChange : public WatchChange { std::vector removed_target_ids, model::DocumentKey document_key, FSTMaybeDocument* new_document) - : - updated_target_ids_{std::move(updated_target_ids)}, + : updated_target_ids_{std::move(updated_target_ids)}, removed_target_ids_{std::move(removed_target_ids)}, document_key_{std::move(document_key)}, new_document_{new_document} { } - Type type() const override { return Type::Document; } + Type type() const override { + return Type::Document; + } /** The new document applies to all of these targets. */ const std::vector& updated_target_ids() const { @@ -120,11 +121,12 @@ bool operator==(const DocumentWatchChange& lhs, const DocumentWatchChange& rhs); class ExistenceFilterWatchChange : public WatchChange { public: ExistenceFilterWatchChange(ExistenceFilter filter, model::TargetId target_id) - : filter_{filter}, - target_id_{target_id} { + : filter_{filter}, target_id_{target_id} { } - Type type() const override { return Type::ExistenceFilter; } + Type type() const override { + return Type::ExistenceFilter; + } const ExistenceFilter& filter() const { return filter_; @@ -168,13 +170,15 @@ class WatchTargetChange : public WatchChange { std::vector target_ids, NSData* resume_token, util::Status cause) - : state_{state}, + : state_{state}, target_ids_{std::move(target_ids)}, resume_token_{resume_token}, cause_{std::move(cause)} { } - Type type() const override { return Type::TargetChange; } + Type type() const override { + return Type::TargetChange; + } /** What kind of change occurred to the watch target. */ WatchTargetChangeState state() const { From 134acafd18cb66d31269697d66a44f77b807e010 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 15:37:11 -0500 Subject: [PATCH 036/107] Review feedback --- .../Tests/Remote/FSTRemoteEventTests.mm | 30 +++--------------- Firestore/Source/Remote/FSTRemoteStore.mm | 7 ++--- .../firebase/firestore/testutil/testutil.h | 31 +++++++++++++++++++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b898fa312f6..b58d60774c9 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -55,31 +55,9 @@ namespace { -// Degenerate case to end recursion. -void AddChanges(std::vector> *result) { -} - -template -void AddChanges(std::vector> *result, Head head, Tail... tail) { - result->push_back(std::move(head)); - AddChanges(result, std::move(tail)...); -} - -// Works around the fact that move-only types (in this case, `unique_ptr`) don't work with -// `initialzer_list`. Desired (doesn't work): -// -// std::unique_ptr x, y; -// std::vector> foo{std::move(x), std::move(y)}; -// -// Actual: -// -// std::unique_ptr x, y; -// std::vector> foo = Changes(std::move(x), std::move(y)); -template -std::vector> Changes(Args... args) { - std::vector> result; - AddChanges(&result, std::move(args)...); - return result; +template +std::vector> Changes(Elems... elems) { + return VectorOfUniquePtrs(std::move(elems)...); } // These helpers work around the fact that `make_unique` cannot deduce the @@ -222,7 +200,7 @@ - (void)setUp { * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. * @param outstandingResponses The number of outstanding ACKs a target has to receive before it is - * considered active, or an `_noOutstandingResponses` all targets are already active. + * considered active, or `_noOutstandingResponses` if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. * @param watchChanges The watch changes to apply before creating the remote event. Supported diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 78829e8bae4..bc503e2a0c9 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -267,11 +267,10 @@ - (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { } - (void)stopListeningToTargetID:(TargetId)targetID { - auto found = _listenTargets.find(targetID); - HARD_ASSERT(found != _listenTargets.end(), - "stopListeningToTargetID: target not currently watched: %s", targetID); + size_t num_erased = _listenTargets.erase(targetID); + HARD_ASSERT(num_erased == 1, "stopListeningToTargetID: target not currently watched: %s", + targetID); - _listenTargets.erase(found); if (_watchStream->IsOpen()) { [self sendUnwatchRequestForTargetID:@(targetID)]; } diff --git a/Firestore/core/test/firebase/firestore/testutil/testutil.h b/Firestore/core/test/firebase/firestore/testutil/testutil.h index 3db1fac2688..4701eda3e22 100644 --- a/Firestore/core/test/firebase/firestore/testutil/testutil.h +++ b/Firestore/core/test/firebase/firestore/testutil/testutil.h @@ -182,6 +182,37 @@ inline std::vector ResumeToken(int64_t snapshot_version) { return {snapshot_string.begin(), snapshot_string.end()}; } +// Degenerate case to end recursion of `MoveIntoVector`. +template +void MoveIntoVector(std::vector>* result) { +} + +template +void MoveIntoVector(std::vector>* result, + Head head, + Tail... tail) { + result->push_back(std::move(head)); + MoveIntoVector(result, std::move(tail)...); +} + +// Works around the fact that move-only types (in this case, `unique_ptr`) don't +// work with `initialzer_list`. Desired (doesn't work): +// +// std::unique_ptr x, y; +// std::vector> foo{std::move(x), std::move(y)}; +// +// Actual: +// +// std::unique_ptr x, y; +// std::vector> foo = Changes(std::move(x), +// std::move(y)); +template +std::vector> VectorOfUniquePtrs(Elems... elems) { + std::vector> result; + MoveIntoVector(&result, std::move(elems)...); + return result; +} + } // namespace testutil } // namespace firestore } // namespace firebase From f8dd5a55d789e9c645a56ad769e7806643ed6d78 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 15:43:37 -0500 Subject: [PATCH 037/107] Review feedback --- .../Example/Tests/Remote/FSTRemoteEventTests.mm | 1 + .../Tests/Remote/FSTSerializerBetaTests.mm | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b58d60774c9..e7ba8df3183 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -48,6 +48,7 @@ using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; +using firebase::firestore::testutil::VectorOfUniquePtrs; using firebase::firestore::util::MakeString; using firebase::firestore::util::Status; diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index c6a3c8099d9..ed5c1b0b9c2 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -81,7 +81,7 @@ bool Equals(const WatchChange &lhs, const WatchChange &rhs) { return static_cast(lhs) == static_cast(rhs); } -bool operator==(const WatchChange &lhs, const WatchChange &rhs) { +bool IsWatchChangeEqual(const WatchChange &lhs, const WatchChange &rhs) { if (lhs.type() != rhs.type()) { return false; } @@ -809,7 +809,7 @@ - (void)testConvertsTargetChangeWithAdded { [listenResponse.targetChange.targetIdsArray addValue:4]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsTargetChangeWithRemoved { @@ -827,7 +827,7 @@ - (void)testConvertsTargetChangeWithRemoved { [listenResponse.targetChange.targetIdsArray addValue:4]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsTargetChangeWithNoChange { @@ -838,7 +838,7 @@ - (void)testConvertsTargetChangeWithNoChange { [listenResponse.targetChange.targetIdsArray addValue:4]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsDocumentChangeWithTargetIds { @@ -856,7 +856,7 @@ - (void)testConvertsDocumentChangeWithTargetIds { [listenResponse.documentChange.targetIdsArray addValue:2]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsDocumentChangeWithRemovedTargetIds { @@ -875,7 +875,7 @@ - (void)testConvertsDocumentChangeWithRemovedTargetIds { [listenResponse.documentChange.targetIdsArray addValue:2]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsDocumentChangeWithDeletions { @@ -889,7 +889,7 @@ - (void)testConvertsDocumentChangeWithDeletions { [listenResponse.documentDelete.removedTargetIdsArray addValue:2]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } - (void)testConvertsDocumentChangeWithRemoves { @@ -901,7 +901,7 @@ - (void)testConvertsDocumentChangeWithRemoves { [listenResponse.documentRemove.removedTargetIdsArray addValue:2]; std::unique_ptr actual = [self.serializer decodedWatchChange:listenResponse]; - XCTAssertTrue(*actual == expected); + XCTAssertTrue(IsWatchChangeEqual(*actual, expected)); } @end From c02df531900d1d51f76394ef3c20d47665ea5579 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 15:47:53 -0500 Subject: [PATCH 038/107] comment --- Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index ed5c1b0b9c2..aa9a3cc997a 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -81,6 +81,7 @@ bool Equals(const WatchChange &lhs, const WatchChange &rhs) { return static_cast(lhs) == static_cast(rhs); } +// Compares two `WatchChange`s taking into account their actual derived type. bool IsWatchChangeEqual(const WatchChange &lhs, const WatchChange &rhs) { if (lhs.type() != rhs.type()) { return false; From ce17913634d80cee1b06fc8c64d1d6b6b7ea27ca Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 17:46:34 -0500 Subject: [PATCH 039/107] Appease linter --- Firestore/core/test/firebase/firestore/testutil/testutil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firestore/core/test/firebase/firestore/testutil/testutil.h b/Firestore/core/test/firebase/firestore/testutil/testutil.h index 4701eda3e22..3f19c777580 100644 --- a/Firestore/core/test/firebase/firestore/testutil/testutil.h +++ b/Firestore/core/test/firebase/firestore/testutil/testutil.h @@ -184,7 +184,7 @@ inline std::vector ResumeToken(int64_t snapshot_version) { // Degenerate case to end recursion of `MoveIntoVector`. template -void MoveIntoVector(std::vector>* result) { +void MoveIntoVector(std::vector>*) { } template From a87cf7e252dd5376718b01f65250ab0385adb200 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 17:58:05 -0500 Subject: [PATCH 040/107] Initial --- .../firebase/firestore/remote/remote_event.h | 108 ++++++++++++++++++ .../firebase/firestore/remote/remote_event.mm | 28 +++++ 2 files changed, 136 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/remote/remote_event.h create mode 100644 Firestore/core/src/firebase/firestore/remote/remote_event.mm diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h new file mode 100644 index 00000000000..904d2daa67c --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -0,0 +1,108 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ + +#if !defined(__OBJC__) +// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` +// (the latter is used to represent the resume token). +#error "This header only supports Objective-C++" +#endif // !defined(__OBJC__) + +#import + +#import "Firestore/Source/Remote/FSTRemoteEvent.h" + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" + +@class FSTMaybeDocument; +@class FSTTargetState; + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace remote { + +class WatchChangeAggregator { + public: + WatchChangeAggregator() { + } + + /** + * Processes and adds the DocumentWatchChange to the current set of changes. + */ + void HandleDocumentChange(const DocumentWatchChange& document_change); + + /** Processes and adds the WatchTargetChange to the current set of changes. */ + void HandleTargetChange(const WatchTargetChange& target_change); + + /** Removes the in-memory state for the provided target. */ + void RemoveTarget(model::TargetId target_id); + + /** + * Handles existence filters and synthesizes deletes for filter mismatches. + * Targets that are invalidated by filter mismatches are added to + * `targetMismatches`. + */ + void HandleExistenceFilter( + const ExistenceFilterWatchChange& existence_filter); + + /** + * Increment the number of acks needed from watch before we can consider the + * server to be 'in-sync' with the client's active targets. + */ + void RecordTargetRequest(model::TargetId target_id); + + /** + * Converts the current state into a remote event with the snapshot version + * taken from the initializer. + */ + FSTRemoteEvent* CreateRemoteEvent(const SnapshotVersion& snapshot_version); + + private: + /** The internal state of all tracked targets. */ + std::unordered_map target_states_; + + /** Keeps track of document to update */ + std::unordered_map pending_document_updates_; + + /** A mapping of document keys to their set of target IDs. */ + std::unordered_map, model::DocumentKeyHash> + pending_document_target_mappings_; + + /** + * A list of targets with existence filter mismatches. These targets are known to be inconsistent + * and their listens needs to be re-established by `RemoteStore`. + */ + std::unordered_set pending_target_resets_; + + id target_metadata_provider_; +}; + +} // namespace remote +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ + +NS_ASSUME_NONNULL_END diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm new file mode 100644 index 00000000000..0d0e0036c34 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" + +#import "Firestore/Source/Model/FSTDocument.h" + +namespace firebase { +namespace firestore { +namespace remote { + +} // namespace remote +} // namespace firestore +} // namespace firebase + From d6a137a694740aeb958a7bfaa10a05cf2bb8ca58 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 22 Jan 2019 19:00:38 -0500 Subject: [PATCH 041/107] wip --- .../firebase/firestore/remote/remote_event.h | 100 ++++++++++-- .../firebase/firestore/remote/remote_event.mm | 154 +++++++++++++++++- 2 files changed, 242 insertions(+), 12 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 904d2daa67c..29082aa2c20 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -25,8 +25,6 @@ #import -#import "Firestore/Source/Remote/FSTRemoteEvent.h" - #include #include @@ -35,6 +33,7 @@ #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTMaybeDocument; +@class FSTRemoteEvent; @class FSTTargetState; NS_ASSUME_NONNULL_BEGIN @@ -43,6 +42,85 @@ namespace firebase { namespace firestore { namespace remote { +/** Tracks the internal state of a Watch target. */ +class TargetState { + public: + TargetState(); + + /** + * Whether this target has been marked 'current'. + * + * 'Current' has special meaning in the RPC protocol: It implies that the + * Watch backend has sent us all changes up to the point at which the target + * was added and that the target is consistent with the rest of the watch + * stream. + */ + bool IsCurrent() const { + return is_current_; + } + + /** The last resume token sent to us for this target. */ + NSData* resume_token() { + return resume_token_; + } + + /** Whether we have modified any state that should trigger a snapshot. */ + bool HasPendingChanges() const { + return has_pending_changes_; + } + + /** Whether this target has pending target adds or target removes. */ + bool IsPending() const { + return outstanding_responses_ != 0; + } + + /** + * Applies the resume token to the `TargetChange`, but only when it has a new + * value. Empty resume tokens are discarded. + */ + void UpdateResumeToken(NSData* resume_token); + + /** Resets the document changes and sets `HasPendingChanges` to false. */ + void ClearPendingChanges(); + + /** + * Creates a target change from the current set of changes. + * + * To reset the document changes after raising this snapshot, call + * `ClearPendingChanges()`. + */ + FSTTargetChange* ToTargetChange() const; + + void RecordTargetRequest(); + void RecordTargetResponse(); + void MarkCurrent(); + void AddDocumentChange((const DocumentKey& document_key, FSTDocumentViewChangeType type); + void RemoveDocumentChange(const DocumentKey& document_key); + + private: + // We initialize to 'true' so that newly-added targets are included in the next RemoteEvent. + bool has_pending_changes_ = true; + + bool is_current_ = false; + + /** + * The number of outstanding responses (adds or removes) that we are waiting + * on. We only consider targets active that have no outstanding responses. + */ + int outstanding_responses_ = 0; + + /** + * Keeps track of the document changes since the last raised snapshot. + * + * These changes are continuously updated as we receive document updates and + * always reflect the current set of changes against the last issued snapshot. + */ + std::unordered_map + document_changes_; + + NSData* resume_token_; +}; + class WatchChangeAggregator { public: WatchChangeAggregator() { @@ -56,9 +134,6 @@ class WatchChangeAggregator { /** Processes and adds the WatchTargetChange to the current set of changes. */ void HandleTargetChange(const WatchTargetChange& target_change); - /** Removes the in-memory state for the provided target. */ - void RemoveTarget(model::TargetId target_id); - /** * Handles existence filters and synthesizes deletes for filter mismatches. * Targets that are invalidated by filter mismatches are added to @@ -67,18 +142,21 @@ class WatchChangeAggregator { void HandleExistenceFilter( const ExistenceFilterWatchChange& existence_filter); - /** - * Increment the number of acks needed from watch before we can consider the - * server to be 'in-sync' with the client's active targets. - */ - void RecordTargetRequest(model::TargetId target_id); - /** * Converts the current state into a remote event with the snapshot version * taken from the initializer. */ FSTRemoteEvent* CreateRemoteEvent(const SnapshotVersion& snapshot_version); + /** Removes the in-memory state for the provided target. */ + void RemoveTarget(model::TargetId target_id); + + /** + * Increment the number of acks needed from watch before we can consider the + * server to be 'in-sync' with the client's active targets. + */ + void RecordTargetRequest(model::TargetId target_id); + private: /** The internal state of all tracked targets. */ std::unordered_map target_states_; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 0d0e0036c34..e02053d8a42 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -16,13 +16,165 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" +#include + #import "Firestore/Source/Model/FSTDocument.h" +#import "Firestore/Source/Remote/FSTRemoteEvent.h" + +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" + +using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::model::TargetId; namespace firebase { namespace firestore { namespace remote { +TargetState::TargetState() : resume_token_{[NSData data]} { +} + +void TargetState::UpdateResumeToken(NSData* resume_token) { + if (resume_token.length > 0) { + has_pending_changes_ = true; + resume_token_ = [resume_token copy]; + } +} + +void TargetState::ClearPendingChanges() { + has_pending_changes_ = false; + document_changes_.clear(); +} + +FSTTargetChange* TargetState::ToTargetChange() const { + DocumentKeySet added_documents; + DocumentKeySet modified_documents; + DocumentKeySet removed_documents; + + for (const auto& entry : document_changes) { + const DocumentKey& document_key = entry.first; + FSTDocumentViewChangeType change_type = entry.second; + + switch (change_type) { + case FSTDocumentViewChangeTypeAdded: + added_documents = added_documents.insert(document_key); + break; + case FSTDocumentViewChangeTypeModified: + modified_documents = modified_documents.insert(document_key); + break; + case FSTDocumentViewChangeTypeRemoved: + removed_documents = removed_documents.insert(document_key); + break; + default: + HARD_FAIL("Encountered invalid change type: %s", change_type); + } + } + + return [[FSTTargetChange alloc] + initWithResumeToken:resume_token() + current:IsCurrent() + addedDocuments:std::move(added_documents) + modifiedDocuments:std::move(modified_documents) + removedDocuments:std::move(removed_documents)]; +} + +void TargetState::RecordTargetRequest() { + ++outstanding_responses_; +} + +void TargetState::RecordTargetResponse() { + --outstanding_responses_; +} + +void TargetState::MarkCurrent() { + has_pending_changes_ = true; + current_ = true; +} + +void TargetState::AddDocumentChange(const DocumentKey& document_key, + FSTDocumentViewChangeType type) { + has_pending_changes_ = true; + document_changes_[document_key] = type; +} + +void TargetState::RemoveDocumentChange(const DocumentKey& document_key) { + has_pending_changes_ = true; + document_changes_.erase(document_key); +} + +// WatchChangeAggregator + +void WatchChangeAggregator::HandleDocumentChange( + const DocumentWatchChange& document_change) { + for (TargetId target_id : document_change.updated_target_ids()) { + if ([document_change.new_document() isKindOfClass:[FSTDocument class]]) { + AddDocumentToTarget(target_id, document_change.new_document()); + } else if ([documentChange.new_document() + isKindOfClass:[FSTDeletedDocument class]]) { + RemoveDocumentFromTarget(target_id, document_change.document_key(), + document_change.new_document()); + } + } + + for (TargetId target_id : document_change.removed_target_ids()) { + RemoveDocumentFromTarget(target_id, document_change.document_key(), + document_change.new_document()); + } +} + +void WatchChangeAggregator::HandleTargetChange( + const WatchTargetChange& target_change) { + // TODO +} + +void WatchChangeAggregator::HandleExistenceFilter( + const ExistenceFilterWatchChange& existence_filter) { + // TODO +} + +FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( + const SnapshotVersion& snapshot_version) { + // TODO +} + +void WatchChangeAggregator::RecordTargetRequest(TargetId target_id) { + // For each request we get we need to record we need a response for it. + TargetState& target_state = EnsureTargetState(target_id); + target_state.RecordTargetRequest(); +} + +void WatchChangeAggregator::RemoveTarget(TargetId target_id) { + target_states_.erase(target_id); +} + +void WatchChangeAggregator::AddDocumentToTarget(FSTMaybeDocument* document, + TargetId target_id) { + if (!IsActiveTarget(target_id)) { + return; + } + + FSTDocumentViewChangeType change_type = + ContainsDocument(document.key, target_id) + ? FSTDocumentViewChangeTypeModified + : FSTDocumentViewChangeTypeAdded; + + TargetState& target_state = EnsureTargetState(target_id); + target_state.AddDocumentChange(document.key, change_type); + + pending_document_updates_[document.key] = document; + pending_document_target_mappings_[document.key].insert(target_id); +} + +bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, + const DocumentKey& key) { + const DocumentKeySet& existing_keys = + [_targetMetadataProvider remoteKeysForTarget:targetID]; + return existing_keys.contains(key); +} + +TargetState& EnsureTargetState(TargetId target_id) { + return target_states_[target_id]; +} + } // namespace remote } // namespace firestore } // namespace firebase - From 1c99679ba643a758dee6d85436a11edbc267db9c Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 14:44:14 -0500 Subject: [PATCH 042/107] wip --- Firestore/core/src/firebase/firestore/remote/remote_event.h | 4 ++-- Firestore/core/src/firebase/firestore/remote/remote_event.mm | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 29082aa2c20..47811d6932c 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -34,7 +34,7 @@ @class FSTMaybeDocument; @class FSTRemoteEvent; -@class FSTTargetState; +@class FSTTargetChange; NS_ASSUME_NONNULL_BEGIN @@ -115,7 +115,7 @@ class TargetState { * These changes are continuously updated as we receive document updates and * always reflect the current set of changes against the last issued snapshot. */ - std::unordered_map + std::unordered_map document_changes_; NSData* resume_token_; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index e02053d8a42..58be0d6fc39 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -134,6 +134,7 @@ FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( const SnapshotVersion& snapshot_version) { // TODO + return nil; } void WatchChangeAggregator::RecordTargetRequest(TargetId target_id) { From b2e0dd181b5cc066c2ef0b824cabf64c69c29221 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 17:14:26 -0500 Subject: [PATCH 043/107] Initial --- .../Tests/API/FIRQuerySnapshotTests.mm | 5 +- Firestore/Example/Tests/API/FSTAPIHelpers.mm | 3 +- .../Tests/Core/FSTQueryListenerTests.mm | 27 ++++++----- .../Example/Tests/Core/FSTViewSnapshotTest.mm | 46 +++++++++--------- Firestore/Example/Tests/Core/FSTViewTests.mm | 39 +++++++-------- .../Example/Tests/SpecTests/FSTSpecTests.mm | 11 +++-- Firestore/Source/API/FIRDocumentChange.mm | 18 +++---- Firestore/Source/Core/FSTEventManager.mm | 3 +- Firestore/Source/Core/FSTView.mm | 31 ++++++------ Firestore/Source/Core/FSTViewSnapshot.h | 16 ++----- Firestore/Source/Core/FSTViewSnapshot.mm | 47 ++++++++++--------- Firestore/Source/Local/FSTLocalViewChanges.mm | 5 +- Firestore/Source/Remote/FSTRemoteEvent.mm | 21 +++++---- 13 files changed, 138 insertions(+), 134 deletions(-) diff --git a/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm index 1a8e716926a..77b4a8d3524 100644 --- a/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm +++ b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm @@ -31,6 +31,7 @@ #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::firestore::core::DocumentViewChangeType; NS_ASSUME_NONNULL_BEGIN @@ -82,8 +83,8 @@ - (void)testIncludeMetadataChanges { FSTDocumentSet *oldDocuments = FSTTestDocSet(FSTDocumentComparatorByKey, @[ doc1Old, doc2Old ]); FSTDocumentSet *newDocuments = FSTTestDocSet(FSTDocumentComparatorByKey, @[ doc2New, doc2New ]); NSArray *documentChanges = @[ - [FSTDocumentViewChange changeWithDocument:doc1New type:FSTDocumentViewChangeTypeMetadata], - [FSTDocumentViewChange changeWithDocument:doc2New type:FSTDocumentViewChangeTypeModified], + [FSTDocumentViewChange changeWithDocument:doc1New type:DocumentViewChangeType::Metadata], + [FSTDocumentViewChange changeWithDocument:doc2New type:DocumentViewChangeType::Modified], ]; FIRFirestore *firestore = FSTTestFirestore(); diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.mm b/Firestore/Example/Tests/API/FSTAPIHelpers.mm index 8e783c364b2..06bb690cc97 100644 --- a/Firestore/Example/Tests/API/FSTAPIHelpers.mm +++ b/Firestore/Example/Tests/API/FSTAPIHelpers.mm @@ -38,6 +38,7 @@ namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; +using firebase::firestore::core::DocumentViewChangeType; NS_ASSUME_NONNULL_BEGIN @@ -117,7 +118,7 @@ documentChanges = [documentChanges arrayByAddingObject:[FSTDocumentViewChange changeWithDocument:docToAdd - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; if (hasPendingWrites) { const std::string documentKey = util::StringFormat("%s/%s", path, key); mutatedKeys = mutatedKeys.insert(testutil::Key(documentKey)); diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm index 60bac8108f8..b7ee55e0d7f 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm @@ -31,6 +31,7 @@ #include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" #include "absl/memory/memory.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::OnlineState; using firebase::firestore::util::ExecutorLibdispatch; @@ -87,13 +88,13 @@ - (void)testRaisesCollectionEvents { FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2prime ], nil); FSTDocumentViewChange *change1 = - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change2 = - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change3 = - [FSTDocumentViewChange changeWithDocument:doc2prime type:FSTDocumentViewChangeTypeModified]; + [FSTDocumentViewChange changeWithDocument:doc2prime type:DocumentViewChangeType::Modified]; FSTDocumentViewChange *change4 = - [FSTDocumentViewChange changeWithDocument:doc2prime type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc2prime type:DocumentViewChangeType::Added]; [listener queryDidChangeViewSnapshot:snap1]; [listener queryDidChangeViewSnapshot:snap2]; @@ -252,13 +253,13 @@ - (void)testRaisesDocumentMetadataEventsOnlyWhenSpecified { FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc3 ], nil); FSTDocumentViewChange *change1 = - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change2 = - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change3 = - [FSTDocumentViewChange changeWithDocument:doc1Prime type:FSTDocumentViewChangeTypeMetadata]; + [FSTDocumentViewChange changeWithDocument:doc1Prime type:DocumentViewChangeType::Metadata]; FSTDocumentViewChange *change4 = - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Added]; [filteredListener queryDidChangeViewSnapshot:snap1]; [filteredListener queryDidChangeViewSnapshot:snap2]; @@ -346,7 +347,7 @@ - (void)testMetadataOnlyDocumentChangesAreFilteredOutWhenIncludeDocumentMetadata FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime, doc3 ], nil); FSTDocumentViewChange *change3 = - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Added]; [filteredListener queryDidChangeViewSnapshot:snap1]; [filteredListener queryDidChangeViewSnapshot:snap2]; @@ -390,9 +391,9 @@ - (void)testWillWaitForSyncIfOnline { [listener queryDidChangeViewSnapshot:snap3]; FSTDocumentViewChange *change1 = - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change2 = - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added]; FSTViewSnapshot *expectedSnap = [[FSTViewSnapshot alloc] initWithQuery:snap3.query documents:snap3.documents @@ -430,9 +431,9 @@ - (void)testWillRaiseInitialEventWhenGoingOffline { [listener queryDidChangeViewSnapshot:snap2]; // another event FSTDocumentViewChange *change1 = - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added]; FSTDocumentViewChange *change2 = - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]; + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added]; FSTViewSnapshot *expectedSnap1 = [[FSTViewSnapshot alloc] initWithQuery:query documents:snap1.documents diff --git a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm index 581341a6b0c..a3a20ae9158 100644 --- a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm +++ b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm @@ -24,6 +24,8 @@ #import "Firestore/Example/Tests/Util/FSTHelpers.h" +using firebase::firestore::core::DocumentViewChangeType; + NS_ASSUME_NONNULL_BEGIN @interface FSTViewSnapshotTests : XCTestCase @@ -33,7 +35,7 @@ @implementation FSTViewSnapshotTests - (void)testDocumentChangeConstructor { FSTDocument *doc = FSTTestDoc("a/b", 0, @{}, FSTDocumentStateSynced); - FSTDocumentViewChangeType type = FSTDocumentViewChangeTypeModified; + DocumentViewChangeType type = DocumentViewChangeType::Modified; FSTDocumentViewChange *change = [FSTDocumentViewChange changeWithDocument:doc type:type]; XCTAssertEqual(change.document, doc); XCTAssertEqual(change.type, type); @@ -53,56 +55,56 @@ - (void)testTrack { FSTDocument *docModifiedThenModified = FSTTestDoc("b/5", 0, @{}, FSTDocumentStateSynced); [set addChange:[FSTDocumentViewChange changeWithDocument:docAdded - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docRemoved - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docModified - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docAddedThenModified - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docAddedThenModified - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docAddedThenRemoved - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docAddedThenRemoved - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docRemovedThenAdded - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docRemovedThenAdded - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docModifiedThenRemoved - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docModifiedThenRemoved - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docModifiedThenModified - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; [set addChange:[FSTDocumentViewChange changeWithDocument:docModifiedThenModified - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; NSArray *changes = [set changes]; XCTAssertEqual(changes.count, 7); XCTAssertEqual(changes[0].document, docAdded); - XCTAssertEqual(changes[0].type, FSTDocumentViewChangeTypeAdded); + XCTAssertEqual(changes[0].type, DocumentViewChangeType::Added); XCTAssertEqual(changes[1].document, docRemoved); - XCTAssertEqual(changes[1].type, FSTDocumentViewChangeTypeRemoved); + XCTAssertEqual(changes[1].type, DocumentViewChangeType::Removed); XCTAssertEqual(changes[2].document, docModified); - XCTAssertEqual(changes[2].type, FSTDocumentViewChangeTypeModified); + XCTAssertEqual(changes[2].type, DocumentViewChangeType::Modified); XCTAssertEqual(changes[3].document, docAddedThenModified); - XCTAssertEqual(changes[3].type, FSTDocumentViewChangeTypeAdded); + XCTAssertEqual(changes[3].type, DocumentViewChangeType::Added); XCTAssertEqual(changes[4].document, docRemovedThenAdded); - XCTAssertEqual(changes[4].type, FSTDocumentViewChangeTypeModified); + XCTAssertEqual(changes[4].type, DocumentViewChangeType::Modified); XCTAssertEqual(changes[5].document, docModifiedThenRemoved); - XCTAssertEqual(changes[5].type, FSTDocumentViewChangeTypeRemoved); + XCTAssertEqual(changes[5].type, DocumentViewChangeType::Removed); XCTAssertEqual(changes[6].document, docModifiedThenModified); - XCTAssertEqual(changes[6].type, FSTDocumentViewChangeTypeModified); + XCTAssertEqual(changes[6].type, DocumentViewChangeType::Modified); } - (void)testViewSnapshotConstructor { @@ -113,7 +115,7 @@ - (void)testViewSnapshotConstructor { [documents documentSetByAddingDocument:FSTTestDoc("c/a", 1, @{}, FSTDocumentStateSynced)]; NSArray *documentChanges = @[ [FSTDocumentViewChange changeWithDocument:FSTTestDoc("c/a", 1, @{}, FSTDocumentStateSynced) - type:FSTDocumentViewChangeTypeAdded] ]; + type:DocumentViewChangeType::Added] ]; BOOL fromCache = YES; DocumentKeySet mutatedKeys; diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm index 759d7940669..6dafea15ca2 100644 --- a/Firestore/Example/Tests/Core/FSTViewTests.mm +++ b/Firestore/Example/Tests/Core/FSTViewTests.mm @@ -32,6 +32,7 @@ #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" namespace testutil = firebase::firestore::testutil; +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::ResourcePath; using firebase::firestore::model::DocumentKeySet; @@ -67,8 +68,8 @@ - (void)testAddsDocumentsBasedOnQuery { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded], - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added], + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added] ])); XCTAssertFalse(snapshot.isFromCache); @@ -101,8 +102,8 @@ - (void)testRemovesDocuments { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeRemoved], - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Removed], + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Added] ])); XCTAssertFalse(snapshot.isFromCache); @@ -162,9 +163,9 @@ - (void)testFiltersDocumentsBasedOnQueryWithFilter { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded], - [FSTDocumentViewChange changeWithDocument:doc5 type:FSTDocumentViewChangeTypeAdded], - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added], + [FSTDocumentViewChange changeWithDocument:doc5 type:DocumentViewChangeType::Added], + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added] ])); XCTAssertTrue(snapshot.isFromCache); @@ -209,9 +210,9 @@ - (void)testUpdatesDocumentsBasedOnQueryWithFilter { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeRemoved], - [FSTDocumentViewChange changeWithDocument:newDoc4 type:FSTDocumentViewChangeTypeAdded], - [FSTDocumentViewChange changeWithDocument:newDoc2 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Removed], + [FSTDocumentViewChange changeWithDocument:newDoc4 type:DocumentViewChangeType::Added], + [FSTDocumentViewChange changeWithDocument:newDoc2 type:DocumentViewChangeType::Added] ])); XCTAssertTrue(snapshot.isFromCache); @@ -243,8 +244,8 @@ - (void)testRemovesDocumentsForQueryWithLimit { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeRemoved], - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Removed], + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added] ])); XCTAssertFalse(snapshot.isFromCache); @@ -293,8 +294,8 @@ - (void)testDoesntReportChangesForDocumentBeyondLimitOfQuery { XCTAssertEqualObjects( snapshot.documentChanges, (@[ - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeRemoved], - [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Removed], + [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::Added] ])); XCTAssertFalse(snapshot.isFromCache); @@ -684,8 +685,8 @@ - (void)testSuppressesWriteAcknowledgementIfWatchHasNotCaughtUp { XCTAssertEqualObjects( (@[ - [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded], - [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded] + [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::Added], + [FSTDocumentViewChange changeWithDocument:doc2 type:DocumentViewChangeType::Added] ]), viewChange.snapshot.documentChanges); @@ -694,7 +695,7 @@ - (void)testSuppressesWriteAcknowledgementIfWatchHasNotCaughtUp { // The 'doc1Committed' update is suppressed XCTAssertEqualObjects( (@[ [FSTDocumentViewChange changeWithDocument:doc2Modified - type:FSTDocumentViewChangeTypeModified] ]), + type:DocumentViewChangeType::Modified] ]), viewChange.snapshot.documentChanges); changes = @@ -703,9 +704,9 @@ - (void)testSuppressesWriteAcknowledgementIfWatchHasNotCaughtUp { XCTAssertEqualObjects( (@[ [FSTDocumentViewChange changeWithDocument:doc1Acknowledged - type:FSTDocumentViewChangeTypeModified], + type:DocumentViewChangeType::Modified], [FSTDocumentViewChange changeWithDocument:doc2Acknowledged - type:FSTDocumentViewChangeTypeMetadata] + type:DocumentViewChangeType::Metadata] ]), viewChange.snapshot.documentChanges); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 04a2553fb05..b053f79141c 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -49,6 +49,7 @@ namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; using firebase::firestore::auth::User; +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; @@ -177,7 +178,7 @@ - (SnapshotVersion)parseVersion:(NSNumber *_Nullable)version { } - (FSTDocumentViewChange *)parseChange:(NSDictionary *)jsonDoc - ofType:(FSTDocumentViewChangeType)type { + ofType:(DocumentViewChangeType)type { NSNumber *version = jsonDoc[@"version"]; NSDictionary *options = jsonDoc[@"options"]; FSTDocumentState documentState = [options[@"hasLocalMutations"] isEqualToNumber:@YES] @@ -497,22 +498,22 @@ - (void)validateEvent:(FSTQueryEvent *)actual matches:(NSDictionary *)expected { NSMutableArray *removed = expected[@"removed"]; for (NSDictionary *changeSpec in removed) { [expectedChanges addObject:[self parseChange:changeSpec - ofType:FSTDocumentViewChangeTypeRemoved]]; + ofType:DocumentViewChangeType::Removed]]; } NSMutableArray *added = expected[@"added"]; for (NSDictionary *changeSpec in added) { [expectedChanges addObject:[self parseChange:changeSpec - ofType:FSTDocumentViewChangeTypeAdded]]; + ofType:DocumentViewChangeType::Added]]; } NSMutableArray *modified = expected[@"modified"]; for (NSDictionary *changeSpec in modified) { [expectedChanges addObject:[self parseChange:changeSpec - ofType:FSTDocumentViewChangeTypeModified]]; + ofType:DocumentViewChangeType::Modified]]; } NSMutableArray *metadata = expected[@"metadata"]; for (NSDictionary *changeSpec in metadata) { [expectedChanges addObject:[self parseChange:changeSpec - ofType:FSTDocumentViewChangeTypeMetadata]]; + ofType:DocumentViewChangeType::Metadata]]; } XCTAssertEqualObjects(actual.viewSnapshot.documentChanges, expectedChanges); diff --git a/Firestore/Source/API/FIRDocumentChange.mm b/Firestore/Source/API/FIRDocumentChange.mm index 973e4f73a9a..159196345e1 100644 --- a/Firestore/Source/API/FIRDocumentChange.mm +++ b/Firestore/Source/API/FIRDocumentChange.mm @@ -24,6 +24,8 @@ #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +using firebase::firestore::core::DocumentViewChangeType; + NS_ASSUME_NONNULL_BEGIN @interface FIRDocumentChange () @@ -38,12 +40,12 @@ - (instancetype)initWithType:(FIRDocumentChangeType)type @implementation FIRDocumentChange (Internal) + (FIRDocumentChangeType)documentChangeTypeForChange:(FSTDocumentViewChange *)change { - if (change.type == FSTDocumentViewChangeTypeAdded) { + if (change.type == DocumentViewChangeType::Added) { return FIRDocumentChangeTypeAdded; - } else if (change.type == FSTDocumentViewChangeTypeModified || - change.type == FSTDocumentViewChangeTypeMetadata) { + } else if (change.type == DocumentViewChangeType::Modified || + change.type == DocumentViewChangeType::Metadata) { return FIRDocumentChangeTypeModified; - } else if (change.type == FSTDocumentViewChangeTypeRemoved) { + } else if (change.type == DocumentViewChangeType::Removed) { return FIRDocumentChangeTypeRemoved; } else { HARD_FAIL("Unknown FSTDocumentViewChange: %s", change.type); @@ -66,7 +68,7 @@ + (FIRDocumentChangeType)documentChangeTypeForChange:(FSTDocumentViewChange *)ch document:change.document fromCache:snapshot.isFromCache hasPendingWrites:snapshot.mutatedKeys.contains(change.document.key)]; - HARD_ASSERT(change.type == FSTDocumentViewChangeTypeAdded, + HARD_ASSERT(change.type == DocumentViewChangeType::Added, "Invalid event type for first snapshot"); HARD_ASSERT(!lastDocument || snapshot.query.comparator(lastDocument, change.document) == NSOrderedAscending, @@ -83,7 +85,7 @@ + (FIRDocumentChangeType)documentChangeTypeForChange:(FSTDocumentViewChange *)ch FSTDocumentSet *indexTracker = snapshot.oldDocuments; NSMutableArray *changes = [NSMutableArray array]; for (FSTDocumentViewChange *change in snapshot.documentChanges) { - if (!includeMetadataChanges && change.type == FSTDocumentViewChangeTypeMetadata) { + if (!includeMetadataChanges && change.type == DocumentViewChangeType::Metadata) { continue; } @@ -96,12 +98,12 @@ + (FIRDocumentChangeType)documentChangeTypeForChange:(FSTDocumentViewChange *)ch NSUInteger oldIndex = NSNotFound; NSUInteger newIndex = NSNotFound; - if (change.type != FSTDocumentViewChangeTypeAdded) { + if (change.type != DocumentViewChangeType::Added) { oldIndex = [indexTracker indexOfKey:change.document.key]; HARD_ASSERT(oldIndex != NSNotFound, "Index for document not found"); indexTracker = [indexTracker documentSetByRemovingKey:change.document.key]; } - if (change.type != FSTDocumentViewChangeTypeRemoved) { + if (change.type != DocumentViewChangeType::Removed) { indexTracker = [indexTracker documentSetByAddingDocument:change.document]; newIndex = [indexTracker indexOfKey:change.document.key]; } diff --git a/Firestore/Source/Core/FSTEventManager.mm b/Firestore/Source/Core/FSTEventManager.mm index 224b841ff0e..fedfbd031ad 100644 --- a/Firestore/Source/Core/FSTEventManager.mm +++ b/Firestore/Source/Core/FSTEventManager.mm @@ -22,6 +22,7 @@ #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::OnlineState; using firebase::firestore::model::TargetId; @@ -127,7 +128,7 @@ - (void)queryDidChangeViewSnapshot:(FSTViewSnapshot *)snapshot { // Remove the metadata-only changes. NSMutableArray *changes = [NSMutableArray array]; for (FSTDocumentViewChange *change in snapshot.documentChanges) { - if (change.type != FSTDocumentViewChangeTypeMetadata) { + if (change.type != DocumentViewChangeType::Metadata) { [changes addObject:change]; } } diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index 2dc95d57eb7..3aa5dd89132 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -28,6 +28,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::MaybeDocumentMap; @@ -156,8 +157,8 @@ - (instancetype)initWithSnapshot:(nullable FSTViewSnapshot *)snapshot #pragma mark - FSTView -static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChangeType c1, - FSTDocumentViewChangeType c2); +static NSComparisonResult FSTCompareDocumentViewChangeTypes(firebase::firestore::core::DocumentViewChangeType c1, + firebase::firestore::core::DocumentViewChangeType c2); @interface FSTView () @@ -262,7 +263,7 @@ - (FSTViewDocumentChanges *)computeChangesWithDocuments:(const MaybeDocumentMap if (![self shouldWaitForSyncedDocument:newDoc oldDocument:oldDoc]) { [changeSet addChange:[FSTDocumentViewChange changeWithDocument:newDoc - type:FSTDocumentViewChangeTypeModified]]; + type:DocumentViewChangeType::Modified]]; changeApplied = YES; if (lastDocInLimit && self.query.comparator(newDoc, lastDocInLimit) > 0) { @@ -274,19 +275,19 @@ - (FSTViewDocumentChanges *)computeChangesWithDocuments:(const MaybeDocumentMap } else if (oldDocHadPendingMutations != newDocHasPendingMutations) { [changeSet addChange:[FSTDocumentViewChange changeWithDocument:newDoc - type:FSTDocumentViewChangeTypeMetadata]]; + type:DocumentViewChangeType::Metadata]]; changeApplied = YES; } } else if (!oldDoc && newDoc) { [changeSet addChange:[FSTDocumentViewChange changeWithDocument:newDoc - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; changeApplied = YES; } else if (oldDoc && !newDoc) { [changeSet addChange:[FSTDocumentViewChange changeWithDocument:oldDoc - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; changeApplied = YES; if (lastDocInLimit) { @@ -318,7 +319,7 @@ - (FSTViewDocumentChanges *)computeChangesWithDocuments:(const MaybeDocumentMap newMutatedKeys = newMutatedKeys.erase(oldDoc.key); [changeSet addChange:[FSTDocumentViewChange changeWithDocument:oldDoc - type:FSTDocumentViewChangeTypeRemoved]]; + type:DocumentViewChangeType::Removed]]; } } @@ -485,26 +486,26 @@ - (void)applyTargetChange:(nullable FSTTargetChange *)targetChange { @end -static inline int DocumentViewChangeTypePosition(FSTDocumentViewChangeType changeType) { +static inline int DocumentViewChangeTypePosition(DocumentViewChangeType changeType) { switch (changeType) { - case FSTDocumentViewChangeTypeRemoved: + case DocumentViewChangeType::Removed: return 0; - case FSTDocumentViewChangeTypeAdded: + case DocumentViewChangeType::Added: return 1; - case FSTDocumentViewChangeTypeModified: + case DocumentViewChangeType::Modified: return 2; - case FSTDocumentViewChangeTypeMetadata: + case DocumentViewChangeType::Metadata: // A metadata change is converted to a modified change at the public API layer. Since we sort // by document key and then change type, metadata and modified changes must be sorted // equivalently. return 2; default: - HARD_FAIL("Unknown FSTDocumentViewChangeType %s", changeType); + HARD_FAIL("Unknown DocumentViewChangeType %s", changeType); } } -static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChangeType c1, - FSTDocumentViewChangeType c2) { +static NSComparisonResult FSTCompareDocumentViewChangeTypes(DocumentViewChangeType c1, + DocumentViewChangeType c2) { int pos1 = DocumentViewChangeTypePosition(c1); int pos2 = DocumentViewChangeTypePosition(c2); if (pos1 == pos2) { diff --git a/Firestore/Source/Core/FSTViewSnapshot.h b/Firestore/Source/Core/FSTViewSnapshot.h index b67a2eedc44..4e85cefa843 100644 --- a/Firestore/Source/Core/FSTViewSnapshot.h +++ b/Firestore/Source/Core/FSTViewSnapshot.h @@ -16,6 +16,7 @@ #import +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" using firebase::firestore::model::DocumentKeySet; @@ -29,26 +30,15 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - FSTDocumentViewChange -/** - * The types of changes that can happen to a document with respect to a view. - * NOTE: We sort document changes by their type, so the ordering of this enum is significant. - */ -typedef NS_ENUM(NSInteger, FSTDocumentViewChangeType) { - FSTDocumentViewChangeTypeRemoved = 0, - FSTDocumentViewChangeTypeAdded, - FSTDocumentViewChangeTypeModified, - FSTDocumentViewChangeTypeMetadata, -}; - /** A change to a single document's state within a view. */ @interface FSTDocumentViewChange : NSObject - (id)init __attribute__((unavailable("Use a static constructor method."))); -+ (instancetype)changeWithDocument:(FSTDocument *)document type:(FSTDocumentViewChangeType)type; ++ (instancetype)changeWithDocument:(FSTDocument *)document type:(firebase::firestore::core::DocumentViewChangeType)type; /** The type of change for the document. */ -@property(nonatomic, assign, readonly) FSTDocumentViewChangeType type; +@property(nonatomic, assign, readonly) firebase::firestore::core::DocumentViewChangeType type; /** The document whose status changed. */ @property(nonatomic, strong, readonly) FSTDocument *document; diff --git a/Firestore/Source/Core/FSTViewSnapshot.mm b/Firestore/Source/Core/FSTViewSnapshot.mm index 7b356c4d4bf..b8d4d0f8ef0 100644 --- a/Firestore/Source/Core/FSTViewSnapshot.mm +++ b/Firestore/Source/Core/FSTViewSnapshot.mm @@ -30,6 +30,7 @@ #include "Firestore/core/src/firebase/firestore/util/string_format.h" #include "absl/strings/str_join.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::immutable::SortedMap; using firebase::firestore::model::DocumentKey; using firebase::firestore::util::WrapNSString; @@ -41,20 +42,20 @@ @interface FSTDocumentViewChange () -+ (instancetype)changeWithDocument:(FSTDocument *)document type:(FSTDocumentViewChangeType)type; ++ (instancetype)changeWithDocument:(FSTDocument *)document type:(DocumentViewChangeType)type; - (instancetype)initWithDocument:(FSTDocument *)document - type:(FSTDocumentViewChangeType)type NS_DESIGNATED_INITIALIZER; + type:(DocumentViewChangeType)type NS_DESIGNATED_INITIALIZER; @end @implementation FSTDocumentViewChange -+ (instancetype)changeWithDocument:(FSTDocument *)document type:(FSTDocumentViewChangeType)type { ++ (instancetype)changeWithDocument:(FSTDocument *)document type:(DocumentViewChangeType)type { return [[FSTDocumentViewChange alloc] initWithDocument:document type:type]; } -- (instancetype)initWithDocument:(FSTDocument *)document type:(FSTDocumentViewChangeType)type { +- (instancetype)initWithDocument:(FSTDocument *)document type:(DocumentViewChangeType)type { self = [super init]; if (self) { _document = document; @@ -111,42 +112,42 @@ - (void)addChange:(FSTDocumentViewChange *)change { FSTDocumentViewChange *oldChange = oldChangeIter->second; // Merge the new change with the existing change. - if (change.type != FSTDocumentViewChangeTypeAdded && - oldChange.type == FSTDocumentViewChangeTypeMetadata) { + if (change.type != DocumentViewChangeType::Added && + oldChange.type == DocumentViewChangeType::Metadata) { _changeMap = _changeMap.insert(key, change); - } else if (change.type == FSTDocumentViewChangeTypeMetadata && - oldChange.type != FSTDocumentViewChangeTypeRemoved) { + } else if (change.type == DocumentViewChangeType::Metadata && + oldChange.type != DocumentViewChangeType::Removed) { FSTDocumentViewChange *newChange = [FSTDocumentViewChange changeWithDocument:change.document type:oldChange.type]; _changeMap = _changeMap.insert(key, newChange); - } else if (change.type == FSTDocumentViewChangeTypeModified && - oldChange.type == FSTDocumentViewChangeTypeModified) { + } else if (change.type == DocumentViewChangeType::Modified && + oldChange.type == DocumentViewChangeType::Modified) { FSTDocumentViewChange *newChange = [FSTDocumentViewChange changeWithDocument:change.document - type:FSTDocumentViewChangeTypeModified]; + type:DocumentViewChangeType::Modified]; _changeMap = _changeMap.insert(key, newChange); - } else if (change.type == FSTDocumentViewChangeTypeModified && - oldChange.type == FSTDocumentViewChangeTypeAdded) { + } else if (change.type == DocumentViewChangeType::Modified && + oldChange.type == DocumentViewChangeType::Added) { FSTDocumentViewChange *newChange = [FSTDocumentViewChange changeWithDocument:change.document - type:FSTDocumentViewChangeTypeAdded]; + type:DocumentViewChangeType::Added]; _changeMap = _changeMap.insert(key, newChange); - } else if (change.type == FSTDocumentViewChangeTypeRemoved && - oldChange.type == FSTDocumentViewChangeTypeAdded) { + } else if (change.type == DocumentViewChangeType::Removed && + oldChange.type == DocumentViewChangeType::Added) { _changeMap = _changeMap.erase(key); - } else if (change.type == FSTDocumentViewChangeTypeRemoved && - oldChange.type == FSTDocumentViewChangeTypeModified) { + } else if (change.type == DocumentViewChangeType::Removed && + oldChange.type == DocumentViewChangeType::Modified) { FSTDocumentViewChange *newChange = [FSTDocumentViewChange changeWithDocument:oldChange.document - type:FSTDocumentViewChangeTypeRemoved]; + type:DocumentViewChangeType::Removed]; _changeMap = _changeMap.insert(key, newChange); - } else if (change.type == FSTDocumentViewChangeTypeAdded && - oldChange.type == FSTDocumentViewChangeTypeRemoved) { + } else if (change.type == DocumentViewChangeType::Added && + oldChange.type == DocumentViewChangeType::Removed) { FSTDocumentViewChange *newChange = [FSTDocumentViewChange changeWithDocument:change.document - type:FSTDocumentViewChangeTypeModified]; + type:DocumentViewChangeType::Modified]; _changeMap = _changeMap.insert(key, newChange); } else { // This includes these cases, which don't make sense: @@ -206,7 +207,7 @@ + (instancetype)snapshotForInitialDocuments:(FSTDocumentSet *)documents for (FSTDocument *doc in documents.documentEnumerator) { [viewChanges addObject:[FSTDocumentViewChange changeWithDocument:doc - type:FSTDocumentViewChangeTypeAdded]]; + type:DocumentViewChangeType::Added]]; } return [[FSTViewSnapshot alloc] initWithQuery:query diff --git a/Firestore/Source/Local/FSTLocalViewChanges.mm b/Firestore/Source/Local/FSTLocalViewChanges.mm index e88cb8fda97..4396190923c 100644 --- a/Firestore/Source/Local/FSTLocalViewChanges.mm +++ b/Firestore/Source/Local/FSTLocalViewChanges.mm @@ -21,6 +21,7 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Model/FSTDocument.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::TargetId; @@ -44,11 +45,11 @@ + (instancetype)changesForViewSnapshot:(FSTViewSnapshot *)viewSnapshot for (FSTDocumentViewChange *docChange in viewSnapshot.documentChanges) { switch (docChange.type) { - case FSTDocumentViewChangeTypeAdded: + case DocumentViewChangeType::Added: addedKeys = addedKeys.insert(docChange.document.key); break; - case FSTDocumentViewChangeTypeRemoved: + case DocumentViewChangeType::Removed: removedKeys = removedKeys.insert(docChange.document.key); break; diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index c8dee8f6c5a..8898f98a5de 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -33,6 +33,7 @@ #include "Firestore/core/src/firebase/firestore/util/hashing.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeyHash; using firebase::firestore::model::DocumentKeySet; @@ -135,7 +136,7 @@ - (FSTTargetChange *)toTargetChange; - (void)recordTargetRequest; - (void)recordTargetResponse; - (void)markCurrent; -- (void)addDocumentChangeWithType:(FSTDocumentViewChangeType)type +- (void)addDocumentChangeWithType:(DocumentViewChangeType)type forKey:(const DocumentKey &)documentKey; - (void)removeDocumentChangeForKey:(const DocumentKey &)documentKey; @@ -154,7 +155,7 @@ @implementation FSTTargetState { * These changes are continuously updated as we receive document updates and always reflect the * current set of changes against the last issued snapshot. */ - std::unordered_map _documentChanges; + std::unordered_map _documentChanges; } - (instancetype)init { @@ -197,7 +198,7 @@ - (void)markCurrent { _current = true; } -- (void)addDocumentChangeWithType:(FSTDocumentViewChangeType)type +- (void)addDocumentChangeWithType:(DocumentViewChangeType)type forKey:(const DocumentKey &)documentKey { _hasPendingChanges = YES; _documentChanges[documentKey] = type; @@ -215,13 +216,13 @@ - (FSTTargetChange *)toTargetChange { for (const auto &entry : _documentChanges) { switch (entry.second) { - case FSTDocumentViewChangeTypeAdded: + case DocumentViewChangeType::Added: addedDocuments = addedDocuments.insert(entry.first); break; - case FSTDocumentViewChangeTypeModified: + case DocumentViewChangeType::Modified: modifiedDocuments = modifiedDocuments.insert(entry.first); break; - case FSTDocumentViewChangeTypeRemoved: + case DocumentViewChangeType::Removed: removedDocuments = removedDocuments.insert(entry.first); break; default: @@ -481,9 +482,9 @@ - (void)addDocument:(FSTMaybeDocument *)document toTarget:(TargetId)targetID { return; } - FSTDocumentViewChangeType changeType = [self containsDocument:document.key inTarget:targetID] - ? FSTDocumentViewChangeTypeModified - : FSTDocumentViewChangeTypeAdded; + DocumentViewChangeType changeType = [self containsDocument:document.key inTarget:targetID] + ? DocumentViewChangeType::Modified + : DocumentViewChangeType::Added; FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; [targetState addDocumentChangeWithType:changeType forKey:document.key]; @@ -508,7 +509,7 @@ - (void)removeDocument:(FSTMaybeDocument *_Nullable)document FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; if ([self containsDocument:key inTarget:targetID]) { - [targetState addDocumentChangeWithType:FSTDocumentViewChangeTypeRemoved forKey:key]; + [targetState addDocumentChangeWithType:DocumentViewChangeType::Removed forKey:key]; } else { // The document may have entered and left the target before we raised a snapshot, so we can just // ignore the change. From e076f25817e59486080d15a51b2fd6281c6d9b39 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 17:15:40 -0500 Subject: [PATCH 044/107] style.sh --- Firestore/Example/Tests/API/FSTAPIHelpers.mm | 8 ++++---- Firestore/Example/Tests/SpecTests/FSTSpecTests.mm | 3 +-- Firestore/Source/Core/FSTView.mm | 5 +++-- Firestore/Source/Core/FSTViewSnapshot.h | 3 ++- Firestore/Source/Remote/FSTRemoteEvent.mm | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.mm b/Firestore/Example/Tests/API/FSTAPIHelpers.mm index 06bb690cc97..bced5089be1 100644 --- a/Firestore/Example/Tests/API/FSTAPIHelpers.mm +++ b/Firestore/Example/Tests/API/FSTAPIHelpers.mm @@ -115,10 +115,10 @@ FSTTestDoc(util::StringFormat("%s/%s", path, key), 1, docsToAdd[key], hasPendingWrites ? FSTDocumentStateLocalMutations : FSTDocumentStateSynced); newDocuments = [newDocuments documentSetByAddingDocument:docToAdd]; - documentChanges = [documentChanges - arrayByAddingObject:[FSTDocumentViewChange - changeWithDocument:docToAdd - type:DocumentViewChangeType::Added]]; + documentChanges = + [documentChanges arrayByAddingObject:[FSTDocumentViewChange + changeWithDocument:docToAdd + type:DocumentViewChangeType::Added]]; if (hasPendingWrites) { const std::string documentKey = util::StringFormat("%s/%s", path, key); mutatedKeys = mutatedKeys.insert(testutil::Key(documentKey)); diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index b053f79141c..f0d0536db27 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -177,8 +177,7 @@ - (SnapshotVersion)parseVersion:(NSNumber *_Nullable)version { return testutil::Version(version.longLongValue); } -- (FSTDocumentViewChange *)parseChange:(NSDictionary *)jsonDoc - ofType:(DocumentViewChangeType)type { +- (FSTDocumentViewChange *)parseChange:(NSDictionary *)jsonDoc ofType:(DocumentViewChangeType)type { NSNumber *version = jsonDoc[@"version"]; NSDictionary *options = jsonDoc[@"options"]; FSTDocumentState documentState = [options[@"hasLocalMutations"] isEqualToNumber:@YES] diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index 3aa5dd89132..01f5775ee65 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -157,8 +157,9 @@ - (instancetype)initWithSnapshot:(nullable FSTViewSnapshot *)snapshot #pragma mark - FSTView -static NSComparisonResult FSTCompareDocumentViewChangeTypes(firebase::firestore::core::DocumentViewChangeType c1, - firebase::firestore::core::DocumentViewChangeType c2); +static NSComparisonResult FSTCompareDocumentViewChangeTypes( + firebase::firestore::core::DocumentViewChangeType c1, + firebase::firestore::core::DocumentViewChangeType c2); @interface FSTView () diff --git a/Firestore/Source/Core/FSTViewSnapshot.h b/Firestore/Source/Core/FSTViewSnapshot.h index 4e85cefa843..4af098bb539 100644 --- a/Firestore/Source/Core/FSTViewSnapshot.h +++ b/Firestore/Source/Core/FSTViewSnapshot.h @@ -35,7 +35,8 @@ NS_ASSUME_NONNULL_BEGIN - (id)init __attribute__((unavailable("Use a static constructor method."))); -+ (instancetype)changeWithDocument:(FSTDocument *)document type:(firebase::firestore::core::DocumentViewChangeType)type; ++ (instancetype)changeWithDocument:(FSTDocument *)document + type:(firebase::firestore::core::DocumentViewChangeType)type; /** The type of change for the document. */ @property(nonatomic, assign, readonly) firebase::firestore::core::DocumentViewChangeType type; diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 8898f98a5de..154129d70aa 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -483,8 +483,8 @@ - (void)addDocument:(FSTMaybeDocument *)document toTarget:(TargetId)targetID { } DocumentViewChangeType changeType = [self containsDocument:document.key inTarget:targetID] - ? DocumentViewChangeType::Modified - : DocumentViewChangeType::Added; + ? DocumentViewChangeType::Modified + : DocumentViewChangeType::Added; FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; [targetState addDocumentChangeWithType:changeType forKey:document.key]; From 4b7c6a7dd46e4bb463209f6014754222f4a95393 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 17:47:16 -0500 Subject: [PATCH 045/107] forgotten file --- .../firebase/firestore/core/view_snapshot.h | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/core/view_snapshot.h diff --git a/Firestore/core/src/firebase/firestore/core/view_snapshot.h b/Firestore/core/src/firebase/firestore/core/view_snapshot.h new file mode 100644 index 00000000000..55ec48975d0 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/core/view_snapshot.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ + +namespace firebase { +namespace firestore { +namespace core { + +enum class DocumentViewChangeType { Removed, Added, Modified, Metadata }; + +} // namespace core +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_CORE_VIEW_SNAPSHOT_H_ From 48fbab65385c1719d27697f5c9c6b300a639cffa Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 18:33:11 -0500 Subject: [PATCH 046/107] pt. 1 compiles --- .../firebase/firestore/remote/remote_event.h | 81 ++++++++++++++++--- .../firebase/firestore/remote/remote_event.mm | 71 +++++++++++----- 2 files changed, 123 insertions(+), 29 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 47811d6932c..6355f8f1510 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -27,17 +27,44 @@ #include #include +#include +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTMaybeDocument; +@class FSTQueryData; @class FSTRemoteEvent; @class FSTTargetChange; NS_ASSUME_NONNULL_BEGIN +/** + * Interface implemented by RemoteStore to expose target metadata to the + * FSTWatchChangeAggregator. + */ +@protocol FSTTargetMetadataProvider + +/** + * Returns the set of remote document keys for the given target ID as of the + * last raised snapshot. + */ +- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: + (firebase::firestore::model::TargetId)targetID; + +/** + * Returns the FSTQueryData for an active target ID or 'null' if this query has + * become inactive + */ +- (nullable FSTQueryData*)queryDataForTarget: + (firebase::firestore::model::TargetId)targetID; + +@end + namespace firebase { namespace firestore { namespace remote { @@ -60,7 +87,7 @@ class TargetState { } /** The last resume token sent to us for this target. */ - NSData* resume_token() { + NSData* resume_token() const { return resume_token_; } @@ -94,11 +121,13 @@ class TargetState { void RecordTargetRequest(); void RecordTargetResponse(); void MarkCurrent(); - void AddDocumentChange((const DocumentKey& document_key, FSTDocumentViewChangeType type); - void RemoveDocumentChange(const DocumentKey& document_key); + void AddDocumentChange(const model::DocumentKey& document_key, + core::DocumentViewChangeType type); + void RemoveDocumentChange(const model::DocumentKey& document_key); private: - // We initialize to 'true' so that newly-added targets are included in the next RemoteEvent. + // We initialize to 'true' so that newly-added targets are included in the + // next RemoteEvent. bool has_pending_changes_ = true; bool is_current_ = false; @@ -115,7 +144,9 @@ class TargetState { * These changes are continuously updated as we receive document updates and * always reflect the current set of changes against the last issued snapshot. */ - std::unordered_map + std::unordered_map document_changes_; NSData* resume_token_; @@ -146,7 +177,8 @@ class WatchChangeAggregator { * Converts the current state into a remote event with the snapshot version * taken from the initializer. */ - FSTRemoteEvent* CreateRemoteEvent(const SnapshotVersion& snapshot_version); + FSTRemoteEvent* CreateRemoteEvent( + const model::SnapshotVersion& snapshot_version); /** Removes the in-memory state for the provided target. */ void RemoveTarget(model::TargetId target_id); @@ -158,19 +190,46 @@ class WatchChangeAggregator { void RecordTargetRequest(model::TargetId target_id); private: + void AddDocumentToTarget(model::TargetId target_id, + FSTMaybeDocument* document); + void RemoveDocumentFromTarget(model::TargetId target_id, + const model::DocumentKey& key, + FSTMaybeDocument* _Nullable updated_document); + bool TargetContainsDocument(model::TargetId target_id, + const model::DocumentKey& key); + + /** + * Returns true if the given target_id is active. Active targets are those for which there are no + * pending requests to add a listen and are in the current list of targets the client cares about. + * + * Clients can repeatedly listen and stop listening to targets, so this check is useful in + * preventing in preventing race conditions for a target where events arrive but the server hasn't + * yet acknowledged the intended change in state. + */ + bool IsActiveTarget(model::TargetId target_id) const; + FSTQueryData* QueryDataForActiveTarget(model::TargetId target_id) const; + + TargetState& EnsureTargetState(model::TargetId target_id); + /** The internal state of all tracked targets. */ - std::unordered_map target_states_; + std::unordered_map target_states_; /** Keeps track of document to update */ - std::unordered_map pending_document_updates_; + std::unordered_map + pending_document_updates_; /** A mapping of document keys to their set of target IDs. */ - std::unordered_map, model::DocumentKeyHash> + std::unordered_map, + model::DocumentKeyHash> pending_document_target_mappings_; /** - * A list of targets with existence filter mismatches. These targets are known to be inconsistent - * and their listens needs to be re-established by `RemoteStore`. + * A list of targets with existence filter mismatches. These targets are known + * to be inconsistent and their listens needs to be re-established by + * `RemoteStore`. */ std::unordered_set pending_target_resets_; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 58be0d6fc39..2231f218671 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -21,8 +21,9 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" - +using firebase::firestore::core::DocumentViewChangeType; +using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; @@ -50,18 +51,18 @@ DocumentKeySet modified_documents; DocumentKeySet removed_documents; - for (const auto& entry : document_changes) { + for (const auto& entry : document_changes_) { const DocumentKey& document_key = entry.first; - FSTDocumentViewChangeType change_type = entry.second; + DocumentViewChangeType change_type = entry.second; switch (change_type) { - case FSTDocumentViewChangeTypeAdded: + case DocumentViewChangeType::Added: added_documents = added_documents.insert(document_key); break; - case FSTDocumentViewChangeTypeModified: + case DocumentViewChangeType::Modified: modified_documents = modified_documents.insert(document_key); break; - case FSTDocumentViewChangeTypeRemoved: + case DocumentViewChangeType::Removed: removed_documents = removed_documents.insert(document_key); break; default: @@ -87,11 +88,11 @@ void TargetState::MarkCurrent() { has_pending_changes_ = true; - current_ = true; + is_current_ = true; } void TargetState::AddDocumentChange(const DocumentKey& document_key, - FSTDocumentViewChangeType type) { + DocumentViewChangeType type) { has_pending_changes_ = true; document_changes_[document_key] = type; } @@ -108,7 +109,7 @@ for (TargetId target_id : document_change.updated_target_ids()) { if ([document_change.new_document() isKindOfClass:[FSTDocument class]]) { AddDocumentToTarget(target_id, document_change.new_document()); - } else if ([documentChange.new_document() + } else if ([document_change.new_document() isKindOfClass:[FSTDeletedDocument class]]) { RemoveDocumentFromTarget(target_id, document_change.document_key(), document_change.new_document()); @@ -147,16 +148,16 @@ target_states_.erase(target_id); } -void WatchChangeAggregator::AddDocumentToTarget(FSTMaybeDocument* document, - TargetId target_id) { +void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, FSTMaybeDocument* document + ) { if (!IsActiveTarget(target_id)) { return; } - FSTDocumentViewChangeType change_type = - ContainsDocument(document.key, target_id) - ? FSTDocumentViewChangeTypeModified - : FSTDocumentViewChangeTypeAdded; + DocumentViewChangeType change_type = + TargetContainsDocument(target_id, document.key) + ? DocumentViewChangeType::Modified + : DocumentViewChangeType::Added; TargetState& target_state = EnsureTargetState(target_id); target_state.AddDocumentChange(document.key, change_type); @@ -165,14 +166,48 @@ pending_document_target_mappings_[document.key].insert(target_id); } +void WatchChangeAggregator::RemoveDocumentFromTarget( + TargetId target_id, + const DocumentKey& key, + FSTMaybeDocument* _Nullable updated_document) { + if (!IsActiveTarget(target_id)) { + return; + } + + TargetState& target_state = EnsureTargetState(target_id); + if (TargetContainsDocument(target_id, key)) { + target_state.AddDocumentChange(key, DocumentViewChangeType::Removed); + } else { + // The document may have entered and left the target before we raised a + // snapshot, so we can just ignore the change. + target_state.RemoveDocumentChange(key); + } + pending_document_target_mappings_[key].insert(target_id); + + if (updated_document) { + pending_document_updates_[key] = updated_document; + } +} + bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, const DocumentKey& key) { const DocumentKeySet& existing_keys = - [_targetMetadataProvider remoteKeysForTarget:targetID]; + [target_metadata_provider_ remoteKeysForTarget:target_id]; return existing_keys.contains(key); } -TargetState& EnsureTargetState(TargetId target_id) { +bool WatchChangeAggregator::IsActiveTarget(TargetId target_id) const { + return QueryDataForActiveTarget(target_id) != nil; +} + +FSTQueryData* WatchChangeAggregator::QueryDataForActiveTarget(TargetId target_id) const { + auto target_state = target_states_.find(target_id); + return target_state != target_states_.end() && target_state->second.IsPending() + ? nil + : [target_metadata_provider_ queryDataForTarget:target_id]; +} + +TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { return target_states_[target_id]; } From 0325248cb32ea8449404cd2cdd8b230284c2609f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 18:50:19 -0500 Subject: [PATCH 047/107] Wip --- .../firebase/firestore/remote/remote_event.mm | 80 +++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 2231f218671..08063ae085a 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -18,6 +18,8 @@ #include +#import "Firestore/Source/Core/FSTQuery.h" +#import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" @@ -134,8 +136,72 @@ FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( const SnapshotVersion& snapshot_version) { - // TODO - return nil; + std::unordered_map target_changes; + + for (auto& entry : target_states_) { + TargetId target_id = entry.first; + TargetState& target_state = entry.second; + + FSTQueryData* queryData = QueryDataForActiveTarget(target_id); + if (queryData) { + if (target_state.IsCurrent() && [queryData.query isDocumentQuery]) { + // Document queries for document that don't exist can produce an empty + // result set. To update our local cache, we synthesize a document + // delete if we have not previously received the document. This resolves + // the limbo state of the document, removing it from limboDocumentRefs. + DocumentKey key{queryData.query.path}; + if (pending_document_updates_.find(key) == + pending_document_updates_.end() && + !TargetContainsDocument(target_id, key)) { + RemoveDocumentFromTarget( + target_id, key, + [FSTDeletedDocument documentWithKey:key + version:snapshot_version + hasCommittedMutations:NO]); + } + } + + if (target_state.HasPendingChanges()) { + target_changes[target_id] = target_state.ToTargetChange(); + target_state.ClearPendingChanges(); + } + } + } + + DocumentKeySet resolved_limbo_documents; + + // We extract the set of limbo-only document updates as the GC logic + // special-cases documents that do not appear in the query cache. + // + // TODO(gsoltis): Expand on this comment. + for (const auto& entry : pending_document_target_mappings_) { + bool is_only_limbo_target = true; + + for (TargetId target_id : entry.second) { + FSTQueryData* queryData = QueryDataForActiveTarget(target_id); + if (queryData && queryData.purpose != FSTQueryPurposeLimboResolution) { + is_only_limbo_target = false; + break; + } + } + + if (is_only_limbo_target) { + resolved_limbo_documents = resolved_limbo_documents.insert(entry.first); + } + } + + FSTRemoteEvent* remote_event = + [[FSTRemoteEvent alloc] initWithSnapshotVersion:snapshot_version + targetChanges:target_changes + targetMismatches:pending_target_resets_ + documentUpdates:pending_document_updates_ + limboDocuments:resolved_limbo_documents]; + + pending_document_updates_.clear(); + pending_document_target_mappings_.clear(); + pending_target_resets_.clear(); + + return remote_event; } void WatchChangeAggregator::RecordTargetRequest(TargetId target_id) { @@ -148,8 +214,8 @@ target_states_.erase(target_id); } -void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, FSTMaybeDocument* document - ) { +void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, + FSTMaybeDocument* document) { if (!IsActiveTarget(target_id)) { return; } @@ -200,9 +266,11 @@ return QueryDataForActiveTarget(target_id) != nil; } -FSTQueryData* WatchChangeAggregator::QueryDataForActiveTarget(TargetId target_id) const { +FSTQueryData* WatchChangeAggregator::QueryDataForActiveTarget( + TargetId target_id) const { auto target_state = target_states_.find(target_id); - return target_state != target_states_.end() && target_state->second.IsPending() + return target_state != target_states_.end() && + target_state->second.IsPending() ? nil : [target_metadata_provider_ queryDataForTarget:target_id]; } From acbc626f9c78424fb3b462d91cff4498980c7736 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 23 Jan 2019 19:04:09 -0500 Subject: [PATCH 048/107] wip --- .../firebase/firestore/remote/remote_event.h | 25 ++++-- .../firebase/firestore/remote/remote_event.mm | 76 +++++++++++++++++-- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 6355f8f1510..83d6b1aff5b 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -199,16 +199,27 @@ class WatchChangeAggregator { const model::DocumentKey& key); /** - * Returns true if the given target_id is active. Active targets are those for which there are no - * pending requests to add a listen and are in the current list of targets the client cares about. - * - * Clients can repeatedly listen and stop listening to targets, so this check is useful in - * preventing in preventing race conditions for a target where events arrive but the server hasn't - * yet acknowledged the intended change in state. - */ + * Returns true if the given target_id is active. Active targets are those for + * which there are no pending requests to add a listen and are in the current + * list of targets the client cares about. + * + * Clients can repeatedly listen and stop listening to targets, so this check + * is useful in preventing in preventing race conditions for a target where + * events arrive but the server hasn't yet acknowledged the intended change in + * state. + */ bool IsActiveTarget(model::TargetId target_id) const; FSTQueryData* QueryDataForActiveTarget(model::TargetId target_id) const; + int GetCurrentDocumentCountForTarget(model::TargetId target_id); + + /** + * Resets the state of a Watch target to its initial state (e.g. sets + * 'current' to false, clears the resume token and removes its target mapping + * from all documents). + */ + void ResetTarget(model::TargetId target_id); + TargetState& EnsureTargetState(model::TargetId target_id); /** The internal state of all tracked targets. */ diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 08063ae085a..94e8b4c36e7 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -131,7 +131,69 @@ void WatchChangeAggregator::HandleExistenceFilter( const ExistenceFilterWatchChange& existence_filter) { - // TODO + TargetId target_id = existence_filter.target_id(); + int expected_count = existence_filter.filter().count(); + + FSTQueryData* query_data = QueryDataForActiveTarget(target_id); + if (query_data) { + FSTQuery* query = query_data.query; + if ([query isDocumentQuery]) { + if (expected_count == 0) { + // The existence filter told us the document does not exist. We deduce + // that this document does not exist and apply a deleted document to our + // updates. Without applying this deleted document there might be + // another query that will raise this document as part of a snapshot + // until it is resolved, essentially exposing inconsistency between + // queries. + DocumentKey key{query.path}; + RemoveDocumentFromTarget( + target_id, key, + [FSTDeletedDocument documentWithKey:key + version:SnapshotVersion::None() + hasCommittedMutations:NO]); + } else { + HARD_ASSERT(expected_count == 1, + "Single document existence filter with count: %s", + expected_count); + } + } else { + int current_size = GetCurrentDocumentCountForTarget(target_id); + if (current_size != expected_count) { + // Existence filter mismatch: We reset the mapping and raise a new + // snapshot with `isFromCache:true`. + ResetTarget(target_id); + pending_target_resets_.insert(target_id); + } + } + } +} + +int WatchChangeAggregator::GetCurrentDocumentCountForTarget( + TargetId target_id) { + TargetState& target_state = EnsureTargetState(target_id); + FSTTargetChange* target_change = target_state.ToTargetChange(); + return ([target_metadata_provider_ remoteKeysForTarget:target_id].size() + + target_change.addedDocuments.size() - + target_change.removedDocuments.size()); +} + +void WatchChangeAggregator::ResetTarget(TargetId target_id) { + auto current_target_state = target_states_.find(target_id); + HARD_ASSERT(current_target_state != target_states_.end() && + !(current_target_state->second.IsPending()), + "Should only reset active targets"); + + target_states_[target_id] = {}; + + // Trigger removal for any documents currently mapped to this target. These + // removals will be part of the initial snapshot if Watch does not resend + // these documents. + DocumentKeySet existingKeys = + [target_metadata_provider_ remoteKeysForTarget:target_id]; + + for (const DocumentKey& key : existingKeys) { + RemoveDocumentFromTarget(target_id, key, nil); + } } FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( @@ -142,14 +204,14 @@ TargetId target_id = entry.first; TargetState& target_state = entry.second; - FSTQueryData* queryData = QueryDataForActiveTarget(target_id); - if (queryData) { - if (target_state.IsCurrent() && [queryData.query isDocumentQuery]) { + FSTQueryData* query_data = QueryDataForActiveTarget(target_id); + if (query_data) { + if (target_state.IsCurrent() && [query_data.query isDocumentQuery]) { // Document queries for document that don't exist can produce an empty // result set. To update our local cache, we synthesize a document // delete if we have not previously received the document. This resolves // the limbo state of the document, removing it from limboDocumentRefs. - DocumentKey key{queryData.query.path}; + DocumentKey key{query_data.query.path}; if (pending_document_updates_.find(key) == pending_document_updates_.end() && !TargetContainsDocument(target_id, key)) { @@ -178,8 +240,8 @@ bool is_only_limbo_target = true; for (TargetId target_id : entry.second) { - FSTQueryData* queryData = QueryDataForActiveTarget(target_id); - if (queryData && queryData.purpose != FSTQueryPurposeLimboResolution) { + FSTQueryData* query_data = QueryDataForActiveTarget(target_id); + if (query_data && query_data.purpose != FSTQueryPurposeLimboResolution) { is_only_limbo_target = false; break; } From 78395d84bd4616b35253ca7b478dd20fdd9fb047 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 14:50:56 -0500 Subject: [PATCH 049/107] In theory, all methods implemented --- .../firebase/firestore/remote/remote_event.h | 3 + .../firebase/firestore/remote/remote_event.mm | 73 +++++++++++++++++-- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 83d6b1aff5b..8dcc48800d7 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -180,6 +180,9 @@ class WatchChangeAggregator { FSTRemoteEvent* CreateRemoteEvent( const model::SnapshotVersion& snapshot_version); + std::vector GetTargetIds( + const WatchTargetChange& target_change) const; + /** Removes the in-memory state for the provided target. */ void RemoveTarget(model::TargetId target_id); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index cd72ad3112c..53564072537 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -126,7 +126,74 @@ void WatchChangeAggregator::HandleTargetChange( const WatchTargetChange& target_change) { - // TODO + for (TargetId target_id : GetTargetIds(target_change)) { + TargetState& target_state = EnsureTargetState(target_id); + switch (target_change.state()) { + case WatchTargetChangeState::NoChange: + if (IsActiveTarget(target_id)) { + target_state.UpdateResumeToken(target_change.resume_token()); + } + break; + case WatchTargetChangeState::Added: + // We need to decrement the number of pending acks needed from watch for + // this target_id. + target_state.RecordTargetResponse(); + if (!target_state.IsPending()) { + // We have a freshly added target, so we need to reset any state that + // we had previously. This can happen e.g. when remove and add back a + // target for existence filter mismatches. + target_state.ClearPendingChanges(); + } + target_state.UpdateResumeToken(target_change.resume_token()); + break; + case WatchTargetChangeState::Removed: + // We need to keep track of removed targets to we can post-filter and + // remove any target changes. + target_state.RecordTargetResponse(); + if (!target_state.IsPending()) { + RemoveTarget(target_id); + } + HARD_ASSERT(target_change.cause().ok(), + "WatchChangeAggregator does not handle errored targets"); + break; + case WatchTargetChangeState::Current: + if (IsActiveTarget(target_id)) { + target_state.MarkCurrent(); + target_state.UpdateResumeToken(target_change.resume_token()); + } + break; + case WatchTargetChangeState::Reset: + if (IsActiveTarget(target_id)) { + // Reset the target and synthesizes removes for all existing + // documents. The backend will re-add any documents that still match + // the target before it sends the next global snapshot. + ResetTarget(target_id); + target_state.UpdateResumeToken(target_change.resume_token()); + } + break; + default: + HARD_FAIL("Unknown target watch change state: %s", + target_change.state()); + } + } +} + +std::vector WatchChangeAggregator::GetTargetIds(const WatchTargetChange& target_change) const { + if (!target_change.target_ids().empty()) { + return target_change.target_ids(); + } + + std::vector result; + result.reserve(target_states_.size()); + for (const auto& entry : target_states_) { + result.push_back(entry.first); + } + + return result; +} + +void WatchChangeAggregator::RemoveTarget(TargetId target_id) { + target_states_.erase(target_id); } void WatchChangeAggregator::HandleExistenceFilter( @@ -272,10 +339,6 @@ target_state.RecordTargetRequest(); } -void WatchChangeAggregator::RemoveTarget(TargetId target_id) { - target_states_.erase(target_id); -} - void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, FSTMaybeDocument* document) { if (!IsActiveTarget(target_id)) { From 4fee491bd6c849435569487b05e30cd65c524837 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 16:23:01 -0500 Subject: [PATCH 050/107] wip --- Firestore/Source/Core/FSTSyncEngine.mm | 2 +- Firestore/Source/Remote/FSTRemoteEvent.h | 64 +-- Firestore/Source/Remote/FSTRemoteEvent.mm | 485 ------------------ Firestore/Source/Remote/FSTRemoteStore.mm | 12 +- .../firebase/firestore/remote/remote_event.h | 2 +- .../firebase/firestore/remote/remote_event.mm | 3 +- 6 files changed, 12 insertions(+), 556 deletions(-) diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm index 41340b93521..65079d9684c 100644 --- a/Firestore/Source/Core/FSTSyncEngine.mm +++ b/Firestore/Source/Core/FSTSyncEngine.mm @@ -134,7 +134,7 @@ explicit LimboResolution(const DocumentKey &key) : key{key} { /** * Set to true once we've received a document. This is used in remoteKeysForTarget and - * ultimately used by FSTWatchChangeAggregator to decide whether it needs to manufacture a delete + * ultimately used by `WatchChangeAggregator` to decide whether it needs to manufacture a delete * event for the target once the target is CURRENT. */ bool document_received = false; diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index e5c5d602686..3a97a4be138 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -25,6 +25,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" @class FSTMaybeDocument; @@ -32,24 +33,6 @@ NS_ASSUME_NONNULL_BEGIN -/** - * Interface implemented by RemoteStore to expose target metadata to the FSTWatchChangeAggregator. - */ -@protocol FSTTargetMetadataProvider - -/** - * Returns the set of remote document keys for the given target ID as of the last raised snapshot. - */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: - (firebase::firestore::model::TargetId)targetID; - -/** - * Returns the FSTQueryData for an active target ID or 'null' if this query has become inactive - */ -- (nullable FSTQueryData *)queryDataForTarget:(firebase::firestore::model::TargetId)targetID; - -@end - #pragma mark - FSTTargetChange /** @@ -155,49 +138,4 @@ NS_ASSUME_NONNULL_BEGIN @end -#pragma mark - FSTWatchChangeAggregator - -/** - * A helper class to accumulate watch changes into a FSTRemoteEvent and other target - * information. - */ -@interface FSTWatchChangeAggregator : NSObject - -- (instancetype)initWithTargetMetadataProvider:(id)targetMetadataProvider - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** Processes and adds the DocumentWatchChange to the current set of changes. */ -- (void)handleDocumentChange: - (const firebase::firestore::remote::DocumentWatchChange &)documentChange; - -/** Processes and adds the WatchTargetChange to the current set of changes. */ -- (void)handleTargetChange:(const firebase::firestore::remote::WatchTargetChange &)targetChange; - -/** Removes the in-memory state for the provided target. */ -- (void)removeTarget:(firebase::firestore::model::TargetId)targetID; - -/** - * Handles existence filters and synthesizes deletes for filter mismatches. Targets that are - * invalidated by filter mismatches are added to `targetMismatches`. - */ -- (void)handleExistenceFilter: - (const firebase::firestore::remote::ExistenceFilterWatchChange &)existenceFilter; - -/** - * Increment the number of acks needed from watch before we can consider the server to be 'in-sync' - * with the client's active targets. - */ -- (void)recordTargetRequest:(firebase::firestore::model::TargetId)targetID; - -/** - * Converts the current state into a remote event with the snapshot version taken from the - * initializer. - */ -- (FSTRemoteEvent *)remoteEventAtSnapshotVersion: - (const firebase::firestore::model::SnapshotVersion &)snapshotVersion; - -@end - NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 00ea188e1da..408c2501ce8 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -98,149 +98,6 @@ - (BOOL)isEqual:(id)other { @end -#pragma mark - FSTTargetState - -/** Tracks the internal state of a Watch target. */ -@interface FSTTargetState : NSObject - -/** - * Whether this target has been marked 'current'. - * - * 'Current' has special meaning in the RPC protocol: It implies that the Watch backend has sent us - * all changes up to the point at which the target was added and that the target is consistent with - * the rest of the watch stream. - */ -@property(nonatomic) BOOL current; - -/** The last resume token sent to us for this target. */ -@property(nonatomic, readonly, strong) NSData *resumeToken; - -/** Whether we have modified any state that should trigger a snapshot. */ -@property(nonatomic, readonly) BOOL hasPendingChanges; - -/** Whether this target has pending target adds or target removes. */ -- (BOOL)isPending; - -/** - * Applies the resume token to the TargetChange, but only when it has a new value. Empty - * resumeTokens are discarded. - */ -- (void)updateResumeToken:(NSData *)resumeToken; - -/** Resets the document changes and sets `hasPendingChanges` to false. */ -- (void)clearPendingChanges; -/** - * Creates a target change from the current set of changes. - * - * To reset the document changes after raising this snapshot, call `clearPendingChanges()`. - */ -- (FSTTargetChange *)toTargetChange; - -- (void)recordTargetRequest; -- (void)recordTargetResponse; -- (void)markCurrent; -- (void)addDocumentChangeWithType:(DocumentViewChangeType)type - forKey:(const DocumentKey &)documentKey; -- (void)removeDocumentChangeForKey:(const DocumentKey &)documentKey; - -@end - -@implementation FSTTargetState { - /** - * The number of outstanding responses (adds or removes) that we are waiting on. We only consider - * targets active that have no outstanding responses. - */ - int _outstandingResponses; - - /** - * Keeps track of the document changes since the last raised snapshot. - * - * These changes are continuously updated as we receive document updates and always reflect the - * current set of changes against the last issued snapshot. - */ - std::unordered_map _documentChanges; -} - -- (instancetype)init { - if (self = [super init]) { - _resumeToken = [NSData data]; - _outstandingResponses = 0; - - // We initialize to 'true' so that newly-added targets are included in the next RemoteEvent. - _hasPendingChanges = YES; - } - return self; -} - -- (BOOL)isPending { - return _outstandingResponses != 0; -} - -- (void)updateResumeToken:(NSData *)resumeToken { - if (resumeToken.length > 0) { - _hasPendingChanges = YES; - _resumeToken = [resumeToken copy]; - } -} - -- (void)clearPendingChanges { - _hasPendingChanges = NO; - _documentChanges.clear(); -} - -- (void)recordTargetRequest { - _outstandingResponses += 1; -} - -- (void)recordTargetResponse { - _outstandingResponses -= 1; -} - -- (void)markCurrent { - _hasPendingChanges = YES; - _current = true; -} - -- (void)addDocumentChangeWithType:(DocumentViewChangeType)type - forKey:(const DocumentKey &)documentKey { - _hasPendingChanges = YES; - _documentChanges[documentKey] = type; -} - -- (void)removeDocumentChangeForKey:(const DocumentKey &)documentKey { - _hasPendingChanges = YES; - _documentChanges.erase(documentKey); -} - -- (FSTTargetChange *)toTargetChange { - DocumentKeySet addedDocuments; - DocumentKeySet modifiedDocuments; - DocumentKeySet removedDocuments; - - for (const auto &entry : _documentChanges) { - switch (entry.second) { - case DocumentViewChangeType::kAdded: - addedDocuments = addedDocuments.insert(entry.first); - break; - case DocumentViewChangeType::kModified: - modifiedDocuments = modifiedDocuments.insert(entry.first); - break; - case DocumentViewChangeType::kRemoved: - removedDocuments = removedDocuments.insert(entry.first); - break; - default: - HARD_FAIL("Encountered invalid change type: %s", entry.second); - } - } - - return [[FSTTargetChange alloc] initWithResumeToken:_resumeToken - current:_current - addedDocuments:std::move(addedDocuments) - modifiedDocuments:std::move(modifiedDocuments) - removedDocuments:std::move(removedDocuments)]; -} -@end - #pragma mark - FSTRemoteEvent @implementation FSTRemoteEvent { @@ -291,346 +148,4 @@ @implementation FSTRemoteEvent { @end -#pragma mark - FSTWatchChangeAggregator - -@implementation FSTWatchChangeAggregator { - /** The internal state of all tracked targets. */ - std::unordered_map _targetStates; - - /** Keeps track of document to update */ - std::unordered_map _pendingDocumentUpdates; - - /** A mapping of document keys to their set of target IDs. */ - std::unordered_map, DocumentKeyHash> - _pendingDocumentTargetMappings; - - /** - * A list of targets with existence filter mismatches. These targets are known to be inconsistent - * and their listens needs to be re-established by RemoteStore. - */ - std::unordered_set _pendingTargetResets; - - id _targetMetadataProvider; -} - -- (instancetype)initWithTargetMetadataProvider: - (id)targetMetadataProvider { - self = [super init]; - if (self) { - _targetMetadataProvider = targetMetadataProvider; - } - return self; -} - -- (void)handleDocumentChange:(const DocumentWatchChange &)documentChange { - for (TargetId targetID : documentChange.updated_target_ids()) { - if ([documentChange.new_document() isKindOfClass:[FSTDocument class]]) { - [self addDocument:documentChange.new_document() toTarget:targetID]; - } else if ([documentChange.new_document() isKindOfClass:[FSTDeletedDocument class]]) { - [self removeDocument:documentChange.new_document() - withKey:documentChange.document_key() - fromTarget:targetID]; - } - } - - for (TargetId targetID : documentChange.removed_target_ids()) { - [self removeDocument:documentChange.new_document() - withKey:documentChange.document_key() - fromTarget:targetID]; - } -} - -- (void)handleTargetChange:(const WatchTargetChange &)targetChange { - for (TargetId targetID : [self targetIdsForChange:targetChange]) { - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - switch (targetChange.state()) { - case WatchTargetChangeState::NoChange: - if ([self isActiveTarget:targetID]) { - [targetState updateResumeToken:targetChange.resume_token()]; - } - break; - case WatchTargetChangeState::Added: - // We need to decrement the number of pending acks needed from watch for this targetId. - [targetState recordTargetResponse]; - if (!targetState.isPending) { - // We have a freshly added target, so we need to reset any state that we had previously. - // This can happen e.g. when remove and add back a target for existence filter mismatches. - [targetState clearPendingChanges]; - } - [targetState updateResumeToken:targetChange.resume_token()]; - break; - case WatchTargetChangeState::Removed: - // We need to keep track of removed targets to we can post-filter and remove any target - // changes. - [targetState recordTargetResponse]; - if (!targetState.isPending) { - [self removeTarget:targetID]; - } - HARD_ASSERT(targetChange.cause().ok(), - "WatchChangeAggregator does not handle errored targets"); - break; - case WatchTargetChangeState::Current: - if ([self isActiveTarget:targetID]) { - [targetState markCurrent]; - [targetState updateResumeToken:targetChange.resume_token()]; - } - break; - case WatchTargetChangeState::Reset: - if ([self isActiveTarget:targetID]) { - // Reset the target and synthesizes removes for all existing documents. The backend will - // re-add any documents that still match the target before it sends the next global - // snapshot. - [self resetTarget:targetID]; - [targetState updateResumeToken:targetChange.resume_token()]; - } - break; - default: - HARD_FAIL("Unknown target watch change state: %s", targetChange.state()); - } - } -} - -/** - * Returns all targetIds that the watch change applies to: either the targetIds explicitly listed - * in the change or the targetIds of all currently active targets. - */ -- (std::vector)targetIdsForChange:(const WatchTargetChange &)targetChange { - if (!targetChange.target_ids().empty()) { - return targetChange.target_ids(); - } - - std::vector result; - result.reserve(_targetStates.size()); - for (const auto &entry : _targetStates) { - result.push_back(entry.first); - } - - return result; -} - -- (void)removeTarget:(TargetId)targetID { - _targetStates.erase(targetID); -} - -- (void)handleExistenceFilter:(const ExistenceFilterWatchChange &)existenceFilter { - TargetId targetID = existenceFilter.target_id(); - int expectedCount = existenceFilter.filter().count(); - - FSTQueryData *queryData = [self queryDataForActiveTarget:targetID]; - if (queryData) { - FSTQuery *query = queryData.query; - if ([query isDocumentQuery]) { - if (expectedCount == 0) { - // The existence filter told us the document does not exist. We deduce that this document - // does not exist and apply a deleted document to our updates. Without applying this deleted - // document there might be another query that will raise this document as part of a snapshot - // until it is resolved, essentially exposing inconsistency between queries. - DocumentKey key{query.path}; - [self removeDocument:[FSTDeletedDocument documentWithKey:key - version:SnapshotVersion::None() - hasCommittedMutations:NO] - withKey:key - fromTarget:targetID]; - } else { - HARD_ASSERT(expectedCount == 1, "Single document existence filter with count: %s", - expectedCount); - } - } else { - int currentSize = [self currentDocumentCountForTarget:targetID]; - if (currentSize != expectedCount) { - // Existence filter mismatch: We reset the mapping and raise a new snapshot with - // `isFromCache:true`. - [self resetTarget:targetID]; - _pendingTargetResets.insert(targetID); - } - } - } -} - -- (int)currentDocumentCountForTarget:(TargetId)targetID { - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - FSTTargetChange *targetChange = [targetState toTargetChange]; - return ([_targetMetadataProvider remoteKeysForTarget:targetID].size() + - targetChange.addedDocuments.size() - targetChange.removedDocuments.size()); -} - -/** - * Resets the state of a Watch target to its initial state (e.g. sets 'current' to false, clears the - * resume token and removes its target mapping from all documents). - */ -- (void)resetTarget:(TargetId)targetID { - auto currentTargetState = _targetStates.find(targetID); - HARD_ASSERT(currentTargetState != _targetStates.end() && !(currentTargetState->second.isPending), - "Should only reset active targets"); - - _targetStates[targetID] = [FSTTargetState new]; - - // Trigger removal for any documents currently mapped to this target. These removals will be part - // of the initial snapshot if Watch does not resend these documents. - DocumentKeySet existingKeys = [_targetMetadataProvider remoteKeysForTarget:targetID]; - - for (const DocumentKey &key : existingKeys) { - [self removeDocument:nil withKey:key fromTarget:targetID]; - } -} - -/** - * Adds the provided document to the internal list of document updates and its document key to the - * given target's mapping. - */ -- (void)addDocument:(FSTMaybeDocument *)document toTarget:(TargetId)targetID { - if (![self isActiveTarget:targetID]) { - return; - } - - DocumentViewChangeType changeType = [self containsDocument:document.key inTarget:targetID] - ? DocumentViewChangeType::kModified - : DocumentViewChangeType::kAdded; - - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - [targetState addDocumentChangeWithType:changeType forKey:document.key]; - - _pendingDocumentUpdates[document.key] = document; - _pendingDocumentTargetMappings[document.key].insert(targetID); -} - -/** - * Removes the provided document from the target mapping. If the document no longer matches the - * target, but the document's state is still known (e.g. we know that the document was deleted or we - * received the change that caused the filter mismatch), the new document can be provided to update - * the remote document cache. - */ -- (void)removeDocument:(FSTMaybeDocument *_Nullable)document - withKey:(const DocumentKey &)key - fromTarget:(TargetId)targetID { - if (![self isActiveTarget:targetID]) { - return; - } - - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - - if ([self containsDocument:key inTarget:targetID]) { - [targetState addDocumentChangeWithType:DocumentViewChangeType::kRemoved forKey:key]; - } else { - // The document may have entered and left the target before we raised a snapshot, so we can just - // ignore the change. - [targetState removeDocumentChangeForKey:key]; - } - _pendingDocumentTargetMappings[key].insert(targetID); - - if (document) { - _pendingDocumentUpdates[key] = document; - } -} - -/** - * Returns whether the LocalStore considers the document to be part of the specified target. - */ -- (BOOL)containsDocument:(const DocumentKey &)key inTarget:(TargetId)targetID { - const DocumentKeySet &existingKeys = [_targetMetadataProvider remoteKeysForTarget:targetID]; - return existingKeys.contains(key); -} - -- (FSTTargetState *)ensureTargetStateForTarget:(TargetId)targetID { - if (!_targetStates[targetID]) { - _targetStates[targetID] = [FSTTargetState new]; - } - - return _targetStates[targetID]; -} - -/** - * Returns YES if the given targetId is active. Active targets are those for which there are no - * pending requests to add a listen and are in the current list of targets the client cares about. - * - * Clients can repeatedly listen and stop listening to targets, so this check is useful in - * preventing in preventing race conditions for a target where events arrive but the server hasn't - * yet acknowledged the intended change in state. - */ -- (BOOL)isActiveTarget:(TargetId)targetID { - return [self queryDataForActiveTarget:targetID] != nil; -} - -- (nullable FSTQueryData *)queryDataForActiveTarget:(TargetId)targetID { - auto targetState = _targetStates.find(targetID); - return targetState != _targetStates.end() && targetState->second.isPending - ? nil - : [_targetMetadataProvider queryDataForTarget:targetID]; -} - -- (FSTRemoteEvent *)remoteEventAtSnapshotVersion:(const SnapshotVersion &)snapshotVersion { - std::unordered_map targetChanges; - - for (const auto &entry : _targetStates) { - TargetId targetID = entry.first; - FSTTargetState *targetState = entry.second; - - FSTQueryData *queryData = [self queryDataForActiveTarget:targetID]; - if (queryData) { - if (targetState.current && [queryData.query isDocumentQuery]) { - // Document queries for document that don't exist can produce an empty result set. To update - // our local cache, we synthesize a document delete if we have not previously received the - // document. This resolves the limbo state of the document, removing it from - // limboDocumentRefs. - DocumentKey key{queryData.query.path}; - if (_pendingDocumentUpdates.find(key) == _pendingDocumentUpdates.end() && - ![self containsDocument:key inTarget:targetID]) { - [self removeDocument:[FSTDeletedDocument documentWithKey:key - version:snapshotVersion - hasCommittedMutations:NO] - withKey:key - fromTarget:targetID]; - } - } - - if (targetState.hasPendingChanges) { - targetChanges[targetID] = [targetState toTargetChange]; - [targetState clearPendingChanges]; - } - } - } - - DocumentKeySet resolvedLimboDocuments; - - // We extract the set of limbo-only document updates as the GC logic special-cases documents that - // do not appear in the query cache. - // - // TODO(gsoltis): Expand on this comment. - for (const auto &entry : _pendingDocumentTargetMappings) { - BOOL isOnlyLimboTarget = YES; - - for (TargetId targetID : entry.second) { - FSTQueryData *queryData = [self queryDataForActiveTarget:targetID]; - if (queryData && queryData.purpose != FSTQueryPurposeLimboResolution) { - isOnlyLimboTarget = NO; - break; - } - } - - if (isOnlyLimboTarget) { - resolvedLimboDocuments = resolvedLimboDocuments.insert(entry.first); - } - } - - FSTRemoteEvent *remoteEvent = - [[FSTRemoteEvent alloc] initWithSnapshotVersion:snapshotVersion - targetChanges:targetChanges - targetMismatches:_pendingTargetResets - documentUpdates:_pendingDocumentUpdates - limboDocuments:resolvedLimboDocuments]; - - _pendingDocumentUpdates.clear(); - _pendingDocumentTargetMappings.clear(); - _pendingTargetResets.clear(); - - return remoteEvent; -} - -- (void)recordTargetRequest:(TargetId)targetID { - // For each request we get we need to record we need a response for it. - FSTTargetState *targetState = [self ensureTargetStateForTarget:targetID]; - [targetState recordTargetRequest]; -} -@end - NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index bc503e2a0c9..7862cb05fde 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -36,6 +36,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -60,6 +61,7 @@ using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; using util::AsyncQueue; @@ -87,8 +89,6 @@ @interface FSTRemoteStore () @property(nonatomic, strong, readonly) FSTOnlineStateTracker *onlineStateTracker; -@property(nonatomic, strong, nullable) FSTWatchChangeAggregator *watchChangeAggregator; - /** * A list of up to kMaxPendingWrites writes that we have fetched from the LocalStore via * fillWritePipeline and have or will send to the write stream. @@ -107,6 +107,8 @@ @interface FSTRemoteStore () @end @implementation FSTRemoteStore { + std::unique_ptr _watchChangeAggregator; + /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; /** @@ -241,7 +243,7 @@ - (void)credentialDidChange { - (void)startWatchStream { HARD_ASSERT([self shouldStartWatchStream], "startWatchStream: called when shouldStartWatchStream: is false."); - _watchChangeAggregator = [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:self]; + _watchChangeAggregator = absl::make_unique(self); _watchStream->Start(); [self.onlineStateTracker handleWatchStreamStart]; @@ -262,7 +264,7 @@ - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { } - (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { - [self.watchChangeAggregator recordTargetRequest:queryData.targetID]; + _watchChangeAggregator->RecordTargetRequest(queryData.targetID); _watchStream->WatchQuery(queryData); } @@ -287,7 +289,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { } - (void)sendUnwatchRequestForTargetID:(FSTBoxedTargetID *)targetID { - [self.watchChangeAggregator recordTargetRequest:targetID.intValue]; + _watchChangeAggregator->RecordTargetRequest(queryData.targetID); _watchStream->UnwatchTargetId([targetID intValue]); } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 8dcc48800d7..be24d1e6a83 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Interface implemented by RemoteStore to expose target metadata to the - * FSTWatchChangeAggregator. + * `WatchChangeAggregator`. */ @protocol FSTTargetMetadataProvider diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 53564072537..4f76654a86b 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -178,7 +178,8 @@ } } -std::vector WatchChangeAggregator::GetTargetIds(const WatchTargetChange& target_change) const { +std::vector WatchChangeAggregator::GetTargetIds( + const WatchTargetChange& target_change) const { if (!target_change.target_ids().empty()) { return target_change.target_ids(); } From 626efecfeec1bd8fbf3431772b0ba4c1f17bf06d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 17:07:56 -0500 Subject: [PATCH 051/107] Almost compiles --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 12 +-- .../Tests/Remote/FSTRemoteEventTests.mm | 83 ++++++++++--------- Firestore/Example/Tests/Util/FSTHelpers.mm | 22 ++--- Firestore/Source/Remote/FSTRemoteStore.mm | 18 ++-- .../firebase/firestore/remote/remote_event.h | 4 +- 5 files changed, 72 insertions(+), 67 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 3c4042579fb..f32c3dd1bae 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -37,6 +37,7 @@ #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -50,6 +51,7 @@ using firebase::firestore::model::MaybeDocumentMap; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::util::Status; @@ -904,12 +906,12 @@ - (void)testPersistsResumeTokens { NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken}; - FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] - initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider + WatchChangeAggregator aggregator{ + [FSTTestTargetMetadataProvider providerWithSingleResultForKey:testutil::Key("foo/bar") - targets:{targetID}]]; - [aggregator handleTargetChange:watchChange]; - FSTRemoteEvent *remoteEvent = [aggregator remoteEventAtSnapshotVersion:testutil::Version(1000)]; + targets:{targetID}]}; + aggregator.HandleTargetChange(watchChange); + FSTRemoteEvent *remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); [self applyRemoteEvent:remoteEvent]; // Stop listening so that the query should become inactive (but persistent) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index e7ba8df3183..b29245c90e4 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -30,6 +30,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -46,6 +47,7 @@ using firebase::firestore::remote::ExistenceFilter; using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::testutil::VectorOfUniquePtrs; @@ -135,7 +137,7 @@ - (void)setUp { /** * Creates an aggregator initialized with the set of provided `WatchChange`s. Tests can add further - * changes via `handleDocumentChange`, `handleTargetChange` and `handleExistenceFilterChange`. + * changes via `HandleDocumentChange`, `HandleTargetChange` and `HandleExistenceFilterChange`. * * @param targetMap A map of query data for all active targets. The map must include an entry for * every target referenced by any of the watch changes. @@ -147,13 +149,12 @@ - (void)setUp { * @param watchChanges The watch changes to apply before returning the aggregator. Supported * changes are `DocumentWatchChange` and `WatchTargetChange`. */ -- (FSTWatchChangeAggregator *) +- (WatchChangeAggregator) aggregatorWithTargetMap:(const std::unordered_map &)targetMap outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { - FSTWatchChangeAggregator *aggregator = - [[FSTWatchChangeAggregator alloc] initWithTargetMetadataProvider:_targetMetadataProvider]; + WatchChangeAggregator aggregator{_targetMetadataProvider}; std::vector targetIDs; for (const auto &kv : targetMap) { @@ -168,18 +169,18 @@ - (void)setUp { TargetId targetID = kv.first; int count = kv.second; for (int i = 0; i < count; ++i) { - [aggregator recordTargetRequest:targetID]; + aggregator.RecordTargetRequest(targetID); } } for (const std::unique_ptr &change : watchChanges) { switch (change->type()) { case WatchChange::Type::Document: { - [aggregator handleDocumentChange:*static_cast(change.get())]; + aggregator.HandleDocumentChange(*static_cast(change.get())); break; } case WatchChange::Type::TargetChange: { - [aggregator handleTargetChange:*static_cast(change.get())]; + aggregator.HandleTargetChange(*static_cast(change.get())); break; } default: @@ -187,8 +188,8 @@ - (void)setUp { } } - [aggregator handleTargetChange:WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, - _resumeToken1}]; + aggregator.HandleTargetChange(WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, + _resumeToken1}); return aggregator; } @@ -213,11 +214,11 @@ - (void)setUp { outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:outstandingResponses existingKeys:existingKeys changes:watchChanges]; - return [aggregator remoteEventAtSnapshotVersion:testutil::Version(snapshotVersion)]; + return aggregator.CreateRemoteEvent(testutil::Version(snapshotVersion)); } - (void)testWillAccumulateDocumentAddedAndRemovedEvents { @@ -378,13 +379,13 @@ - (void)testWillHandleSingleReset { // Reset target WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; - [aggregator handleTargetChange:change]; + aggregator.HandleTargetChange(change); - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 0); @@ -493,15 +494,15 @@ - (void)testTargetAddedChangeWillResetPreviousState { - (void)testNoChangeWillStillMarkTheAffectedTargets { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; WatchTargetChange change{WatchTargetChangeState::NoChange, {1}, _resumeToken1}; - [aggregator handleTargetChange:change]; + aggregator.HandleTargetChange(change); - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 0); @@ -521,13 +522,13 @@ - (void)testExistenceFilterMismatchClearsTarget { auto change2 = MakeDocChange({1}, {}, doc2.key, doc2); auto change3 = MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); - FSTWatchChangeAggregator *aggregator = [self + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1.key, doc2.key} changes:Changes(std::move(change1), std::move(change2), std::move(change3))]; - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); @@ -547,9 +548,9 @@ - (void)testExistenceFilterMismatchClearsTarget { // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. ExistenceFilterWatchChange change4{ExistenceFilter{1}, 1}; - [aggregator handleExistenceFilter:change4]; + aggregator.HandleExistenceFilter(change4); - event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(4)]; + event = aggregator.CreateRemoteEvent(testutil::Version(4)); FSTTargetChange *targetChange3 = FSTTestTargetChange( DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}, [NSData data], NO); @@ -563,24 +564,24 @@ - (void)testExistenceFilterMismatchClearsTarget { - (void)testExistenceFilterMismatchRemovesCurrentChanges { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; WatchTargetChange markCurrent{WatchTargetChangeState::Current, {1}, _resumeToken1}; - [aggregator handleTargetChange:markCurrent]; + aggregator.HandleTargetChange(markCurrent); FSTDocument *doc1 = FSTTestDoc("docs/1", 1, @{@"value" : @1}, FSTDocumentStateSynced); DocumentWatchChange addDoc{{1}, {}, doc1.key, doc1}; - [aggregator handleDocumentChange:addDoc]; + aggregator.HandleDocumentChange(addDoc); // The existence filter mismatch will remove the document from target 1, but not synthesize a // document delete. ExistenceFilterWatchChange existenceFilter{ExistenceFilter{0}, 1}; - [aggregator handleExistenceFilter:existenceFilter]; + aggregator.HandleExistenceFilter(existenceFilter); - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 1); @@ -602,13 +603,13 @@ - (void)testDocumentUpdate { FSTDocument *doc2 = FSTTestDoc("docs/2", 2, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = MakeDocChange({1}, {}, doc2.key, doc2); - FSTWatchChangeAggregator *aggregator = + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change1), std::move(change2))]; - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 2); @@ -622,17 +623,17 @@ - (void)testDocumentUpdate { version:testutil::Version(3) hasCommittedMutations:NO]; DocumentWatchChange change3{{}, {1}, deletedDoc1.key, deletedDoc1}; - [aggregator handleDocumentChange:change3]; + aggregator.HandleDocumentChange(change3); FSTDocument *updatedDoc2 = FSTTestDoc("docs/2", 3, @{@"value" : @2}, FSTDocumentStateSynced); DocumentWatchChange change4{{1}, {}, updatedDoc2.key, updatedDoc2}; - [aggregator handleDocumentChange:change4]; + aggregator.HandleDocumentChange(change4); FSTDocument *doc3 = FSTTestDoc("docs/3", 3, @{@"value" : @3}, FSTDocumentStateSynced); DocumentWatchChange change5{{1}, {}, doc3.key, doc3}; - [aggregator handleDocumentChange:change5]; + aggregator.HandleDocumentChange(change5); - event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); XCTAssertEqual(event.documentUpdates.size(), 3); @@ -655,19 +656,19 @@ - (void)testDocumentUpdate { - (void)testResumeTokensHandledPerTarget { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; - [aggregator handleTargetChange:change1]; + aggregator.HandleTargetChange(change1); NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding]; WatchTargetChange change2{WatchTargetChangeState::Current, {2}, resumeToken2}; - [aggregator handleTargetChange:change2]; + aggregator.HandleTargetChange(change2); - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.targetChanges.size(), 2); FSTTargetChange *targetChange1 = @@ -682,23 +683,23 @@ - (void)testResumeTokensHandledPerTarget { - (void)testLastResumeTokenWins { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; - FSTWatchChangeAggregator *aggregator = [self aggregatorWithTargetMap:targetMap + WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; - [aggregator handleTargetChange:change1]; + aggregator.HandleTargetChange(change1); NSData *resumeToken2 = [@"resume2" dataUsingEncoding:NSUTF8StringEncoding]; WatchTargetChange change2{WatchTargetChangeState::NoChange, {1}, resumeToken2}; - [aggregator handleTargetChange:change2]; + aggregator.HandleTargetChange(change2); NSData *resumeToken3 = [@"resume3" dataUsingEncoding:NSUTF8StringEncoding]; WatchTargetChange change3{WatchTargetChangeState::NoChange, {2}, resumeToken3}; - [aggregator handleTargetChange:change3]; + aggregator.HandleTargetChange(change3); - FSTRemoteEvent *event = [aggregator remoteEventAtSnapshotVersion:testutil::Version(3)]; + FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.targetChanges.size(), 2); FSTTargetChange *targetChange1 = diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 2d02c5902f7..41b40fa0f8c 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -49,6 +49,7 @@ #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -72,6 +73,7 @@ using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::WatchChangeAggregator; NS_ASSUME_NONNULL_BEGIN @@ -377,12 +379,12 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; - FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] - initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider + WatchChangeAggregator aggregator{ + [FSTTestTargetMetadataProvider providerWithEmptyResultForKey:doc.key - targets:addedToTargets]]; - [aggregator handleDocumentChange:change]; - return [aggregator remoteEventAtSnapshotVersion:doc.version]; + targets:addedToTargets]}; + aggregator.HandleDocumentChange(change); + return aggregator.CreateRemoteEvent(doc.version); } FSTTargetChange *FSTTestTargetChangeMarkCurrent() { @@ -425,13 +427,13 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { std::vector listens = updatedInTargets; listens.insert(listens.end(), removedFromTargets.begin(), removedFromTargets.end()); - FSTWatchChangeAggregator *aggregator = [[FSTWatchChangeAggregator alloc] - initWithTargetMetadataProvider:[FSTTestTargetMetadataProvider + WatchChangeAggregator aggregator{ + [FSTTestTargetMetadataProvider providerWithSingleResultForKey:doc.key listenTargets:listens - limboTargets:limboTargets]]; - [aggregator handleDocumentChange:change]; - return [aggregator remoteEventAtSnapshotVersion:doc.version]; + limboTargets:limboTargets]}; + aggregator.HandleDocumentChange(change); + return aggregator.CreateRemoteEvent(doc.version); } FSTRemoteEvent *FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 7862cb05fde..868166cbcd3 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -108,8 +108,8 @@ @interface FSTRemoteStore () @implementation FSTRemoteStore { std::unique_ptr _watchChangeAggregator; - /** The client-side proxy for interacting with the backend. */ + std::shared_ptr _datastore; /** * A mapping of watched targets that the client cares about tracking and the @@ -289,7 +289,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { } - (void)sendUnwatchRequestForTargetID:(FSTBoxedTargetID *)targetID { - _watchChangeAggregator->RecordTargetRequest(queryData.targetID); + _watchChangeAggregator->RecordTargetRequest(targetID); _watchStream->UnwatchTargetId([targetID intValue]); } @@ -302,7 +302,7 @@ - (BOOL)shouldStartWatchStream { } - (void)cleanUpWatchStreamState { - _watchChangeAggregator = nil; + _watchChangeAggregator.reset(); } - (void)watchStreamDidOpen { @@ -324,16 +324,14 @@ - (void)watchStreamDidChange:(const WatchChange &)change // There was an error on a target, don't wait for a consistent snapshot to raise events return [self processTargetErrorForWatchChange:watchTargetChange]; } else { - [self.watchChangeAggregator handleTargetChange:watchTargetChange]; + _watchChangeAggregator->HandleTargetChange(watchTargetChange); } } else if (change.type() == WatchChange::Type::Document) { - [self.watchChangeAggregator - handleDocumentChange:static_cast(change)]; + _watchChangeAggregator->HandleDocumentChange(static_cast(change)); } else { HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, "Expected watchChange to be an instance of ExistenceFilterWatchChange"); - [self.watchChangeAggregator - handleExistenceFilter:static_cast(change)]; + _watchChangeAggregator->HandleExistenceFilter(static_cast(change)); } if (snapshotVersion != SnapshotVersion::None() && @@ -374,7 +372,7 @@ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotV "Can't raise event for unknown SnapshotVersion"); FSTRemoteEvent *remoteEvent = - [self.watchChangeAggregator remoteEventAtSnapshotVersion:snapshotVersion]; + _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when // applying the completed FSTRemoteEvent. @@ -438,7 +436,7 @@ - (void)processTargetErrorForWatchChange:(const WatchTargetChange &)change { auto found = _listenTargets.find(targetID); if (found != _listenTargets.end()) { _listenTargets.erase(found); - [self.watchChangeAggregator removeTarget:targetID]; + _watchChangeAggregator->RemoveTarget(targetID); [self.syncEngine rejectListenWithTargetID:targetID error:util::MakeNSError(change.cause())]; } } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index be24d1e6a83..789275609ce 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -154,7 +154,9 @@ class TargetState { class WatchChangeAggregator { public: - WatchChangeAggregator() { + explicit WatchChangeAggregator( + id target_metadata_provider) + : target_metadata_provider_{target_metadata_provider} { } /** From d5defb19d3377f02dd6369c17f1bdc276046497a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 17:40:07 -0500 Subject: [PATCH 052/107] appease linter --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 7 ++-- .../Tests/Remote/FSTRemoteEventTests.mm | 40 +++++++++---------- Firestore/Example/Tests/Util/FSTHelpers.mm | 13 +++--- Firestore/Source/Remote/FSTRemoteStore.mm | 8 ++-- .../firebase/firestore/remote/remote_event.h | 5 ++- 5 files changed, 35 insertions(+), 38 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index f32c3dd1bae..98835fad06f 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -906,10 +906,9 @@ - (void)testPersistsResumeTokens { NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken}; - WatchChangeAggregator aggregator{ - [FSTTestTargetMetadataProvider - providerWithSingleResultForKey:testutil::Key("foo/bar") - targets:{targetID}]}; + WatchChangeAggregator aggregator{[FSTTestTargetMetadataProvider + providerWithSingleResultForKey:testutil::Key("foo/bar") + targets:{targetID}]}; aggregator.HandleTargetChange(watchChange); FSTRemoteEvent *remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); [self applyRemoteEvent:remoteEvent]; diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b29245c90e4..b0f5abea849 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -188,8 +188,8 @@ - (void)setUp { } } - aggregator.HandleTargetChange(WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, - _resumeToken1}); + aggregator.HandleTargetChange( + WatchTargetChange{WatchTargetChangeState::NoChange, targetIDs, _resumeToken1}); return aggregator; } @@ -215,9 +215,9 @@ - (void)setUp { existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:outstandingResponses - existingKeys:existingKeys - changes:watchChanges]; + outstandingResponses:outstandingResponses + existingKeys:existingKeys + changes:watchChanges]; return aggregator.CreateRemoteEvent(testutil::Version(snapshotVersion)); } @@ -380,9 +380,9 @@ - (void)testWillHandleSingleReset { WatchTargetChange change{WatchTargetChangeState::Reset, {1}}; WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:{}]; + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:{}]; aggregator.HandleTargetChange(change); FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); @@ -495,9 +495,9 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:{}]; + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:{}]; WatchTargetChange change{WatchTargetChangeState::NoChange, {1}, _resumeToken1}; aggregator.HandleTargetChange(change); @@ -565,9 +565,9 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { std::unordered_map targetMap{[self queryDataForTargets:{1}]}; WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:{}]; + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:{}]; WatchTargetChange markCurrent{WatchTargetChangeState::Current, {1}, _resumeToken1}; aggregator.HandleTargetChange(markCurrent); @@ -657,9 +657,9 @@ - (void)testResumeTokensHandledPerTarget { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:{}]; + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; aggregator.HandleTargetChange(change1); @@ -684,9 +684,9 @@ - (void)testLastResumeTokenWins { std::unordered_map targetMap{[self queryDataForTargets:{1, 2}]}; WatchChangeAggregator aggregator = [self aggregatorWithTargetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:{}]; + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:{}]; WatchTargetChange change1{WatchTargetChangeState::Current, {1}, _resumeToken1}; aggregator.HandleTargetChange(change1); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 41b40fa0f8c..ffd04dd8c1b 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -380,9 +380,7 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { "Docs from remote updates shouldn't have local changes."); DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; WatchChangeAggregator aggregator{ - [FSTTestTargetMetadataProvider - providerWithEmptyResultForKey:doc.key - targets:addedToTargets]}; + [FSTTestTargetMetadataProvider providerWithEmptyResultForKey:doc.key targets:addedToTargets]}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } @@ -427,11 +425,10 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { std::vector listens = updatedInTargets; listens.insert(listens.end(), removedFromTargets.begin(), removedFromTargets.end()); - WatchChangeAggregator aggregator{ - [FSTTestTargetMetadataProvider - providerWithSingleResultForKey:doc.key - listenTargets:listens - limboTargets:limboTargets]}; + WatchChangeAggregator aggregator{[FSTTestTargetMetadataProvider + providerWithSingleResultForKey:doc.key + listenTargets:listens + limboTargets:limboTargets]}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index d6e78c0f649..f7347d32f83 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -327,11 +327,12 @@ - (void)watchStreamDidChange:(const WatchChange &)change _watchChangeAggregator->HandleTargetChange(watchTargetChange); } } else if (change.type() == WatchChange::Type::Document) { - _watchChangeAggregator->HandleDocumentChange(static_cast(change)); + _watchChangeAggregator->HandleDocumentChange(static_cast(change)); } else { HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, "Expected watchChange to be an instance of ExistenceFilterWatchChange"); - _watchChangeAggregator->HandleExistenceFilter(static_cast(change)); + _watchChangeAggregator->HandleExistenceFilter( + static_cast(change)); } if (snapshotVersion != SnapshotVersion::None() && @@ -371,8 +372,7 @@ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotV HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); - FSTRemoteEvent *remoteEvent = - _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); + FSTRemoteEvent *remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when // applying the completed FSTRemoteEvent. diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 789275609ce..77e406372be 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -256,6 +257,6 @@ class WatchChangeAggregator { } // namespace firestore } // namespace firebase -#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ - NS_ASSUME_NONNULL_END + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ From 52b21714a0bb696fb5b7a57d536a87b78a867971 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 18:35:02 -0500 Subject: [PATCH 053/107] Bring method order into compliance --- .../Tests/Remote/FSTRemoteEventTests.mm | 2 +- Firestore/Source/Remote/FSTRemoteStore.mm | 4 +- .../firebase/firestore/remote/remote_event.h | 79 ++++++++++++---- .../firebase/firestore/remote/remote_event.mm | 94 ++++++++++--------- 4 files changed, 111 insertions(+), 68 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b0f5abea849..b728ee94777 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -169,7 +169,7 @@ - (void)setUp { TargetId targetID = kv.first; int count = kv.second; for (int i = 0; i < count; ++i) { - aggregator.RecordTargetRequest(targetID); + aggregator.RecordPendingTargetRequest(targetID); } } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index f7347d32f83..507c4c6ec6f 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -264,7 +264,7 @@ - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { } - (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { - _watchChangeAggregator->RecordTargetRequest(queryData.targetID); + _watchChangeAggregator->RecordPendingTargetRequest(queryData.targetID); _watchStream->WatchQuery(queryData); } @@ -289,7 +289,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { } - (void)sendUnwatchRequestForTargetID:(TargetId)targetID { - _watchChangeAggregator->RecordTargetRequest(targetID); + _watchChangeAggregator->RecordPendingTargetRequest(targetID); _watchStream->UnwatchTargetId(targetID); } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 77e406372be..35c4bb25baf 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -153,6 +153,10 @@ class TargetState { NSData* resume_token_; }; +/** + * A helper class to accumulate watch changes into a `RemoteEvent` and other + * target information. + */ class WatchChangeAggregator { public: explicit WatchChangeAggregator( @@ -161,31 +165,31 @@ class WatchChangeAggregator { } /** - * Processes and adds the DocumentWatchChange to the current set of changes. + * Processes and adds the `DocumentWatchChange` to the current set of changes. */ void HandleDocumentChange(const DocumentWatchChange& document_change); - /** Processes and adds the WatchTargetChange to the current set of changes. */ + /** + * Processes and adds the `WatchTargetChange` to the current set of changes. + */ void HandleTargetChange(const WatchTargetChange& target_change); /** * Handles existence filters and synthesizes deletes for filter mismatches. * Targets that are invalidated by filter mismatches are added to - * `targetMismatches`. + * `pending_target_resets_`. */ void HandleExistenceFilter( const ExistenceFilterWatchChange& existence_filter); /** * Converts the current state into a remote event with the snapshot version - * taken from the initializer. + * taken from the initializer. Resets the accumulated changes before + * returning. */ FSTRemoteEvent* CreateRemoteEvent( const model::SnapshotVersion& snapshot_version); - std::vector GetTargetIds( - const WatchTargetChange& target_change) const; - /** Removes the in-memory state for the provided target. */ void RemoveTarget(model::TargetId target_id); @@ -193,31 +197,63 @@ class WatchChangeAggregator { * Increment the number of acks needed from watch before we can consider the * server to be 'in-sync' with the client's active targets. */ - void RecordTargetRequest(model::TargetId target_id); + void RecordPendingTargetRequest(model::TargetId target_id); private: + /** + * Returns all `targetId`s that the watch change applies to: either the + * `targetId`s explicitly listed in the change or the `targetId`s of all + * currently active targets. + */ + std::vector GetTargetIds( + const WatchTargetChange& target_change) const; + + /** + * Adds the provided document to the internal list of document updates and its + * document key to the given target's mapping. + */ void AddDocumentToTarget(model::TargetId target_id, FSTMaybeDocument* document); + + /** + * Removes the provided document from the target mapping. If the document no + * longer matches the target, but the document's state is still known (e.g. we + * know that the document was deleted or we received the change that caused + * the filter mismatch), the new document can be provided to update the remote + * document cache. + */ void RemoveDocumentFromTarget(model::TargetId target_id, const model::DocumentKey& key, FSTMaybeDocument* _Nullable updated_document); - bool TargetContainsDocument(model::TargetId target_id, - const model::DocumentKey& key); /** - * Returns true if the given target_id is active. Active targets are those for - * which there are no pending requests to add a listen and are in the current - * list of targets the client cares about. + * Returns the current count of documents in the target. This includes both + * the number of documents that the LocalStore considers to be part of the + * target as well as any accumulated changes. + */ + int GetCurrentDocumentCountForTarget(model::TargetId target_id); + + // PORTING NOTE: this method exists only for consistency with other platforms; + // in C++, it's pretty much unnecessary. + TargetState& EnsureTargetState(model::TargetId target_id); + + /** + * Returns true if the given `target_id` is active. Active targets are those + * for which there are no pending requests to add a listen and are in the + * current list of targets the client cares about. * * Clients can repeatedly listen and stop listening to targets, so this check - * is useful in preventing in preventing race conditions for a target where - * events arrive but the server hasn't yet acknowledged the intended change in - * state. + * is useful in preventing race conditions for a target where events arrive + * but the server hasn't yet acknowledged the intended change in state. */ bool IsActiveTarget(model::TargetId target_id) const; - FSTQueryData* QueryDataForActiveTarget(model::TargetId target_id) const; - int GetCurrentDocumentCountForTarget(model::TargetId target_id); + /** + * Returns the `FSTQueryData` for an active target (i.e., a target that the + * user is still interested in that has no outstanding target change + * requests). + */ + FSTQueryData* QueryDataForActiveTarget(model::TargetId target_id) const; /** * Resets the state of a Watch target to its initial state (e.g. sets @@ -226,12 +262,15 @@ class WatchChangeAggregator { */ void ResetTarget(model::TargetId target_id); - TargetState& EnsureTargetState(model::TargetId target_id); + /** Returns whether the local store considers the document to be part of the + * specified target. */ + bool TargetContainsDocument(model::TargetId target_id, + const model::DocumentKey& key); /** The internal state of all tracked targets. */ std::unordered_map target_states_; - /** Keeps track of document to update */ + /** Keeps track of the documents to update since the last raised snapshot. */ std::unordered_map diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 4f76654a86b..9fa6c40b9dd 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -128,6 +128,7 @@ const WatchTargetChange& target_change) { for (TargetId target_id : GetTargetIds(target_change)) { TargetState& target_state = EnsureTargetState(target_id); + switch (target_change.state()) { case WatchTargetChangeState::NoChange: if (IsActiveTarget(target_id)) { @@ -149,6 +150,7 @@ case WatchTargetChangeState::Removed: // We need to keep track of removed targets to we can post-filter and // remove any target changes. + // We need to decrement the number of pending acks needed from watch for this targetId. target_state.RecordTargetResponse(); if (!target_state.IsPending()) { RemoveTarget(target_id); @@ -193,10 +195,6 @@ return result; } -void WatchChangeAggregator::RemoveTarget(TargetId target_id) { - target_states_.erase(target_id); -} - void WatchChangeAggregator::HandleExistenceFilter( const ExistenceFilterWatchChange& existence_filter) { TargetId target_id = existence_filter.target_id(); @@ -236,34 +234,6 @@ } } -int WatchChangeAggregator::GetCurrentDocumentCountForTarget( - TargetId target_id) { - TargetState& target_state = EnsureTargetState(target_id); - FSTTargetChange* target_change = target_state.ToTargetChange(); - return ([target_metadata_provider_ remoteKeysForTarget:target_id].size() + - target_change.addedDocuments.size() - - target_change.removedDocuments.size()); -} - -void WatchChangeAggregator::ResetTarget(TargetId target_id) { - auto current_target_state = target_states_.find(target_id); - HARD_ASSERT(current_target_state != target_states_.end() && - !(current_target_state->second.IsPending()), - "Should only reset active targets"); - - target_states_[target_id] = {}; - - // Trigger removal for any documents currently mapped to this target. These - // removals will be part of the initial snapshot if Watch does not resend - // these documents. - DocumentKeySet existingKeys = - [target_metadata_provider_ remoteKeysForTarget:target_id]; - - for (const DocumentKey& key : existingKeys) { - RemoveDocumentFromTarget(target_id, key, nil); - } -} - FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( const SnapshotVersion& snapshot_version) { std::unordered_map target_changes; @@ -327,6 +297,8 @@ documentUpdates:pending_document_updates_ limboDocuments:resolved_limbo_documents]; + // Re-initialize the current state to ensure that we do not modify the + // generated `RemoteEvent`. pending_document_updates_.clear(); pending_document_target_mappings_.clear(); pending_target_resets_.clear(); @@ -334,12 +306,6 @@ return remote_event; } -void WatchChangeAggregator::RecordTargetRequest(TargetId target_id) { - // For each request we get we need to record we need a response for it. - TargetState& target_state = EnsureTargetState(target_id); - target_state.RecordTargetRequest(); -} - void WatchChangeAggregator::AddDocumentToTarget(TargetId target_id, FSTMaybeDocument* document) { if (!IsActiveTarget(target_id)) { @@ -381,11 +347,27 @@ } } -bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, - const DocumentKey& key) { - const DocumentKeySet& existing_keys = - [target_metadata_provider_ remoteKeysForTarget:target_id]; - return existing_keys.contains(key); +void WatchChangeAggregator::RemoveTarget(TargetId target_id) { + target_states_.erase(target_id); +} + +int WatchChangeAggregator::GetCurrentDocumentCountForTarget( + TargetId target_id) { + TargetState& target_state = EnsureTargetState(target_id); + FSTTargetChange* target_change = target_state.ToTargetChange(); + return ([target_metadata_provider_ remoteKeysForTarget:target_id].size() + + target_change.addedDocuments.size() - + target_change.removedDocuments.size()); +} + +void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { + // For each request we get we need to record we need a response for it. + TargetState& target_state = EnsureTargetState(target_id); + target_state.RecordTargetRequest(); +} + +TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { + return target_states_[target_id]; } bool WatchChangeAggregator::IsActiveTarget(TargetId target_id) const { @@ -401,8 +383,30 @@ : [target_metadata_provider_ queryDataForTarget:target_id]; } -TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { - return target_states_[target_id]; +void WatchChangeAggregator::ResetTarget(TargetId target_id) { + auto current_target_state = target_states_.find(target_id); + HARD_ASSERT(current_target_state != target_states_.end() && + !(current_target_state->second.IsPending()), + "Should only reset active targets"); + + target_states_[target_id] = {}; + + // Trigger removal for any documents currently mapped to this target. These + // removals will be part of the initial snapshot if Watch does not resend + // these documents. + DocumentKeySet existingKeys = + [target_metadata_provider_ remoteKeysForTarget:target_id]; + + for (const DocumentKey& key : existingKeys) { + RemoveDocumentFromTarget(target_id, key, nil); + } +} + +bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, + const DocumentKey& key) { + const DocumentKeySet& existing_keys = + [target_metadata_provider_ remoteKeysForTarget:target_id]; + return existing_keys.contains(key); } } // namespace remote From e5fcf94c26a93b5f79576234e75a0cde0775f0c3 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 24 Jan 2019 18:50:55 -0500 Subject: [PATCH 054/107] Compliacne, pt.2 --- .../firebase/firestore/remote/remote_event.h | 41 ++++++++++--------- .../firebase/firestore/remote/remote_event.mm | 25 ++++++----- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 35c4bb25baf..e19a9badc06 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -83,8 +83,8 @@ class TargetState { * was added and that the target is consistent with the rest of the watch * stream. */ - bool IsCurrent() const { - return is_current_; + bool Current() const { + return current_; } /** The last resume token sent to us for this target. */ @@ -92,25 +92,22 @@ class TargetState { return resume_token_; } - /** Whether we have modified any state that should trigger a snapshot. */ - bool HasPendingChanges() const { - return has_pending_changes_; - } - /** Whether this target has pending target adds or target removes. */ bool IsPending() const { return outstanding_responses_ != 0; } + /** Whether we have modified any state that should trigger a snapshot. */ + bool HasPendingChanges() const { + return has_pending_changes_; + } + /** * Applies the resume token to the `TargetChange`, but only when it has a new * value. Empty resume tokens are discarded. */ void UpdateResumeToken(NSData* resume_token); - /** Resets the document changes and sets `HasPendingChanges` to false. */ - void ClearPendingChanges(); - /** * Creates a target change from the current set of changes. * @@ -119,20 +116,17 @@ class TargetState { */ FSTTargetChange* ToTargetChange() const; - void RecordTargetRequest(); - void RecordTargetResponse(); - void MarkCurrent(); + /** Resets the document changes and sets `HasPendingChanges` to false. */ + void ClearPendingChanges(); + void AddDocumentChange(const model::DocumentKey& document_key, core::DocumentViewChangeType type); void RemoveDocumentChange(const model::DocumentKey& document_key); + void RecordPendingTargetRequest(); + void RecordTargetResponse(); + void MarkCurrent(); private: - // We initialize to 'true' so that newly-added targets are included in the - // next RemoteEvent. - bool has_pending_changes_ = true; - - bool is_current_ = false; - /** * The number of outstanding responses (adds or removes) that we are waiting * on. We only consider targets active that have no outstanding responses. @@ -151,6 +145,15 @@ class TargetState { document_changes_; NSData* resume_token_; + + bool current_ = false; + + /** + * Whether this target state should be included in the next snapshot. We + * initialize to true so that newly-added targets are included in the next + * RemoteEvent. + */ + bool has_pending_changes_ = true; }; /** diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 9fa6c40b9dd..44456770387 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -33,6 +33,8 @@ namespace firestore { namespace remote { +// TargetState + TargetState::TargetState() : resume_token_{[NSData data]} { } @@ -43,11 +45,6 @@ } } -void TargetState::ClearPendingChanges() { - has_pending_changes_ = false; - document_changes_.clear(); -} - FSTTargetChange* TargetState::ToTargetChange() const { DocumentKeySet added_documents; DocumentKeySet modified_documents; @@ -74,13 +71,18 @@ return [[FSTTargetChange alloc] initWithResumeToken:resume_token() - current:IsCurrent() + current:Current() addedDocuments:std::move(added_documents) modifiedDocuments:std::move(modified_documents) removedDocuments:std::move(removed_documents)]; } -void TargetState::RecordTargetRequest() { +void TargetState::ClearPendingChanges() { + has_pending_changes_ = false; + document_changes_.clear(); +} + +void TargetState::RecordPendingTargetRequest() { ++outstanding_responses_; } @@ -90,7 +92,7 @@ void TargetState::MarkCurrent() { has_pending_changes_ = true; - is_current_ = true; + current_ = true; } void TargetState::AddDocumentChange(const DocumentKey& document_key, @@ -150,7 +152,8 @@ case WatchTargetChangeState::Removed: // We need to keep track of removed targets to we can post-filter and // remove any target changes. - // We need to decrement the number of pending acks needed from watch for this targetId. + // We need to decrement the number of pending acks needed from watch for + // this targetId. target_state.RecordTargetResponse(); if (!target_state.IsPending()) { RemoveTarget(target_id); @@ -244,7 +247,7 @@ FSTQueryData* query_data = QueryDataForActiveTarget(target_id); if (query_data) { - if (target_state.IsCurrent() && [query_data.query isDocumentQuery]) { + if (target_state.Current() && [query_data.query isDocumentQuery]) { // Document queries for document that don't exist can produce an empty // result set. To update our local cache, we synthesize a document // delete if we have not previously received the document. This resolves @@ -363,7 +366,7 @@ void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { // For each request we get we need to record we need a response for it. TargetState& target_state = EnsureTargetState(target_id); - target_state.RecordTargetRequest(); + target_state.RecordPendingTargetRequest(); } TargetState& WatchChangeAggregator::EnsureTargetState(TargetId target_id) { From 7a48512485fb25810a64ecec2f10a9db7cb8b747 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 25 Jan 2019 17:25:26 -0500 Subject: [PATCH 055/107] core compiles --- Firestore/Source/Core/FSTSyncEngine.mm | 16 ++-- Firestore/Source/Core/FSTView.h | 16 +++- Firestore/Source/Core/FSTView.mm | 22 +++-- Firestore/Source/Local/FSTLocalStore.mm | 20 +++-- Firestore/Source/Remote/FSTRemoteEvent.h | 60 +------------- Firestore/Source/Remote/FSTRemoteEvent.mm | 61 +------------- Firestore/Source/Remote/FSTRemoteStore.mm | 4 +- .../firebase/firestore/remote/remote_event.h | 83 ++++++++++++++++++- .../firebase/firestore/remote/remote_event.mm | 27 +++--- 9 files changed, 147 insertions(+), 162 deletions(-) diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm index 57ec5434316..8e7ff023052 100644 --- a/Firestore/Source/Core/FSTSyncEngine.mm +++ b/Firestore/Source/Core/FSTSyncEngine.mm @@ -43,6 +43,7 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" +#include "absl/types/optional.h" using firebase::firestore::auth::HashUser; using firebase::firestore::auth::User; @@ -57,6 +58,7 @@ using firebase::firestore::model::OnlineState; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::TargetChange; using firebase::firestore::util::AsyncQueue; NS_ASSUME_NONNULL_BEGIN @@ -324,23 +326,23 @@ - (void)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // Update `receivedDocument` as appropriate for any limbo targets. for (const auto &entry : remoteEvent.targetChanges) { TargetId targetID = entry.first; - FSTTargetChange *change = entry.second; + const TargetChange &change = entry.second; const auto iter = _limboResolutionsByTarget.find(targetID); if (iter != _limboResolutionsByTarget.end()) { LimboResolution &limboResolution = iter->second; // Since this is a limbo resolution lookup, it's for a single document and it could be // added, modified, or removed, but not a combination. - HARD_ASSERT(change.addedDocuments.size() + change.modifiedDocuments.size() + - change.removedDocuments.size() <= + HARD_ASSERT(change.added_documents().size() + change.modified_documents().size() + + change.removed_documents().size() <= 1, "Limbo resolution for single document contains multiple changes."); - if (change.addedDocuments.size() > 0) { + if (change.added_documents().size() > 0) { limboResolution.document_received = true; - } else if (change.modifiedDocuments.size() > 0) { + } else if (change.modified_documents().size() > 0) { HARD_ASSERT(limboResolution.document_received, "Received change for limbo target document without add."); - } else if (change.removedDocuments.size() > 0) { + } else if (change.removed_documents().size() > 0) { HARD_ASSERT(limboResolution.document_received, "Received remove for limbo target document without add."); limboResolution.document_received = false; @@ -498,7 +500,7 @@ - (void)emitNewSnapshotsAndNotifyLocalStoreWithChanges:(const MaybeDocumentMap & previousChanges:viewDocChanges]; } - FSTTargetChange *_Nullable targetChange = nil; + absl::optional targetChange; if (remoteEvent) { auto it = remoteEvent.targetChanges.find(queryView.targetID); if (it != remoteEvent.targetChanges.end()) { diff --git a/Firestore/Source/Core/FSTView.h b/Firestore/Source/Core/FSTView.h index 1a25cd4ea7d..a5a9f7ae785 100644 --- a/Firestore/Source/Core/FSTView.h +++ b/Firestore/Source/Core/FSTView.h @@ -20,11 +20,23 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" + +#include "absl/types/optional.h" + +namespace firebase { +namespace firestore { +namespace remote { + +//class TargetChange; + +} // namespace remote +} // namespace firestore +} // namespace firebase @class FSTDocumentSet; @class FSTDocumentViewChangeSet; @class FSTQuery; -@class FSTTargetChange; @class FSTViewSnapshot; NS_ASSUME_NONNULL_BEGIN @@ -140,7 +152,7 @@ typedef NS_ENUM(NSInteger, FSTLimboDocumentChangeType) { * @return A new FSTViewChange with the given docs, changes, and sync state. */ - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange:(nullable FSTTargetChange *)targetChange; + targetChange:(const absl::optional&)targetChange; /** * Applies an OnlineState change to the view, potentially generating an FSTViewChange if the diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index d400544bd58..99b21dee62c 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -26,6 +26,7 @@ #import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" using firebase::firestore::core::DocumentViewChangeType; @@ -33,6 +34,7 @@ using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::MaybeDocumentMap; using firebase::firestore::model::OnlineState; +using firebase::firestore::remote::TargetChange; NS_ASSUME_NONNULL_BEGIN @@ -343,11 +345,11 @@ - (BOOL)shouldWaitForSyncedDocument:(FSTDocument *)newDoc oldDocument:(FSTDocume } - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges { - return [self applyChangesToDocuments:docChanges targetChange:nil]; + return [self applyChangesToDocuments:docChanges targetChange:{}]; } - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange:(nullable FSTTargetChange *)targetChange { + targetChange:(const absl::optional&)targetChange { HARD_ASSERT(!docChanges.needsRefill, "Cannot apply changes that need a refill"); FSTDocumentSet *oldDocuments = self.documentSet; @@ -392,7 +394,7 @@ - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - (FSTViewChange *)applyChangedOnlineState:(OnlineState)onlineState { if (self.isCurrent && onlineState == OnlineState::Offline) { // If we're offline, set `current` to NO and then call applyChanges to refresh our syncState - // and generate an FSTViewChange as appropriate. We are guaranteed to get a new FSTTargetChange + // and generate an FSTViewChange as appropriate. We are guaranteed to get a new `TargetChange` // that sets `current` back to YES once the client is back online. self.current = NO; return @@ -433,20 +435,22 @@ - (BOOL)shouldBeLimboDocumentKey:(const DocumentKey &)key { /** * Updates syncedDocuments and current based on the given change. */ -- (void)applyTargetChange:(nullable FSTTargetChange *)targetChange { - if (targetChange) { - for (const DocumentKey &key : targetChange.addedDocuments) { +- (void)applyTargetChange:(const absl::optional&)maybeTargetChange { + if (maybeTargetChange.has_value()) { + const TargetChange& target_change = maybeTargetChange.value(); + + for (const DocumentKey &key : target_change.added_documents()) { _syncedDocuments = _syncedDocuments.insert(key); } - for (const DocumentKey &key : targetChange.modifiedDocuments) { + for (const DocumentKey &key : target_change.modified_documents()) { HARD_ASSERT(_syncedDocuments.find(key) != _syncedDocuments.end(), "Modified document %s not found in view.", key.ToString()); } - for (const DocumentKey &key : targetChange.removedDocuments) { + for (const DocumentKey &key : target_change.removed_documents()) { _syncedDocuments = _syncedDocuments.erase(key); } - self.current = targetChange.current; + self.current = target_change.current(); } } diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 11f0aec0898..bda772354b9 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -42,6 +42,7 @@ #include "Firestore/core/src/firebase/firestore/local/reference_set.h" #include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" @@ -60,6 +61,7 @@ using firebase::firestore::model::ListenSequenceNumber; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::TargetChange; NS_ASSUME_NONNULL_BEGIN @@ -216,7 +218,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { DocumentKeySet authoritativeUpdates; for (const auto &entry : remoteEvent.targetChanges) { TargetId targetID = entry.first; - FSTTargetChange *change = entry.second; + const TargetChange& change = entry.second; // Do not ref/unref unassigned targetIDs - it may lead to leaks. auto found = _targetIDs.find(targetID); @@ -233,20 +235,20 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // If the document is only updated while removing it from a target then watch isn't obligated // to send the absolute latest version: it can send the first version that caused the document // not to match. - for (const DocumentKey &key : change.addedDocuments) { + for (const DocumentKey &key : change.added_documents()) { authoritativeUpdates = authoritativeUpdates.insert(key); } - for (const DocumentKey &key : change.modifiedDocuments) { + for (const DocumentKey &key : change.modified_documents()) { authoritativeUpdates = authoritativeUpdates.insert(key); } - _queryCache->RemoveMatchingKeys(change.removedDocuments, targetID); - _queryCache->AddMatchingKeys(change.addedDocuments, targetID); + _queryCache->RemoveMatchingKeys(change.removed_documents(), targetID); + _queryCache->AddMatchingKeys(change.added_documents(), targetID); // Update the resume token if the change includes one. Don't clear any preexisting value. // Bump the sequence number as well, so that documents being removed now are ordered later // than documents that were previously removed from this target. - NSData *resumeToken = change.resumeToken; + NSData *resumeToken = change.resume_token(); if (resumeToken.length > 0) { FSTQueryData *oldQueryData = queryData; queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshotVersion @@ -328,7 +330,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { */ - (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData oldQueryData:(FSTQueryData *)oldQueryData - change:(FSTTargetChange *)change { + change:(const TargetChange&)change { // Avoid clearing any existing value if (newQueryData.resumeToken.length == 0) return NO; @@ -348,8 +350,8 @@ - (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData // worth persisting. Note that the RemoteStore keeps an in-memory view of the currently active // targets which includes the current resume token, so stream failure or user changes will still // use an up-to-date resume token regardless of what we do here. - size_t changes = change.addedDocuments.size() + change.modifiedDocuments.size() + - change.removedDocuments.size(); + size_t changes = change.added_documents().size() + change.modified_documents().size() + + change.removed_documents().size(); return changes > 0; } diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 3a97a4be138..588cd6ec057 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -33,62 +33,6 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTTargetChange - -/** - * An FSTTargetChange specifies the set of changes for a specific target as part of an - * FSTRemoteEvent. These changes track which documents are added, modified or emoved, as well as the - * target's resume token and whether the target is marked CURRENT. - * - * The actual changes *to* documents are not part of the FSTTargetChange since documents may be part - * of multiple targets. - */ -@interface FSTTargetChange : NSObject - -/** - * Creates a new target change with the given SnapshotVersion. - */ -- (instancetype)initWithResumeToken:(NSData *)resumeToken - current:(BOOL)current - addedDocuments:(firebase::firestore::model::DocumentKeySet)addedDocuments - modifiedDocuments:(firebase::firestore::model::DocumentKeySet)modifiedDocuments - removedDocuments:(firebase::firestore::model::DocumentKeySet)removedDocuments - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/** - * An opaque, server-assigned token that allows watching a query to be resumed after - * disconnecting without retransmitting all the data that matches the query. The resume token - * essentially identifies a point in time from which the server should resume sending results. - */ -@property(nonatomic, strong, readonly) NSData *resumeToken; - -/** - * The "current" (synced) status of this target. Note that "current" has special meaning in the RPC - * protocol that implies that a target is both up-to-date and consistent with the rest of the watch - * stream. - */ -@property(nonatomic, assign, readonly) BOOL current; - -/** - * The set of documents that were newly assigned to this target as part of this remote event. - */ -- (const firebase::firestore::model::DocumentKeySet &)addedDocuments; - -/** - * The set of documents that were already assigned to this target but received an update during this - * remote event. - */ -- (const firebase::firestore::model::DocumentKeySet &)modifiedDocuments; - -/** - * The set of documents that were removed from this target as part of this remote event. - */ -- (const firebase::firestore::model::DocumentKeySet &)removedDocuments; - -@end - #pragma mark - FSTRemoteEvent /** @@ -100,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype) initWithSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion targetChanges: - (std::unordered_map) + (std::unordered_map) targetChanges targetMismatches: (std::unordered_set)targetMismatches @@ -119,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN - (const firebase::firestore::model::DocumentKeySet &)limboDocumentChanges; /** A map from target to changes to the target. See TargetChange. */ -- (const std::unordered_map &) +- (const std::unordered_map &) targetChanges; /** diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 408c2501ce8..46988368cab 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -40,69 +40,16 @@ using firebase::firestore::model::TargetId; using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; using firebase::firestore::util::Hash; NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTTargetChange - -@implementation FSTTargetChange { - DocumentKeySet _addedDocuments; - DocumentKeySet _modifiedDocuments; - DocumentKeySet _removedDocuments; -} - -- (instancetype)initWithResumeToken:(NSData *)resumeToken - current:(BOOL)current - addedDocuments:(DocumentKeySet)addedDocuments - modifiedDocuments:(DocumentKeySet)modifiedDocuments - removedDocuments:(DocumentKeySet)removedDocuments { - if (self = [super init]) { - _resumeToken = [resumeToken copy]; - _current = current; - _addedDocuments = std::move(addedDocuments); - _modifiedDocuments = std::move(modifiedDocuments); - _removedDocuments = std::move(removedDocuments); - } - return self; -} - -- (const DocumentKeySet &)addedDocuments { - return _addedDocuments; -} - -- (const DocumentKeySet &)modifiedDocuments { - return _modifiedDocuments; -} - -- (const DocumentKeySet &)removedDocuments { - return _removedDocuments; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isMemberOfClass:[FSTTargetChange class]]) { - return NO; - } - - return [self current] == [other current] && - [[self resumeToken] isEqualToData:[other resumeToken]] && - [self addedDocuments] == [other addedDocuments] && - [self modifiedDocuments] == [other modifiedDocuments] && - [self removedDocuments] == [other removedDocuments]; -} - -@end - -#pragma mark - FSTRemoteEvent - @implementation FSTRemoteEvent { SnapshotVersion _snapshotVersion; - std::unordered_map _targetChanges; + std::unordered_map _targetChanges; std::unordered_set _targetMismatches; std::unordered_map _documentUpdates; DocumentKeySet _limboDocumentChanges; @@ -110,7 +57,7 @@ @implementation FSTRemoteEvent { - (instancetype) initWithSnapshotVersion:(SnapshotVersion)snapshotVersion - targetChanges:(std::unordered_map)targetChanges + targetChanges:(std::unordered_map)targetChanges targetMismatches:(std::unordered_set)targetMismatches documentUpdates:(std::unordered_map) documentUpdates @@ -134,7 +81,7 @@ @implementation FSTRemoteEvent { return _limboDocumentChanges; } -- (const std::unordered_map &)targetChanges { +- (const std::unordered_map &)targetChanges { return _targetChanges; } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 507c4c6ec6f..bb38611193f 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -60,6 +60,7 @@ using firebase::firestore::remote::WriteStream; using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; @@ -377,7 +378,8 @@ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotV // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when // applying the completed FSTRemoteEvent. for (const auto &entry : remoteEvent.targetChanges) { - NSData *resumeToken = entry.second.resumeToken; + const TargetChange& target_change = entry.second; + NSData *resumeToken = target_change.resume_token(); if (resumeToken.length > 0) { TargetId targetID = entry.first; auto found = _listenTargets.find(targetID); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index e19a9badc06..d08f53d4984 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -40,7 +40,6 @@ @class FSTMaybeDocument; @class FSTQueryData; @class FSTRemoteEvent; -@class FSTTargetChange; NS_ASSUME_NONNULL_BEGIN @@ -70,6 +69,82 @@ namespace firebase { namespace firestore { namespace remote { +/** + * A `TargetChange` specifies the set of changes for a specific target as part + * of an `FSTRemoteEvent`. These changes track which documents are added, + * modified or emoved, as well as the target's resume token and whether the + * target is marked CURRENT. + * + * The actual changes *to* documents are not part of the `TargetChange` since + * documents may be part of multiple targets. + */ +class TargetChange { + public: + TargetChange() = default; + + TargetChange(NSData* resume_token, + bool current, + model::DocumentKeySet added_documents, + model::DocumentKeySet modified_documents, + model::DocumentKeySet removed_documents) + : resume_token_{resume_token}, + current_{current}, + added_documents_{std::move(added_documents)}, + modified_documents_{std::move(modified_documents)}, + removed_documents_{std::move(removed_documents)} { + } + + /** + * An opaque, server-assigned token that allows watching a query to be resumed + * after disconnecting without retransmitting all the data that matches the + * query. The resume token essentially identifies a point in time from which + * the server should resume sending results. + */ + NSData* resume_token() const { + return resume_token_; + } + + /** + * The "current" (synced) status of this target. Note that "current" has + * special meaning in the RPC protocol that implies that a target is both + * up-to-date and consistent with the rest of the watch stream. + */ + bool current() const { + return current_; + } + + /** + * The set of documents that were newly assigned to this target as part of + * this remote event. + */ + const model::DocumentKeySet& added_documents() const { + return added_documents_; + } + + /** + * The set of documents that were already assigned to this target but received + * an update during this remote event. + */ + const model::DocumentKeySet& modified_documents() const { + return modified_documents_; + } + + /** + * The set of documents that were removed from this target as part of this + * remote event. + */ + const model::DocumentKeySet& removed_documents() const { + return removed_documents_; + } + + private: + NSData* resume_token_ = nil; + bool current_ = false; + model::DocumentKeySet added_documents_; + model::DocumentKeySet modified_documents_; + model::DocumentKeySet removed_documents_; +}; + /** Tracks the internal state of a Watch target. */ class TargetState { public: @@ -78,12 +153,12 @@ class TargetState { /** * Whether this target has been marked 'current'. * - * 'Current' has special meaning in the RPC protocol: It implies that the + * 'current' has special meaning in the RPC protocol: It implies that the * Watch backend has sent us all changes up to the point at which the target * was added and that the target is consistent with the rest of the watch * stream. */ - bool Current() const { + bool current() const { return current_; } @@ -114,7 +189,7 @@ class TargetState { * To reset the document changes after raising this snapshot, call * `ClearPendingChanges()`. */ - FSTTargetChange* ToTargetChange() const; + TargetChange ToTargetChange() const; /** Resets the document changes and sets `HasPendingChanges` to false. */ void ClearPendingChanges(); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 44456770387..f6f870ef335 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -45,7 +45,7 @@ } } -FSTTargetChange* TargetState::ToTargetChange() const { +TargetChange TargetState::ToTargetChange() const { DocumentKeySet added_documents; DocumentKeySet modified_documents; DocumentKeySet removed_documents; @@ -69,12 +69,9 @@ } } - return [[FSTTargetChange alloc] - initWithResumeToken:resume_token() - current:Current() - addedDocuments:std::move(added_documents) - modifiedDocuments:std::move(modified_documents) - removedDocuments:std::move(removed_documents)]; + return TargetChange{resume_token(), current(), std::move(added_documents), + std::move(modified_documents), + std::move(removed_documents)}; } void TargetState::ClearPendingChanges() { @@ -239,7 +236,7 @@ FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( const SnapshotVersion& snapshot_version) { - std::unordered_map target_changes; + std::unordered_map target_changes; for (auto& entry : target_states_) { TargetId target_id = entry.first; @@ -247,7 +244,7 @@ FSTQueryData* query_data = QueryDataForActiveTarget(target_id); if (query_data) { - if (target_state.Current() && [query_data.query isDocumentQuery]) { + if (target_state.current() && [query_data.query isDocumentQuery]) { // Document queries for document that don't exist can produce an empty // result set. To update our local cache, we synthesize a document // delete if we have not previously received the document. This resolves @@ -296,9 +293,9 @@ FSTRemoteEvent* remote_event = [[FSTRemoteEvent alloc] initWithSnapshotVersion:snapshot_version targetChanges:target_changes - targetMismatches:pending_target_resets_ - documentUpdates:pending_document_updates_ - limboDocuments:resolved_limbo_documents]; + targetMismatches:std::move(pending_target_resets_) + documentUpdates:std::move(pending_document_updates_) + limboDocuments:std::move(resolved_limbo_documents)]; // Re-initialize the current state to ensure that we do not modify the // generated `RemoteEvent`. @@ -357,10 +354,10 @@ int WatchChangeAggregator::GetCurrentDocumentCountForTarget( TargetId target_id) { TargetState& target_state = EnsureTargetState(target_id); - FSTTargetChange* target_change = target_state.ToTargetChange(); + TargetChange target_change = target_state.ToTargetChange(); return ([target_metadata_provider_ remoteKeysForTarget:target_id].size() + - target_change.addedDocuments.size() - - target_change.removedDocuments.size()); + target_change.added_documents().size() - + target_change.removed_documents().size()); } void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { From 66d8af2437443e936570faf782dd99f1bcfc986f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 25 Jan 2019 20:00:48 -0500 Subject: [PATCH 056/107] unit tests compile --- .../Tests/Core/FSTQueryListenerTests.mm | 48 +++--- Firestore/Example/Tests/Core/FSTViewTests.mm | 19 +-- .../Tests/Remote/FSTRemoteEventTests.mm | 149 +++++++++--------- Firestore/Example/Tests/Util/FSTHelpers.h | 16 +- Firestore/Example/Tests/Util/FSTHelpers.mm | 35 +--- .../firebase/firestore/remote/remote_event.h | 2 + .../firebase/firestore/remote/remote_event.mm | 22 ++- 7 files changed, 139 insertions(+), 152 deletions(-) diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm index 12b4f9ecaf0..d0d8f45703d 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm @@ -28,12 +28,14 @@ #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" #include "absl/memory/memory.h" using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::OnlineState; +using firebase::firestore::remote::TargetChange; using firebase::firestore::util::ExecutorLibdispatch; NS_ASSUME_NONNULL_BEGIN @@ -84,8 +86,8 @@ - (void)testRaisesCollectionEvents { FSTQueryListener *otherListener = [self listenToQuery:query accumulatingSnapshots:otherAccum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2prime ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2prime ], absl::nullopt); FSTDocumentViewChange *change1 = [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::kAdded]; @@ -142,7 +144,7 @@ - (void)testRaisesEventForEmptyCollectionAfterSync { accumulatingSnapshots:accum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], absl::nullopt); FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[], FSTTestTargetChangeMarkCurrent()); [listener queryDidChangeViewSnapshot:snap1]; @@ -167,8 +169,8 @@ - (void)testMutingAsyncListenerPreventsAllSubsequentEvents { }]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *viewSnapshot1 = FSTTestApplyChanges(view, @[ doc1 ], nil); - FSTViewSnapshot *viewSnapshot2 = FSTTestApplyChanges(view, @[ doc2 ], nil); + FSTViewSnapshot *viewSnapshot1 = FSTTestApplyChanges(view, @[ doc1 ], absl::nullopt); + FSTViewSnapshot *viewSnapshot2 = FSTTestApplyChanges(view, @[ doc2 ], absl::nullopt); FSTViewSnapshotHandler handler = listener.asyncSnapshotHandler; handler(viewSnapshot1, nil); @@ -204,11 +206,11 @@ - (void)testDoesNotRaiseEventsForMetadataChangesUnlessSpecified { accumulatingSnapshots:fullAccum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], absl::nullopt); - FSTTargetChange *ackTarget = FSTTestTargetChangeAckDocuments({doc1.key}); + TargetChange ackTarget = FSTTestTargetChangeAckDocuments({doc1.key}); FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[], ackTarget); - FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc2 ], nil); + FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc2 ], absl::nullopt); [filteredListener queryDidChangeViewSnapshot:snap1]; // local event [filteredListener queryDidChangeViewSnapshot:snap2]; // no event @@ -248,9 +250,9 @@ - (void)testRaisesDocumentMetadataEventsOnlyWhenSpecified { accumulatingSnapshots:fullAccum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime ], nil); - FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc3 ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime ], absl::nullopt); + FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc3 ], absl::nullopt); FSTDocumentViewChange *change1 = [FSTDocumentViewChange changeWithDocument:doc1 type:DocumentViewChangeType::kAdded]; @@ -303,10 +305,10 @@ - (void)testRaisesQueryMetadataEventsOnlyWhenHasPendingWritesOnTheQueryChanges { accumulatingSnapshots:fullAccum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime ], nil); - FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc3 ], nil); - FSTViewSnapshot *snap4 = FSTTestApplyChanges(view, @[ doc2Prime ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime ], absl::nullopt); + FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[ doc3 ], absl::nullopt); + FSTViewSnapshot *snap4 = FSTTestApplyChanges(view, @[ doc2Prime ], absl::nullopt); [fullListener queryDidChangeViewSnapshot:snap1]; [fullListener queryDidChangeViewSnapshot:snap2]; // Emits no events. @@ -343,8 +345,8 @@ - (void)testMetadataOnlyDocumentChangesAreFilteredOutWhenIncludeDocumentMetadata accumulatingSnapshots:filteredAccum]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime, doc3 ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc1Prime, doc3 ], absl::nullopt); FSTDocumentViewChange *change3 = [FSTDocumentViewChange changeWithDocument:doc3 type:DocumentViewChangeType::kAdded]; @@ -378,8 +380,8 @@ - (void)testWillWaitForSyncIfOnline { accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2 ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2 ], absl::nullopt); FSTViewSnapshot *snap3 = FSTTestApplyChanges(view, @[], FSTTestTargetChangeAckDocuments({doc1.key, doc2.key})); @@ -420,8 +422,8 @@ - (void)testWillRaiseInitialEventWhenGoingOffline { accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], nil); - FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2 ], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[ doc1 ], absl::nullopt); + FSTViewSnapshot *snap2 = FSTTestApplyChanges(view, @[ doc2 ], absl::nullopt); [listener applyChangedOnlineState:OnlineState::Online]; // no event [listener queryDidChangeViewSnapshot:snap1]; // no event @@ -463,7 +465,7 @@ - (void)testWillRaiseInitialEventWhenGoingOfflineAndThereAreNoDocs { accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], absl::nullopt); [listener applyChangedOnlineState:OnlineState::Online]; // no event [listener queryDidChangeViewSnapshot:snap1]; // no event @@ -490,7 +492,7 @@ - (void)testWillRaiseInitialEventWhenStartingOfflineAndThereAreNoDocs { accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], nil); + FSTViewSnapshot *snap1 = FSTTestApplyChanges(view, @[], absl::nullopt); [listener applyChangedOnlineState:OnlineState::Offline]; // no event [listener queryDidChangeViewSnapshot:snap1]; // event diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm index 9173b3ce579..2f15e554a92 100644 --- a/Firestore/Example/Tests/Core/FSTViewTests.mm +++ b/Firestore/Example/Tests/Core/FSTViewTests.mm @@ -30,6 +30,7 @@ #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +#include "absl/types/optional.h" namespace testutil = firebase::firestore::testutil; using firebase::firestore::core::DocumentViewChangeType; @@ -89,7 +90,7 @@ - (void)testRemovesDocuments { FSTTestDoc("rooms/eros/messages/3", 0, @{@"text" : @"msg3"}, FSTDocumentStateSynced); // initial state - FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); + FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); // delete doc2, add doc3 FSTViewSnapshot *snapshot = @@ -120,10 +121,10 @@ - (void)testReturnsNilIfThereAreNoChanges { FSTTestDoc("rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, FSTDocumentStateSynced); // initial state - FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); + FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); // reapply same docs, no changes - FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); + FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); XCTAssertNil(snapshot); } @@ -131,7 +132,7 @@ - (void)testDoesNotReturnNilForFirstChanges { FSTQuery *query = [self queryForMessages]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:DocumentKeySet{}]; - FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[], nil); + FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[], absl::nullopt); XCTAssertNotNil(snapshot); } @@ -155,7 +156,7 @@ - (void)testFiltersDocumentsBasedOnQueryWithFilter { FSTDocument *doc5 = FSTTestDoc("rooms/eros/messages/5", 0, @{@"sort" : @1}, FSTDocumentStateSynced); - FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4, doc5 ], nil); + FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4, doc5 ], absl::nullopt); XCTAssertEqual(snapshot.query, query); @@ -189,7 +190,7 @@ - (void)testUpdatesDocumentsBasedOnQueryWithFilter { FSTTestDoc("rooms/eros/messages/3", 0, @{@"sort" : @2}, FSTDocumentStateSynced); FSTDocument *doc4 = FSTTestDoc("rooms/eros/messages/4", 0, @{}, FSTDocumentStateSynced); - FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4 ], nil); + FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4 ], absl::nullopt); XCTAssertEqual(snapshot.query, query); @@ -202,7 +203,7 @@ - (void)testUpdatesDocumentsBasedOnQueryWithFilter { FSTDocument *newDoc4 = FSTTestDoc("rooms/eros/messages/4", 1, @{@"sort" : @0}, FSTDocumentStateSynced); - snapshot = FSTTestApplyChanges(view, @[ newDoc2, newDoc3, newDoc4 ], nil); + snapshot = FSTTestApplyChanges(view, @[ newDoc2, newDoc3, newDoc4 ], absl::nullopt); XCTAssertEqual(snapshot.query, query); @@ -232,7 +233,7 @@ - (void)testRemovesDocumentsForQueryWithLimit { FSTTestDoc("rooms/eros/messages/3", 0, @{@"text" : @"msg3"}, FSTDocumentStateSynced); // initial state - FSTTestApplyChanges(view, @[ doc1, doc3 ], nil); + FSTTestApplyChanges(view, @[ doc1, doc3 ], absl::nullopt); // add doc2, which should push out doc3 FSTViewSnapshot *snapshot = FSTTestApplyChanges( @@ -269,7 +270,7 @@ - (void)testDoesntReportChangesForDocumentBeyondLimitOfQuery { FSTTestDoc("rooms/eros/messages/4", 0, @{@"num" : @4}, FSTDocumentStateSynced); // initial state - FSTTestApplyChanges(view, @[ doc1, doc2 ], nil); + FSTTestApplyChanges(view, @[ doc1, doc2 ], absl::nullopt); // change doc2 to 5, and add doc3 and doc4. // doc2 will be modified + removed = removed diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index b728ee94777..0f85982b3ae 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -46,6 +46,7 @@ using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilter; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; @@ -252,31 +253,29 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // 'change1' and 'change2' affect six different targets XCTAssertEqual(event.targetChanges.size(), 6); - FSTTargetChange *targetChange1 = - FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, - DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{newDoc.key}, + DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); - FSTTargetChange *targetChange2 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{existingDoc.key}, DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(2), targetChange2); + TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, + DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(2) == targetChange2); - FSTTargetChange *targetChange3 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{existingDoc.key}, DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(3), targetChange3); + TargetChange targetChange3{_resumeToken1, false, DocumentKeySet{}, + DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(3) == targetChange3); - FSTTargetChange *targetChange4 = - FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{}, - DocumentKeySet{existingDoc.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(4), targetChange4); + TargetChange targetChange4{_resumeToken1, false, DocumentKeySet{newDoc.key}, DocumentKeySet{}, + DocumentKeySet{existingDoc.key}}; + XCTAssertTrue(event.targetChanges.at(4) == targetChange4); - FSTTargetChange *targetChange5 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{existingDoc.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(5), targetChange5); + TargetChange targetChange5{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{existingDoc.key}}; + XCTAssertTrue(event.targetChanges.at(5) == targetChange5); - FSTTargetChange *targetChange6 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{existingDoc.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(6), targetChange6); + TargetChange targetChange6{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{existingDoc.key}}; + XCTAssertTrue(event.targetChanges.at(6) == targetChange6); } - (void)testWillIgnoreEventsForPendingTargets { @@ -368,9 +367,9 @@ - (void)testWillKeepResetMappingEvenWithUpdates { XCTAssertEqual(event.targetChanges.size(), 1); // Only doc3 is part of the new mapping - FSTTargetChange *expectedChange = FSTTestTargetChange( - DocumentKeySet{doc3.key}, DocumentKeySet{}, DocumentKeySet{doc1.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), expectedChange); + TargetChange expectedChange{_resumeToken1, false, DocumentKeySet{doc3.key}, DocumentKeySet{}, + DocumentKeySet{doc1.key}}; + XCTAssertTrue(event.targetChanges.at(1) == expectedChange); } - (void)testWillHandleSingleReset { @@ -392,9 +391,9 @@ - (void)testWillHandleSingleReset { XCTAssertEqual(event.targetChanges.size(), 1); // Reset mapping is empty - FSTTargetChange *expectedChange = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, [NSData data], NO); - XCTAssertEqualObjects(event.targetChanges.at(1), expectedChange); + TargetChange expectedChange{ + [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == expectedChange); } - (void)testWillHandleTargetAddAndRemovalInSameBatch { @@ -418,13 +417,13 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { XCTAssertEqual(event.targetChanges.size(), 2); - FSTTargetChange *targetChange1 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1b.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{doc1b.key}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); - FSTTargetChange *targetChange2 = FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{doc1b.key}, - DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(2), targetChange2); + TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{doc1b.key}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(2) == targetChange2); } - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { @@ -442,9 +441,9 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.targetChanges.size(), 1); - FSTTargetChange *targetChange = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, _resumeToken1, YES); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange); + TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); } - (void)testTargetAddedChangeWillResetPreviousState { @@ -480,15 +479,15 @@ - (void)testTargetAddedChangeWillResetPreviousState { // doc1 was before the remove, so it does not show up in the mapping. // Current was before the remove. - FSTTargetChange *targetChange1 = FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{doc2.key}, - DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{doc2.key}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); // Doc1 was before the remove // Current was before the remove - FSTTargetChange *targetChange3 = FSTTestTargetChange( - DocumentKeySet{doc1.key}, DocumentKeySet{}, DocumentKeySet{doc2.key}, _resumeToken1, YES); - XCTAssertEqualObjects(event.targetChanges.at(3), targetChange3); + TargetChange targetChange3{_resumeToken1, true, DocumentKeySet{doc1.key}, DocumentKeySet{}, + DocumentKeySet{doc2.key}}; + XCTAssertTrue(event.targetChanges.at(3) == targetChange3); } - (void)testNoChangeWillStillMarkTheAffectedTargets { @@ -508,9 +507,9 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { XCTAssertEqual(event.documentUpdates.size(), 0); XCTAssertEqual(event.targetChanges.size(), 1); - FSTTargetChange *targetChange = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange); + TargetChange targetChange{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange); } - (void)testExistenceFilterMismatchClearsTarget { @@ -537,13 +536,13 @@ - (void)testExistenceFilterMismatchClearsTarget { XCTAssertEqual(event.targetChanges.size(), 2); - FSTTargetChange *targetChange1 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}, DocumentKeySet{}, _resumeToken1, YES); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{doc1.key, doc2.key}, + DocumentKeySet{}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); - FSTTargetChange *targetChange2 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(2), targetChange2); + TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(2) == targetChange2); // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. @@ -552,9 +551,9 @@ - (void)testExistenceFilterMismatchClearsTarget { event = aggregator.CreateRemoteEvent(testutil::Version(4)); - FSTTargetChange *targetChange3 = FSTTestTargetChange( - DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}, [NSData data], NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange3); + TargetChange targetChange3{ + [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange3); XCTAssertEqual(event.targetChanges.size(), 1); XCTAssertEqual(event.targetMismatches.size(), 1); @@ -590,9 +589,9 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { XCTAssertEqual(event.targetChanges.size(), 1); - FSTTargetChange *targetChange1 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, [NSData data], NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{ + [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); } - (void)testDocumentUpdate { @@ -647,10 +646,9 @@ - (void)testDocumentUpdate { // Target is unchanged XCTAssertEqual(event.targetChanges.size(), 1); - FSTTargetChange *targetChange = - FSTTestTargetChange(DocumentKeySet{doc3.key}, DocumentKeySet{updatedDoc2.key}, - DocumentKeySet{deletedDoc1.key}, _resumeToken1, NO); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange); + TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{doc3.key}, + DocumentKeySet{updatedDoc2.key}, DocumentKeySet{deletedDoc1.key}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); } - (void)testResumeTokensHandledPerTarget { @@ -671,13 +669,13 @@ - (void)testResumeTokensHandledPerTarget { FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.targetChanges.size(), 2); - FSTTargetChange *targetChange1 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, _resumeToken1, YES); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); - FSTTargetChange *targetChange2 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, resumeToken2, YES); - XCTAssertEqualObjects(event.targetChanges.at(2), targetChange2); + TargetChange targetChange2{resumeToken2, true, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(2) == targetChange2); } - (void)testLastResumeTokenWins { @@ -702,13 +700,13 @@ - (void)testLastResumeTokenWins { FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); XCTAssertEqual(event.targetChanges.size(), 2); - FSTTargetChange *targetChange1 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, resumeToken2, YES); - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange1); + TargetChange targetChange1{resumeToken2, true, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(1) == targetChange1); - FSTTargetChange *targetChange2 = - FSTTestTargetChange(DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}, resumeToken3, NO); - XCTAssertEqualObjects(event.targetChanges.at(2), targetChange2); + TargetChange targetChange2{resumeToken3, false, DocumentKeySet{}, DocumentKeySet{}, + DocumentKeySet{}}; + XCTAssertTrue(event.targetChanges.at(2) == targetChange2); } - (void)testSynthesizeDeletes { @@ -786,11 +784,10 @@ - (void)testSeparatesDocumentUpdates { std::move(deletedDocChange), std::move(missingDocChange))]; - FSTTargetChange *targetChange = - FSTTestTargetChange(DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, - DocumentKeySet{deletedDoc.key}, _resumeToken1, NO); + TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{newDoc.key}, + DocumentKeySet{existingDoc.key}, DocumentKeySet{deletedDoc.key}}; - XCTAssertEqualObjects(event.targetChanges.at(1), targetChange); + XCTAssertTrue(event.targetChanges.at(1) == targetChange2); } - (void)testTracksLimboDocuments { diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index a276ef4900b..6b975448dfa 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -27,7 +27,9 @@ #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" @class FIRGeoPoint; @class FSTDeleteMutation; @@ -43,7 +45,6 @@ @class FSTRemoteEvent; @class FSTSetMutation; @class FSTSortOrder; -@class FSTTargetChange; @class FIRTimestamp; @class FSTTransformMutation; @class FSTView; @@ -258,7 +259,7 @@ FSTDocumentSet *FSTTestDocSet(NSComparator comp, NSArray *docs); /** Computes changes to the view with the docs and then applies them and returns the snapshot. */ FSTViewSnapshot *_Nullable FSTTestApplyChanges(FSTView *view, NSArray *docs, - FSTTargetChange *_Nullable targetChange); + const absl::optional & targetChange); /** Creates a set mutation for the document key at the given path. */ FSTSetMutation *FSTTestSetMutation(NSString *path, NSDictionary *values); @@ -305,17 +306,10 @@ FSTLocalViewChanges *FSTTestViewChanges(firebase::firestore::model::TargetId tar NSArray *removedKeys); /** Creates a test target change that acks all 'docs' and marks the target as CURRENT */ -FSTTargetChange *FSTTestTargetChangeAckDocuments(firebase::firestore::model::DocumentKeySet docs); +firebase::firestore::remote::TargetChange FSTTestTargetChangeAckDocuments(firebase::firestore::model::DocumentKeySet docs); /** Creates a test target change that marks the target as CURRENT */ -FSTTargetChange *FSTTestTargetChangeMarkCurrent(); - -/** Creates a test target change. */ -FSTTargetChange *FSTTestTargetChange(firebase::firestore::model::DocumentKeySet added, - firebase::firestore::model::DocumentKeySet modified, - firebase::firestore::model::DocumentKeySet removed, - NSData *resumeToken, - BOOL current); +firebase::firestore::remote::TargetChange FSTTestTargetChangeMarkCurrent(); /** Creates a resume token to match the given snapshot version. */ NSData *_Nullable FSTTestResumeTokenFromSnapshotVersion(FSTTestSnapshotVersion watchSnapshot); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index ffd04dd8c1b..75f6a6ee48b 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -73,6 +73,7 @@ using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChangeAggregator; NS_ASSUME_NONNULL_BEGIN @@ -299,7 +300,7 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { FSTViewSnapshot *_Nullable FSTTestApplyChanges(FSTView *view, NSArray *docs, - FSTTargetChange *_Nullable targetChange) { + const absl::optional& targetChange) { return [view applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(docs)] targetChange:targetChange] .snapshot; @@ -385,32 +386,12 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { return aggregator.CreateRemoteEvent(doc.version); } -FSTTargetChange *FSTTestTargetChangeMarkCurrent() { - return [[FSTTargetChange alloc] initWithResumeToken:[NSData data] - current:YES - addedDocuments:DocumentKeySet {} - modifiedDocuments:DocumentKeySet {} - removedDocuments:DocumentKeySet{}]; -} - -FSTTargetChange *FSTTestTargetChangeAckDocuments(DocumentKeySet docs) { - return [[FSTTargetChange alloc] initWithResumeToken:[NSData data] - current:YES - addedDocuments:docs - modifiedDocuments:DocumentKeySet {} - removedDocuments:DocumentKeySet{}]; -} - -FSTTargetChange *FSTTestTargetChange(DocumentKeySet added, - DocumentKeySet modified, - DocumentKeySet removed, - NSData *resumeToken, - BOOL current) { - return [[FSTTargetChange alloc] initWithResumeToken:resumeToken - current:current - addedDocuments:added - modifiedDocuments:modified - removedDocuments:removed]; +TargetChange FSTTestTargetChangeMarkCurrent() { + return {[NSData data], true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; +} + +TargetChange FSTTestTargetChangeAckDocuments(DocumentKeySet docs) { + return {[NSData data], true, std::move(docs), DocumentKeySet{}, DocumentKeySet{}}; } FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index d08f53d4984..02ea3dec400 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -145,6 +145,8 @@ class TargetChange { model::DocumentKeySet removed_documents_; }; +bool operator==(const TargetChange& lhs, const TargetChange& rhs); + /** Tracks the internal state of a Watch target. */ class TargetState { public: diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index f6f870ef335..c94eb04daa1 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -33,6 +33,16 @@ namespace firestore { namespace remote { +// TargetChange + +bool operator==(const TargetChange& lhs, const TargetChange& rhs) { + return [lhs.resume_token() isEqualToData:rhs.resume_token()] && + lhs.current() == rhs.current() && + lhs.added_documents() == rhs.added_documents() && + lhs.modified_documents() == rhs.modified_documents() && + lhs.removed_documents() == rhs.removed_documents(); +} + // TargetState TargetState::TargetState() : resume_token_{[NSData data]} { @@ -290,12 +300,12 @@ } } - FSTRemoteEvent* remote_event = - [[FSTRemoteEvent alloc] initWithSnapshotVersion:snapshot_version - targetChanges:target_changes - targetMismatches:std::move(pending_target_resets_) - documentUpdates:std::move(pending_document_updates_) - limboDocuments:std::move(resolved_limbo_documents)]; + FSTRemoteEvent* remote_event = [[FSTRemoteEvent alloc] + initWithSnapshotVersion:snapshot_version + targetChanges:target_changes + targetMismatches:std::move(pending_target_resets_) + documentUpdates:std::move(pending_document_updates_) + limboDocuments:std::move(resolved_limbo_documents)]; // Re-initialize the current state to ensure that we do not modify the // generated `RemoteEvent`. From 594a8415d2c8eba14964658e224f5efc17c48bf5 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 25 Jan 2019 20:06:20 -0500 Subject: [PATCH 057/107] Fix unit test -- all pass --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 0f85982b3ae..22b750a7a54 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -486,7 +486,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { // Doc1 was before the remove // Current was before the remove TargetChange targetChange3{_resumeToken1, true, DocumentKeySet{doc1.key}, DocumentKeySet{}, - DocumentKeySet{doc2.key}}; + DocumentKeySet{doc2.key}}; XCTAssertTrue(event.targetChanges.at(3) == targetChange3); } @@ -536,8 +536,8 @@ - (void)testExistenceFilterMismatchClearsTarget { XCTAssertEqual(event.targetChanges.size(), 2); - TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{doc1.key, doc2.key}, - DocumentKeySet{}, DocumentKeySet{}}; + TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, + DocumentKeySet{doc1.key, doc2.key}, DocumentKeySet{}}; XCTAssertTrue(event.targetChanges.at(1) == targetChange1); TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, From 77d9cd73d727ebc03186e9ba505bbb57bb4c7fda Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Sat, 26 Jan 2019 16:39:02 -0500 Subject: [PATCH 058/107] style.sh --- Firestore/Example/Tests/Core/FSTViewTests.mm | 3 ++- Firestore/Example/Tests/Util/FSTHelpers.h | 10 ++++++---- Firestore/Example/Tests/Util/FSTHelpers.mm | 2 +- Firestore/Source/Core/FSTView.h | 8 +++++--- Firestore/Source/Core/FSTView.mm | 6 +++--- Firestore/Source/Local/FSTLocalStore.mm | 11 ++++++----- Firestore/Source/Remote/FSTRemoteEvent.h | 8 ++++---- Firestore/Source/Remote/FSTRemoteEvent.mm | 12 ++++++------ Firestore/Source/Remote/FSTRemoteStore.mm | 2 +- .../src/firebase/firestore/remote/remote_event.h | 1 + 10 files changed, 35 insertions(+), 28 deletions(-) diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm index 2f15e554a92..5e6c432d40b 100644 --- a/Firestore/Example/Tests/Core/FSTViewTests.mm +++ b/Firestore/Example/Tests/Core/FSTViewTests.mm @@ -156,7 +156,8 @@ - (void)testFiltersDocumentsBasedOnQueryWithFilter { FSTDocument *doc5 = FSTTestDoc("rooms/eros/messages/5", 0, @{@"sort" : @1}, FSTDocumentStateSynced); - FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4, doc5 ], absl::nullopt); + FSTViewSnapshot *snapshot = + FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4, doc5 ], absl::nullopt); XCTAssertEqual(snapshot.query, query); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index 6b975448dfa..446c1fdc47c 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -257,9 +257,10 @@ NSComparator FSTTestDocComparator(const absl::string_view fieldPath); FSTDocumentSet *FSTTestDocSet(NSComparator comp, NSArray *docs); /** Computes changes to the view with the docs and then applies them and returns the snapshot. */ -FSTViewSnapshot *_Nullable FSTTestApplyChanges(FSTView *view, - NSArray *docs, - const absl::optional & targetChange); +FSTViewSnapshot *_Nullable FSTTestApplyChanges( + FSTView *view, + NSArray *docs, + const absl::optional &targetChange); /** Creates a set mutation for the document key at the given path. */ FSTSetMutation *FSTTestSetMutation(NSString *path, NSDictionary *values); @@ -306,7 +307,8 @@ FSTLocalViewChanges *FSTTestViewChanges(firebase::firestore::model::TargetId tar NSArray *removedKeys); /** Creates a test target change that acks all 'docs' and marks the target as CURRENT */ -firebase::firestore::remote::TargetChange FSTTestTargetChangeAckDocuments(firebase::firestore::model::DocumentKeySet docs); +firebase::firestore::remote::TargetChange FSTTestTargetChangeAckDocuments( + firebase::firestore::model::DocumentKeySet docs); /** Creates a test target change that marks the target as CURRENT */ firebase::firestore::remote::TargetChange FSTTestTargetChangeMarkCurrent(); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 75f6a6ee48b..f4030f21c8c 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -300,7 +300,7 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { FSTViewSnapshot *_Nullable FSTTestApplyChanges(FSTView *view, NSArray *docs, - const absl::optional& targetChange) { + const absl::optional &targetChange) { return [view applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(docs)] targetChange:targetChange] .snapshot; diff --git a/Firestore/Source/Core/FSTView.h b/Firestore/Source/Core/FSTView.h index a5a9f7ae785..c06ca67e568 100644 --- a/Firestore/Source/Core/FSTView.h +++ b/Firestore/Source/Core/FSTView.h @@ -28,7 +28,7 @@ namespace firebase { namespace firestore { namespace remote { -//class TargetChange; +// class TargetChange; } // namespace remote } // namespace firestore @@ -151,8 +151,10 @@ typedef NS_ENUM(NSInteger, FSTLimboDocumentChangeType) { * @param targetChange A target change to apply for computing limbo docs and sync state. * @return A new FSTViewChange with the given docs, changes, and sync state. */ -- (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange:(const absl::optional&)targetChange; +- (FSTViewChange *) + applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges + targetChange: + (const absl::optional &)targetChange; /** * Applies an OnlineState change to the view, potentially generating an FSTViewChange if the diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index 99b21dee62c..0efdc79b1b3 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -349,7 +349,7 @@ - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges } - (FSTViewChange *)applyChangesToDocuments:(FSTViewDocumentChanges *)docChanges - targetChange:(const absl::optional&)targetChange { + targetChange:(const absl::optional &)targetChange { HARD_ASSERT(!docChanges.needsRefill, "Cannot apply changes that need a refill"); FSTDocumentSet *oldDocuments = self.documentSet; @@ -435,9 +435,9 @@ - (BOOL)shouldBeLimboDocumentKey:(const DocumentKey &)key { /** * Updates syncedDocuments and current based on the given change. */ -- (void)applyTargetChange:(const absl::optional&)maybeTargetChange { +- (void)applyTargetChange:(const absl::optional &)maybeTargetChange { if (maybeTargetChange.has_value()) { - const TargetChange& target_change = maybeTargetChange.value(); + const TargetChange &target_change = maybeTargetChange.value(); for (const DocumentKey &key : target_change.added_documents()) { _syncedDocuments = _syncedDocuments.insert(key); diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index bda772354b9..58ac3a48e7f 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -218,7 +218,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { DocumentKeySet authoritativeUpdates; for (const auto &entry : remoteEvent.targetChanges) { TargetId targetID = entry.first; - const TargetChange& change = entry.second; + const TargetChange &change = entry.second; // Do not ref/unref unassigned targetIDs - it may lead to leaks. auto found = _targetIDs.find(targetID); @@ -330,7 +330,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { */ - (BOOL)shouldPersistQueryData:(FSTQueryData *)newQueryData oldQueryData:(FSTQueryData *)oldQueryData - change:(const TargetChange&)change { + change:(const TargetChange &)change { // Avoid clearing any existing value if (newQueryData.resumeToken.length == 0) return NO; @@ -376,9 +376,10 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run( + "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h index 588cd6ec057..38667aa136d 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ b/Firestore/Source/Remote/FSTRemoteEvent.h @@ -44,8 +44,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype) initWithSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion targetChanges: - (std::unordered_map) - targetChanges + (std::unordered_map)targetChanges targetMismatches: (std::unordered_set)targetMismatches documentUpdates: @@ -63,8 +63,8 @@ NS_ASSUME_NONNULL_BEGIN - (const firebase::firestore::model::DocumentKeySet &)limboDocumentChanges; /** A map from target to changes to the target. See TargetChange. */ -- (const std::unordered_map &) - targetChanges; +- (const std::unordered_map &)targetChanges; /** * A set of targets that is known to be inconsistent. Listens for these targets should be diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm index 46988368cab..89ab3ebb541 100644 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ b/Firestore/Source/Remote/FSTRemoteEvent.mm @@ -55,13 +55,13 @@ @implementation FSTRemoteEvent { DocumentKeySet _limboDocumentChanges; } -- (instancetype) - initWithSnapshotVersion:(SnapshotVersion)snapshotVersion - targetChanges:(std::unordered_map)targetChanges - targetMismatches:(std::unordered_set)targetMismatches - documentUpdates:(std::unordered_map) +- (instancetype)initWithSnapshotVersion:(SnapshotVersion)snapshotVersion + targetChanges:(std::unordered_map)targetChanges + targetMismatches:(std::unordered_set)targetMismatches + documentUpdates: + (std::unordered_map) documentUpdates - limboDocuments:(DocumentKeySet)limboDocuments { + limboDocuments:(DocumentKeySet)limboDocuments { self = [super init]; if (self) { _snapshotVersion = std::move(snapshotVersion); diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index bb38611193f..4e309b95724 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -378,7 +378,7 @@ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotV // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when // applying the completed FSTRemoteEvent. for (const auto &entry : remoteEvent.targetChanges) { - const TargetChange& target_change = entry.second; + const TargetChange &target_change = entry.second; NSData *resumeToken = target_change.resume_token(); if (resumeToken.length > 0) { TargetId targetID = entry.first; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 02ea3dec400..e8b6f01ba9e 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" From fdf05a7e2ea5381e1989269295612db3646829f6 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Sat, 26 Jan 2019 16:55:06 -0500 Subject: [PATCH 059/107] Review feedback --- Firestore/core/src/firebase/firestore/remote/remote_event.mm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 44456770387..9064ce5c545 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -176,10 +176,8 @@ target_state.UpdateResumeToken(target_change.resume_token()); } break; - default: - HARD_FAIL("Unknown target watch change state: %s", - target_change.state()); } + HARD_FAIL("Unknown target watch change state: %s", target_change.state()); } } From c71a5419e6ed1e8e2b12735f6a2d58d211fe5614 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Sat, 26 Jan 2019 16:59:44 -0500 Subject: [PATCH 060/107] undo formatting --- Firestore/Source/Local/FSTLocalStore.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 58ac3a48e7f..034c16e532a 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -376,10 +376,9 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run( - "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { From 24a745eaa21924ec2aafd116d026c9b4ddb2adfd Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Sat, 26 Jan 2019 18:29:25 -0500 Subject: [PATCH 061/107] fix --- .../core/src/firebase/firestore/remote/remote_event.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 9064ce5c545..d9203f532c8 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -136,7 +136,7 @@ if (IsActiveTarget(target_id)) { target_state.UpdateResumeToken(target_change.resume_token()); } - break; + continue; case WatchTargetChangeState::Added: // We need to decrement the number of pending acks needed from watch for // this target_id. @@ -148,7 +148,7 @@ target_state.ClearPendingChanges(); } target_state.UpdateResumeToken(target_change.resume_token()); - break; + continue; case WatchTargetChangeState::Removed: // We need to keep track of removed targets to we can post-filter and // remove any target changes. @@ -160,13 +160,13 @@ } HARD_ASSERT(target_change.cause().ok(), "WatchChangeAggregator does not handle errored targets"); - break; + continue; case WatchTargetChangeState::Current: if (IsActiveTarget(target_id)) { target_state.MarkCurrent(); target_state.UpdateResumeToken(target_change.resume_token()); } - break; + continue; case WatchTargetChangeState::Reset: if (IsActiveTarget(target_id)) { // Reset the target and synthesizes removes for all existing @@ -175,7 +175,7 @@ ResetTarget(target_id); target_state.UpdateResumeToken(target_change.resume_token()); } - break; + continue; } HARD_FAIL("Unknown target watch change state: %s", target_change.state()); } From e3dd85e0b04a2e8f3531a3e082b2aa3f91513c45 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Sun, 27 Jan 2019 16:54:46 -0500 Subject: [PATCH 062/107] Temp code --- Firestore/Source/Core/FSTView.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Firestore/Source/Core/FSTView.h b/Firestore/Source/Core/FSTView.h index c06ca67e568..6c0620194df 100644 --- a/Firestore/Source/Core/FSTView.h +++ b/Firestore/Source/Core/FSTView.h @@ -20,7 +20,6 @@ #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "absl/types/optional.h" @@ -28,7 +27,7 @@ namespace firebase { namespace firestore { namespace remote { -// class TargetChange; +class TargetChange; } // namespace remote } // namespace firestore From 1eb409675315b76fe9ab762671f302395eff148b Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 15:50:30 -0500 Subject: [PATCH 063/107] Implementation --- .../firebase/firestore/remote/remote_event.h | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index e8b6f01ba9e..d786120d450 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -234,6 +234,74 @@ class TargetState { bool has_pending_changes_ = true; }; +/** + * An event from the RemoteStore. It is split into `TargetChanges` (changes to + * the state or the set of documents in our watched targets) and + * `DocumentUpdates` (changes to the actual documents). + */ +class RemoteEvent { + RemoteEvent(model::SnapshotVersion snapshot_version, + std::unordered_map target_changes, + std::unordered_set target_mismatches, + std::unordered_map document_updates, + model::DocumentKeySet limbo_document_changes) + : snapshot_version_{snapshot_version}, + target_changes_{std::move(target_changes)}, + target_mismatches_{std::move(target_mismatches)}, + document_updates_{std::move(document_updates)}, + limbo_document_changes_{std::move(limbo_document_changes)} { + } + + /** The snapshot version this event brings us up to. */ + const model::SnapshotVersion& snapshot_version() const { + return snapshot_version_; + } + + /** + * A set of which document updates are due only to limbo resolution targets. + */ + const model::DocumentKeySet& limbo_document_changes() const { + return limbo_document_changes_; + } + + /** A map from target to changes to the target. See TargetChange. */ + const std::unordered_map& target_changes() + const { + return target_changes_; + } + + /** + * A set of targets that is known to be inconsistent. Listens for these + * targets should be re-established without resume tokens. + */ + const std::unordered_set& target_mismatches() const { + return target_mismatches_; + } + + /** + * A set of which documents have changed or been deleted, along with the doc's + * new values (if not deleted). + */ + const std::unordered_map& + document_updates() const { + return document_updates_; + } + + private: + model::SnapshotVersion snapshot_version_; + std::unordered_map target_changes_; + std::unordered_set target_mismatches_; + std::unordered_map + document_updates_; + model::DocumentKeySet limbo_document_changes_; +}; + /** * A helper class to accumulate watch changes into a `RemoteEvent` and other * target information. From 4147c3d6a60f792e6d7e39d4981770b75e17b734 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 17:14:03 -0500 Subject: [PATCH 064/107] Updating references wip (FSTRemoteEventsTests still to do) --- .../Tests/Core/FSTQueryListenerTests.mm | 1 - Firestore/Example/Tests/Core/FSTViewTests.mm | 1 - .../Tests/Integration/FSTDatastoreTests.mm | 13 +-- .../Example/Tests/Local/FSTLocalStoreTests.mm | 6 +- .../Tests/Remote/FSTRemoteEventTests.mm | 3 +- Firestore/Example/Tests/Util/FSTHelpers.h | 18 +++- Firestore/Example/Tests/Util/FSTHelpers.mm | 8 +- Firestore/Source/Core/FSTSyncEngine.h | 1 - Firestore/Source/Core/FSTSyncEngine.mm | 34 +++---- Firestore/Source/Core/FSTView.mm | 1 - Firestore/Source/Local/FSTLocalStore.h | 13 ++- Firestore/Source/Local/FSTLocalStore.mm | 16 +-- Firestore/Source/Local/FSTLocalViewChanges.h | 1 - Firestore/Source/Remote/FSTRemoteEvent.h | 85 ---------------- Firestore/Source/Remote/FSTRemoteEvent.mm | 98 ------------------- Firestore/Source/Remote/FSTRemoteStore.h | 6 +- Firestore/Source/Remote/FSTRemoteStore.mm | 14 +-- .../firebase/firestore/remote/remote_event.h | 9 +- .../firebase/firestore/remote/remote_event.mm | 13 +-- 19 files changed, 81 insertions(+), 260 deletions(-) delete mode 100644 Firestore/Source/Remote/FSTRemoteEvent.h delete mode 100644 Firestore/Source/Remote/FSTRemoteEvent.mm diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm index d0d8f45703d..83852d06701 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm @@ -22,7 +22,6 @@ #import "Firestore/Source/Core/FSTView.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Util/FSTAsyncQueryListener.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm index 5e6c432d40b..b429d55ff54 100644 --- a/Firestore/Example/Tests/Core/FSTViewTests.mm +++ b/Firestore/Example/Tests/Core/FSTViewTests.mm @@ -24,7 +24,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index 4943d04ab34..ebb39093956 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -29,7 +29,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" @@ -40,6 +39,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/precondition.h" #include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -57,6 +57,7 @@ using firebase::firestore::model::TargetId; using firebase::firestore::remote::Datastore; using firebase::firestore::remote::GrpcConnection; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::util::AsyncQueue; using firebase::firestore::util::ExecutorLibdispatch; @@ -79,17 +80,17 @@ - (void)expectListenEventWithDescription:(NSString *)description; @property(nonatomic, weak, nullable) XCTestCase *testCase; @property(nonatomic, strong) NSMutableArray *writeEvents; -@property(nonatomic, strong) NSMutableArray *listenEvents; @property(nonatomic, strong) NSMutableArray *writeEventExpectations; @property(nonatomic, strong) NSMutableArray *listenEventExpectations; @end -@implementation FSTRemoteStoreEventCapture +@implementation FSTRemoteStoreEventCapture { + std::vector _listenEvents; +} - (instancetype)initWithTestCase:(XCTestCase *_Nullable)testCase { if (self = [super init]) { _writeEvents = [NSMutableArray array]; - _listenEvents = [NSMutableArray array]; _testCase = testCase; _writeEventExpectations = [NSMutableArray array]; _listenEventExpectations = [NSMutableArray array]; @@ -134,8 +135,8 @@ - (DocumentKeySet)remoteKeysForTarget:(TargetId)targetId { return DocumentKeySet{}; } -- (void)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { - [self.listenEvents addObject:remoteEvent]; +- (void)applyRemoteEvent:(const RemoteEvent&)remoteEvent { + _listenEvents.push_back(remoteEvent); XCTestExpectation *expectation = [self.listenEventExpectations objectAtIndex:0]; [self.listenEventExpectations removeObjectAtIndex:0]; [expectation fulfill]; diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 98835fad06f..069261068b3 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -27,7 +27,6 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Example/Tests/Local/FSTLocalStoreTests.h" @@ -51,6 +50,7 @@ using firebase::firestore::model::MaybeDocumentMap; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; @@ -133,7 +133,7 @@ - (void)writeMutations:(NSArray *)mutations { _lastChanges = result.changes; } -- (void)applyRemoteEvent:(FSTRemoteEvent *)event { +- (void)applyRemoteEvent:(const RemoteEvent&)event { _lastChanges = [self.localStore applyRemoteEvent:event]; } @@ -910,7 +910,7 @@ - (void)testPersistsResumeTokens { providerWithSingleResultForKey:testutil::Key("foo/bar") targets:{targetID}]}; aggregator.HandleTargetChange(watchChange); - FSTRemoteEvent *remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); + RemoteEvent remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); [self applyRemoteEvent:remoteEvent]; // Stop listening so that the query should become inactive (but persistent) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index 22b750a7a54..a66281551dc 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -14,8 +14,6 @@ * limitations under the License. */ -#import "Firestore/Source/Remote/FSTRemoteEvent.h" - #import #include @@ -46,6 +44,7 @@ using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilter; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index 446c1fdc47c..c876f2071f4 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -20,7 +20,6 @@ #include #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" @@ -42,7 +41,6 @@ @class FSTLocalViewChanges; @class FSTPatchMutation; @class FSTQuery; -@class FSTRemoteEvent; @class FSTSetMutation; @class FSTSortOrder; @class FIRTimestamp; @@ -51,6 +49,16 @@ @class FSTViewSnapshot; @class FSTObjectValue; +namespace firebase { +namespace firestore { +namespace remote { + +class RemoteEvent; + +} // namespace remote +} // namespace firestore +} // namespace firebase + NS_ASSUME_NONNULL_BEGIN #define FSTAssertIsKindOfClass(value, classType) \ @@ -285,17 +293,17 @@ FSTDeleteMutation *FSTTestDeleteMutation(NSString *path); firebase::firestore::model::MaybeDocumentMap FSTTestDocUpdates(NSArray *docs); /** Creates a remote event that inserts a new document. */ -FSTRemoteEvent *FSTTestAddedRemoteEvent( +firebase::firestore::remote::RemoteEvent FSTTestAddedRemoteEvent( FSTMaybeDocument *doc, const std::vector &addedToTargets); /** Creates a remote event with changes to a document. */ -FSTRemoteEvent *FSTTestUpdateRemoteEvent( +firebase::firestore::remote::RemoteEvent FSTTestUpdateRemoteEvent( FSTMaybeDocument *doc, const std::vector &updatedInTargets, const std::vector &removedFromTargets); /** Creates a remote event with changes to a document. Allows for identifying limbo targets */ -FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( +firebase::firestore::remote::RemoteEvent FSTTestUpdateRemoteEventWithLimboTargets( FSTMaybeDocument *doc, const std::vector &updatedInTargets, const std::vector &removedFromTargets, diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index f4030f21c8c..701478eb6bb 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -38,7 +38,6 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -73,6 +72,7 @@ using firebase::firestore::model::TargetId; using firebase::firestore::model::TransformOperation; using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChangeAggregator; @@ -375,7 +375,7 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { @end -FSTRemoteEvent *FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, +RemoteEvent FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, const std::vector &addedToTargets) { HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); @@ -394,7 +394,7 @@ TargetChange FSTTestTargetChangeAckDocuments(DocumentKeySet docs) { return {[NSData data], true, std::move(docs), DocumentKeySet{}, DocumentKeySet{}}; } -FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( +RemoteEvent FSTTestUpdateRemoteEventWithLimboTargets( FSTMaybeDocument *doc, const std::vector &updatedInTargets, const std::vector &removedFromTargets, @@ -414,7 +414,7 @@ TargetChange FSTTestTargetChangeAckDocuments(DocumentKeySet docs) { return aggregator.CreateRemoteEvent(doc.version); } -FSTRemoteEvent *FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, +RemoteEvent FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, const std::vector &updatedInTargets, const std::vector &removedFromTargets) { return FSTTestUpdateRemoteEventWithLimboTargets(doc, updatedInTargets, removedFromTargets, {}); diff --git a/Firestore/Source/Core/FSTSyncEngine.h b/Firestore/Source/Core/FSTSyncEngine.h index b4c4af93c22..c99b06616f4 100644 --- a/Firestore/Source/Core/FSTSyncEngine.h +++ b/Firestore/Source/Core/FSTSyncEngine.h @@ -26,7 +26,6 @@ @class FSTLocalStore; @class FSTMutation; @class FSTQuery; -@class FSTRemoteEvent; @class FSTRemoteStore; @class FSTViewSnapshot; diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm index 8e7ff023052..86794d0fec5 100644 --- a/Firestore/Source/Core/FSTSyncEngine.mm +++ b/Firestore/Source/Core/FSTSyncEngine.mm @@ -33,7 +33,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" @@ -41,6 +40,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "absl/types/optional.h" @@ -58,6 +58,7 @@ using firebase::firestore::model::OnlineState; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; using firebase::firestore::util::AsyncQueue; @@ -253,7 +254,7 @@ - (void)writeMutations:(NSArray *)mutations FSTLocalWriteResult *result = [self.localStore locallyWriteMutations:mutations]; [self addMutationCompletionBlock:completion batchID:result.batchID]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:result.changes remoteEvent:nil]; + [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:result.changes remoteEvent:absl::nullopt]; [self.remoteStore fillWritePipeline]; } @@ -320,11 +321,11 @@ - (void)transactionWithRetries:(int)retries }); } -- (void)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { +- (void)applyRemoteEvent:(const RemoteEvent &)remoteEvent { [self assertDelegateExistsForSelector:_cmd]; // Update `receivedDocument` as appropriate for any limbo targets. - for (const auto &entry : remoteEvent.targetChanges) { + for (const auto &entry : remoteEvent.target_changes()) { TargetId targetID = entry.first; const TargetChange &change = entry.second; const auto iter = _limboResolutionsByTarget.find(targetID); @@ -392,13 +393,8 @@ - (void)rejectListenWithTargetID:(const TargetId)targetID error:(NSError *)error version:SnapshotVersion::None() hasCommittedMutations:NO]; DocumentKeySet limboDocuments = DocumentKeySet{doc.key}; - FSTRemoteEvent *event = [[FSTRemoteEvent alloc] initWithSnapshotVersion:SnapshotVersion::None() - targetChanges:{} - targetMismatches:{} - documentUpdates:{ - { limboKey, doc } - } - limboDocuments:std::move(limboDocuments)]; + RemoteEvent event{SnapshotVersion::None(), /*target_changes=*/{}, /*target_mismatches=*/{}, + /*document_updates=*/{{limboKey, doc}}, std::move(limboDocuments)}; [self applyRemoteEvent:event]; } else { auto found = _queryViewsByTarget.find(targetID); @@ -424,7 +420,7 @@ - (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult *)batchResult { [self processUserCallbacksForBatchID:batchResult.batch.batchID error:nil]; MaybeDocumentMap changes = [self.localStore acknowledgeBatchWithResult:batchResult]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:nil]; + [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; } - (void)rejectFailedWriteWithBatchID:(BatchId)batchID error:(NSError *)error { @@ -441,7 +437,7 @@ - (void)rejectFailedWriteWithBatchID:(BatchId)batchID error:(NSError *)error { // consistently happen before listen events. [self processUserCallbacksForBatchID:batchID error:error]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:nil]; + [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; } - (void)processUserCallbacksForBatchID:(BatchId)batchID error:(NSError *_Nullable)error { @@ -483,7 +479,8 @@ - (void)removeAndCleanupQuery:(FSTQueryView *)queryView { * Computes a new snapshot from the changes and calls the registered callback with the new snapshot. */ - (void)emitNewSnapshotsAndNotifyLocalStoreWithChanges:(const MaybeDocumentMap &)changes - remoteEvent:(FSTRemoteEvent *_Nullable)remoteEvent { + remoteEvent:(const absl::optional &) + maybeRemoteEvent { NSMutableArray *newSnapshots = [NSMutableArray array]; NSMutableArray *documentChangesInAllViews = [NSMutableArray array]; @@ -501,9 +498,10 @@ - (void)emitNewSnapshotsAndNotifyLocalStoreWithChanges:(const MaybeDocumentMap & } absl::optional targetChange; - if (remoteEvent) { - auto it = remoteEvent.targetChanges.find(queryView.targetID); - if (it != remoteEvent.targetChanges.end()) { + if (maybeRemoteEvent.has_value()) { + const RemoteEvent &remoteEvent = maybeRemoteEvent.value(); + auto it = remoteEvent.target_changes().find(queryView.targetID); + if (it != remoteEvent.target_changes().end()) { targetChange = it->second; } } @@ -593,7 +591,7 @@ - (void)credentialDidChangeWithUser:(const firebase::firestore::auth::User &)use if (userChanged) { // Notify local store and emit any resulting events from swapping out the mutation queue. MaybeDocumentMap changes = [self.localStore userDidChange:user]; - [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:nil]; + [self emitNewSnapshotsAndNotifyLocalStoreWithChanges:changes remoteEvent:absl::nullopt]; } // Notify remote store so it can restart its streams. diff --git a/Firestore/Source/Core/FSTView.mm b/Firestore/Source/Core/FSTView.mm index 0efdc79b1b3..86b9cde8303 100644 --- a/Firestore/Source/Core/FSTView.mm +++ b/Firestore/Source/Core/FSTView.mm @@ -23,7 +23,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" diff --git a/Firestore/Source/Local/FSTLocalStore.h b/Firestore/Source/Local/FSTLocalStore.h index 60f8d2ee4a7..6e2f8996c5a 100644 --- a/Firestore/Source/Local/FSTLocalStore.h +++ b/Firestore/Source/Local/FSTLocalStore.h @@ -25,6 +25,16 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +namespace firebase { +namespace firestore { +namespace remote { + +class RemoteEvent; + +} // namespace remote +} // namespace firestore +} // namespace firebase + @class FSTLocalViewChanges; @class FSTLocalWriteResult; @class FSTMutation; @@ -32,7 +42,6 @@ @class FSTMutationBatchResult; @class FSTQuery; @class FSTQueryData; -@class FSTRemoteEvent; @protocol FSTPersistence; NS_ASSUME_NONNULL_BEGIN @@ -147,7 +156,7 @@ NS_ASSUME_NONNULL_BEGIN * * LocalDocuments are re-calculated if there are remaining mutations in the queue. */ -- (firebase::firestore::model::MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent; +- (firebase::firestore::model::MaybeDocumentMap)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent&)remoteEvent; /** * Returns the keys of the documents that are associated with the given targetID in the remote diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 034c16e532a..b745dcc8034 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -33,7 +33,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/core/target_id_generator.h" @@ -61,6 +60,7 @@ using firebase::firestore::model::ListenSequenceNumber; using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; NS_ASSUME_NONNULL_BEGIN @@ -210,13 +210,13 @@ - (void)setLastStreamToken:(nullable NSData *)streamToken { return self.queryCache->GetLastRemoteSnapshotVersion(); } -- (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { +- (MaybeDocumentMap)applyRemoteEvent:(const RemoteEvent&)remoteEvent { return self.persistence.run("Apply remote event", [&]() -> MaybeDocumentMap { // TODO(gsoltis): move the sequence number into the reference delegate. ListenSequenceNumber sequenceNumber = self.persistence.currentSequenceNumber; DocumentKeySet authoritativeUpdates; - for (const auto &entry : remoteEvent.targetChanges) { + for (const auto &entry : remoteEvent.target_changes()) { TargetId targetID = entry.first; const TargetChange &change = entry.second; @@ -251,7 +251,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { NSData *resumeToken = change.resume_token(); if (resumeToken.length > 0) { FSTQueryData *oldQueryData = queryData; - queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshotVersion + queryData = [queryData queryDataByReplacingSnapshotVersion:remoteEvent.snapshot_version() resumeToken:resumeToken sequenceNumber:sequenceNumber]; _targetIDs[targetID] = queryData; @@ -263,16 +263,16 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { } MaybeDocumentMap changedDocs; - const DocumentKeySet &limboDocuments = remoteEvent.limboDocumentChanges; + const DocumentKeySet &limboDocuments = remoteEvent.limbo_document_changes(); DocumentKeySet updatedKeys; - for (const auto &kv : remoteEvent.documentUpdates) { + for (const auto &kv : remoteEvent.document_updates()) { updatedKeys = updatedKeys.insert(kv.first); } // Each loop iteration only affects its "own" doc, so it's safe to get all the remote // documents in advance in a single call. MaybeDocumentMap existingDocs = _remoteDocumentCache->GetAll(updatedKeys); - for (const auto &kv : remoteEvent.documentUpdates) { + for (const auto &kv : remoteEvent.document_updates()) { const DocumentKey &key = kv.first; FSTMaybeDocument *doc = kv.second; FSTMaybeDocument *existingDoc = nil; @@ -306,7 +306,7 @@ - (MaybeDocumentMap)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent { // events when we get permission denied errors while trying to resolve the state of a locally // cached document that is in limbo. const SnapshotVersion &lastRemoteVersion = _queryCache->GetLastRemoteSnapshotVersion(); - const SnapshotVersion &remoteVersion = remoteEvent.snapshotVersion; + const SnapshotVersion &remoteVersion = remoteEvent.snapshot_version(); if (remoteVersion != SnapshotVersion::None()) { HARD_ASSERT(remoteVersion >= lastRemoteVersion, "Watch stream reverted to previous snapshot?? (%s < %s)", diff --git a/Firestore/Source/Local/FSTLocalViewChanges.h b/Firestore/Source/Local/FSTLocalViewChanges.h index dcc20055adf..fdcc3b1c960 100644 --- a/Firestore/Source/Local/FSTLocalViewChanges.h +++ b/Firestore/Source/Local/FSTLocalViewChanges.h @@ -22,7 +22,6 @@ @class FSTDocumentSet; @class FSTMutation; @class FSTQuery; -@class FSTRemoteEvent; @class FSTViewSnapshot; NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Source/Remote/FSTRemoteEvent.h b/Firestore/Source/Remote/FSTRemoteEvent.h deleted file mode 100644 index 38667aa136d..00000000000 --- a/Firestore/Source/Remote/FSTRemoteEvent.h +++ /dev/null @@ -1,85 +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 - -#include -#include -#include -#include - -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" - -@class FSTMaybeDocument; -@class FSTQueryData; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTRemoteEvent - -/** - * An event from the RemoteStore. It is split into targetChanges (changes to the state or the set - * of documents in our watched targets) and documentUpdates (changes to the actual documents). - */ -@interface FSTRemoteEvent : NSObject - -- (instancetype) - initWithSnapshotVersion:(firebase::firestore::model::SnapshotVersion)snapshotVersion - targetChanges: - (std::unordered_map)targetChanges - targetMismatches: - (std::unordered_set)targetMismatches - documentUpdates: - (std::unordered_map)documentUpdates - limboDocuments:(firebase::firestore::model::DocumentKeySet)limboDocuments; - -/** The snapshot version this event brings us up to. */ -- (const firebase::firestore::model::SnapshotVersion &)snapshotVersion; - -/** - * A set of which document updates are due only to limbo resolution targets. - */ -- (const firebase::firestore::model::DocumentKeySet &)limboDocumentChanges; - -/** A map from target to changes to the target. See TargetChange. */ -- (const std::unordered_map &)targetChanges; - -/** - * A set of targets that is known to be inconsistent. Listens for these targets should be - * re-established without resume tokens. - */ -- (const std::unordered_set &)targetMismatches; - -/** - * A set of which documents have changed or been deleted, along with the doc's new values (if not - * deleted). - */ -- (const std::unordered_map &)documentUpdates; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTRemoteEvent.mm b/Firestore/Source/Remote/FSTRemoteEvent.mm deleted file mode 100644 index 89ab3ebb541..00000000000 --- a/Firestore/Source/Remote/FSTRemoteEvent.mm +++ /dev/null @@ -1,98 +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/Remote/FSTRemoteEvent.h" - -#include -#include -#include -#include - -#import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Core/FSTViewSnapshot.h" -#import "Firestore/Source/Local/FSTQueryData.h" -#import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Util/FSTClasses.h" - -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/hashing.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" - -using firebase::firestore::core::DocumentViewChangeType; -using firebase::firestore::model::DocumentKey; -using firebase::firestore::model::DocumentKeyHash; -using firebase::firestore::model::DocumentKeySet; -using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::TargetId; -using firebase::firestore::remote::DocumentWatchChange; -using firebase::firestore::remote::ExistenceFilterWatchChange; -using firebase::firestore::remote::TargetChange; -using firebase::firestore::remote::WatchTargetChange; -using firebase::firestore::remote::WatchTargetChangeState; -using firebase::firestore::util::Hash; - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTRemoteEvent { - SnapshotVersion _snapshotVersion; - std::unordered_map _targetChanges; - std::unordered_set _targetMismatches; - std::unordered_map _documentUpdates; - DocumentKeySet _limboDocumentChanges; -} - -- (instancetype)initWithSnapshotVersion:(SnapshotVersion)snapshotVersion - targetChanges:(std::unordered_map)targetChanges - targetMismatches:(std::unordered_set)targetMismatches - documentUpdates: - (std::unordered_map) - documentUpdates - limboDocuments:(DocumentKeySet)limboDocuments { - self = [super init]; - if (self) { - _snapshotVersion = std::move(snapshotVersion); - _targetChanges = std::move(targetChanges); - _targetMismatches = std::move(targetMismatches); - _documentUpdates = std::move(documentUpdates); - _limboDocumentChanges = std::move(limboDocuments); - } - return self; -} - -- (const SnapshotVersion &)snapshotVersion { - return _snapshotVersion; -} - -- (const DocumentKeySet &)limboDocumentChanges { - return _limboDocumentChanges; -} - -- (const std::unordered_map &)targetChanges { - return _targetChanges; -} - -- (const std::unordered_map &)documentUpdates { - return _documentUpdates; -} - -- (const std::unordered_set &)targetMismatches { - return _targetMismatches; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 267c81e5ef9..5ccb9956647 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -18,18 +18,16 @@ #include -#import "Firestore/Source/Remote/FSTRemoteEvent.h" - #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" @class FSTLocalStore; @class FSTMutationBatch; @class FSTMutationBatchResult; @class FSTQueryData; -@class FSTRemoteEvent; @class FSTTransaction; NS_ASSUME_NONNULL_BEGIN @@ -47,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN * any pending mutation batches that would become visible because of the snapshot version the * remote event contains. */ -- (void)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent; +- (void)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent &)remoteEvent; /** * Rejects the listen for the given targetID. This can be triggered by the backend for any active diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 4e309b95724..7c4bcd4e3e4 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -29,7 +29,6 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" #import "Firestore/Source/Remote/FSTOnlineStateTracker.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTStream.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" @@ -60,6 +59,7 @@ using firebase::firestore::remote::WriteStream; using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; @@ -366,18 +366,18 @@ - (void)watchStreamWasInterruptedWithError:(const Status &)error { } /** - * Takes a batch of changes from the Datastore, repackages them as a RemoteEvent, and passes that + * Takes a batch of changes from the Datastore, repackages them as a `RemoteEvent`, and passes that * on to the SyncEngine. */ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotVersion { HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); - FSTRemoteEvent *remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); + RemoteEvent remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); - // Update in-memory resume tokens. FSTLocalStore will update the persistent view of these when - // applying the completed FSTRemoteEvent. - for (const auto &entry : remoteEvent.targetChanges) { + // Update in-memory resume tokens. `FSTLocalStore` will update the persistent view of these when + // applying the completed `RemoteEvent`. + for (const auto &entry : remoteEvent.target_changes()) { const TargetChange &target_change = entry.second; NSData *resumeToken = target_change.resume_token(); if (resumeToken.length > 0) { @@ -396,7 +396,7 @@ - (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotV // Re-establish listens for the targets that have been invalidated by existence filter // mismatches. - for (TargetId targetID : remoteEvent.targetMismatches) { + for (TargetId targetID : remoteEvent.target_mismatches()) { auto found = _listenTargets.find(targetID); if (found == _listenTargets.end()) { // A watched target might have been removed already. diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index d786120d450..acfd1ec27d8 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -40,7 +40,6 @@ @class FSTMaybeDocument; @class FSTQueryData; -@class FSTRemoteEvent; NS_ASSUME_NONNULL_BEGIN @@ -72,8 +71,8 @@ namespace remote { /** * A `TargetChange` specifies the set of changes for a specific target as part - * of an `FSTRemoteEvent`. These changes track which documents are added, - * modified or emoved, as well as the target's resume token and whether the + * of an `RemoteEvent`. These changes track which documents are added, + * modified or removed, as well as the target's resume token and whether the * target is marked CURRENT. * * The actual changes *to* documents are not part of the `TargetChange` since @@ -240,6 +239,7 @@ class TargetState { * `DocumentUpdates` (changes to the actual documents). */ class RemoteEvent { + public: RemoteEvent(model::SnapshotVersion snapshot_version, std::unordered_map target_changes, std::unordered_set target_mismatches, @@ -336,8 +336,7 @@ class WatchChangeAggregator { * taken from the initializer. Resets the accumulated changes before * returning. */ - FSTRemoteEvent* CreateRemoteEvent( - const model::SnapshotVersion& snapshot_version); + RemoteEvent CreateRemoteEvent(const model::SnapshotVersion& snapshot_version); /** Removes the in-memory state for the provided target. */ void RemoveTarget(model::TargetId target_id); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 787e7b596af..fd4355ddab2 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -21,7 +21,6 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTDocument.h" -#import "Firestore/Source/Remote/FSTRemoteEvent.h" using firebase::firestore::core::DocumentViewChangeType; using firebase::firestore::model::DocumentKey; @@ -242,7 +241,7 @@ } } -FSTRemoteEvent* WatchChangeAggregator::CreateRemoteEvent( +RemoteEvent WatchChangeAggregator::CreateRemoteEvent( const SnapshotVersion& snapshot_version) { std::unordered_map target_changes; @@ -298,12 +297,10 @@ } } - FSTRemoteEvent* remote_event = [[FSTRemoteEvent alloc] - initWithSnapshotVersion:snapshot_version - targetChanges:target_changes - targetMismatches:std::move(pending_target_resets_) - documentUpdates:std::move(pending_document_updates_) - limboDocuments:std::move(resolved_limbo_documents)]; + RemoteEvent remote_event{snapshot_version, std::move(target_changes), + std::move(pending_target_resets_), + std::move(pending_document_updates_), + std::move(resolved_limbo_documents)}; // Re-initialize the current state to ensure that we do not modify the // generated `RemoteEvent`. From 3b3b01209b88918572d199ebffecbabf797edbfd Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 17:18:21 -0500 Subject: [PATCH 065/107] Unit tests compile --- .../Tests/Remote/FSTRemoteEventTests.mm | 222 +++++++++--------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index a66281551dc..cd7711474f5 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -208,7 +208,7 @@ - (void)setUp { * @param watchChanges The watch changes to apply before creating the remote event. Supported * changes are `DocumentWatchChange` and `WatchTargetChange`. */ -- (FSTRemoteEvent *) +- (RemoteEvent) remoteEventAtSnapshotVersion:(FSTTestSnapshotVersion)snapshotVersion targetMap:(std::unordered_map)targetMap outstandingResponses:(const std::unordered_map &)outstandingResponses @@ -238,43 +238,43 @@ - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // with the default resume token (`_resumeToken1`). // As `existingDoc` is provided as an existing key, any updates to this document will be treated // as modifications rather than adds. - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{existingDoc.key} changes:Changes(std::move(change1), std::move(change2))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 2); - XCTAssertEqualObjects(event.documentUpdates.at(existingDoc.key), existingDoc); - XCTAssertEqualObjects(event.documentUpdates.at(newDoc.key), newDoc); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 2); + XCTAssertEqualObjects(event.document_updates().at(existingDoc.key), existingDoc); + XCTAssertEqualObjects(event.document_updates().at(newDoc.key), newDoc); // 'change1' and 'change2' affect six different targets - XCTAssertEqual(event.targetChanges.size(), 6); + XCTAssertEqual(event.target_changes().size(), 6); TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(2) == targetChange2); + XCTAssertTrue(event.target_changes().at(2) == targetChange2); TargetChange targetChange3{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{existingDoc.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(3) == targetChange3); + XCTAssertTrue(event.target_changes().at(3) == targetChange3); TargetChange targetChange4{_resumeToken1, false, DocumentKeySet{newDoc.key}, DocumentKeySet{}, DocumentKeySet{existingDoc.key}}; - XCTAssertTrue(event.targetChanges.at(4) == targetChange4); + XCTAssertTrue(event.target_changes().at(4) == targetChange4); TargetChange targetChange5{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{existingDoc.key}}; - XCTAssertTrue(event.targetChanges.at(5) == targetChange5); + XCTAssertTrue(event.target_changes().at(5) == targetChange5); TargetChange targetChange6{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{existingDoc.key}}; - XCTAssertTrue(event.targetChanges.at(6) == targetChange6); + XCTAssertTrue(event.target_changes().at(6) == targetChange6); } - (void)testWillIgnoreEventsForPendingTargets { @@ -290,20 +290,20 @@ - (void)testWillIgnoreEventsForPendingTargets { // We're waiting for the unwatch and watch ack std::unordered_map outstandingResponses{{1, 2}}; - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:outstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change1), std::move(change2), std::move(change3), std::move(change4))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); // doc1 is ignored because it was part of an inactive target, but doc2 is in the changes // because it become active. - XCTAssertEqual(event.documentUpdates.size(), 1); - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); + XCTAssertEqual(event.document_updates().size(), 1); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.target_changes().size(), 1); } - (void)testWillIgnoreEventsForRemovedTargets { @@ -316,18 +316,18 @@ - (void)testWillIgnoreEventsForRemovedTargets { // We're waiting for the unwatch ack std::unordered_map outstandingResponses{{1, 1}}; - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:outstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change1), std::move(change2))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); // doc1 is ignored because it was part of an inactive target - XCTAssertEqual(event.documentUpdates.size(), 0); + XCTAssertEqual(event.document_updates().size(), 0); // Target 1 is ignored because it was removed - XCTAssertEqual(event.targetChanges.size(), 0); + XCTAssertEqual(event.target_changes().size(), 0); } - (void)testWillKeepResetMappingEvenWithUpdates { @@ -349,7 +349,7 @@ - (void)testWillKeepResetMappingEvenWithUpdates { // Remove doc2 again, should not show up in reset mapping auto change5 = MakeDocChange({}, {1}, doc2.key, doc2); - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses @@ -357,18 +357,18 @@ - (void)testWillKeepResetMappingEvenWithUpdates { changes:Changes(std::move(change1), std::move(change2), std::move(change3), std::move(change4), std::move(change5))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 3); - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); - XCTAssertEqualObjects(event.documentUpdates.at(doc3.key), doc3); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 3); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); + XCTAssertEqualObjects(event.document_updates().at(doc3.key), doc3); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.target_changes().size(), 1); // Only doc3 is part of the new mapping TargetChange expectedChange{_resumeToken1, false, DocumentKeySet{doc3.key}, DocumentKeySet{}, DocumentKeySet{doc1.key}}; - XCTAssertTrue(event.targetChanges.at(1) == expectedChange); + XCTAssertTrue(event.target_changes().at(1) == expectedChange); } - (void)testWillHandleSingleReset { @@ -383,16 +383,16 @@ - (void)testWillHandleSingleReset { changes:{}]; aggregator.HandleTargetChange(change); - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 0); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 0); + XCTAssertEqual(event.target_changes().size(), 1); // Reset mapping is empty TargetChange expectedChange{ [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == expectedChange); + XCTAssertTrue(event.target_changes().at(1) == expectedChange); } - (void)testWillHandleTargetAddAndRemovalInSameBatch { @@ -404,25 +404,25 @@ - (void)testWillHandleTargetAddAndRemovalInSameBatch { FSTDocument *doc1b = FSTTestDoc("docs/1", 1, @{@"value" : @2}, FSTDocumentStateSynced); auto change2 = MakeDocChange({2}, {1}, doc1b.key, doc1b); - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{doc1a.key} changes:Changes(std::move(change1), std::move(change2))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 1); - XCTAssertEqualObjects(event.documentUpdates.at(doc1b.key), doc1b); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 1); + XCTAssertEqualObjects(event.document_updates().at(doc1b.key), doc1b); - XCTAssertEqual(event.targetChanges.size(), 2); + XCTAssertEqual(event.target_changes().size(), 2); TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1b.key}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{doc1b.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(2) == targetChange2); + XCTAssertTrue(event.target_changes().at(2) == targetChange2); } - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { @@ -430,19 +430,19 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { auto change = MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(change))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 0); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 0); + XCTAssertEqual(event.target_changes().size(), 1); TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); } - (void)testTargetAddedChangeWillResetPreviousState { @@ -459,7 +459,7 @@ - (void)testTargetAddedChangeWillResetPreviousState { std::unordered_map outstandingResponses{{1, 2}, {2, 1}}; - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:outstandingResponses @@ -468,25 +468,25 @@ - (void)testTargetAddedChangeWillResetPreviousState { std::move(change3), std::move(change4), std::move(change5), std::move(change6))]; - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 2); - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 2); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); // target 1 and 3 are affected (1 because of re-add), target 2 is not because of remove - XCTAssertEqual(event.targetChanges.size(), 2); + XCTAssertEqual(event.target_changes().size(), 2); // doc1 was before the remove, so it does not show up in the mapping. // Current was before the remove. TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{doc2.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); // Doc1 was before the remove // Current was before the remove TargetChange targetChange3{_resumeToken1, true, DocumentKeySet{doc1.key}, DocumentKeySet{}, DocumentKeySet{doc2.key}}; - XCTAssertTrue(event.targetChanges.at(3) == targetChange3); + XCTAssertTrue(event.target_changes().at(3) == targetChange3); } - (void)testNoChangeWillStillMarkTheAffectedTargets { @@ -500,15 +500,15 @@ - (void)testNoChangeWillStillMarkTheAffectedTargets { WatchTargetChange change{WatchTargetChangeState::NoChange, {1}, _resumeToken1}; aggregator.HandleTargetChange(change); - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 0); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 0); + XCTAssertEqual(event.target_changes().size(), 1); TargetChange targetChange{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange); + XCTAssertTrue(event.target_changes().at(1) == targetChange); } - (void)testExistenceFilterMismatchClearsTarget { @@ -526,22 +526,22 @@ - (void)testExistenceFilterMismatchClearsTarget { existingKeys:DocumentKeySet{doc1.key, doc2.key} changes:Changes(std::move(change1), std::move(change2), std::move(change3))]; - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 2); - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 2); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); - XCTAssertEqual(event.targetChanges.size(), 2); + XCTAssertEqual(event.target_changes().size(), 2); TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(2) == targetChange2); + XCTAssertTrue(event.target_changes().at(2) == targetChange2); // The existence filter mismatch will remove the document from target 1, // but not synthesize a document delete. @@ -552,11 +552,11 @@ - (void)testExistenceFilterMismatchClearsTarget { TargetChange targetChange3{ [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{doc1.key, doc2.key}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange3); + XCTAssertTrue(event.target_changes().at(1) == targetChange3); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.target_changes().size(), 1); XCTAssertEqual(event.targetMismatches.size(), 1); - XCTAssertEqual(event.documentUpdates.size(), 0); + XCTAssertEqual(event.document_updates().size(), 0); } - (void)testExistenceFilterMismatchRemovesCurrentChanges { @@ -579,18 +579,18 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { ExistenceFilterWatchChange existenceFilter{ExistenceFilter{0}, 1}; aggregator.HandleExistenceFilter(existenceFilter); - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 1); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 1); XCTAssertEqual(event.targetMismatches.size(), 1); - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.target_changes().size(), 1); TargetChange targetChange1{ [NSData data], false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); } - (void)testDocumentUpdate { @@ -607,12 +607,12 @@ - (void)testDocumentUpdate { existingKeys:DocumentKeySet {} changes:Changes(std::move(change1), std::move(change2))]; - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 2); - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), doc1); - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), doc2); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 2); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); [_targetMetadataProvider setSyncedKeys:DocumentKeySet{doc1.key, doc2.key} forQueryData:targetMap[1]]; @@ -633,21 +633,21 @@ - (void)testDocumentUpdate { event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.snapshotVersion, testutil::Version(3)); - XCTAssertEqual(event.documentUpdates.size(), 3); + XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); + XCTAssertEqual(event.document_updates().size(), 3); // doc1 is replaced - XCTAssertEqualObjects(event.documentUpdates.at(doc1.key), deletedDoc1); + XCTAssertEqualObjects(event.document_updates().at(doc1.key), deletedDoc1); // doc2 is updated - XCTAssertEqualObjects(event.documentUpdates.at(doc2.key), updatedDoc2); + XCTAssertEqualObjects(event.document_updates().at(doc2.key), updatedDoc2); // doc3 is new - XCTAssertEqualObjects(event.documentUpdates.at(doc3.key), doc3); + XCTAssertEqualObjects(event.document_updates().at(doc3.key), doc3); // Target is unchanged - XCTAssertEqual(event.targetChanges.size(), 1); + XCTAssertEqual(event.target_changes().size(), 1); TargetChange targetChange1{_resumeToken1, false, DocumentKeySet{doc3.key}, DocumentKeySet{updatedDoc2.key}, DocumentKeySet{deletedDoc1.key}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); } - (void)testResumeTokensHandledPerTarget { @@ -665,16 +665,16 @@ - (void)testResumeTokensHandledPerTarget { WatchTargetChange change2{WatchTargetChangeState::Current, {2}, resumeToken2}; aggregator.HandleTargetChange(change2); - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.targetChanges.size(), 2); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); + XCTAssertEqual(event.target_changes().size(), 2); TargetChange targetChange1{_resumeToken1, true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); TargetChange targetChange2{resumeToken2, true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(2) == targetChange2); + XCTAssertTrue(event.target_changes().at(2) == targetChange2); } - (void)testLastResumeTokenWins { @@ -696,16 +696,16 @@ - (void)testLastResumeTokenWins { WatchTargetChange change3{WatchTargetChangeState::NoChange, {2}, resumeToken3}; aggregator.HandleTargetChange(change3); - FSTRemoteEvent *event = aggregator.CreateRemoteEvent(testutil::Version(3)); - XCTAssertEqual(event.targetChanges.size(), 2); + RemoteEvent event = aggregator.CreateRemoteEvent(testutil::Version(3)); + XCTAssertEqual(event.target_changes().size(), 2); TargetChange targetChange1{resumeToken2, true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange1); + XCTAssertTrue(event.target_changes().at(1) == targetChange1); TargetChange targetChange2{resumeToken3, false, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; - XCTAssertTrue(event.targetChanges.at(2) == targetChange2); + XCTAssertTrue(event.target_changes().at(2) == targetChange2); } - (void)testSynthesizeDeletes { @@ -713,7 +713,7 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); auto resolveLimboTarget = MakeTargetChange(WatchTargetChangeState::Current, {1}); - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses @@ -721,10 +721,10 @@ - (void)testSynthesizeDeletes { changes:Changes(std::move(resolveLimboTarget))]; FSTDeletedDocument *expected = [FSTDeletedDocument documentWithKey:limboKey - version:event.snapshotVersion + version:event.snapshot_version() hasCommittedMutations:NO]; - XCTAssertEqualObjects(event.documentUpdates.at(limboKey), expected); - XCTAssertTrue(event.limboDocumentChanges.contains(limboKey)); + XCTAssertEqualObjects(event.document_updates().at(limboKey), expected); + XCTAssertTrue(event.limbo_document_changes().contains(limboKey)); } - (void)testDoesntSynthesizeDeletesForWrongState { @@ -732,14 +732,14 @@ - (void)testDoesntSynthesizeDeletesForWrongState { auto wrongState = MakeTargetChange(WatchTargetChangeState::NoChange, {1}); - FSTRemoteEvent *event = [self remoteEventAtSnapshotVersion:3 + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet {} changes:Changes(std::move(wrongState))]; - XCTAssertEqual(event.documentUpdates.size(), 0); - XCTAssertEqual(event.limboDocumentChanges.size(), 0); + XCTAssertEqual(event.document_updates().size(), 0); + XCTAssertEqual(event.limbo_document_changes().size(), 0); } - (void)testDoesntSynthesizeDeletesForExistingDoc { @@ -747,15 +747,15 @@ - (void)testDoesntSynthesizeDeletesForExistingDoc { auto hasDocument = MakeTargetChange(WatchTargetChangeState::Current, {3}); - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses existingKeys:DocumentKeySet{FSTTestDocKey(@"coll/limbo")} changes:Changes(std::move(hasDocument))]; - XCTAssertEqual(event.documentUpdates.size(), 0); - XCTAssertEqual(event.limboDocumentChanges.size(), 0); + XCTAssertEqual(event.document_updates().size(), 0); + XCTAssertEqual(event.limbo_document_changes().size(), 0); } - (void)testSeparatesDocumentUpdates { @@ -774,7 +774,7 @@ - (void)testSeparatesDocumentUpdates { FSTDeletedDocument *missingDoc = FSTTestDeletedDoc("docs/missing", 1, NO); auto missingDocChange = MakeDocChange({}, {1}, missingDoc.key, missingDoc); - FSTRemoteEvent *event = [self + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses @@ -786,7 +786,7 @@ - (void)testSeparatesDocumentUpdates { TargetChange targetChange2{_resumeToken1, false, DocumentKeySet{newDoc.key}, DocumentKeySet{existingDoc.key}, DocumentKeySet{deletedDoc.key}}; - XCTAssertTrue(event.targetChanges.at(1) == targetChange2); + XCTAssertTrue(event.target_changes().at(1) == targetChange2); } - (void)testTracksLimboDocuments { @@ -805,7 +805,7 @@ - (void)testTracksLimboDocuments { auto docChange3 = MakeDocChange({1}, {}, doc3.key, doc3); auto targetsChange = MakeTargetChange(WatchTargetChangeState::Current, {1, 2}); - FSTRemoteEvent *event = + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 targetMap:targetMap outstandingResponses:_noOutstandingResponses @@ -813,7 +813,7 @@ - (void)testTracksLimboDocuments { changes:Changes(std::move(docChange1), std::move(docChange2), std::move(docChange3), std::move(targetsChange))]; - DocumentKeySet limboDocChanges = event.limboDocumentChanges; + DocumentKeySet limboDocChanges = event.limbo_document_changes(); // Doc1 is in both limbo and non-limbo targets, therefore not tracked as limbo XCTAssertFalse(limboDocChanges.contains(doc1.key)); // Doc2 is only in the limbo target, so is tracked as a limbo document From f1140d9fc4975a3df97f56c4372f96e8c2b73a22 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 17:26:42 -0500 Subject: [PATCH 066/107] Unit tests compile and pass --- Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index cd7711474f5..d3260fce6ce 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -555,7 +555,7 @@ - (void)testExistenceFilterMismatchClearsTarget { XCTAssertTrue(event.target_changes().at(1) == targetChange3); XCTAssertEqual(event.target_changes().size(), 1); - XCTAssertEqual(event.targetMismatches.size(), 1); + XCTAssertEqual(event.target_mismatches().size(), 1); XCTAssertEqual(event.document_updates().size(), 0); } @@ -583,7 +583,7 @@ - (void)testExistenceFilterMismatchRemovesCurrentChanges { XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); XCTAssertEqual(event.document_updates().size(), 1); - XCTAssertEqual(event.targetMismatches.size(), 1); + XCTAssertEqual(event.target_mismatches().size(), 1); XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); XCTAssertEqual(event.target_changes().size(), 1); From 7ee766fe01a9ee42921f07386d9f869feda4bdaf Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 17:27:55 -0500 Subject: [PATCH 067/107] style.sh --- .../Tests/Integration/FSTDatastoreTests.mm | 3 ++- .../Example/Tests/Local/FSTLocalStoreTests.mm | 2 +- .../Tests/Remote/FSTRemoteEventTests.mm | 27 +++++++++---------- Firestore/Example/Tests/Util/FSTHelpers.mm | 6 ++--- Firestore/Source/Local/FSTLocalStore.h | 3 ++- Firestore/Source/Local/FSTLocalStore.mm | 9 ++++--- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index ebb39093956..8abb74d2fc2 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -20,6 +20,7 @@ #import #include +#include #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" @@ -135,7 +136,7 @@ - (DocumentKeySet)remoteKeysForTarget:(TargetId)targetId { return DocumentKeySet{}; } -- (void)applyRemoteEvent:(const RemoteEvent&)remoteEvent { +- (void)applyRemoteEvent:(const RemoteEvent &)remoteEvent { _listenEvents.push_back(remoteEvent); XCTestExpectation *expectation = [self.listenEventExpectations objectAtIndex:0]; [self.listenEventExpectations removeObjectAtIndex:0]; diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 069261068b3..6363c652be8 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -133,7 +133,7 @@ - (void)writeMutations:(NSArray *)mutations { _lastChanges = result.changes; } -- (void)applyRemoteEvent:(const RemoteEvent&)event { +- (void)applyRemoteEvent:(const RemoteEvent &)event { _lastChanges = [self.localStore applyRemoteEvent:event]; } diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index d3260fce6ce..baaa627b63d 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -431,10 +431,10 @@ - (void)testTargetCurrentChangeWillMarkTheTargetCurrent { auto change = MakeTargetChange(WatchTargetChangeState::Current, {1}, _resumeToken1); RemoteEvent event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:Changes(std::move(change))]; + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:Changes(std::move(change))]; XCTAssertEqual(event.snapshot_version(), testutil::Version(3)); XCTAssertEqual(event.document_updates().size(), 0); @@ -713,12 +713,11 @@ - (void)testSynthesizeDeletes { DocumentKey limboKey = testutil::Key("coll/limbo"); auto resolveLimboTarget = MakeTargetChange(WatchTargetChangeState::Current, {1}); - RemoteEvent event = - [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:Changes(std::move(resolveLimboTarget))]; + RemoteEvent event = [self remoteEventAtSnapshotVersion:3 + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:Changes(std::move(resolveLimboTarget))]; FSTDeletedDocument *expected = [FSTDeletedDocument documentWithKey:limboKey version:event.snapshot_version() @@ -733,10 +732,10 @@ - (void)testDoesntSynthesizeDeletesForWrongState { auto wrongState = MakeTargetChange(WatchTargetChangeState::NoChange, {1}); RemoteEvent event = [self remoteEventAtSnapshotVersion:3 - targetMap:targetMap - outstandingResponses:_noOutstandingResponses - existingKeys:DocumentKeySet {} - changes:Changes(std::move(wrongState))]; + targetMap:targetMap + outstandingResponses:_noOutstandingResponses + existingKeys:DocumentKeySet {} + changes:Changes(std::move(wrongState))]; XCTAssertEqual(event.document_updates().size(), 0); XCTAssertEqual(event.limbo_document_changes().size(), 0); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 701478eb6bb..e352c3853f2 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -376,7 +376,7 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { @end RemoteEvent FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, - const std::vector &addedToTargets) { + const std::vector &addedToTargets) { HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; @@ -415,8 +415,8 @@ RemoteEvent FSTTestUpdateRemoteEventWithLimboTargets( } RemoteEvent FSTTestUpdateRemoteEvent(FSTMaybeDocument *doc, - const std::vector &updatedInTargets, - const std::vector &removedFromTargets) { + const std::vector &updatedInTargets, + const std::vector &removedFromTargets) { return FSTTestUpdateRemoteEventWithLimboTargets(doc, updatedInTargets, removedFromTargets, {}); } diff --git a/Firestore/Source/Local/FSTLocalStore.h b/Firestore/Source/Local/FSTLocalStore.h index 6e2f8996c5a..21f05b68e4c 100644 --- a/Firestore/Source/Local/FSTLocalStore.h +++ b/Firestore/Source/Local/FSTLocalStore.h @@ -156,7 +156,8 @@ NS_ASSUME_NONNULL_BEGIN * * LocalDocuments are re-calculated if there are remaining mutations in the queue. */ -- (firebase::firestore::model::MaybeDocumentMap)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent&)remoteEvent; +- (firebase::firestore::model::MaybeDocumentMap)applyRemoteEvent: + (const firebase::firestore::remote::RemoteEvent &)remoteEvent; /** * Returns the keys of the documents that are associated with the given targetID in the remote diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index b745dcc8034..d6529d1fd14 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -210,7 +210,7 @@ - (void)setLastStreamToken:(nullable NSData *)streamToken { return self.queryCache->GetLastRemoteSnapshotVersion(); } -- (MaybeDocumentMap)applyRemoteEvent:(const RemoteEvent&)remoteEvent { +- (MaybeDocumentMap)applyRemoteEvent:(const RemoteEvent &)remoteEvent { return self.persistence.run("Apply remote event", [&]() -> MaybeDocumentMap { // TODO(gsoltis): move the sequence number into the reference delegate. ListenSequenceNumber sequenceNumber = self.persistence.currentSequenceNumber; @@ -376,9 +376,10 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run( + "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { From f00494a461a1944713cd32b5a2c089d2f19aab3d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 28 Jan 2019 17:49:40 -0500 Subject: [PATCH 068/107] Minor improvements --- .../src/firebase/firestore/remote/remote_event.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index acfd1ec27d8..e154b9ee623 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -259,14 +259,7 @@ class RemoteEvent { return snapshot_version_; } - /** - * A set of which document updates are due only to limbo resolution targets. - */ - const model::DocumentKeySet& limbo_document_changes() const { - return limbo_document_changes_; - } - - /** A map from target to changes to the target. See TargetChange. */ + /** A map from target to changes to the target. See `TargetChange`. */ const std::unordered_map& target_changes() const { return target_changes_; @@ -291,6 +284,13 @@ class RemoteEvent { return document_updates_; } + /** + * A set of which document updates are due only to limbo resolution targets. + */ + const model::DocumentKeySet& limbo_document_changes() const { + return limbo_document_changes_; + } + private: model::SnapshotVersion snapshot_version_; std::unordered_map target_changes_; From 766e940ce4c0b553b611f68cf8808ab3f43682de Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 14:13:38 -0500 Subject: [PATCH 069/107] Review feedback --- Firestore/Example/Tests/Util/FSTHelpers.mm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index f4030f21c8c..04022769093 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -387,11 +387,19 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { } TargetChange FSTTestTargetChangeMarkCurrent() { - return {[NSData data], true, DocumentKeySet{}, DocumentKeySet{}, DocumentKeySet{}}; + return {[NSData data], + /*current=*/true, + /*added_documents=*/DocumentKeySet{}, + /*modified_documents=*/DocumentKeySet{}, + /*removed_documents=*/DocumentKeySet{}}; } TargetChange FSTTestTargetChangeAckDocuments(DocumentKeySet docs) { - return {[NSData data], true, std::move(docs), DocumentKeySet{}, DocumentKeySet{}}; + return {[NSData data], + /*current=*/true, + /*added_documents*/ std::move(docs), + /*modified_documents*/ DocumentKeySet{}, + /*removed_documents*/ DocumentKeySet{}}; } FSTRemoteEvent *FSTTestUpdateRemoteEventWithLimboTargets( From 90450fdeb8c5a5137aa78114d94962ec0ed4ba7e Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 15:04:35 -0500 Subject: [PATCH 070/107] Initial implementation --- .../firestore/remote/online_state_tracker.h | 134 +++++++++++++++ .../firestore/remote/online_state_tracker.mm | 156 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/remote/online_state_tracker.h create mode 100644 Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h new file mode 100644 index 00000000000..90b027ee610 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -0,0 +1,134 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ + +#if !defined(__OBJC__) +// TODO(varconst): make it a pure C++ file when it no longer needs to rely on +// `FSTOnlineStateDelegate`. +#error "This header only supports Objective-C++" +#endif // !defined(__OBJC__) + +#import + +#include + +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" + +@protocol FSTOnlineStateDelegate; + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace remote { + +/** + * A component used by the `FSTRemoteStore` to track the `OnlineState` (that is, + * whether or not the client as a whole should be considered to be online or + * offline), implementing the appropriate heuristics. + * + * In particular, when the client is trying to connect to the backend, we allow + * up to `kMaxWatchStreamFailures` within `kOnlineStateTimeout` for a connection + * to succeed. If we have too many failures or the timeout elapses, then we set + * the `OnlineState` to `Offline`, and the client will behave as if it is + * offline (`getDocument()` calls will return cached data, etc.). + */ +class OnlineStateTracker { + public: + explicit OnlineStateTracker(util::AsyncQueue* worker_queue, + id online_state_delegate) + : worker_queue_{worker_queue}, + online_state_delegate_{online_state_delegate} { + } + + /** + * Called by `FSTRemoteStore` when a watch stream is started (including on + * each backoff attempt). + * + * If this is the first attempt, it sets the `OnlineState` to `Unknown` and + * starts the `onlineStateTimer`. + */ + void HandleWatchStreamStart(); + + /** + * Called by `FSTRemoteStore` when a watch stream fails. + * + * Updates our `OnlineState` as appropriate. The first failure moves us to + * `OnlineState::Unknown`. We then may allow multiple failures (based on + * `kMaxWatchStreamFailures`) before we actually transition to + * `OnlineState::Offline`. + */ + void HandleWatchStreamFailure(const util::Status& error); + + /** + * Explicitly sets the `OnlineState` to the specified state. + * + * Note that this resets the timers / failure counters, etc. used by our + * `Offline` heuristics, so it must not be used in place of + * `HandleWatchStreamStart` and `HandleWatchStreamFailure`. + */ + void UpdateState(model::OnlineState new_state); + + private: + void SetAndBroadcastState(model::OnlineState new_state); + void LogClientOfflineWarningIfNecessary(const std::string& reason); + void ClearOnlineStateTimer(); + + /** The current `OnlineState`. */ + model::OnlineState state_ = model::OnlineState::Unknown; + + /** + * A count of consecutive failures to open the stream. If it reaches the + * maximum defined by `kMaxWatchStreamFailures`, we'll revert to + * `OnlineState::Offline`. + */ + int watch_stream_failures_ = 0; + + /** + * Whether the client should log a warning message if it fails to connect to + * the backend (initially true, cleared after a successful stream, or if we've + * logged the message already). + */ + bool should_warn_client_is_offline_ = true; + + /** + * A timer that elapses after `kOnlineStateTimeout`, at which point we + * transition from `OnlineState` `Unknown` to `Offline` without waiting for + * the stream to actually fail (`kMaxWatchStreamFailures` times). + */ + util::DelayedOperation online_state_timer_; + + /** + * The worker queue to use for running timers (and to call + * `OnlineStateDelegate`). + */ + util::AsyncQueue* worker_queue_ = nullptr; + + /** A delegate to be notified on `OnlineState` changes. */ + id online_state_delegate_ = nil; +}; + +} // namespace remote +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm new file mode 100644 index 00000000000..3e39bd72583 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm @@ -0,0 +1,156 @@ +/* + * Copyright 2019 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/online_state_tracker.h" + +#include // NOLINT(build/c++11) + +#import "Firestore/Source/Remote/FSTRemoteStore.h" + +#include "Firestore/core/src/firebase/firestore/util/executor.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" +#include "Firestore/core/src/firebase/firestore/util/string_format.h" + +namespace chr = std::chrono; +using firebase::firestore::model::OnlineState; +using firebase::firestore::util::AsyncQueue; +using firebase::firestore::util::DelayedOperation; +using firebase::firestore::util::Status; +using firebase::firestore::util::StringFormat; +using firebase::firestore::util::TimerId; + +NS_ASSUME_NONNULL_BEGIN + +namespace { + +// To deal with transient failures, we allow multiple stream attempts before +// giving up and transitioning from OnlineState Unknown to Offline. +// TODO(mikelehen): This used to be set to 2 as a mitigation for b/66228394. +// @jdimond thinks that bug is sufficiently fixed so that we can set this back +// to 1. If that works okay, we could potentially remove this logic entirely. +const int kMaxWatchStreamFailures = 1; + +// To deal with stream attempts that don't succeed or fail in a timely manner, +// we have a timeout for OnlineState to reach Online or Offline. If the timeout +// is reached, we transition to Offline rather than waiting indefinitely. +const AsyncQueue::Milliseconds kOnlineStateTimeout = chr::seconds(10); + +} // namespace + +namespace firebase { +namespace firestore { +namespace remote { + +void OnlineStateTracker::HandleWatchStreamStart() { + if (watch_stream_failures_ != 0) { + return; + } + + SetAndBroadcastState(OnlineState::Unknown); + + HARD_ASSERT(!online_state_timer_, + "online_state_timer_ shouldn't be started yet"); + online_state_timer_ = worker_queue_->EnqueueAfterDelay( + kOnlineStateTimeout, TimerId::OnlineStateTimeout, [this] { + online_state_timer_ = {}; + + HARD_ASSERT(state_ == OnlineState::Unknown, + "Timer should be canceled if we transitioned to a " + "different state."); + LogClientOfflineWarningIfNecessary(StringFormat( + "Backend didn't respond within %s seconds.", + chr::duration_cast(kOnlineStateTimeout).count())); + SetAndBroadcastState(OnlineState::Offline); + + // NOTE: `HandleWatchStreamFailure` will continue to increment + // `watch_stream_failures_` even though we are already marked `Offline` + // but this is non-harmful. + }); +} + +void OnlineStateTracker::HandleWatchStreamFailure(const Status& error) { + if (state_ == OnlineState::Online) { + SetAndBroadcastState(OnlineState::Unknown); + + // To get to `OnlineState`::Online, `UpdateState` must have been called + // which would have reset our heuristics. + HARD_ASSERT(watch_stream_failures_ == 0, + "watch_stream_failures_ must be 0"); + HARD_ASSERT(!online_state_timer_, + "online_state_timer_ must not be set yet"); + } else { + ++watch_stream_failures_; + + if (watch_stream_failures_ >= kMaxWatchStreamFailures) { + ClearOnlineStateTimer(); + + LogClientOfflineWarningIfNecessary( + StringFormat("Connection failed %s times. Most recent error: %s", + kMaxWatchStreamFailures, error.error_message())); + + SetAndBroadcastState(OnlineState::Offline); + } + } +} + +void OnlineStateTracker::UpdateState(OnlineState new_state) { + ClearOnlineStateTimer(); + watch_stream_failures_ = 0; + + if (new_state == OnlineState::Online) { + // We've connected to watch at least once. Don't warn the developer about + // being offline going forward. + should_warn_client_is_offline_ = false; + } + + SetAndBroadcastState(new_state); +} + +void OnlineStateTracker::SetAndBroadcastState(OnlineState new_state) { + if (new_state != state_) { + state_ = new_state; + [online_state_delegate_ applyChangedOnlineState:new_state]; + } +} + +void OnlineStateTracker::LogClientOfflineWarningIfNecessary( + const std::string& reason) { + std::string message = + StringFormat("Could not reach Cloud Firestore backend. %s\n This " + "typically indicates that your device does not have a " + "healthy Internet connection at the moment. The client will " + "operate in offline mode until it is able to successfully " + "connect to the backend.", + reason); + + if (should_warn_client_is_offline_) { + LOG_WARN("%s", message); + should_warn_client_is_offline_ = false; + } else { + LOG_DEBUG("%s", message); + } +} + +void OnlineStateTracker::ClearOnlineStateTimer() { + online_state_timer_.Cancel(); +} + +} // namespace remote +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END From ed7ee521c361e69440155482531403d9b1a7699a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 15:10:47 -0500 Subject: [PATCH 071/107] Updating references --- .../Source/Remote/FSTOnlineStateTracker.h | 72 ------- .../Source/Remote/FSTOnlineStateTracker.mm | 175 ------------------ Firestore/Source/Remote/FSTRemoteStore.h | 5 +- Firestore/Source/Remote/FSTRemoteStore.mm | 40 ++-- .../firestore/remote/online_state_tracker.h | 2 + 5 files changed, 20 insertions(+), 274 deletions(-) delete mode 100644 Firestore/Source/Remote/FSTOnlineStateTracker.h delete mode 100644 Firestore/Source/Remote/FSTOnlineStateTracker.mm diff --git a/Firestore/Source/Remote/FSTOnlineStateTracker.h b/Firestore/Source/Remote/FSTOnlineStateTracker.h deleted file mode 100644 index 56aad0539a8..00000000000 --- a/Firestore/Source/Remote/FSTOnlineStateTracker.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 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 - -#include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/util/async_queue.h" - -@protocol FSTOnlineStateDelegate; - -NS_ASSUME_NONNULL_BEGIN - -/** - * A component used by the FSTRemoteStore to track the OnlineState (that is, whether or not the - * client as a whole should be considered to be online or offline), implementing the appropriate - * heuristics. - * - * In particular, when the client is trying to connect to the backend, we allow up to - * kMaxWatchStreamFailures within kOnlineStateTimeout for a connection to succeed. If we have too - * many failures or the timeout elapses, then we set the OnlineState to Offline, and - * the client will behave as if it is offline (getDocument() calls will return cached data, etc.). - */ -@interface FSTOnlineStateTracker : NSObject - -- (instancetype)initWithWorkerQueue:(firebase::firestore::util::AsyncQueue *)queue; - -- (instancetype)init NS_UNAVAILABLE; - -/** A delegate to be notified on OnlineState changes. */ -@property(nonatomic, weak) id onlineStateDelegate; - -/** - * Called by FSTRemoteStore when a watch stream is started (including on each backoff attempt). - * - * If this is the first attempt, it sets the OnlineState to Unknown and starts the - * onlineStateTimer. - */ -- (void)handleWatchStreamStart; - -/** - * Called by FSTRemoteStore when a watch stream fails. - * - * Updates our OnlineState as appropriate. The first failure moves us to OnlineState::Unknown. - * We then may allow multiple failures (based on kMaxWatchStreamFailures) before we actually - * transition to OnlineState::Offline. - */ -- (void)handleWatchStreamFailure:(NSError *)error; - -/** - * Explicitly sets the OnlineState to the specified state. - * - * Note that this resets the timers / failure counters, etc. used by our Offline heuristics, so - * it must not be used in place of handleWatchStreamStart and handleWatchStreamFailure. - */ -- (void)updateState:(firebase::firestore::model::OnlineState)newState; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTOnlineStateTracker.mm b/Firestore/Source/Remote/FSTOnlineStateTracker.mm deleted file mode 100644 index be4feab4bfa..00000000000 --- a/Firestore/Source/Remote/FSTOnlineStateTracker.mm +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2018 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/Remote/FSTOnlineStateTracker.h" - -#include // NOLINT(build/c++11) - -#import "Firestore/Source/Remote/FSTRemoteStore.h" - -#include "Firestore/core/src/firebase/firestore/util/executor.h" -#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" -#include "Firestore/core/src/firebase/firestore/util/log.h" - -namespace chr = std::chrono; -using firebase::firestore::model::OnlineState; -using firebase::firestore::util::AsyncQueue; -using firebase::firestore::util::DelayedOperation; -using firebase::firestore::util::TimerId; - -NS_ASSUME_NONNULL_BEGIN - -namespace { - -// To deal with transient failures, we allow multiple stream attempts before giving up and -// transitioning from OnlineState Unknown to Offline. -// TODO(mikelehen): This used to be set to 2 as a mitigation for b/66228394. @jdimond thinks that -// bug is sufficiently fixed so that we can set this back to 1. If that works okay, we could -// potentially remove this logic entirely. -const int kMaxWatchStreamFailures = 1; - -// To deal with stream attempts that don't succeed or fail in a timely manner, we have a -// timeout for OnlineState to reach Online or Offline. If the timeout is reached, we transition -// to Offline rather than waiting indefinitely. -const AsyncQueue::Milliseconds kOnlineStateTimeout = chr::seconds(10); - -} // namespace - -@interface FSTOnlineStateTracker () - -/** The current OnlineState. */ -@property(nonatomic, assign) OnlineState state; - -/** - * A count of consecutive failures to open the stream. If it reaches the maximum defined by - * kMaxWatchStreamFailures, we'll revert to OnlineState::Offline. - */ -@property(nonatomic, assign) int watchStreamFailures; - -/** - * Whether the client should log a warning message if it fails to connect to the backend - * (initially YES, cleared after a successful stream, or if we've logged the message already). - */ -@property(nonatomic, assign) BOOL shouldWarnClientIsOffline; - -@end - -@implementation FSTOnlineStateTracker { - /** - * A timer that elapses after kOnlineStateTimeout, at which point we transition from OnlineState - * Unknown to Offline without waiting for the stream to actually fail (kMaxWatchStreamFailures - * times). - */ - DelayedOperation _onlineStateTimer; - - /** The worker queue to use for running timers (and to call onlineStateDelegate). */ - AsyncQueue *_workerQueue; -} - -- (instancetype)initWithWorkerQueue:(AsyncQueue *)workerQueue { - if (self = [super init]) { - _workerQueue = workerQueue; - _state = OnlineState::Unknown; - _shouldWarnClientIsOffline = YES; - } - return self; -} - -- (void)handleWatchStreamStart { - if (self.watchStreamFailures == 0) { - [self setAndBroadcastState:OnlineState::Unknown]; - - HARD_ASSERT(!_onlineStateTimer, "_onlineStateTimer shouldn't be started yet"); - _onlineStateTimer = - _workerQueue->EnqueueAfterDelay(kOnlineStateTimeout, TimerId::OnlineStateTimeout, [self] { - _onlineStateTimer = {}; - HARD_ASSERT(self.state == OnlineState::Unknown, - "Timer should be canceled if we transitioned to a different state."); - [self logClientOfflineWarningIfNecessaryWithReason: - [NSString stringWithFormat:@"Backend didn't respond within %lld seconds.", - chr::duration_cast(kOnlineStateTimeout) - .count()]]; - [self setAndBroadcastState:OnlineState::Offline]; - - // NOTE: handleWatchStreamFailure will continue to increment - // watchStreamFailures even though we are already marked Offline but this is - // non-harmful. - }); - } -} - -- (void)handleWatchStreamFailure:(NSError *)error { - if (self.state == OnlineState::Online) { - [self setAndBroadcastState:OnlineState::Unknown]; - - // To get to OnlineState::Online, updateState: must have been called which would have reset - // our heuristics. - HARD_ASSERT(self.watchStreamFailures == 0, "watchStreamFailures must be 0"); - HARD_ASSERT(!_onlineStateTimer, "_onlineStateTimer must not be set yet"); - } else { - self.watchStreamFailures++; - if (self.watchStreamFailures >= kMaxWatchStreamFailures) { - [self clearOnlineStateTimer]; - [self logClientOfflineWarningIfNecessaryWithReason: - [NSString stringWithFormat:@"Connection failed %d times. Most recent error: %@", - kMaxWatchStreamFailures, error]]; - [self setAndBroadcastState:OnlineState::Offline]; - } - } -} - -- (void)updateState:(OnlineState)newState { - [self clearOnlineStateTimer]; - self.watchStreamFailures = 0; - - if (newState == OnlineState::Online) { - // We've connected to watch at least once. Don't warn the developer about being offline going - // forward. - self.shouldWarnClientIsOffline = NO; - } - - [self setAndBroadcastState:newState]; -} - -- (void)setAndBroadcastState:(OnlineState)newState { - if (newState != self.state) { - self.state = newState; - [self.onlineStateDelegate applyChangedOnlineState:newState]; - } -} - -- (void)logClientOfflineWarningIfNecessaryWithReason:(NSString *)reason { - NSString *message = [NSString - stringWithFormat: - @"Could not reach Cloud Firestore backend. %@\n This typically indicates that your " - @"device does not have a healthy Internet connection at the moment. The client will " - @"operate in offline mode until it is able to successfully connect to the backend.", - reason]; - if (self.shouldWarnClientIsOffline) { - LOG_WARN("%s", message); - self.shouldWarnClientIsOffline = NO; - } else { - LOG_DEBUG("%s", message); - } -} - -- (void)clearOnlineStateTimer { - _onlineStateTimer.Cancel(); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 5ccb9956647..233a219e859 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -106,14 +106,13 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore datastore: (std::shared_ptr)datastore - workerQueue:(firebase::firestore::util::AsyncQueue *)queue; + workerQueue:(firebase::firestore::util::AsyncQueue *)queue + onlineStateDelegate:(id) onlineStateDelegate; - (instancetype)init NS_UNAVAILABLE; @property(nonatomic, weak) id syncEngine; -@property(nonatomic, weak) id onlineStateDelegate; - /** Starts up the remote store, creating streams, restoring state from LocalStore, etc. */ - (void)start; diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 7c4bcd4e3e4..68ebfe0ba46 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -28,13 +28,13 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTOnlineStateTracker.h" #import "Firestore/Source/Remote/FSTStream.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/remote/online_state_tracker.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" @@ -88,8 +88,6 @@ @interface FSTRemoteStore () #pragma mark Watch Stream -@property(nonatomic, strong, readonly) FSTOnlineStateTracker *onlineStateTracker; - /** * A list of up to kMaxPendingWrites writes that we have fetched from the LocalStore via * fillWritePipeline and have or will send to the write stream. @@ -108,9 +106,11 @@ @interface FSTRemoteStore () @end @implementation FSTRemoteStore { + OnlineStateTracker _onlineStateTracker; + std::unique_ptr _watchChangeAggregator; - /** The client-side proxy for interacting with the backend. */ + /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; /** * A mapping of watched targets that the client cares about tracking and the @@ -133,13 +133,15 @@ @implementation FSTRemoteStore { - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore datastore:(std::shared_ptr)datastore - workerQueue:(AsyncQueue *)queue { + workerQueue:(AsyncQueue *)queue + onlineStateDelegate:(id) onlineStateDelegate +{ if (self = [super init]) { _localStore = localStore; _datastore = std::move(datastore); _writePipeline = [NSMutableArray array]; - _onlineStateTracker = [[FSTOnlineStateTracker alloc] initWithWorkerQueue:queue]; + _onlineStateTracker = OnlineStateTracker{queue, onlineStateDelegate}; _datastore->Start(); // Create streams (but note they're not started yet) @@ -156,16 +158,6 @@ - (void)start { [self enableNetwork]; } -@dynamic onlineStateDelegate; - -- (nullable id)onlineStateDelegate { - return self.onlineStateTracker.onlineStateDelegate; -} - -- (void)setOnlineStateDelegate:(nullable id)delegate { - self.onlineStateTracker.onlineStateDelegate = delegate; -} - #pragma mark Online/Offline state - (BOOL)canUseNetwork { @@ -184,7 +176,7 @@ - (void)enableNetwork { if ([self shouldStartWatchStream]) { [self startWatchStream]; } else { - [self.onlineStateTracker updateState:OnlineState::Unknown]; + _onlineStateTracker.UpdateState(OnlineState::Unknown); } // This will start the write stream if necessary. @@ -197,7 +189,7 @@ - (void)disableNetwork { [self disableNetworkInternal]; // Set the OnlineState to Offline so get()s return from cache, etc. - [self.onlineStateTracker updateState:OnlineState::Offline]; + _onlineStateTracker.UpdateState(OnlineState::Offline); } /** Disables the network, setting the OnlineState to the specified targetOnlineState. */ @@ -234,7 +226,7 @@ - (void)credentialDidChange { LOG_DEBUG("FSTRemoteStore %s restarting streams for new credential", (__bridge void *)self); _isNetworkEnabled = NO; [self disableNetworkInternal]; - [self.onlineStateTracker updateState:OnlineState::Unknown]; + _onlineStateTracker.UpdateState(OnlineState::Unknown); [self enableNetwork]; } } @@ -247,7 +239,7 @@ - (void)startWatchStream { _watchChangeAggregator = absl::make_unique(self); _watchStream->Start(); - [self.onlineStateTracker handleWatchStreamStart]; + _onlineStateTracker.HandleWatchStreamStart(); } - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { @@ -284,7 +276,7 @@ - (void)stopListeningToTargetID:(TargetId)targetID { // Revert to OnlineState::Unknown if the watch stream is not open and we have no listeners, // since without any listens to send we cannot confirm if the stream is healthy and upgrade // to OnlineState::Online. - [self.onlineStateTracker updateState:OnlineState::Unknown]; + _onlineStateTracker.UpdateState(OnlineState::Unknown); } } } @@ -316,7 +308,7 @@ - (void)watchStreamDidOpen { - (void)watchStreamDidChange:(const WatchChange &)change snapshotVersion:(const SnapshotVersion &)snapshotVersion { // Mark the connection as Online because we got a message from the server. - [self.onlineStateTracker updateState:OnlineState::Online]; + _onlineStateTracker.UpdateState(OnlineState::Online); if (change.type() == WatchChange::Type::TargetChange) { const WatchTargetChange &watchTargetChange = static_cast(change); @@ -355,13 +347,13 @@ - (void)watchStreamWasInterruptedWithError:(const Status &)error { // If we still need the watch stream, retry the connection. if ([self shouldStartWatchStream]) { - [self.onlineStateTracker handleWatchStreamFailure:util::MakeNSError(error)]; + _onlineStateTracker.HandleWatchStreamFailure(error); [self startWatchStream]; } else { // We don't need to restart the watch stream because there are no active targets. The online // state is set to unknown because there is no active attempt at establishing a connection. - [self.onlineStateTracker updateState:OnlineState::Unknown]; + _onlineStateTracker.UpdateState(OnlineState::Unknown); } } diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h index 90b027ee610..b006aa2e1bb 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -52,6 +52,8 @@ namespace remote { */ class OnlineStateTracker { public: + OnlineStateTracker() = default; + explicit OnlineStateTracker(util::AsyncQueue* worker_queue, id online_state_delegate) : worker_queue_{worker_queue}, From 920a921f4552e1f4b7d2bd84bc4664d27abfa7c0 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:13:15 -0500 Subject: [PATCH 072/107] All compiles --- Firestore/Example/Tests/Integration/FSTDatastoreTests.mm | 3 ++- .../Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm | 5 ++--- Firestore/Source/Core/FSTFirestoreClient.mm | 5 ++--- Firestore/Source/Remote/FSTRemoteStore.h | 2 +- Firestore/Source/Remote/FSTRemoteStore.mm | 8 ++++---- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index 8abb74d2fc2..b5bbadc5467 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -186,7 +186,8 @@ - (void)setUp { _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:_datastore - workerQueue:_testWorkerQueue.get()]; + workerQueue:_testWorkerQueue.get() + onlineStateDelegate:nil]; _testWorkerQueue->Enqueue([=] { [_remoteStore start]; }); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index e34349e716a..eb5af316c0c 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -155,7 +155,8 @@ - (instancetype)initWithPersistence:(id)persistence std::make_shared(_databaseInfo, _workerQueue.get(), &_credentialProvider); _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:_datastore - workerQueue:_workerQueue.get()]; + workerQueue:_workerQueue.get() + onlineStateDelegate:self]; _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore @@ -163,8 +164,6 @@ - (instancetype)initWithPersistence:(id)persistence _remoteStore.syncEngine = _syncEngine; _eventManager = [FSTEventManager eventManagerWithSyncEngine:_syncEngine]; - _remoteStore.onlineStateDelegate = self; - // Set up internal event tracking for the spec tests. NSMutableArray *events = [NSMutableArray array]; _eventHandler = ^(FSTQueryEvent *e) { diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index 9f6b33df461..69231711920 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -228,7 +228,8 @@ - (void)initializeWithUser:(const User &)user settings:(FIRFirestoreSettings *)s _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:std::move(datastore) - workerQueue:_workerQueue.get()]; + workerQueue:_workerQueue.get() + onlineStateDelegate:self]; _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore @@ -239,8 +240,6 @@ - (void)initializeWithUser:(const User &)user settings:(FIRFirestoreSettings *)s // Setup wiring for remote store. _remoteStore.syncEngine = _syncEngine; - _remoteStore.onlineStateDelegate = self; - // NOTE: RemoteStore depends on LocalStore (for persisting stream tokens, refilling mutation // queue, etc.) so must be started after LocalStore. [_localStore start]; diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 233a219e859..2e27221ae27 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -107,7 +107,7 @@ NS_ASSUME_NONNULL_BEGIN datastore: (std::shared_ptr)datastore workerQueue:(firebase::firestore::util::AsyncQueue *)queue - onlineStateDelegate:(id) onlineStateDelegate; + onlineStateDelegate:(id _Nullable)onlineStateDelegate; - (instancetype)init NS_UNAVAILABLE; diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 68ebfe0ba46..f16a9cd5bd4 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -59,6 +59,7 @@ using firebase::firestore::remote::WriteStream; using firebase::firestore::remote::DocumentWatchChange; using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::OnlineStateTracker; using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; @@ -134,8 +135,7 @@ @implementation FSTRemoteStore { - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore datastore:(std::shared_ptr)datastore workerQueue:(AsyncQueue *)queue - onlineStateDelegate:(id) onlineStateDelegate -{ + onlineStateDelegate:(id _Nullable)onlineStateDelegate { if (self = [super init]) { _localStore = localStore; _datastore = std::move(datastore); @@ -214,7 +214,7 @@ - (void)shutdown { [self disableNetworkInternal]; // Set the OnlineState to Unknown (rather than Offline) to avoid potentially triggering // spurious listener events with cached data, etc. - [self.onlineStateTracker updateState:OnlineState::Unknown]; + _onlineStateTracker.UpdateState(OnlineState::Unknown); _datastore->Shutdown(); } @@ -308,7 +308,7 @@ - (void)watchStreamDidOpen { - (void)watchStreamDidChange:(const WatchChange &)change snapshotVersion:(const SnapshotVersion &)snapshotVersion { // Mark the connection as Online because we got a message from the server. - _onlineStateTracker.UpdateState(OnlineState::Online); + _onlineStateTracker.UpdateState(OnlineState::Online); if (change.type() == WatchChange::Type::TargetChange) { const WatchTargetChange &watchTargetChange = static_cast(change); From 3d509ec45d5982e3d9a1acae91cc5d807826ddb0 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:16:59 -0500 Subject: [PATCH 073/107] style.sh --- Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index eb5af316c0c..68a1e69b21f 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -156,7 +156,7 @@ - (instancetype)initWithPersistence:(id)persistence _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:_datastore workerQueue:_workerQueue.get() - onlineStateDelegate:self]; + onlineStateDelegate:self]; _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore From b2d8ce438616b559e226affd2956d8d79b91eef3 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:34:20 -0500 Subject: [PATCH 074/107] Minor consistency changes --- .../firestore/remote/online_state_tracker.h | 16 ++++++++-------- .../firestore/remote/online_state_tracker.mm | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h index b006aa2e1bb..b046aa2271e 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -89,7 +89,7 @@ class OnlineStateTracker { void UpdateState(model::OnlineState new_state); private: - void SetAndBroadcastState(model::OnlineState new_state); + void SetAndBroadcast(model::OnlineState new_state); void LogClientOfflineWarningIfNecessary(const std::string& reason); void ClearOnlineStateTimer(); @@ -103,13 +103,6 @@ class OnlineStateTracker { */ int watch_stream_failures_ = 0; - /** - * Whether the client should log a warning message if it fails to connect to - * the backend (initially true, cleared after a successful stream, or if we've - * logged the message already). - */ - bool should_warn_client_is_offline_ = true; - /** * A timer that elapses after `kOnlineStateTimeout`, at which point we * transition from `OnlineState` `Unknown` to `Offline` without waiting for @@ -117,6 +110,13 @@ class OnlineStateTracker { */ util::DelayedOperation online_state_timer_; + /** + * Whether the client should log a warning message if it fails to connect to + * the backend (initially true, cleared after a successful stream, or if we've + * logged the message already). + */ + bool should_warn_client_is_offline_ = true; + /** * The worker queue to use for running timers (and to call * `OnlineStateDelegate`). diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm index 3e39bd72583..feb994e16d1 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm @@ -60,7 +60,7 @@ return; } - SetAndBroadcastState(OnlineState::Unknown); + SetAndBroadcast(OnlineState::Unknown); HARD_ASSERT(!online_state_timer_, "online_state_timer_ shouldn't be started yet"); @@ -74,7 +74,7 @@ LogClientOfflineWarningIfNecessary(StringFormat( "Backend didn't respond within %s seconds.", chr::duration_cast(kOnlineStateTimeout).count())); - SetAndBroadcastState(OnlineState::Offline); + SetAndBroadcast(OnlineState::Offline); // NOTE: `HandleWatchStreamFailure` will continue to increment // `watch_stream_failures_` even though we are already marked `Offline` @@ -84,7 +84,7 @@ void OnlineStateTracker::HandleWatchStreamFailure(const Status& error) { if (state_ == OnlineState::Online) { - SetAndBroadcastState(OnlineState::Unknown); + SetAndBroadcast(OnlineState::Unknown); // To get to `OnlineState`::Online, `UpdateState` must have been called // which would have reset our heuristics. @@ -102,7 +102,7 @@ StringFormat("Connection failed %s times. Most recent error: %s", kMaxWatchStreamFailures, error.error_message())); - SetAndBroadcastState(OnlineState::Offline); + SetAndBroadcast(OnlineState::Offline); } } } @@ -117,10 +117,10 @@ should_warn_client_is_offline_ = false; } - SetAndBroadcastState(new_state); + SetAndBroadcast(new_state); } -void OnlineStateTracker::SetAndBroadcastState(OnlineState new_state) { +void OnlineStateTracker::SetAndBroadcast(OnlineState new_state) { if (new_state != state_) { state_ = new_state; [online_state_delegate_ applyChangedOnlineState:new_state]; From 355ced06f88487196cca84bac028fbd8de2378fb Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:49:33 -0500 Subject: [PATCH 075/107] Skeleton --- .../firebase/firestore/remote/remote_store.h | 62 +++++ .../firebase/firestore/remote/remote_store.mm | 233 ++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 Firestore/core/src/firebase/firestore/remote/remote_store.h create mode 100644 Firestore/core/src/firebase/firestore/remote/remote_store.mm diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h new file mode 100644 index 00000000000..88f5265c2f5 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ + +#if !defined(__OBJC__) +// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` +// (the latter is used to represent the resume token). +#error "This header only supports Objective-C++" +#endif // !defined(__OBJC__) + +#import + +#include +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" +#include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" + +@class FSTMaybeDocument; +@class FSTQueryData; + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace remote { + +class RemoteStore { + public: + + private: +}; + +} // namespace remote +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm new file mode 100644 index 00000000000..9b2a7b14fea --- /dev/null +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -0,0 +1,233 @@ +/* + * Copyright 2019 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. + */ + +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" + +namespace firebase { +namespace firestore { +namespace remote { + +void RemoteStore::StartWatchStream() { + HARD_ASSERT([self shouldStartWatchStream], + "startWatchStream: called when shouldStartWatchStream: is false."); + _watchChangeAggregator = absl::make_unique(self); + _watchStream->Start(); + + _onlineStateTracker.HandleWatchStreamStart(); +} + +void RemoteStore::ListenToTarget(FSTQueryData* query_data) { + TargetId targetKey = queryData.targetID; + HARD_ASSERT(_listenTargets.find(targetKey) == _listenTargets.end(), + "listenToQuery called with duplicate target id: %s", targetKey); + + _listenTargets[targetKey] = queryData; + + if ([self shouldStartWatchStream]) { + [self startWatchStream]; + } else if (_watchStream->IsOpen()) { + [self sendWatchRequestWithQueryData:queryData]; + } +} + +void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { + _watchChangeAggregator->RecordPendingTargetRequest(queryData.targetID); + _watchStream->WatchQuery(queryData); +} + +void RemoteStore::StopListening(TargetId target_id) { + size_t num_erased = _listenTargets.erase(targetID); + HARD_ASSERT(num_erased == 1, "stopListeningToTargetID: target not currently watched: %s", + targetID); + + if (_watchStream->IsOpen()) { + [self sendUnwatchRequestForTargetID:targetID]; + } + if (_listenTargets.empty()) { + if (_watchStream->IsOpen()) { + _watchStream->MarkIdle(); + } else if ([self canUseNetwork]) { + // Revert to OnlineState::Unknown if the watch stream is not open and we have no listeners, + // since without any listens to send we cannot confirm if the stream is healthy and upgrade + // to OnlineState::Online. + _onlineStateTracker.UpdateState(OnlineState::Unknown); + } + } +} + +void RemoteStore::SendUnwatchRequest(TargetId target_id) { + _watchChangeAggregator->RecordPendingTargetRequest(targetID); + _watchStream->UnwatchTargetId(targetID); +} + +bool RemoteStore::ShouldStartWatchStream() const { + return [self canUseNetwork] && !_watchStream->IsStarted() && !_listenTargets.empty(); +} + +void RemoteStore::CleanUpWatchStreamState() { + _watchChangeAggregator.reset(); +} + +void RemoteStore::OnWatchStreamOpen() { + // Restore any existing watches. + for (const auto &kv : _listenTargets) { + [self sendWatchRequestWithQueryData:kv.second]; + } +} + +void RemoteStore::OnWatchStreamChange(const WatchChange& change, const SnapshotVersion& snapshot_version) { + // Mark the connection as Online because we got a message from the server. + _onlineStateTracker.UpdateState(OnlineState::Online); + + if (change.type() == WatchChange::Type::TargetChange) { + const WatchTargetChange &watchTargetChange = static_cast(change); + if (watchTargetChange.state() == WatchTargetChangeState::Removed && + !watchTargetChange.cause().ok()) { + // There was an error on a target, don't wait for a consistent snapshot to raise events + return [self processTargetErrorForWatchChange:watchTargetChange]; + } else { + _watchChangeAggregator->HandleTargetChange(watchTargetChange); + } + } else if (change.type() == WatchChange::Type::Document) { + _watchChangeAggregator->HandleDocumentChange(static_cast(change)); + } else { + HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, + "Expected watchChange to be an instance of ExistenceFilterWatchChange"); + _watchChangeAggregator->HandleExistenceFilter( + static_cast(change)); + } + + if (snapshotVersion != SnapshotVersion::None() && + snapshotVersion >= [self.localStore lastRemoteSnapshotVersion]) { + // We have received a target change with a global snapshot if the snapshot version is not + // equal to SnapshotVersion.None(). + [self raiseWatchSnapshotWithSnapshotVersion:snapshotVersion]; + } +} + +void RemoteStore::OnWatchStreamError(const Status& error) { + if (error.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. + HARD_ASSERT(![self shouldStartWatchStream], + "Watch stream was stopped gracefully while still needed."); + } + + [self cleanUpWatchStreamState]; + + // If we still need the watch stream, retry the connection. + if ([self shouldStartWatchStream]) { + _onlineStateTracker.HandleWatchStreamFailure(error); + + [self startWatchStream]; + } else { + // We don't need to restart the watch stream because there are no active targets. The online + // state is set to unknown because there is no active attempt at establishing a connection. + _onlineStateTracker.UpdateState(OnlineState::Unknown); + } +} + +/** + * Takes a batch of changes from the Datastore, repackages them as a `RemoteEvent`, and passes that + * on to the SyncEngine. + */ +void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { + HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), + "Can't raise event for unknown SnapshotVersion"); + + RemoteEvent remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); + + // Update in-memory resume tokens. `FSTLocalStore` will update the persistent view of these when + // applying the completed `RemoteEvent`. + for (const auto &entry : remoteEvent.target_changes()) { + const TargetChange &target_change = entry.second; + NSData *resumeToken = target_change.resume_token(); + if (resumeToken.length > 0) { + TargetId targetID = entry.first; + auto found = _listenTargets.find(targetID); + FSTQueryData *queryData = found != _listenTargets.end() ? found->second : nil; + // A watched target might have been removed already. + if (queryData) { + _listenTargets[targetID] = + [queryData queryDataByReplacingSnapshotVersion:snapshotVersion + resumeToken:resumeToken + sequenceNumber:queryData.sequenceNumber]; + } + } + } + + // Re-establish listens for the targets that have been invalidated by existence filter + // mismatches. + for (TargetId targetID : remoteEvent.target_mismatches()) { + auto found = _listenTargets.find(targetID); + if (found == _listenTargets.end()) { + // A watched target might have been removed already. + continue; + } + FSTQueryData *queryData = found->second; + + // Clear the resume token for the query, since we're in a known mismatch state. + queryData = [[FSTQueryData alloc] initWithQuery:queryData.query + targetID:targetID + listenSequenceNumber:queryData.sequenceNumber + purpose:queryData.purpose]; + _listenTargets[targetID] = queryData; + + // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send a + // resume token so that we get a full update. + [self sendUnwatchRequestForTargetID:targetID]; + + // Mark the query we send as being on behalf of an existence filter mismatch, but don't + // actually retain that in _listenTargets. This ensures that we flag the first re-listen this + // way without impacting future listens of this target (that might happen e.g. on reconnect). + FSTQueryData *requestQueryData = + [[FSTQueryData alloc] initWithQuery:queryData.query + targetID:targetID + listenSequenceNumber:queryData.sequenceNumber + purpose:FSTQueryPurposeExistenceFilterMismatch]; + [self sendWatchRequestWithQueryData:requestQueryData]; + } + + // Finally handle remote event + [self.syncEngine applyRemoteEvent:remoteEvent]; +} + +/** Process a target error and passes the error along to SyncEngine. */ +void RemoteStore::ProcessTargetError(const WatchTargetChange& change) { + HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); + // Ignore targets that have been removed already. + for (TargetId targetID : change.target_ids()) { + auto found = _listenTargets.find(targetID); + if (found != _listenTargets.end()) { + _listenTargets.erase(found); + _watchChangeAggregator->RemoveTarget(targetID); + [self.syncEngine rejectListenWithTargetID:targetID error:util::MakeNSError(change.cause())]; + } + } +} + +/* +_watchChangeAggregator +_watchStream +_onlineStateTracker +_listenTargets +_syncEngine + +[canUseNetwork] + + */ +} // namespace remote +} // namespace firestore +} // namespace firebase From df4c82eb9134bb00e673a7c38949bfecc1acb39a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:50:55 -0500 Subject: [PATCH 076/107] Pseudochange --- Firestore/core/src/firebase/firestore/remote/remote_event.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index e154b9ee623..2e6c2d5ae6c 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -447,3 +447,4 @@ class WatchChangeAggregator { NS_ASSUME_NONNULL_END #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ + From 9b494ee10904ac6db97ae6c8d04d141356ef6769 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:51:15 -0500 Subject: [PATCH 077/107] Undo pseudochange --- Firestore/core/src/firebase/firestore/remote/remote_event.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 2e6c2d5ae6c..e154b9ee623 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -447,4 +447,3 @@ class WatchChangeAggregator { NS_ASSUME_NONNULL_END #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_EVENT_H_ - From c5a82f9f182cd1f30f171e2a7e4310f479a879a1 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 29 Jan 2019 16:57:10 -0500 Subject: [PATCH 078/107] unstyle --- Firestore/Source/Local/FSTLocalStore.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index b056b9be5e9..e157702a720 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -375,10 +375,9 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(BatchId)batchID { } - (nullable FSTMaybeDocument *)readDocument:(const DocumentKey &)key { - return self.persistence.run( - "ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { - return [self.localDocuments documentForKey:key]; - }); + return self.persistence.run("ReadDocument", [&]() -> FSTMaybeDocument *_Nullable { + return [self.localDocuments documentForKey:key]; + }); } - (FSTQueryData *)allocateQuery:(FSTQuery *)query { From 65b6ae2bb50f74f07afc6d1799fa60b3f03c4ae1 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 14:58:26 -0500 Subject: [PATCH 079/107] Review feedback --- .../Tests/Integration/FSTDatastoreTests.mm | 3 +- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 2 +- .../SpecTests/FSTSyncEngineTestDriver.mm | 17 ++++++----- Firestore/Source/Core/FSTEventManager.h | 4 ++- Firestore/Source/Core/FSTFirestoreClient.h | 2 +- Firestore/Source/Core/FSTFirestoreClient.mm | 8 ++---- Firestore/Source/Remote/FSTRemoteStore.h | 24 +++++----------- Firestore/Source/Remote/FSTRemoteStore.mm | 4 +-- .../firestore/remote/online_state_tracker.h | 28 ++++++------------- .../firestore/remote/online_state_tracker.mm | 2 +- 10 files changed, 36 insertions(+), 58 deletions(-) diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index b5bbadc5467..f057cb5deab 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -55,6 +55,7 @@ using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::Precondition; +using firebase::firestore::model::OnlineState; using firebase::firestore::model::TargetId; using firebase::firestore::remote::Datastore; using firebase::firestore::remote::GrpcConnection; @@ -187,7 +188,7 @@ - (void)setUp { _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:_datastore workerQueue:_testWorkerQueue.get() - onlineStateDelegate:nil]; + onlineStateHandler:[](OnlineState) {}]; _testWorkerQueue->Enqueue([=] { [_remoteStore start]; }); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 0622aa4290e..b3b2a1d2a5c 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -86,7 +86,7 @@ typedef std::unordered_map +@interface FSTSyncEngineTestDriver : NSObject /** * Initializes the underlying FSTSyncEngine with the given local persistence implementation and diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 68a1e69b21f..8d7b7a236da 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -153,10 +153,14 @@ - (instancetype)initWithPersistence:(id)persistence _datastore = std::make_shared(_databaseInfo, _workerQueue.get(), &_credentialProvider); - _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore - datastore:_datastore - workerQueue:_workerQueue.get() - onlineStateDelegate:self]; + _remoteStore = + [[FSTRemoteStore alloc] initWithLocalStore:_localStore + datastore:_datastore + workerQueue:_workerQueue.get() + onlineStateHandler:[self](OnlineState onlineState) { + [self.syncEngine applyChangedOnlineState:onlineState]; + [self.eventManager applyChangedOnlineState:onlineState]; + }]; _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore @@ -202,11 +206,6 @@ - (void)drainQueue { return _currentUser; } -- (void)applyChangedOnlineState:(OnlineState)onlineState { - [self.syncEngine applyChangedOnlineState:onlineState]; - [self.eventManager applyChangedOnlineState:onlineState]; -} - - (void)start { _workerQueue->EnqueueBlocking([&] { [self.localStore start]; diff --git a/Firestore/Source/Core/FSTEventManager.h b/Firestore/Source/Core/FSTEventManager.h index 67951b91984..814eb725833 100644 --- a/Firestore/Source/Core/FSTEventManager.h +++ b/Firestore/Source/Core/FSTEventManager.h @@ -75,7 +75,7 @@ NS_ASSUME_NONNULL_BEGIN * EventManager is responsible for mapping queries to query event emitters. It handles "fan-out." * (Identical queries will re-use the same watch on the backend.) */ -@interface FSTEventManager : NSObject +@interface FSTEventManager : NSObject + (instancetype)eventManagerWithSyncEngine:(FSTSyncEngine *)syncEngine; @@ -84,6 +84,8 @@ NS_ASSUME_NONNULL_BEGIN - (firebase::firestore::model::TargetId)addListener:(FSTQueryListener *)listener; - (void)removeListener:(FSTQueryListener *)listener; +- (void)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; + @end NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h index f4d850dda6d..1d2e3abe66c 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.h +++ b/Firestore/Source/Core/FSTFirestoreClient.h @@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN * SDK architecture. It is responsible for creating the worker queue that is shared by all of the * other components in the system. */ -@interface FSTFirestoreClient : NSObject +@interface FSTFirestoreClient : NSObject /** * Creates and returns a FSTFirestoreClient with the given parameters. diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index 69231711920..6f9161f1706 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -229,7 +229,9 @@ - (void)initializeWithUser:(const User &)user settings:(FIRFirestoreSettings *)s _remoteStore = [[FSTRemoteStore alloc] initWithLocalStore:_localStore datastore:std::move(datastore) workerQueue:_workerQueue.get() - onlineStateDelegate:self]; + onlineStateHandler:[self](OnlineState onlineState) { + [self.syncEngine applyChangedOnlineState:onlineState]; + }]; _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore @@ -266,10 +268,6 @@ - (void)credentialDidChangeWithUser:(const User &)user { [self.syncEngine credentialDidChangeWithUser:user]; } -- (void)applyChangedOnlineState:(OnlineState)onlineState { - [self.syncEngine applyChangedOnlineState:onlineState]; -} - - (void)disableNetworkWithCompletion:(nullable FSTVoidErrorBlock)completion { _workerQueue->Enqueue([self, completion] { [self.remoteStore disableNetwork]; diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 2e27221ae27..c52868bf788 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -16,6 +16,7 @@ #import +#include #include #include "Firestore/core/src/firebase/firestore/auth/user.h" @@ -83,18 +84,6 @@ NS_ASSUME_NONNULL_BEGIN @end -/** - * A protocol for the FSTRemoteStore online state delegate, called whenever the state of the - * online streams of the FSTRemoteStore changes. - * Note that this protocol only supports the watch stream for now. - */ -@protocol FSTOnlineStateDelegate - -/** Called whenever the online state of the watch stream changes */ -- (void)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; - -@end - #pragma mark - FSTRemoteStore /** @@ -103,11 +92,12 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FSTRemoteStore : NSObject -- (instancetype)initWithLocalStore:(FSTLocalStore *)localStore - datastore: - (std::shared_ptr)datastore - workerQueue:(firebase::firestore::util::AsyncQueue *)queue - onlineStateDelegate:(id _Nullable)onlineStateDelegate; +- (instancetype) + initWithLocalStore:(FSTLocalStore *)localStore + datastore:(std::shared_ptr)datastore + workerQueue:(firebase::firestore::util::AsyncQueue *)queue + onlineStateHandler: + (std::function)onlineStateHandler; - (instancetype)init NS_UNAVAILABLE; diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index f16a9cd5bd4..c765e5c46a7 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -135,13 +135,13 @@ @implementation FSTRemoteStore { - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore datastore:(std::shared_ptr)datastore workerQueue:(AsyncQueue *)queue - onlineStateDelegate:(id _Nullable)onlineStateDelegate { + onlineStateHandler:(std::function)onlineStateHandler { if (self = [super init]) { _localStore = localStore; _datastore = std::move(datastore); _writePipeline = [NSMutableArray array]; - _onlineStateTracker = OnlineStateTracker{queue, onlineStateDelegate}; + _onlineStateTracker = OnlineStateTracker{queue, std::move(onlineStateHandler)}; _datastore->Start(); // Create streams (but note they're not started yet) diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h index b046aa2271e..45a620936c9 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -17,24 +17,13 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ -#if !defined(__OBJC__) -// TODO(varconst): make it a pure C++ file when it no longer needs to rely on -// `FSTOnlineStateDelegate`. -#error "This header only supports Objective-C++" -#endif // !defined(__OBJC__) - -#import - +#include #include #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/status.h" -@protocol FSTOnlineStateDelegate; - -NS_ASSUME_NONNULL_BEGIN - namespace firebase { namespace firestore { namespace remote { @@ -54,10 +43,11 @@ class OnlineStateTracker { public: OnlineStateTracker() = default; - explicit OnlineStateTracker(util::AsyncQueue* worker_queue, - id online_state_delegate) + explicit OnlineStateTracker( + util::AsyncQueue* worker_queue, + std::function online_state_handler) : worker_queue_{worker_queue}, - online_state_delegate_{online_state_delegate} { + online_state_handler_{online_state_handler} { } /** @@ -119,18 +109,16 @@ class OnlineStateTracker { /** * The worker queue to use for running timers (and to call - * `OnlineStateDelegate`). + * `online_state_handler_`). */ util::AsyncQueue* worker_queue_ = nullptr; - /** A delegate to be notified on `OnlineState` changes. */ - id online_state_delegate_ = nil; + /** A callback to be notified on `OnlineState` changes. */ + std::function online_state_handler_; }; } // namespace remote } // namespace firestore } // namespace firebase -NS_ASSUME_NONNULL_END - #endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_ONLINE_STATE_TRACKER_H_ diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm index feb994e16d1..77ce2cea939 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm @@ -123,7 +123,7 @@ void OnlineStateTracker::SetAndBroadcast(OnlineState new_state) { if (new_state != state_) { state_ = new_state; - [online_state_delegate_ applyChangedOnlineState:new_state]; + online_state_handler_(new_state); } } From 151f99d3ffe9f0bc0e8eee3411be25d77824a2c2 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 15:22:51 -0500 Subject: [PATCH 080/107] Change extension --- .../{online_state_tracker.mm => online_state_tracker.cc} | 6 ------ 1 file changed, 6 deletions(-) rename Firestore/core/src/firebase/firestore/remote/{online_state_tracker.mm => online_state_tracker.cc} (98%) diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc similarity index 98% rename from Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm rename to Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc index 77ce2cea939..28d10405c2d 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.mm +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc @@ -18,8 +18,6 @@ #include // NOLINT(build/c++11) -#import "Firestore/Source/Remote/FSTRemoteStore.h" - #include "Firestore/core/src/firebase/firestore/util/executor.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" @@ -33,8 +31,6 @@ using firebase::firestore::util::StringFormat; using firebase::firestore::util::TimerId; -NS_ASSUME_NONNULL_BEGIN - namespace { // To deal with transient failures, we allow multiple stream attempts before @@ -152,5 +148,3 @@ } // namespace remote } // namespace firestore } // namespace firebase - -NS_ASSUME_NONNULL_END From 06947a57237c1b919f430c279332a1ae8542737f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 15:31:49 -0500 Subject: [PATCH 081/107] style --- .../firestore/remote/online_state_tracker.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc index 28d10405c2d..afdc69d93d4 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.cc @@ -125,13 +125,13 @@ void OnlineStateTracker::SetAndBroadcast(OnlineState new_state) { void OnlineStateTracker::LogClientOfflineWarningIfNecessary( const std::string& reason) { - std::string message = - StringFormat("Could not reach Cloud Firestore backend. %s\n This " - "typically indicates that your device does not have a " - "healthy Internet connection at the moment. The client will " - "operate in offline mode until it is able to successfully " - "connect to the backend.", - reason); + std::string message = StringFormat( + "Could not reach Cloud Firestore backend. %s\n This " + "typically indicates that your device does not have a " + "healthy Internet connection at the moment. The client will " + "operate in offline mode until it is able to successfully " + "connect to the backend.", + reason); if (should_warn_client_is_offline_) { LOG_WARN("%s", message); From 26bb8a9982fae11781767c58996ef5c6aa58b754 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 16:00:10 -0500 Subject: [PATCH 082/107] wip --- Firestore/Source/Remote/FSTRemoteStore.h | 62 ----- Firestore/Source/Remote/FSTRemoteStore.mm | 27 +- .../firebase/firestore/remote/remote_store.h | 132 ++++++++- .../firebase/firestore/remote/remote_store.mm | 254 +++++++++--------- 4 files changed, 252 insertions(+), 223 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 2e27221ae27..1062e290e5c 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -32,68 +32,6 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTRemoteSyncer - -/** - * A protocol that describes the actions the FSTRemoteStore needs to perform on a cooperating - * synchronization engine. - */ -@protocol FSTRemoteSyncer - -/** - * Applies one remote event to the sync engine, notifying any views of the changes, and releasing - * any pending mutation batches that would become visible because of the snapshot version the - * remote event contains. - */ -- (void)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent &)remoteEvent; - -/** - * Rejects the listen for the given targetID. This can be triggered by the backend for any active - * target. - * - * @param targetID The targetID corresponding to a listen initiated via - * -listenToTargetWithQueryData: on FSTRemoteStore. - * @param error A description of the condition that has forced the rejection. Nearly always this - * will be an indication that the user is no longer authorized to see the data matching the - * target. - */ -- (void)rejectListenWithTargetID:(const firebase::firestore::model::TargetId)targetID - error:(NSError *)error; - -/** - * Applies the result of a successful write of a mutation batch to the sync engine, emitting - * snapshots in any views that the mutation applies to, and removing the batch from the mutation - * queue. - */ -- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult *)batchResult; - -/** - * Rejects the batch, removing the batch from the mutation queue, recomputing the local view of - * any documents affected by the batch and then, emitting snapshots with the reverted value. - */ -- (void)rejectFailedWriteWithBatchID:(firebase::firestore::model::BatchId)batchID - error:(NSError *)error; - -/** - * Returns the set of remote document keys for the given target ID. This list includes the - * documents that were assigned to the target when we received the last snapshot. - */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: - (firebase::firestore::model::TargetId)targetId; - -@end - -/** - * A protocol for the FSTRemoteStore online state delegate, called whenever the state of the - * online streams of the FSTRemoteStore changes. - * Note that this protocol only supports the watch stream for now. - */ -@protocol FSTOnlineStateDelegate - -/** Called whenever the online state of the watch stream changes */ -- (void)applyChangedOnlineState:(firebase::firestore::model::OnlineState)onlineState; - -@end #pragma mark - FSTRemoteStore diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index f16a9cd5bd4..416a87c3123 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -81,12 +81,6 @@ @interface FSTRemoteStore () -/** - * The local store, used to fill the write pipeline with outbound mutations and resolve existence - * filter mismatches. Immutable after initialization. - */ -@property(nonatomic, strong, readonly) FSTLocalStore *localStore; - #pragma mark Watch Stream /** @@ -107,29 +101,10 @@ @interface FSTRemoteStore () @end @implementation FSTRemoteStore { - OnlineStateTracker _onlineStateTracker; - - std::unique_ptr _watchChangeAggregator; - /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; - /** - * A mapping of watched targets that the client cares about tracking and the - * user has explicitly called a 'listen' for this target. - * - * These targets may or may not have been sent to or acknowledged by the - * server. On re-establishing the listen stream, these targets should be sent - * to the server. The targets removed with unlistens are removed eagerly - * without waiting for confirmation from the listen stream. */ - std::unordered_map _listenTargets; - - std::shared_ptr _watchStream; + std::shared_ptr _writeStream; - /** - * Set to YES by 'enableNetwork:' and NO by 'disableNetworkInternal:' and - * indicates the user-preferred network state. - */ - BOOL _isNetworkEnabled; } - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 88f5265c2f5..6e1f0a3b7b2 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -18,39 +18,147 @@ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_REMOTE_STORE_H_ #if !defined(__OBJC__) -// TODO(varconst): the only dependencies are `FSTMaybeDocument` and `NSData` -// (the latter is used to represent the resume token). #error "This header only supports Objective-C++" #endif // !defined(__OBJC__) #import -#include +#include #include -#include -#include -#include -#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h" -#include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" +#include "Firestore/core/src/firebase/firestore/remote/online_state_tracker_.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/util/status.h" -@class FSTMaybeDocument; +@class FSTMutationBatchResult; @class FSTQueryData; NS_ASSUME_NONNULL_BEGIN +/** + * A protocol that describes the actions the FSTRemoteStore needs to perform on a cooperating + * synchronization engine. + */ +@protocol FSTRemoteSyncer + +/** + * Applies one remote event to the sync engine, notifying any views of the changes, and releasing + * any pending mutation batches that would become visible because of the snapshot version the + * remote event contains. + */ +- (void)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent &)remoteEvent; + +/** + * Rejects the listen for the given targetID. This can be triggered by the backend for any active + * target. + * + * @param targetID The targetID corresponding to a listen initiated via + * -listenToTargetWithQueryData: on FSTRemoteStore. + * @param error A description of the condition that has forced the rejection. Nearly always this + * will be an indication that the user is no longer authorized to see the data matching the + * target. + */ +- (void)rejectListenWithTargetID:(const firebase::firestore::model::TargetId)targetID + error:(NSError *)error; + +/** + * Applies the result of a successful write of a mutation batch to the sync engine, emitting + * snapshots in any views that the mutation applies to, and removing the batch from the mutation + * queue. + */ +- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult *)batchResult; + +/** + * Rejects the batch, removing the batch from the mutation queue, recomputing the local view of + * any documents affected by the batch and then, emitting snapshots with the reverted value. + */ +- (void)rejectFailedWriteWithBatchID:(firebase::firestore::model::BatchId)batchID + error:(NSError *)error; + +/** + * Returns the set of remote document keys for the given target ID. This list includes the + * documents that were assigned to the target when we received the last snapshot. + */ +- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: + (firebase::firestore::model::TargetId)targetId; + +@end + namespace firebase { namespace firestore { namespace remote { class RemoteStore { - public: + public: + RemoteStore(); + + // TODO(varconst): remove + id sync_engine() { return sync_engine_; } + + + void ListenToTarget(FSTQueryData* query_data); + void StopListening(model::TargetId target_id); + + // TODO(varconst): all the following member functions should be private. + + void SendWatchRequest(FSTQueryData* query_data); + void SendUnwatchRequest(model::TargetId target_id); + + void StartWatchStream(); + bool ShouldStartWatchStream() const; + + void CleanUpWatchStreamState(); + + void OnWatchStreamOpen(); + + void OnWatchStreamChange(const WatchChange& change, const model::SnapshotVersion& snapshot_version); + void OnWatchStreamError(const util::Status& error); + + /** + * Takes a batch of changes from the `Datastore`, repackages them as a `RemoteEvent`, and passes that + * on to the `SyncEngine`. + */ + void RaiseWatchSnapshot(const model::SnapshotVersion& snapshot_version); + + /** Process a target error and passes the error along to `SyncEngine`. */ + void ProcessTargetError(const WatchTargetChange& change); + + bool CanUseNetwork() const; + + private: + id sync_engine_ = nil; + + /** + * The local store, used to fill the write pipeline with outbound mutations and resolve existence + * filter mismatches. Immutable after initialization. + */ + FSTLocalStore* local_store_ = nil; + + OnlineStateTracker online_state_tracker_; + + std::unique_ptr watch_change_aggregator_; + + /** + * A mapping of watched targets that the client cares about tracking and the + * user has explicitly called a 'listen' for this target. + * + * These targets may or may not have been sent to or acknowledged by the + * server. On re-establishing the listen stream, these targets should be sent + * to the server. The targets removed with unlistens are removed eagerly + * without waiting for confirmation from the listen stream. + */ + std::unordered_map listen_targets_; + + std::shared_ptr watch_stream_; - private: + /** + * Set to true by `EnableNetwork` and false by `DisableNetworkInternal` and + * indicates the user-preferred network state. + */ + bool is_network_enabled_ = false; }; } // namespace remote diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 9b2a7b14fea..89930485a8f 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -16,218 +16,226 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" + namespace firebase { namespace firestore { namespace remote { void RemoteStore::StartWatchStream() { - HARD_ASSERT([self shouldStartWatchStream], - "startWatchStream: called when shouldStartWatchStream: is false."); - _watchChangeAggregator = absl::make_unique(self); - _watchStream->Start(); + HARD_ASSERT(ShouldStartWatchStream(), + "StartWatchStream called when ShouldStartWatchStream: is false."); + watch_change_aggregator_ = absl::make_unique(this); + watch_stream_->Start(); - _onlineStateTracker.HandleWatchStreamStart(); + online_state_tracker_.HandleWatchStreamStart(); } void RemoteStore::ListenToTarget(FSTQueryData* query_data) { - TargetId targetKey = queryData.targetID; - HARD_ASSERT(_listenTargets.find(targetKey) == _listenTargets.end(), + TargetId targetKey = query_data.target_id; + HARD_ASSERT(listen_targets_.find(targetKey) == listen_targets_.end(), "listenToQuery called with duplicate target id: %s", targetKey); - _listenTargets[targetKey] = queryData; + listen_targets_[targetKey] = query_data; - if ([self shouldStartWatchStream]) { - [self startWatchStream]; - } else if (_watchStream->IsOpen()) { - [self sendWatchRequestWithQueryData:queryData]; + if (ShouldStartWatchStream()) { + StartWatchStream(); + } else if (watch_stream_->IsOpen()) { + SendWatchRequest(query_data); } } void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { - _watchChangeAggregator->RecordPendingTargetRequest(queryData.targetID); - _watchStream->WatchQuery(queryData); + watch_change_aggregator_->RecordPendingTargetRequest(query_data.target_id); + watch_stream_->WatchQuery(query_data); } void RemoteStore::StopListening(TargetId target_id) { - size_t num_erased = _listenTargets.erase(targetID); - HARD_ASSERT(num_erased == 1, "stopListeningToTargetID: target not currently watched: %s", - targetID); + size_t num_erased = listen_targets_.erase(target_id); + HARD_ASSERT(num_erased == 1, + "stopListeningToTargetID: target not currently watched: %s", + target_id); - if (_watchStream->IsOpen()) { - [self sendUnwatchRequestForTargetID:targetID]; + if (watch_stream_->IsOpen()) { + SendUnwatchRequest(target_id); } - if (_listenTargets.empty()) { - if (_watchStream->IsOpen()) { - _watchStream->MarkIdle(); - } else if ([self canUseNetwork]) { - // Revert to OnlineState::Unknown if the watch stream is not open and we have no listeners, - // since without any listens to send we cannot confirm if the stream is healthy and upgrade - // to OnlineState::Online. - _onlineStateTracker.UpdateState(OnlineState::Unknown); + if (listen_targets_.empty()) { + if (watch_stream_->IsOpen()) { + watch_stream_->MarkIdle(); + } else if (CanUseNetwork()) { + // Revert to OnlineState::Unknown if the watch stream is not open and we + // have no listeners, since without any listens to send we cannot confirm + // if the stream is healthy and upgrade to OnlineState::Online. + online_state_tracker_.UpdateState(OnlineState::Unknown); } } } void RemoteStore::SendUnwatchRequest(TargetId target_id) { - _watchChangeAggregator->RecordPendingTargetRequest(targetID); - _watchStream->UnwatchTargetId(targetID); + watch_change_aggregator_->RecordPendingTargetRequest(target_id); + watch_stream_->UnwatchTargetId(target_id); } bool RemoteStore::ShouldStartWatchStream() const { - return [self canUseNetwork] && !_watchStream->IsStarted() && !_listenTargets.empty(); + return CanUseNetwork() && !watch_stream_->IsStarted() && + !listen_targets_.empty(); } void RemoteStore::CleanUpWatchStreamState() { - _watchChangeAggregator.reset(); + watch_change_aggregator_.reset(); } void RemoteStore::OnWatchStreamOpen() { // Restore any existing watches. - for (const auto &kv : _listenTargets) { - [self sendWatchRequestWithQueryData:kv.second]; + for (const auto& kv : listen_targets_) { + SendWatchRequest(kv.second); } } -void RemoteStore::OnWatchStreamChange(const WatchChange& change, const SnapshotVersion& snapshot_version) { +void RemoteStore::OnWatchStreamChange(const WatchChange& change, + const SnapshotVersion& snapshot_version) { // Mark the connection as Online because we got a message from the server. - _onlineStateTracker.UpdateState(OnlineState::Online); + online_state_tracker_.UpdateState(OnlineState::Online); if (change.type() == WatchChange::Type::TargetChange) { - const WatchTargetChange &watchTargetChange = static_cast(change); - if (watchTargetChange.state() == WatchTargetChangeState::Removed && - !watchTargetChange.cause().ok()) { - // There was an error on a target, don't wait for a consistent snapshot to raise events - return [self processTargetErrorForWatchChange:watchTargetChange]; + const WatchTargetChange& watch_target_change = + static_cast(change); + if (watch_target_change.state() == WatchTargetChangeState::Removed && + !watch_target_change.cause().ok()) { + // There was an error on a target, don't wait for a consistent snapshot to + // raise events + return ProcessTargetError(watch_target_change); } else { - _watchChangeAggregator->HandleTargetChange(watchTargetChange); + watch_change_aggregator_->HandleTargetChange(watch_target_change); } } else if (change.type() == WatchChange::Type::Document) { - _watchChangeAggregator->HandleDocumentChange(static_cast(change)); + watch_change_aggregator_->HandleDocumentChange( + static_cast(change)); } else { - HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, - "Expected watchChange to be an instance of ExistenceFilterWatchChange"); - _watchChangeAggregator->HandleExistenceFilter( - static_cast(change)); + HARD_ASSERT( + change.type() == WatchChange::Type::ExistenceFilter, + "Expected watchChange to be an instance of ExistenceFilterWatchChange"); + watch_change_aggregator_->HandleExistenceFilter( + static_cast(change)); } - if (snapshotVersion != SnapshotVersion::None() && - snapshotVersion >= [self.localStore lastRemoteSnapshotVersion]) { - // We have received a target change with a global snapshot if the snapshot version is not - // equal to SnapshotVersion.None(). - [self raiseWatchSnapshotWithSnapshotVersion:snapshotVersion]; + if (snapshot_version != SnapshotVersion::None() && + snapshot_version >= [local_store_ lastRemoteSnapshotVersion]) { + // We have received a target change with a global snapshot if the snapshot + // version is not equal to SnapshotVersion.None(). + RaiseWatchSnapshot(snapshot_version); } } void RemoteStore::OnWatchStreamError(const Status& error) { if (error.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. - HARD_ASSERT(![self shouldStartWatchStream], + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWatchStream(), "Watch stream was stopped gracefully while still needed."); } - [self cleanUpWatchStreamState]; + CleanUpWatchStreamState(); // If we still need the watch stream, retry the connection. - if ([self shouldStartWatchStream]) { - _onlineStateTracker.HandleWatchStreamFailure(error); + if (ShouldStartWatchStream()) { + online_state_tracker_.HandleWatchStreamFailure(error); - [self startWatchStream]; + StartWatchStream(); } else { - // We don't need to restart the watch stream because there are no active targets. The online - // state is set to unknown because there is no active attempt at establishing a connection. - _onlineStateTracker.UpdateState(OnlineState::Unknown); + // We don't need to restart the watch stream because there are no active + // targets. The online state is set to unknown because there is no active + // attempt at establishing a connection. + online_state_tracker_.UpdateState(OnlineState::Unknown); } } -/** - * Takes a batch of changes from the Datastore, repackages them as a `RemoteEvent`, and passes that - * on to the SyncEngine. - */ void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { - HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), + HARD_ASSERT(snapshot_version != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); - RemoteEvent remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); + RemoteEvent remote_event = + watch_change_aggregator_->CreateRemoteEvent(snapshot_version); - // Update in-memory resume tokens. `FSTLocalStore` will update the persistent view of these when - // applying the completed `RemoteEvent`. - for (const auto &entry : remoteEvent.target_changes()) { - const TargetChange &target_change = entry.second; - NSData *resumeToken = target_change.resume_token(); + // Update in-memory resume tokens. `FSTLocalStore` will update the persistent + // view of these when applying the completed `RemoteEvent`. + for (const auto& entry : remote_event.target_changes()) { + const TargetChange& target_change = entry.second; + NSData* resumeToken = target_change.resume_token(); if (resumeToken.length > 0) { - TargetId targetID = entry.first; - auto found = _listenTargets.find(targetID); - FSTQueryData *queryData = found != _listenTargets.end() ? found->second : nil; + TargetId target_id = entry.first; + auto found = listen_targets_.find(target_id); + FSTQueryData* query_data = + found != listen_targets_.end() ? found->second : nil; // A watched target might have been removed already. - if (queryData) { - _listenTargets[targetID] = - [queryData queryDataByReplacingSnapshotVersion:snapshotVersion - resumeToken:resumeToken - sequenceNumber:queryData.sequenceNumber]; + if (query_data) { + listen_targets_[target_id] = [query_data + query_dataByReplacingSnapshotVersion:snapshot_version + resumeToken:resumeToken + sequenceNumber:query_data.sequenceNumber]; } } } - // Re-establish listens for the targets that have been invalidated by existence filter - // mismatches. - for (TargetId targetID : remoteEvent.target_mismatches()) { - auto found = _listenTargets.find(targetID); - if (found == _listenTargets.end()) { + // Re-establish listens for the targets that have been invalidated by + // existence filter mismatches. + for (TargetId target_id : remote_event.target_mismatches()) { + auto found = listen_targets_.find(target_id); + if (found == listen_targets_.end()) { // A watched target might have been removed already. continue; } - FSTQueryData *queryData = found->second; - - // Clear the resume token for the query, since we're in a known mismatch state. - queryData = [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:queryData.purpose]; - _listenTargets[targetID] = queryData; - - // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send a - // resume token so that we get a full update. - [self sendUnwatchRequestForTargetID:targetID]; - - // Mark the query we send as being on behalf of an existence filter mismatch, but don't - // actually retain that in _listenTargets. This ensures that we flag the first re-listen this - // way without impacting future listens of this target (that might happen e.g. on reconnect). - FSTQueryData *requestQueryData = - [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:FSTQueryPurposeExistenceFilterMismatch]; - [self sendWatchRequestWithQueryData:requestQueryData]; + FSTQueryData* query_data = found->second; + + // Clear the resume token for the query, since we're in a known mismatch + // state. + query_data = [[FSTQueryData alloc] initWithQuery:query_data.query + target_id:target_id + listenSequenceNumber:query_data.sequenceNumber + purpose:query_data.purpose]; + listen_targets_[target_id] = query_data; + + // Cause a hard reset by unwatching and rewatching immediately, but + // deliberately don't send a resume token so that we get a full update. + SendUnwatchRequest(target_id); + + // Mark the query we send as being on behalf of an existence filter + // mismatch, but don't actually retain that in listen_targets_. This ensures + // that we flag the first re-listen this way without impacting future + // listens of this target (that might happen e.g. on reconnect). + FSTQueryData* request_query_data = [[FSTQueryData alloc] + initWithQuery:query_data.query + target_id:target_id + listenSequenceNumber:query_data.sequenceNumber + purpose:FSTQueryPurposeExistenceFilterMismatch]; + SendWatchRequest(request_query_data); } // Finally handle remote event - [self.syncEngine applyRemoteEvent:remoteEvent]; + [sync_engine_ applyRemoteEvent:remoteEvent]; } -/** Process a target error and passes the error along to SyncEngine. */ void RemoteStore::ProcessTargetError(const WatchTargetChange& change) { HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); + // Ignore targets that have been removed already. - for (TargetId targetID : change.target_ids()) { - auto found = _listenTargets.find(targetID); - if (found != _listenTargets.end()) { - _listenTargets.erase(found); - _watchChangeAggregator->RemoveTarget(targetID); - [self.syncEngine rejectListenWithTargetID:targetID error:util::MakeNSError(change.cause())]; + for (TargetId target_id : change.target_ids()) { + auto found = listen_targets_.find(target_id); + if (found != listen_targets_.end()) { + listen_targets_.erase(found); + watch_change_aggregator_->RemoveTarget(target_id); + [sync_engine_ rejectListenWithTargetID:target_id + error:util::MakeNSError(change.cause())]; } } } -/* -_watchChangeAggregator -_watchStream -_onlineStateTracker -_listenTargets -_syncEngine - -[canUseNetwork] +bool RemoteStore::CanUseNetwork() const { + // PORTING NOTE: This method exists mostly because web also has to take into + // account primary vs. secondary state. + return is_network_enabled_; +} - */ } // namespace remote } // namespace firestore } // namespace firebase From 61f821eace60c09068fcaa38a3f799a971aa27aa Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 16:00:31 -0500 Subject: [PATCH 083/107] Redundant --- .../core/src/firebase/firestore/remote/online_state_tracker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h index 45a620936c9..2344f520a39 100644 --- a/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h +++ b/Firestore/core/src/firebase/firestore/remote/online_state_tracker.h @@ -43,7 +43,7 @@ class OnlineStateTracker { public: OnlineStateTracker() = default; - explicit OnlineStateTracker( + OnlineStateTracker( util::AsyncQueue* worker_queue, std::function online_state_handler) : worker_queue_{worker_queue}, From 448b1fc567fd4d071c20971d2fe165efa57a35f3 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 17:48:13 -0500 Subject: [PATCH 084/107] wip --- Firestore/Source/Core/FSTFirestoreClient.mm | 2 +- Firestore/Source/Remote/FSTRemoteStore.h | 2 +- Firestore/Source/Remote/FSTRemoteStore.mm | 256 ++---------------- Firestore/Source/Remote/FSTStream.h | 27 -- .../firebase/firestore/remote/remote_event.h | 42 +-- .../firebase/firestore/remote/remote_store.h | 125 +++++---- .../firebase/firestore/remote/remote_store.mm | 47 +++- .../firebase/firestore/remote/watch_stream.h | 36 ++- .../firebase/firestore/remote/watch_stream.mm | 10 +- 9 files changed, 209 insertions(+), 338 deletions(-) diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index 69231711920..221b9248643 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -238,7 +238,7 @@ - (void)initializeWithUser:(const User &)user settings:(FIRFirestoreSettings *)s _eventManager = [FSTEventManager eventManagerWithSyncEngine:_syncEngine]; // Setup wiring for remote store. - _remoteStore.syncEngine = _syncEngine; + [_remoteStore setSyncEngine:_syncEngine]; // NOTE: RemoteStore depends on LocalStore (for persisting stream tokens, refilling mutation // queue, etc.) so must be started after LocalStore. diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 1062e290e5c..a585bf17218 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -@property(nonatomic, weak) id syncEngine; +- (void)setSyncEngine:(id)syncEngine; /** Starts up the remote store, creating streams, restoring state from LocalStore, etc. */ - (void)start; diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 416a87c3123..7f02752f067 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -104,6 +104,7 @@ @implementation FSTRemoteStore { /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; + std::unique_ptr _remoteStore; std::shared_ptr _writeStream; } @@ -112,15 +113,13 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore workerQueue:(AsyncQueue *)queue onlineStateDelegate:(id _Nullable)onlineStateDelegate { if (self = [super init]) { - _localStore = localStore; _datastore = std::move(datastore); _writePipeline = [NSMutableArray array]; - _onlineStateTracker = OnlineStateTracker{queue, onlineStateDelegate}; _datastore->Start(); - // Create streams (but note they're not started yet) - _watchStream = _datastore->CreateWatchStream(self); + + _remoteStore = absl::make_unique(localStore, datastore.get(), queue, onlineStateDelegate); _writeStream = _datastore->CreateWriteStream(self); _isNetworkEnabled = NO; @@ -128,6 +127,10 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore return self; } +- (void)setSyncEngine:(id)syncEngine { + _remoteStore->set_sync_engine(syncEngine); +} + - (void)start { // For now, all setup is handled by enableNetwork(). We might expand on this in the future. [self enableNetwork]; @@ -135,21 +138,15 @@ - (void)start { #pragma mark Online/Offline state -- (BOOL)canUseNetwork { - // PORTING NOTE: This method exists mostly because web also has to take into - // account primary vs. secondary state. - return _isNetworkEnabled; -} - - (void)enableNetwork { _isNetworkEnabled = YES; - if ([self canUseNetwork]) { + if (_remoteStore->CanUseNetwork()) { // Load any saved stream token from persistent storage - _writeStream->SetLastStreamToken([self.localStore lastStreamToken]); + _writeStream->SetLastStreamToken([_remoteStore->local_store() lastStreamToken]); - if ([self shouldStartWatchStream]) { - [self startWatchStream]; + if (_remoteStore->ShouldStartWatchStream()) { + _remoteStore->StartWatchStream(); } else { _onlineStateTracker.UpdateState(OnlineState::Unknown); } @@ -178,246 +175,43 @@ - (void)disableNetworkInternal { [self.writePipeline removeAllObjects]; } - [self cleanUpWatchStreamState]; + _remoteStore->CleanUpWatchStreamState(); } #pragma mark Shutdown - (void)shutdown { LOG_DEBUG("FSTRemoteStore %s shutting down", (__bridge void *)self); - _isNetworkEnabled = NO; + _remoteStore->Shutdown(); [self disableNetworkInternal]; + _remoteStore.set_is_network_enabled(false); // Set the OnlineState to Unknown (rather than Offline) to avoid potentially triggering // spurious listener events with cached data, etc. - _onlineStateTracker.UpdateState(OnlineState::Unknown); + _remoteStore.online_state_tracker().UpdateState(OnlineState::Unknown); _datastore->Shutdown(); } - (void)credentialDidChange { - if ([self canUseNetwork]) { + if (_remoteStore->CanUseNetwork()) { // Tear down and re-create our network streams. This will ensure we get a fresh auth token // for the new user and re-fill the write pipeline with new mutations from the LocalStore // (since mutations are per-user). LOG_DEBUG("FSTRemoteStore %s restarting streams for new credential", (__bridge void *)self); - _isNetworkEnabled = NO; + _remoteStore.set_is_network_enabled(false); [self disableNetworkInternal]; - _onlineStateTracker.UpdateState(OnlineState::Unknown); + _remoteStore.online_state_tracker().UpdateState(OnlineState::Unknown); [self enableNetwork]; } } #pragma mark Watch Stream -- (void)startWatchStream { - HARD_ASSERT([self shouldStartWatchStream], - "startWatchStream: called when shouldStartWatchStream: is false."); - _watchChangeAggregator = absl::make_unique(self); - _watchStream->Start(); - - _onlineStateTracker.HandleWatchStreamStart(); -} - - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { - TargetId targetKey = queryData.targetID; - HARD_ASSERT(_listenTargets.find(targetKey) == _listenTargets.end(), - "listenToQuery called with duplicate target id: %s", targetKey); - - _listenTargets[targetKey] = queryData; - - if ([self shouldStartWatchStream]) { - [self startWatchStream]; - } else if (_watchStream->IsOpen()) { - [self sendWatchRequestWithQueryData:queryData]; - } -} - -- (void)sendWatchRequestWithQueryData:(FSTQueryData *)queryData { - _watchChangeAggregator->RecordPendingTargetRequest(queryData.targetID); - _watchStream->WatchQuery(queryData); + _remoteStore->ListenToTarget(queryData); } - (void)stopListeningToTargetID:(TargetId)targetID { - size_t num_erased = _listenTargets.erase(targetID); - HARD_ASSERT(num_erased == 1, "stopListeningToTargetID: target not currently watched: %s", - targetID); - - if (_watchStream->IsOpen()) { - [self sendUnwatchRequestForTargetID:targetID]; - } - if (_listenTargets.empty()) { - if (_watchStream->IsOpen()) { - _watchStream->MarkIdle(); - } else if ([self canUseNetwork]) { - // Revert to OnlineState::Unknown if the watch stream is not open and we have no listeners, - // since without any listens to send we cannot confirm if the stream is healthy and upgrade - // to OnlineState::Online. - _onlineStateTracker.UpdateState(OnlineState::Unknown); - } - } -} - -- (void)sendUnwatchRequestForTargetID:(TargetId)targetID { - _watchChangeAggregator->RecordPendingTargetRequest(targetID); - _watchStream->UnwatchTargetId(targetID); -} - -/** - * Returns YES if the network is enabled, the watch stream has not yet been started and there are - * active watch targets. - */ -- (BOOL)shouldStartWatchStream { - return [self canUseNetwork] && !_watchStream->IsStarted() && !_listenTargets.empty(); -} - -- (void)cleanUpWatchStreamState { - _watchChangeAggregator.reset(); -} - -- (void)watchStreamDidOpen { - // Restore any existing watches. - for (const auto &kv : _listenTargets) { - [self sendWatchRequestWithQueryData:kv.second]; - } -} - -- (void)watchStreamDidChange:(const WatchChange &)change - snapshotVersion:(const SnapshotVersion &)snapshotVersion { - // Mark the connection as Online because we got a message from the server. - _onlineStateTracker.UpdateState(OnlineState::Online); - - if (change.type() == WatchChange::Type::TargetChange) { - const WatchTargetChange &watchTargetChange = static_cast(change); - if (watchTargetChange.state() == WatchTargetChangeState::Removed && - !watchTargetChange.cause().ok()) { - // There was an error on a target, don't wait for a consistent snapshot to raise events - return [self processTargetErrorForWatchChange:watchTargetChange]; - } else { - _watchChangeAggregator->HandleTargetChange(watchTargetChange); - } - } else if (change.type() == WatchChange::Type::Document) { - _watchChangeAggregator->HandleDocumentChange(static_cast(change)); - } else { - HARD_ASSERT(change.type() == WatchChange::Type::ExistenceFilter, - "Expected watchChange to be an instance of ExistenceFilterWatchChange"); - _watchChangeAggregator->HandleExistenceFilter( - static_cast(change)); - } - - if (snapshotVersion != SnapshotVersion::None() && - snapshotVersion >= [self.localStore lastRemoteSnapshotVersion]) { - // We have received a target change with a global snapshot if the snapshot version is not - // equal to SnapshotVersion.None(). - [self raiseWatchSnapshotWithSnapshotVersion:snapshotVersion]; - } -} - -- (void)watchStreamWasInterruptedWithError:(const Status &)error { - if (error.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. - HARD_ASSERT(![self shouldStartWatchStream], - "Watch stream was stopped gracefully while still needed."); - } - - [self cleanUpWatchStreamState]; - - // If we still need the watch stream, retry the connection. - if ([self shouldStartWatchStream]) { - _onlineStateTracker.HandleWatchStreamFailure(error); - - [self startWatchStream]; - } else { - // We don't need to restart the watch stream because there are no active targets. The online - // state is set to unknown because there is no active attempt at establishing a connection. - _onlineStateTracker.UpdateState(OnlineState::Unknown); - } -} - -/** - * Takes a batch of changes from the Datastore, repackages them as a `RemoteEvent`, and passes that - * on to the SyncEngine. - */ -- (void)raiseWatchSnapshotWithSnapshotVersion:(const SnapshotVersion &)snapshotVersion { - HARD_ASSERT(snapshotVersion != SnapshotVersion::None(), - "Can't raise event for unknown SnapshotVersion"); - - RemoteEvent remoteEvent = _watchChangeAggregator->CreateRemoteEvent(snapshotVersion); - - // Update in-memory resume tokens. `FSTLocalStore` will update the persistent view of these when - // applying the completed `RemoteEvent`. - for (const auto &entry : remoteEvent.target_changes()) { - const TargetChange &target_change = entry.second; - NSData *resumeToken = target_change.resume_token(); - if (resumeToken.length > 0) { - TargetId targetID = entry.first; - auto found = _listenTargets.find(targetID); - FSTQueryData *queryData = found != _listenTargets.end() ? found->second : nil; - // A watched target might have been removed already. - if (queryData) { - _listenTargets[targetID] = - [queryData queryDataByReplacingSnapshotVersion:snapshotVersion - resumeToken:resumeToken - sequenceNumber:queryData.sequenceNumber]; - } - } - } - - // Re-establish listens for the targets that have been invalidated by existence filter - // mismatches. - for (TargetId targetID : remoteEvent.target_mismatches()) { - auto found = _listenTargets.find(targetID); - if (found == _listenTargets.end()) { - // A watched target might have been removed already. - continue; - } - FSTQueryData *queryData = found->second; - - // Clear the resume token for the query, since we're in a known mismatch state. - queryData = [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:queryData.purpose]; - _listenTargets[targetID] = queryData; - - // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send a - // resume token so that we get a full update. - [self sendUnwatchRequestForTargetID:targetID]; - - // Mark the query we send as being on behalf of an existence filter mismatch, but don't - // actually retain that in _listenTargets. This ensures that we flag the first re-listen this - // way without impacting future listens of this target (that might happen e.g. on reconnect). - FSTQueryData *requestQueryData = - [[FSTQueryData alloc] initWithQuery:queryData.query - targetID:targetID - listenSequenceNumber:queryData.sequenceNumber - purpose:FSTQueryPurposeExistenceFilterMismatch]; - [self sendWatchRequestWithQueryData:requestQueryData]; - } - - // Finally handle remote event - [self.syncEngine applyRemoteEvent:remoteEvent]; -} - -/** Process a target error and passes the error along to SyncEngine. */ -- (void)processTargetErrorForWatchChange:(const WatchTargetChange &)change { - HARD_ASSERT(!change.cause().ok(), "Handling target error without a cause"); - // Ignore targets that have been removed already. - for (TargetId targetID : change.target_ids()) { - auto found = _listenTargets.find(targetID); - if (found != _listenTargets.end()) { - _listenTargets.erase(found); - _watchChangeAggregator->RemoveTarget(targetID); - [self.syncEngine rejectListenWithTargetID:targetID error:util::MakeNSError(change.cause())]; - } - } -} - -- (DocumentKeySet)remoteKeysForTarget:(TargetId)targetID { - return [self.syncEngine remoteKeysForTarget:targetID]; -} - -- (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { - auto found = _listenTargets.find(targetID); - return found != _listenTargets.end() ? found->second : nil; + _remoteStore->StopListening(targetID); } #pragma mark Write Stream @@ -427,7 +221,7 @@ - (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { * pending writes. */ - (BOOL)shouldStartWriteStream { - return [self canUseNetwork] && !_writeStream->IsStarted() && self.writePipeline.count > 0; + return _remoteStore->CanUseNetwork() && !_writeStream->IsStarted() && self.writePipeline.count > 0; } - (void)startWriteStream { @@ -448,7 +242,7 @@ - (void)fillWritePipeline { BatchId lastBatchIDRetrieved = self.writePipeline.count == 0 ? kBatchIdUnknown : self.writePipeline.lastObject.batchID; while ([self canAddToWritePipeline]) { - FSTMutationBatch *batch = [self.localStore nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; + FSTMutationBatch *batch = [_remoteStore->local_store() nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; if (!batch) { if (self.writePipeline.count == 0) { _writeStream->MarkIdle(); @@ -468,7 +262,7 @@ - (void)fillWritePipeline { * Returns YES if we can add to the write pipeline (i.e. it is not full and the network is enabled). */ - (BOOL)canAddToWritePipeline { - return [self canUseNetwork] && self.writePipeline.count < kMaxPendingWrites; + return _remoteStore->CanUseNetwork() && self.writePipeline.count < kMaxPendingWrites; } /** @@ -495,7 +289,7 @@ - (void)writeStreamDidOpen { */ - (void)writeStreamDidCompleteHandshake { // Record the stream token. - [self.localStore setLastStreamToken:_writeStream->GetLastStreamToken()]; + [_remoteStore->local_store() setLastStreamToken:_writeStream->GetLastStreamToken()]; // Send the write pipeline now that the stream is established. for (FSTMutationBatch *write in self.writePipeline) { @@ -564,7 +358,7 @@ - (void)handleHandshakeError:(const Status &)error { "error code: '%s', details: '%s'", (__bridge void *)self, token, error.code(), error.error_message()); _writeStream->SetLastStreamToken(nil); - [self.localStore setLastStreamToken:nil]; + [_remoteStore->local_store() setLastStreamToken:nil]; } else { // Some other error, don't reset stream token. Our stream logic will just retry with exponential // backoff. diff --git a/Firestore/Source/Remote/FSTStream.h b/Firestore/Source/Remote/FSTStream.h index d4183379329..211a82154f5 100644 --- a/Firestore/Source/Remote/FSTStream.h +++ b/Firestore/Source/Remote/FSTStream.h @@ -24,33 +24,6 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTWatchStreamDelegate - -/** A protocol defining the events that can be emitted by the FSTWatchStream. */ -@protocol FSTWatchStreamDelegate - -/** Called by the FSTWatchStream when it is ready to accept outbound request messages. */ -- (void)watchStreamDidOpen; - -/** - * Called by the FSTWatchStream with changes and the snapshot versions included in in the - * WatchChange responses sent back by the server. - */ -- (void)watchStreamDidChange:(const firebase::firestore::remote::WatchChange &)change - snapshotVersion:(const firebase::firestore::model::SnapshotVersion &)snapshotVersion; - -/** - * Called by the FSTWatchStream when the underlying streaming RPC is interrupted for whatever - * reason, usually because of an error, but possibly due to an idle timeout. The error passed to - * this method may be nil, in which case the stream was closed without attributable fault. - * - * NOTE: This will not be called after `stop` is called on the stream. See "Starting and Stopping" - * on FSTStream for details. - */ -- (void)watchStreamWasInterruptedWithError:(const firebase::firestore::util::Status &)error; - -@end - #pragma mark - FSTWriteStreamDelegate @protocol FSTWriteStreamDelegate diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index e154b9ee623..1f4ce9b0499 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -43,31 +43,33 @@ NS_ASSUME_NONNULL_BEGIN -/** - * Interface implemented by RemoteStore to expose target metadata to the - * `WatchChangeAggregator`. - */ -@protocol FSTTargetMetadataProvider - -/** - * Returns the set of remote document keys for the given target ID as of the - * last raised snapshot. - */ -- (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: - (firebase::firestore::model::TargetId)targetID; +namespace firebase { +namespace firestore { +namespace remote { /** - * Returns the FSTQueryData for an active target ID or 'null' if this query has - * become inactive + * Interface implemented by `RemoteStore` to expose target metadata to the + * `WatchChangeAggregator`. */ -- (nullable FSTQueryData*)queryDataForTarget: - (firebase::firestore::model::TargetId)targetID; +class TargetMetadataProvider { + public: + virtual ~TargetMetadataProvider() { + } -@end + /** + * Returns the set of remote document keys for the given target ID as of the + * last raised snapshot. + */ + virtual model::DocumentKeySet GetRemoteKeysForTarget( + model::TargetId target_id) const = 0; -namespace firebase { -namespace firestore { -namespace remote { + /** + * Returns the FSTQueryData for an active target ID or 'null' if this query + * has become inactive + */ + virtual nullable FSTQueryData* GetQueryDataForTarget( + model::TargetId target_id) const = 0; +}; /** * A `TargetChange` specifies the set of changes for a specific target as part diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 6e1f0a3b7b2..f81d820b577 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -26,61 +26,70 @@ #include #include +#include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/online_state_tracker_.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" +#include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/status.h" +@class FSTLocalStore; @class FSTMutationBatchResult; @class FSTQueryData; NS_ASSUME_NONNULL_BEGIN /** - * A protocol that describes the actions the FSTRemoteStore needs to perform on a cooperating - * synchronization engine. + * A protocol that describes the actions the FSTRemoteStore needs to perform on + * a cooperating synchronization engine. */ @protocol FSTRemoteSyncer /** - * Applies one remote event to the sync engine, notifying any views of the changes, and releasing - * any pending mutation batches that would become visible because of the snapshot version the - * remote event contains. + * Applies one remote event to the sync engine, notifying any views of the + * changes, and releasing any pending mutation batches that would become visible + * because of the snapshot version the remote event contains. */ -- (void)applyRemoteEvent:(const firebase::firestore::remote::RemoteEvent &)remoteEvent; +- (void)applyRemoteEvent: + (const firebase::firestore::remote::RemoteEvent&)remoteEvent; /** - * Rejects the listen for the given targetID. This can be triggered by the backend for any active - * target. + * Rejects the listen for the given targetID. This can be triggered by the + * backend for any active target. * * @param targetID The targetID corresponding to a listen initiated via * -listenToTargetWithQueryData: on FSTRemoteStore. - * @param error A description of the condition that has forced the rejection. Nearly always this - * will be an indication that the user is no longer authorized to see the data matching the - * target. + * @param error A description of the condition that has forced the rejection. + * Nearly always this will be an indication that the user is no longer + * authorized to see the data matching the target. */ -- (void)rejectListenWithTargetID:(const firebase::firestore::model::TargetId)targetID - error:(NSError *)error; +- (void)rejectListenWithTargetID: + (const firebase::firestore::model::TargetId)targetID + error:(NSError*)error; /** - * Applies the result of a successful write of a mutation batch to the sync engine, emitting - * snapshots in any views that the mutation applies to, and removing the batch from the mutation - * queue. + * Applies the result of a successful write of a mutation batch to the sync + * engine, emitting snapshots in any views that the mutation applies to, and + * removing the batch from the mutation queue. */ -- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult *)batchResult; +- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult*)batchResult; /** - * Rejects the batch, removing the batch from the mutation queue, recomputing the local view of - * any documents affected by the batch and then, emitting snapshots with the reverted value. + * Rejects the batch, removing the batch from the mutation queue, recomputing + * the local view of any documents affected by the batch and then, emitting + * snapshots with the reverted value. */ -- (void)rejectFailedWriteWithBatchID:(firebase::firestore::model::BatchId)batchID - error:(NSError *)error; +- (void)rejectFailedWriteWithBatchID: + (firebase::firestore::model::BatchId)batchID + error:(NSError*)error; /** - * Returns the set of remote document keys for the given target ID. This list includes the - * documents that were assigned to the target when we received the last snapshot. + * Returns the set of remote document keys for the given target ID. This list + * includes the documents that were assigned to the target when we received the + * last snapshot. */ - (firebase::firestore::model::DocumentKeySet)remoteKeysForTarget: (firebase::firestore::model::TargetId)targetId; @@ -91,50 +100,72 @@ namespace firebase { namespace firestore { namespace remote { -class RemoteStore { +class RemoteStore : public TargetMetadataProvider, public WatchStreamObserver { public: - RemoteStore(); - - // TODO(varconst): remove - id sync_engine() { return sync_engine_; } - + RemoteStore(FSTLocalStore* local_store, + Util::AsyncQueue* worker_queue, + id _Nullable online_state_delegate); + + // TODO(varconst): remove the getters and setters + id sync_engine() { + return sync_engine_; + } + void sync_engine(id sync_engine) { + sync_engine_ = sync_engine; + } + FSTLocalStore* local_store() { + return local_store_; + } + OnlineStateTracker& online_state_tracker() { return online_state_tracker_; } + void set_is_network_enabled(bool value) { + is_network_enabled_ = value; + } void ListenToTarget(FSTQueryData* query_data); void StopListening(model::TargetId target_id); - // TODO(varconst): all the following member functions should be private. + model::DocumentKeySet GetRemoteKeysForTarget( + model::TargetId target_id) const override; + nullable FSTQueryData* GetQueryDataForTarget( + model::TargetId target_id) const override; - void SendWatchRequest(FSTQueryData* query_data); - void SendUnwatchRequest(model::TargetId target_id); + void OnWatchStreamOpen() override; + void OnWatchStreamChange(const WatchChange& change, + const model::SnapshotVersion& snapshot_version) override; + void OnWatchStreamClose(const util::Status& status) override; + + // TODO(varconst): make private. + bool CanUseNetwork() const; + private: void StartWatchStream(); - bool ShouldStartWatchStream() const; - void CleanUpWatchStreamState(); + /** + * Returns true if the network is enabled, the watch stream has not yet been started and there are + * active watch targets. + */ + bool ShouldStartWatchStream() const; - void OnWatchStreamOpen(); + void SendWatchRequest(FSTQueryData* query_data); + void SendUnwatchRequest(model::TargetId target_id); - void OnWatchStreamChange(const WatchChange& change, const model::SnapshotVersion& snapshot_version); - void OnWatchStreamError(const util::Status& error); + void CleanUpWatchStreamState(); /** - * Takes a batch of changes from the `Datastore`, repackages them as a `RemoteEvent`, and passes that - * on to the `SyncEngine`. - */ + * Takes a batch of changes from the `Datastore`, repackages them as a + * `RemoteEvent`, and passes that on to the `SyncEngine`. + */ void RaiseWatchSnapshot(const model::SnapshotVersion& snapshot_version); /** Process a target error and passes the error along to `SyncEngine`. */ void ProcessTargetError(const WatchTargetChange& change); - bool CanUseNetwork() const; - - private: id sync_engine_ = nil; /** - * The local store, used to fill the write pipeline with outbound mutations and resolve existence - * filter mismatches. Immutable after initialization. - */ + * The local store, used to fill the write pipeline with outbound mutations + * and resolve existence filter mismatches. Immutable after initialization. + */ FSTLocalStore* local_store_ = nil; OnlineStateTracker online_state_tracker_; @@ -150,7 +181,7 @@ class RemoteStore { * to the server. The targets removed with unlistens are removed eagerly * without waiting for confirmation from the listen stream. */ - std::unordered_map listen_targets_; + std::unordered_map listen_targets_; std::shared_ptr watch_stream_; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 89930485a8f..86c710de145 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -18,10 +18,40 @@ #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +using firebase::firestore::model::DocumentKeySet; +using firebase::firestore::model::OnlineState; +using firebase::firestore::model::SnapshotVersion; +using firebase::firestore::model::DocumentKeySet; +using firebase::firestore::model::TargetId; +using firebase::firestore::remote::Datastore; +using firebase::firestore::remote::WatchStream; +using firebase::firestore::remote::DocumentWatchChange; +using firebase::firestore::remote::ExistenceFilterWatchChange; +using firebase::firestore::remote::OnlineStateTracker; +using firebase::firestore::remote::RemoteEvent; +using firebase::firestore::remote::TargetChange; +using firebase::firestore::remote::WatchChange; +using firebase::firestore::remote::WatchChangeAggregator; +using firebase::firestore::remote::WatchTargetChange; +using firebase::firestore::remote::WatchTargetChangeState; +using util::AsyncQueue; +using util::Status; + namespace firebase { namespace firestore { namespace remote { +RemoteStore::RemoteStore( + FSTLocalStore* local_store, + Datastore* datastore, + AsyncQueue* worker_queue, + id _Nullable online_state_delegate) + : local_store_{local_store}, + online_state_tracker_{worker_queue, online_state_delegate} { + // Create streams (but note they're not started yet) + watch_stream_ = datastore->CreateWatchStream(this); +} + void RemoteStore::StartWatchStream() { HARD_ASSERT(ShouldStartWatchStream(), "StartWatchStream called when ShouldStartWatchStream: is false."); @@ -127,8 +157,8 @@ } } -void RemoteStore::OnWatchStreamError(const Status& error) { - if (error.ok()) { +void RemoteStore::OnWatchStreamClose(const Status& status) { + if (status.ok()) { // Graceful stop (due to Stop() or idle timeout). Make sure that's // desirable. HARD_ASSERT(!ShouldStartWatchStream(), @@ -139,7 +169,7 @@ // If we still need the watch stream, retry the connection. if (ShouldStartWatchStream()) { - online_state_tracker_.HandleWatchStreamFailure(error); + online_state_tracker_.HandleWatchStreamFailure(status); StartWatchStream(); } else { @@ -162,11 +192,13 @@ for (const auto& entry : remote_event.target_changes()) { const TargetChange& target_change = entry.second; NSData* resumeToken = target_change.resume_token(); + if (resumeToken.length > 0) { TargetId target_id = entry.first; auto found = listen_targets_.find(target_id); FSTQueryData* query_data = found != listen_targets_.end() ? found->second : nil; + // A watched target might have been removed already. if (query_data) { listen_targets_[target_id] = [query_data @@ -236,6 +268,15 @@ return is_network_enabled_; } +DocumentKeySet RemoteStore::GetRemoteKeysForTarget:(TargetId target_id) const { + return [sync_engine_ remoteKeysForTarget:target_id]; +} + +nullable FSTQueryData* RemoteStore::GetQueryDataForTarget:(TargetId target_id) const { + auto found = listen_targets_.find(target_id); + return found != listen_targets_.end() ? found->second : nil; +} + } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.h b/Firestore/core/src/firebase/firestore/remote/watch_stream.h index 43b1ef32f7f..4ca5d4a4cb4 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.h @@ -24,10 +24,12 @@ #include #include +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" +#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/status.h" #include "absl/strings/string_view.h" @@ -41,10 +43,38 @@ namespace firebase { namespace firestore { namespace remote { +/** An interface defining the events that can be emitted by the `WatchStream`. + */ +class WatchStreamCallback { + public: + /** Called by the `WatchStream` when it is ready to accept outbound request + * messages. */ + virtual void OnWatchStreamOpen() = 0; + + /** + * Called by the `WatchStream` with changes and the snapshot versions + * included in in the `WatchChange` responses sent back by the server. + */ + virtual void OnWatchStreamChange( + const WatchChange& change, + const model::SnapshotVersion& snapshot_version) = 0; + + /** + * Called by the `WatchStream` when the underlying streaming RPC is + * interrupted for whatever reason, usually because of an error, but possibly + * due to an idle timeout. The status passed to this method may be ok, in + * which case the stream was closed without attributable fault. + * + * NOTE: This will not be called after `Stop` is called on the stream. See + * "Starting and Stopping" on `Stream` for details. + */ + virtual void OnWatchStreamClose(const util::Status& status) = 0; +}; + /** * A `Stream` that implements the StreamingWatch RPC. * - * Once the `WatchStream` has called the `streamDidOpen` method on the delegate, + * Once the `WatchStream` has called the `OnWatchStreamOpen` method on the callback, * any number of `WatchQuery` and `UnwatchTargetId` calls can be sent to control * what changes will be sent from the server for WatchChanges. */ @@ -54,7 +84,7 @@ class WatchStream : public Stream { auth::CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate); + WatchStreamCallback* callback); /** * Registers interest in the results of the given query. If the query includes @@ -85,7 +115,7 @@ class WatchStream : public Stream { } bridge::WatchStreamSerializer serializer_bridge_; - bridge::WatchStreamDelegate delegate_bridge_; + WatchStreamCallback* callback_; }; } // namespace remote diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm index 7a487d75664..c55abf8e3aa 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm @@ -36,11 +36,11 @@ CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate) + WatchStreamCallback* callback) : Stream{async_queue, credentials_provider, grpc_connection, TimerId::ListenStreamConnectionBackoff, TimerId::ListenStreamIdle}, serializer_bridge_{serializer}, - delegate_bridge_{delegate} { + callback_{callback} { } void WatchStream::WatchQuery(FSTQueryData* query) { @@ -73,7 +73,7 @@ } void WatchStream::NotifyStreamOpen() { - delegate_bridge_.NotifyDelegateOnOpen(); + callback_->OnWatchStreamOpen(); } Status WatchStream::NotifyStreamResponse(const grpc::ByteBuffer& message) { @@ -92,14 +92,14 @@ // A successful response means the stream is healthy. backoff_.Reset(); - delegate_bridge_.NotifyDelegateOnChange( + callback_->OnWatchStreamChange( *serializer_bridge_.ToWatchChange(response), serializer_bridge_.ToSnapshotVersion(response)); return Status::OK(); } void WatchStream::NotifyStreamClose(const Status& status) { - delegate_bridge_.NotifyDelegateOnClose(status); + callback_->OnWatchStreamClose(status); } } // namespace remote From a7d99ae61f2ebbce226e1ceb3050d127aa97e866 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 17:56:57 -0500 Subject: [PATCH 085/107] wip --- Firestore/Source/Remote/FSTRemoteStore.h | 3 ++- .../src/firebase/firestore/remote/datastore.h | 2 +- .../src/firebase/firestore/remote/remote_event.h | 6 +++--- .../firestore/remote/remote_objc_bridge.h | 16 ---------------- .../src/firebase/firestore/remote/remote_store.h | 2 ++ 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index a585bf17218..f37c077b973 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -22,6 +22,7 @@ #include "Firestore/core/src/firebase/firestore/model/types.h" #include "Firestore/core/src/firebase/firestore/remote/datastore.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" @class FSTLocalStore; @@ -39,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN * FSTRemoteStore handles all interaction with the backend through a simple, clean interface. This * class is not thread safe and should be only called from the worker dispatch queue. */ -@interface FSTRemoteStore : NSObject +@interface FSTRemoteStore : NSObject - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore datastore: diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.h b/Firestore/core/src/firebase/firestore/remote/datastore.h index d6d8a358619..0f235b5be08 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.h +++ b/Firestore/core/src/firebase/firestore/remote/datastore.h @@ -85,7 +85,7 @@ class Datastore : public std::enable_shared_from_this { * shared channel. */ virtual std::shared_ptr CreateWatchStream( - id delegate); + WatchStreamCallback callback); /** * Creates a new `WriteStream` that is still unstarted but uses a common * shared channel. diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index 1f4ce9b0499..dec0dba59ac 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -67,7 +67,7 @@ class TargetMetadataProvider { * Returns the FSTQueryData for an active target ID or 'null' if this query * has become inactive */ - virtual nullable FSTQueryData* GetQueryDataForTarget( + virtual FSTQueryData* GetQueryDataForTarget( model::TargetId target_id) const = 0; }; @@ -311,7 +311,7 @@ class RemoteEvent { class WatchChangeAggregator { public: explicit WatchChangeAggregator( - id target_metadata_provider) + TargetMetadataProvider* target_metadata_provider) : target_metadata_provider_{target_metadata_provider} { } @@ -439,7 +439,7 @@ class WatchChangeAggregator { */ std::unordered_set pending_target_resets_; - id target_metadata_provider_; + TargetMetadataProvider* target_metadata_provider_ = nullptr; }; } // namespace remote diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h index c655063c4b0..e5cefba467a 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h @@ -172,22 +172,6 @@ class DatastoreSerializer { FSTSerializerBeta* serializer_; }; -/** A C++ bridge that invokes methods on an `FSTWatchStreamDelegate`. */ -class WatchStreamDelegate { - public: - explicit WatchStreamDelegate(id delegate) - : delegate_{delegate} { - } - - void NotifyDelegateOnOpen(); - void NotifyDelegateOnChange(const WatchChange& change, - const model::SnapshotVersion& snapshot_version); - void NotifyDelegateOnClose(const util::Status& status); - - private: - __weak id delegate_; -}; - /** A C++ bridge that invokes methods on an `FSTWriteStreamDelegate`. */ class WriteStreamDelegate { public: diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index f81d820b577..225ccba494d 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -26,6 +26,8 @@ #include #include +#import "Firestore/Source/Remote/FSTOnlineStateDelegate.h" + #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" From 6119d54e2f13e1b3a7200e35e21e5f9e3e4f253e Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 18:25:02 -0500 Subject: [PATCH 086/107] core actually compiles --- Firestore/Source/Remote/FSTRemoteStore.mm | 39 +++++++++++-------- .../src/firebase/firestore/remote/datastore.h | 2 +- .../firebase/firestore/remote/datastore.mm | 4 +- .../firebase/firestore/remote/remote_event.mm | 10 ++--- .../firestore/remote/remote_objc_bridge.mm | 15 ------- .../firebase/firestore/remote/remote_store.h | 30 ++++++++------ .../firebase/firestore/remote/remote_store.mm | 29 ++++++++------ 7 files changed, 65 insertions(+), 64 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 84ac93b7078..47623dc53a6 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -36,6 +36,7 @@ #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/remote/online_state_tracker.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" +#include "Firestore/core/src/firebase/firestore/remote/remote_store.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" @@ -61,6 +62,7 @@ using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::OnlineStateTracker; using firebase::firestore::remote::RemoteEvent; +using firebase::firestore::remote::RemoteStore; using firebase::firestore::remote::TargetChange; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; @@ -79,7 +81,7 @@ #pragma mark - FSTRemoteStore -@interface FSTRemoteStore () +@interface FSTRemoteStore () #pragma mark Watch Stream @@ -119,10 +121,11 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore _datastore->Start(); - _remoteStore = absl::make_unique(localStore, datastore.get(), queue, onlineStateDelegate); + _remoteStore = absl::make_unique(localStore, _datastore.get(), queue, + std::move(onlineStateHandler)); _writeStream = _datastore->CreateWriteStream(self); - _isNetworkEnabled = NO; + _remoteStore->set_is_network_enabled(false); } return self; } @@ -139,7 +142,7 @@ - (void)start { #pragma mark Online/Offline state - (void)enableNetwork { - _isNetworkEnabled = YES; + _remoteStore->set_is_network_enabled(true); if (_remoteStore->CanUseNetwork()) { // Load any saved stream token from persistent storage @@ -148,7 +151,7 @@ - (void)enableNetwork { if (_remoteStore->ShouldStartWatchStream()) { _remoteStore->StartWatchStream(); } else { - _onlineStateTracker.UpdateState(OnlineState::Unknown); + _remoteStore->online_state_tracker().UpdateState(OnlineState::Unknown); } // This will start the write stream if necessary. @@ -157,16 +160,16 @@ - (void)enableNetwork { } - (void)disableNetwork { - _isNetworkEnabled = NO; + _remoteStore->set_is_network_enabled(false); [self disableNetworkInternal]; // Set the OnlineState to Offline so get()s return from cache, etc. - _onlineStateTracker.UpdateState(OnlineState::Offline); + _remoteStore->online_state_tracker().UpdateState(OnlineState::Offline); } /** Disables the network, setting the OnlineState to the specified targetOnlineState. */ - (void)disableNetworkInternal { - _watchStream->Stop(); + _remoteStore->watch_stream().Stop(); _writeStream->Stop(); if (self.writePipeline.count > 0) { @@ -182,12 +185,11 @@ - (void)disableNetworkInternal { - (void)shutdown { LOG_DEBUG("FSTRemoteStore %s shutting down", (__bridge void *)self); - _remoteStore->Shutdown(); + _remoteStore->set_is_network_enabled(false); [self disableNetworkInternal]; - _remoteStore.set_is_network_enabled(false); // Set the OnlineState to Unknown (rather than Offline) to avoid potentially triggering // spurious listener events with cached data, etc. - _remoteStore.online_state_tracker().UpdateState(OnlineState::Unknown); + _remoteStore->online_state_tracker().UpdateState(OnlineState::Unknown); _datastore->Shutdown(); } @@ -197,9 +199,9 @@ - (void)credentialDidChange { // for the new user and re-fill the write pipeline with new mutations from the LocalStore // (since mutations are per-user). LOG_DEBUG("FSTRemoteStore %s restarting streams for new credential", (__bridge void *)self); - _remoteStore.set_is_network_enabled(false); + _remoteStore->set_is_network_enabled(false); [self disableNetworkInternal]; - _remoteStore.online_state_tracker().UpdateState(OnlineState::Unknown); + _remoteStore->online_state_tracker().UpdateState(OnlineState::Unknown); [self enableNetwork]; } } @@ -221,7 +223,8 @@ - (void)stopListeningToTargetID:(TargetId)targetID { * pending writes. */ - (BOOL)shouldStartWriteStream { - return _remoteStore->CanUseNetwork() && !_writeStream->IsStarted() && self.writePipeline.count > 0; + return _remoteStore->CanUseNetwork() && !_writeStream->IsStarted() && + self.writePipeline.count > 0; } - (void)startWriteStream { @@ -242,7 +245,8 @@ - (void)fillWritePipeline { BatchId lastBatchIDRetrieved = self.writePipeline.count == 0 ? kBatchIdUnknown : self.writePipeline.lastObject.batchID; while ([self canAddToWritePipeline]) { - FSTMutationBatch *batch = [_remoteStore->local_store() nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; + FSTMutationBatch *batch = + [_remoteStore->local_store() nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; if (!batch) { if (self.writePipeline.count == 0) { _writeStream->MarkIdle(); @@ -311,7 +315,7 @@ - (void)writeStreamDidReceiveResponseWithVersion:(const SnapshotVersion &)commit commitVersion:commitVersion mutationResults:results streamToken:_writeStream->GetLastStreamToken()]; - [self.syncEngine applySuccessfulWriteWithResult:batchResult]; + [_remoteStore->sync_engine() applySuccessfulWriteWithResult:batchResult]; // It's possible that with the completion of this mutation another slot has freed up. [self fillWritePipeline]; @@ -381,7 +385,8 @@ - (void)handleWriteError:(const Status &)error { // bad request so inhibit backoff on the next restart. _writeStream->InhibitBackoff(); - [self.syncEngine rejectFailedWriteWithBatchID:batch.batchID error:util::MakeNSError(error)]; + [_remoteStore->sync_engine() rejectFailedWriteWithBatchID:batch.batchID + error:util::MakeNSError(error)]; // It's possible that with the completion of this mutation another slot has freed up. [self fillWritePipeline]; diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.h b/Firestore/core/src/firebase/firestore/remote/datastore.h index 0f235b5be08..9e2268ea571 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.h +++ b/Firestore/core/src/firebase/firestore/remote/datastore.h @@ -85,7 +85,7 @@ class Datastore : public std::enable_shared_from_this { * shared channel. */ virtual std::shared_ptr CreateWatchStream( - WatchStreamCallback callback); + WatchStreamCallback* callback); /** * Creates a new `WriteStream` that is still unstarted but uses a common * shared channel. diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.mm b/Firestore/core/src/firebase/firestore/remote/datastore.mm index 9cf387fdbec..1bf2376d8f8 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.mm +++ b/Firestore/core/src/firebase/firestore/remote/datastore.mm @@ -151,10 +151,10 @@ void LogGrpcCallFinished(absl::string_view rpc_name, } std::shared_ptr Datastore::CreateWatchStream( - id delegate) { + WatchStreamCallback* callback) { return std::make_shared(worker_queue_, credentials_, serializer_bridge_.GetSerializer(), - &grpc_connection_, delegate); + &grpc_connection_, callback); } std::shared_ptr Datastore::CreateWriteStream( diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index fd4355ddab2..bc0f2f647ea 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -360,9 +360,9 @@ TargetId target_id) { TargetState& target_state = EnsureTargetState(target_id); TargetChange target_change = target_state.ToTargetChange(); - return ([target_metadata_provider_ remoteKeysForTarget:target_id].size() + + return target_metadata_provider_->GetRemoteKeysForTarget(target_id).size() + target_change.added_documents().size() - - target_change.removed_documents().size()); + target_change.removed_documents().size(); } void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { @@ -385,7 +385,7 @@ return target_state != target_states_.end() && target_state->second.IsPending() ? nil - : [target_metadata_provider_ queryDataForTarget:target_id]; + : target_metadata_provider_->GetQueryDataForTarget(target_id); } void WatchChangeAggregator::ResetTarget(TargetId target_id) { @@ -400,7 +400,7 @@ // removals will be part of the initial snapshot if Watch does not resend // these documents. DocumentKeySet existingKeys = - [target_metadata_provider_ remoteKeysForTarget:target_id]; + target_metadata_provider_->GetRemoteKeysForTarget(target_id); for (const DocumentKey& key : existingKeys) { RemoveDocumentFromTarget(target_id, key, nil); @@ -410,7 +410,7 @@ bool WatchChangeAggregator::TargetContainsDocument(TargetId target_id, const DocumentKey& key) { const DocumentKeySet& existing_keys = - [target_metadata_provider_ remoteKeysForTarget:target_id]; + target_metadata_provider_->GetRemoteKeysForTarget(target_id); return existing_keys.contains(key); } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm index 8159fc96806..406f9199f6d 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm @@ -300,21 +300,6 @@ bool IsLoggingEnabled() { return [serializer_ decodedMaybeDocumentFromBatch:response]; } -// WatchStreamDelegate - -void WatchStreamDelegate::NotifyDelegateOnOpen() { - [delegate_ watchStreamDidOpen]; -} - -void WatchStreamDelegate::NotifyDelegateOnChange( - const WatchChange& change, const SnapshotVersion& snapshot_version) { - [delegate_ watchStreamDidChange:change snapshotVersion:snapshot_version]; -} - -void WatchStreamDelegate::NotifyDelegateOnClose(const Status& status) { - [delegate_ watchStreamWasInterruptedWithError:status]; -} - // WriteStreamDelegate void WriteStreamDelegate::NotifyDelegateOnOpen() { diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 225ccba494d..fac7a69d2d4 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -26,12 +26,11 @@ #include #include -#import "Firestore/Source/Remote/FSTOnlineStateDelegate.h" - #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" -#include "Firestore/core/src/firebase/firestore/remote/online_state_tracker_.h" +#include "Firestore/core/src/firebase/firestore/remote/datastore.h" +#include "Firestore/core/src/firebase/firestore/remote/online_state_tracker.h" #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" @@ -102,33 +101,39 @@ namespace firebase { namespace firestore { namespace remote { -class RemoteStore : public TargetMetadataProvider, public WatchStreamObserver { +class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { public: RemoteStore(FSTLocalStore* local_store, - Util::AsyncQueue* worker_queue, - id _Nullable online_state_delegate); + Datastore* datastore, + util::AsyncQueue* worker_queue, + std::function online_state_handler); // TODO(varconst): remove the getters and setters id sync_engine() { return sync_engine_; } - void sync_engine(id sync_engine) { + void set_sync_engine(id sync_engine) { sync_engine_ = sync_engine; } + FSTLocalStore* local_store() { return local_store_; } + OnlineStateTracker& online_state_tracker() { return online_state_tracker_; } + void set_is_network_enabled(bool value) { is_network_enabled_ = value; } + WatchStream& watch_stream() { return *watch_stream_;} + void ListenToTarget(FSTQueryData* query_data); void StopListening(model::TargetId target_id); model::DocumentKeySet GetRemoteKeysForTarget( model::TargetId target_id) const override; - nullable FSTQueryData* GetQueryDataForTarget( + FSTQueryData* GetQueryDataForTarget( model::TargetId target_id) const override; void OnWatchStreamOpen() override; @@ -136,10 +141,10 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamObserver { const model::SnapshotVersion& snapshot_version) override; void OnWatchStreamClose(const util::Status& status) override; - // TODO(varconst): make private. + // TODO(varconst): make the following methods private. + bool CanUseNetwork() const; - private: void StartWatchStream(); /** @@ -148,11 +153,12 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamObserver { */ bool ShouldStartWatchStream() const; + void CleanUpWatchStreamState(); + + private: void SendWatchRequest(FSTQueryData* query_data); void SendUnwatchRequest(model::TargetId target_id); - void CleanUpWatchStreamState(); - /** * Takes a batch of changes from the `Datastore`, repackages them as a * `RemoteEvent`, and passes that on to the `SyncEngine`. diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 86c710de145..95482f4d82b 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -16,7 +16,12 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#import "Firestore/Source/Local/FSTLocalStore.h" +#import "Firestore/Source/Local/FSTQueryData.h" + +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "absl/memory/memory.h" using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::OnlineState; @@ -34,8 +39,8 @@ using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; -using util::AsyncQueue; -using util::Status; +using firebase::firestore::util::AsyncQueue; +using firebase::firestore::util::Status; namespace firebase { namespace firestore { @@ -45,9 +50,9 @@ FSTLocalStore* local_store, Datastore* datastore, AsyncQueue* worker_queue, - id _Nullable online_state_delegate) + std::function online_state_handler) : local_store_{local_store}, - online_state_tracker_{worker_queue, online_state_delegate} { + online_state_tracker_{worker_queue, std::move(online_state_handler)} { // Create streams (but note they're not started yet) watch_stream_ = datastore->CreateWatchStream(this); } @@ -62,7 +67,7 @@ } void RemoteStore::ListenToTarget(FSTQueryData* query_data) { - TargetId targetKey = query_data.target_id; + TargetId targetKey = query_data.targetID; HARD_ASSERT(listen_targets_.find(targetKey) == listen_targets_.end(), "listenToQuery called with duplicate target id: %s", targetKey); @@ -76,7 +81,7 @@ } void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { - watch_change_aggregator_->RecordPendingTargetRequest(query_data.target_id); + watch_change_aggregator_->RecordPendingTargetRequest(query_data.targetID); watch_stream_->WatchQuery(query_data); } @@ -202,7 +207,7 @@ // A watched target might have been removed already. if (query_data) { listen_targets_[target_id] = [query_data - query_dataByReplacingSnapshotVersion:snapshot_version + queryDataByReplacingSnapshotVersion:snapshot_version resumeToken:resumeToken sequenceNumber:query_data.sequenceNumber]; } @@ -222,7 +227,7 @@ // Clear the resume token for the query, since we're in a known mismatch // state. query_data = [[FSTQueryData alloc] initWithQuery:query_data.query - target_id:target_id + targetID:target_id listenSequenceNumber:query_data.sequenceNumber purpose:query_data.purpose]; listen_targets_[target_id] = query_data; @@ -237,14 +242,14 @@ // listens of this target (that might happen e.g. on reconnect). FSTQueryData* request_query_data = [[FSTQueryData alloc] initWithQuery:query_data.query - target_id:target_id + targetID:target_id listenSequenceNumber:query_data.sequenceNumber purpose:FSTQueryPurposeExistenceFilterMismatch]; SendWatchRequest(request_query_data); } // Finally handle remote event - [sync_engine_ applyRemoteEvent:remoteEvent]; + [sync_engine_ applyRemoteEvent:remote_event]; } void RemoteStore::ProcessTargetError(const WatchTargetChange& change) { @@ -268,11 +273,11 @@ return is_network_enabled_; } -DocumentKeySet RemoteStore::GetRemoteKeysForTarget:(TargetId target_id) const { +DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { return [sync_engine_ remoteKeysForTarget:target_id]; } -nullable FSTQueryData* RemoteStore::GetQueryDataForTarget:(TargetId target_id) const { +FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { auto found = listen_targets_.find(target_id); return found != listen_targets_.end() ? found->second : nil; } From 8fa4e74285fd4920384bfee2ef536a59c7ca6559 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 30 Jan 2019 18:26:27 -0500 Subject: [PATCH 087/107] style.sh --- Firestore/Source/Remote/FSTRemoteStore.h | 1 - .../firebase/firestore/remote/remote_event.mm | 4 +-- .../firebase/firestore/remote/remote_store.h | 26 +++++++++++-------- .../firebase/firestore/remote/remote_store.mm | 12 +++++---- .../firebase/firestore/remote/watch_stream.h | 6 ++--- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.h b/Firestore/Source/Remote/FSTRemoteStore.h index 92d3225826c..6b1aa4824af 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.h +++ b/Firestore/Source/Remote/FSTRemoteStore.h @@ -34,7 +34,6 @@ NS_ASSUME_NONNULL_BEGIN - #pragma mark - FSTRemoteStore /** diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index bc0f2f647ea..2a583b2d100 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -361,8 +361,8 @@ TargetState& target_state = EnsureTargetState(target_id); TargetChange target_change = target_state.ToTargetChange(); return target_metadata_provider_->GetRemoteKeysForTarget(target_id).size() + - target_change.added_documents().size() - - target_change.removed_documents().size(); + target_change.added_documents().size() - + target_change.removed_documents().size(); } void WatchChangeAggregator::RecordPendingTargetRequest(TargetId target_id) { diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index fac7a69d2d4..ef6f3f3a923 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -104,9 +104,9 @@ namespace remote { class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { public: RemoteStore(FSTLocalStore* local_store, - Datastore* datastore, + Datastore* datastore, util::AsyncQueue* worker_queue, - std::function online_state_handler); + std::function online_state_handler); // TODO(varconst): remove the getters and setters id sync_engine() { @@ -120,25 +120,29 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { return local_store_; } - OnlineStateTracker& online_state_tracker() { return online_state_tracker_; } + OnlineStateTracker& online_state_tracker() { + return online_state_tracker_; + } void set_is_network_enabled(bool value) { is_network_enabled_ = value; } - WatchStream& watch_stream() { return *watch_stream_;} + WatchStream& watch_stream() { + return *watch_stream_; + } void ListenToTarget(FSTQueryData* query_data); void StopListening(model::TargetId target_id); model::DocumentKeySet GetRemoteKeysForTarget( model::TargetId target_id) const override; - FSTQueryData* GetQueryDataForTarget( - model::TargetId target_id) const override; + FSTQueryData* GetQueryDataForTarget(model::TargetId target_id) const override; void OnWatchStreamOpen() override; - void OnWatchStreamChange(const WatchChange& change, - const model::SnapshotVersion& snapshot_version) override; + void OnWatchStreamChange( + const WatchChange& change, + const model::SnapshotVersion& snapshot_version) override; void OnWatchStreamClose(const util::Status& status) override; // TODO(varconst): make the following methods private. @@ -148,9 +152,9 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void StartWatchStream(); /** - * Returns true if the network is enabled, the watch stream has not yet been started and there are - * active watch targets. - */ + * Returns true if the network is enabled, the watch stream has not yet been + * started and there are active watch targets. + */ bool ShouldStartWatchStream() const; void CleanUpWatchStreamState(); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 95482f4d82b..fbd4fd6b7ec 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -16,6 +16,8 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_store.h" +#include + #import "Firestore/Source/Local/FSTLocalStore.h" #import "Firestore/Source/Local/FSTQueryData.h" @@ -50,7 +52,7 @@ FSTLocalStore* local_store, Datastore* datastore, AsyncQueue* worker_queue, - std::function online_state_handler) + std::function online_state_handler) : local_store_{local_store}, online_state_tracker_{worker_queue, std::move(online_state_handler)} { // Create streams (but note they're not started yet) @@ -208,8 +210,8 @@ if (query_data) { listen_targets_[target_id] = [query_data queryDataByReplacingSnapshotVersion:snapshot_version - resumeToken:resumeToken - sequenceNumber:query_data.sequenceNumber]; + resumeToken:resumeToken + sequenceNumber:query_data.sequenceNumber]; } } } @@ -227,7 +229,7 @@ // Clear the resume token for the query, since we're in a known mismatch // state. query_data = [[FSTQueryData alloc] initWithQuery:query_data.query - targetID:target_id + targetID:target_id listenSequenceNumber:query_data.sequenceNumber purpose:query_data.purpose]; listen_targets_[target_id] = query_data; @@ -242,7 +244,7 @@ // listens of this target (that might happen e.g. on reconnect). FSTQueryData* request_query_data = [[FSTQueryData alloc] initWithQuery:query_data.query - targetID:target_id + targetID:target_id listenSequenceNumber:query_data.sequenceNumber purpose:FSTQueryPurposeExistenceFilterMismatch]; SendWatchRequest(request_query_data); diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.h b/Firestore/core/src/firebase/firestore/remote/watch_stream.h index 4ca5d4a4cb4..f5d29ba488a 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.h @@ -74,9 +74,9 @@ class WatchStreamCallback { /** * A `Stream` that implements the StreamingWatch RPC. * - * Once the `WatchStream` has called the `OnWatchStreamOpen` method on the callback, - * any number of `WatchQuery` and `UnwatchTargetId` calls can be sent to control - * what changes will be sent from the server for WatchChanges. + * Once the `WatchStream` has called the `OnWatchStreamOpen` method on the + * callback, any number of `WatchQuery` and `UnwatchTargetId` calls can be sent + * to control what changes will be sent from the server for WatchChanges. */ class WatchStream : public Stream { public: From 6702112ee31e9926dd1e9477ae023e7834d5e699 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 14:32:28 -0500 Subject: [PATCH 088/107] wip --- .../Firestore_FuzzTests_iOS.xcscheme | 14 ++- .../xcschemes/Firestore_Tests_iOS.xcscheme | 1 + .../Example/Tests/Local/FSTLocalStoreTests.mm | 5 +- .../Tests/Remote/FSTRemoteEventTests.mm | 12 +- Firestore/Example/Tests/Util/FSTHelpers.h | 90 ++++++++------- Firestore/Example/Tests/Util/FSTHelpers.mm | 105 +++++++++--------- 6 files changed, 122 insertions(+), 105 deletions(-) diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme index 763229ed44c..64f6e6851e7 100644 --- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme @@ -7,8 +7,11 @@ buildImplicitDependencies = "YES"> + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + + + + diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 6363c652be8..127ccaa3a33 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -906,9 +906,8 @@ - (void)testPersistsResumeTokens { NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken}; - WatchChangeAggregator aggregator{[FSTTestTargetMetadataProvider - providerWithSingleResultForKey:testutil::Key("foo/bar") - targets:{targetID}]}; + WatchChangeAggregator aggregator{FSTTestTargetMetadataProvider::CreateSingleResultProvider( + testutil::Key("foo/bar"), std::vector{target_id})}; aggregator.HandleTargetChange(watchChange); RemoteEvent remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); [self applyRemoteEvent:remoteEvent]; diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index baaa627b63d..fe81ddf76ba 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -92,13 +92,12 @@ @interface FSTRemoteEventTests : XCTestCase @implementation FSTRemoteEventTests { NSData *_resumeToken1; - FSTTestTargetMetadataProvider *_targetMetadataProvider; + TestTargetMetadataProvider _targetMetadataProvider; std::unordered_map _noOutstandingResponses; } - (void)setUp { _resumeToken1 = [@"resume1" dataUsingEncoding:NSUTF8StringEncoding]; - _targetMetadataProvider = [FSTTestTargetMetadataProvider new]; } /** @@ -145,7 +144,7 @@ - (void)setUp { * considered active, or `_noOutstandingResponses` if all targets are already active. * @param existingKeys The set of documents that are considered synced with the test targets as * part of a previous listen. To modify this set during test execution, invoke - * `[_targetMetadataProvider setSyncedKeys:forQueryData:]`. + * `_targetMetadataProvider.SetSyncedKeys()`. * @param watchChanges The watch changes to apply before returning the aggregator. Supported * changes are `DocumentWatchChange` and `WatchTargetChange`. */ @@ -162,7 +161,7 @@ - (void)setUp { FSTQueryData *queryData = kv.second; targetIDs.push_back(targetID); - [_targetMetadataProvider setSyncedKeys:existingKeys forQueryData:queryData]; + _targetMetadataProvider.SetSyncedKeys(existingKeys, queryData); }; for (const auto &kv : outstandingResponses) { @@ -223,7 +222,7 @@ - (void)setUp { - (void)testWillAccumulateDocumentAddedAndRemovedEvents { // The target map that contains an entry for every target in this test. If a target ID is - // omitted, the target is considered inactive and FSTTestTargetMetadataProvider will fail on + // omitted, the target is considered inactive and `TestTargetMetadataProvider` will fail on // access. std::unordered_map targetMap{ [self queryDataForTargets:{1, 2, 3, 4, 5, 6}]}; @@ -614,8 +613,7 @@ - (void)testDocumentUpdate { XCTAssertEqualObjects(event.document_updates().at(doc1.key), doc1); XCTAssertEqualObjects(event.document_updates().at(doc2.key), doc2); - [_targetMetadataProvider setSyncedKeys:DocumentKeySet{doc1.key, doc2.key} - forQueryData:targetMap[1]]; + _targetMetadataProvider.SetSyncedKeys(DocumentKeySet{doc1.key, doc2.key}, targetMap[1]); FSTDeletedDocument *deletedDoc1 = [FSTDeletedDocument documentWithKey:doc1.key version:testutil::Version(3) diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index c876f2071f4..60d1241fa77 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -17,6 +17,7 @@ #import #include +#include #include #import "Firestore/Source/Model/FSTDocument.h" @@ -141,51 +142,58 @@ inline NSString *FSTRemoveExceptionPrefix(NSString *exception) { } while (0) /** - * An implementation of FSTTargetMetadataProvider that provides controlled access to the - * `FSTTargetMetadataProvider` callbacks. Any target accessed via these callbacks must be + * An implementation of `TargetMetadataProvider` that provides controlled access to the + * `TargetMetadataProvider` callbacks. Any target accessed via these callbacks must be * registered beforehand via the factory methods or via `setSyncedKeys:forQueryData:`. */ -@interface FSTTestTargetMetadataProvider : NSObject - -/** - * Creates an FSTTestTargetMetadataProvider that behaves as if there's an established listen for - * each of the given targets, where each target has previously seen query results containing just - * the given documentKey. - * - * Internally this means that the `remoteKeysForTarget` callback for these targets will return just - * the documentKey and that the provided targets will be returned as active from the - * `queryDataForTarget` target. - */ -+ (instancetype) - providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey - targets: - (const std::vector &)targets; - -+ (instancetype) - providerWithSingleResultForKey:(firebase::firestore::model::DocumentKey)documentKey - listenTargets: - (const std::vector &)listenTargets - limboTargets: - (const std::vector &)limboTargets; - -/** - * Creates an FSTTestTargetMetadataProvider that behaves as if there's an established listen for - * each of the given targets, where each target has not seen any previous document. - * - * Internally this means that the `remoteKeysForTarget` callback for these targets will return an - * empty set of document keys and that the provided targets will be returned as active from the - * `queryDataForTarget` target. - */ -+ (instancetype) - providerWithEmptyResultForKey:(firebase::firestore::model::DocumentKey)documentKey - targets: - (const std::vector &)targets; +namespace firebase { +namespace firestore { +namespace remote { -/** Sets or replaces the local state for the provided query data. */ -- (void)setSyncedKeys:(firebase::firestore::model::DocumentKeySet)keys - forQueryData:(FSTQueryData *)queryData; +class TestTargetMetadataProvider : public TargetMetadataProvider { + public: + /** + * Creates a `TestTargetMetadataProvider` that behaves as if there's an established listen for + * each of the given targets, where each target has previously seen query results containing just + * the given `document_key`. + * + * Internally this means that the `GetRemoteKeysForTarget` callback for these targets will return + * just the `document_key` and that the provided targets will be returned as active from the + * `GetQueryDataForTarget` target. + */ + static TestTargetMetadataProvider CreateSingleResultProvider(model::DocumentKey document_key, + const std::vector &targets); + static TestTargetMetadataProvider CreateSingleResultProvider(model::DocumentKey document_key, + const std::vector &targets, + const std::vector &limbo_targets); + + /** + * Creates an `TestTargetMetadataProvider` that behaves as if there's an established listen for + * each of the given targets, where each target has not seen any previous document. + * + * Internally this means that the `GetRemoteKeysForTarget` callback for these targets will return an + * empty set of document keys and that the provided targets will be returned as active from the + * `GetQueryDataForTarget` target. + */ + static TestTargetMetadataProvider CreateEmptyResultProvider(const model::DocumentKey& document_key, + const std::vector &targets); + + /** Sets or replaces the local state for the provided query data. */ + void SetSyncedKeys(model::DocumentKeySet keys, FSTQueryData* query_data); + + model::DocumentKeySet GetRemoteKeysForTarget( + model::TargetId target_id) const override; + FSTQueryData* GetQueryDataForTarget( + model::TargetId target_id) const override; + + private: + std::unordered_map synced_keys_; + std::unordered_map query_data_; +}; -@end +} // namespace remote +} // namespace firestore +} // namespace firebase /** Creates a new FIRTimestamp from components. Note that year, month, and day are all one-based. */ FIRTimestamp *FSTTestTimestamp(int year, int month, int day, int hour, int minute, int second); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index e5182240d19..9dbc80383cd 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -23,9 +23,7 @@ #include #include #include -#include #include -#include #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" @@ -306,74 +304,77 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { .snapshot; } -@implementation FSTTestTargetMetadataProvider { - std::unordered_map _syncedKeys; - std::unordered_map _queryData; -} +namespace firebase { +namespace firestore { +namespace remote { -+ (instancetype)providerWithSingleResultForKey:(DocumentKey)documentKey - listenTargets:(const std::vector &)listenTargets - limboTargets:(const std::vector &)limboTargets { - FSTTestTargetMetadataProvider *metadataProvider = [FSTTestTargetMetadataProvider new]; - FSTQuery *query = [FSTQuery queryWithPath:documentKey.path()]; +TestTargetMetadataProvider CreateSingleResultProvider(DocumentKey document_key, + const std::vector &listen_targets, + const std::vector &limbo_targets) { + TestTargetMetadataProvider metadata_provider; + FSTQuery *query = [FSTQuery queryWithPath:document_key.path()]; - for (TargetId targetID : listenTargets) { - FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID - listenSequenceNumber:0 - purpose:FSTQueryPurposeListen]; - [metadataProvider setSyncedKeys:DocumentKeySet{documentKey} forQueryData:queryData]; + for (TargetId target_id : listen_targets) { + FSTQueryData *query_data = [[FSTQueryData alloc] initWithQuery:query + targetID:target_id + listenSequenceNumber:0 + purpose:FSTQueryPurposeListen]; + metadata_provider.SetSyncedKeys(DocumentKeySet{document_key}, query_data); } - for (TargetId targetID : limboTargets) { - FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID - listenSequenceNumber:0 - purpose:FSTQueryPurposeLimboResolution]; - [metadataProvider setSyncedKeys:DocumentKeySet{documentKey} forQueryData:queryData]; + for (TargetId target_id : limbo_targets) { + FSTQueryData *query_data = [[FSTQueryData alloc] initWithQuery:query + targetID:target_id + listenSequenceNumber:0 + purpose:FSTQueryPurposeLimboResolution]; + metadata_provider.SetSyncedKeys(DocumentKeySet{document_key}, query_data); } - return metadataProvider; + return metadata_provider; } -+ (instancetype)providerWithSingleResultForKey:(DocumentKey)documentKey - targets:(const std::vector &)targets { - return [self providerWithSingleResultForKey:documentKey listenTargets:targets limboTargets:{}]; +TestTargetMetadataProvider CreateSingleResultProvider(DocumentKey document_key, + const std::vector &targets) { + return CreateSingleResultProvider(document_key, targets, /*limbo_targets=*/{}); } -+ (instancetype)providerWithEmptyResultForKey:(DocumentKey)documentKey - targets:(const std::vector &)targets { - FSTTestTargetMetadataProvider *metadataProvider = [FSTTestTargetMetadataProvider new]; - FSTQuery *query = [FSTQuery queryWithPath:documentKey.path()]; +TestTargetMetadataProvider CreateEmptyResultProvider(DocumentKey document_key, + const std::vector &targets) { + TestTargetMetadataProvider metadata_provider; + FSTQuery *query = [FSTQuery queryWithPath:document_key.path()]; - for (TargetId targetID : targets) { - FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query - targetID:targetID - listenSequenceNumber:0 - purpose:FSTQueryPurposeListen]; - [metadataProvider setSyncedKeys:DocumentKeySet {} forQueryData:queryData]; + for (TargetId target_id : targets) { + FSTQueryData *query_data = [[FSTQueryData alloc] initWithQuery:query + targetID:target_id + listenSequenceNumber:0 + purpose:FSTQueryPurposeListen]; + metadata_provider.SetSyncedKeys(DocumentKeySet{}, query_data); } - return metadataProvider; + return metadata_provider; } -- (void)setSyncedKeys:(DocumentKeySet)keys forQueryData:(FSTQueryData *)queryData { - _syncedKeys[queryData.targetID] = keys; - _queryData[queryData.targetID] = queryData; +void TestTargetMetadataProvider::SetSyncedKeys(DocumentKeySet keys, FSTQueryData *query_data) { + synced_keys_[query_data.targetID] = keys; + query_data_[query_data.targetID] = query_data; } -- (DocumentKeySet)remoteKeysForTarget:(TargetId)targetID { - auto it = _syncedKeys.find(targetID); - HARD_ASSERT(it != _syncedKeys.end(), "Cannot process unknown target %s", targetID); +DocumentKeySet TestTargetMetadataProvider::GetRemoteKeysForTarget(TargetId target_id) const { + auto it = synced_keys_.find(target_id); + HARD_ASSERT(it != synced_keys_.end(), "Cannot process unknown target %s", target_id); return it->second; } -- (nullable FSTQueryData *)queryDataForTarget:(TargetId)targetID { - auto it = _queryData.find(targetID); - HARD_ASSERT(it != _queryData.end(), "Cannot process unknown target %s", targetID); +FSTQueryData *TestTargetMetadataProvider::GetQueryDataForTarget(TargetId target_id) const { + auto it = query_data_.find(target_id); + HARD_ASSERT(it != query_data_.end(), "Cannot process unknown target %s", target_id); return it->second; } -@end +} // namespace remote +} // namespace firestore +} // namespace firebase + +using firebase::firestore::remote::TestTargetMetadataProvider; RemoteEvent FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, const std::vector &addedToTargets) { @@ -381,7 +382,7 @@ RemoteEvent FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, "Docs from remote updates shouldn't have local changes."); DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; WatchChangeAggregator aggregator{ - [FSTTestTargetMetadataProvider providerWithEmptyResultForKey:doc.key targets:addedToTargets]}; + TestTargetMetadataProvider::CreateEmptyResultProvider(doc.key, addedToTargets)}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } @@ -414,10 +415,8 @@ RemoteEvent FSTTestUpdateRemoteEventWithLimboTargets( std::vector listens = updatedInTargets; listens.insert(listens.end(), removedFromTargets.begin(), removedFromTargets.end()); - WatchChangeAggregator aggregator{[FSTTestTargetMetadataProvider - providerWithSingleResultForKey:doc.key - listenTargets:listens - limboTargets:limboTargets]}; + WatchChangeAggregator aggregator{ + TestTargetMetadataProvider::CreateSingleResultProvider(doc.key, listens, limboTargets)}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } From 4ec169ec4b5f75800b26548f8f203070c350f22a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 14:48:26 -0500 Subject: [PATCH 089/107] unit tests compile --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 6 ++++-- .../Tests/Remote/FSTRemoteEventTests.mm | 3 ++- .../Example/Tests/SpecTests/FSTMockDatastore.h | 2 +- .../Tests/SpecTests/FSTMockDatastore.mm | 18 +++++++++--------- Firestore/Example/Tests/Util/FSTHelpers.mm | 16 +++++++++------- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 127ccaa3a33..03ed9562b4e 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -51,6 +51,7 @@ using firebase::firestore::model::SnapshotVersion; using firebase::firestore::model::TargetId; using firebase::firestore::remote::RemoteEvent; +using firebase::firestore::remote::TestTargetMetadataProvider; using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; using firebase::firestore::remote::WatchTargetChangeState; @@ -906,8 +907,9 @@ - (void)testPersistsResumeTokens { NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); WatchTargetChange watchChange{WatchTargetChangeState::Current, {targetID}, resumeToken}; - WatchChangeAggregator aggregator{FSTTestTargetMetadataProvider::CreateSingleResultProvider( - testutil::Key("foo/bar"), std::vector{target_id})}; + auto metadataProvider = TestTargetMetadataProvider::CreateSingleResultProvider( + testutil::Key("foo/bar"), std::vector{targetID}); + WatchChangeAggregator aggregator{&metadataProvider}; aggregator.HandleTargetChange(watchChange); RemoteEvent remoteEvent = aggregator.CreateRemoteEvent(testutil::Version(1000)); [self applyRemoteEvent:remoteEvent]; diff --git a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm index fe81ddf76ba..3172d63e812 100644 --- a/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm +++ b/Firestore/Example/Tests/Remote/FSTRemoteEventTests.mm @@ -46,6 +46,7 @@ using firebase::firestore::remote::ExistenceFilterWatchChange; using firebase::firestore::remote::RemoteEvent; using firebase::firestore::remote::TargetChange; +using firebase::firestore::remote::TestTargetMetadataProvider; using firebase::firestore::remote::WatchChange; using firebase::firestore::remote::WatchChangeAggregator; using firebase::firestore::remote::WatchTargetChange; @@ -153,7 +154,7 @@ - (void)setUp { outstandingResponses:(const std::unordered_map &)outstandingResponses existingKeys:(DocumentKeySet)existingKeys changes:(const std::vector> &)watchChanges { - WatchChangeAggregator aggregator{_targetMetadataProvider}; + WatchChangeAggregator aggregator{&_targetMetadataProvider}; std::vector targetIDs; for (const auto &kv : targetMap) { diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h index 9d58e3416bb..59afab20fa1 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h @@ -39,7 +39,7 @@ class MockDatastore : public Datastore { util::AsyncQueue* worker_queue, auth::CredentialsProvider* credentials); - std::shared_ptr CreateWatchStream(id delegate) override; + std::shared_ptr CreateWatchStream(WatchStreamCallback* callback) override; std::shared_ptr CreateWriteStream(id delegate) override; /** diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index f8b6a2d6f87..3d7214c246e 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -70,11 +70,11 @@ CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate, + WatchStreamCallback* callback, MockDatastore* datastore) - : WatchStream{worker_queue, credentials_provider, serializer, grpc_connection, delegate}, + : WatchStream{worker_queue, credentials_provider, serializer, grpc_connection, callback}, datastore_{datastore}, - delegate_{delegate} { + callback_{callback} { } const std::unordered_map& ActiveTargets() const { @@ -84,7 +84,7 @@ void Start() override { HARD_ASSERT(!open_, "Trying to start already started watch stream"); open_ = true; - [delegate_ watchStreamDidOpen]; + callback_->OnWatchStreamOpen(); } void Stop() override { @@ -118,7 +118,7 @@ void UnwatchTargetId(model::TargetId target_id) override { void FailStream(const Status& error) { open_ = false; - [delegate_ watchStreamWasInterruptedWithError:error]; + callback_->OnWatchStreamClose(error); } void WriteWatchChange(const WatchChange& change, SnapshotVersion snap) { @@ -145,14 +145,14 @@ void WriteWatchChange(const WatchChange& change, SnapshotVersion snap) { } } - [delegate_ watchStreamDidChange:change snapshotVersion:snap]; + callback_->OnWatchStreamChange(change, snap); } private: bool open_ = false; std::unordered_map active_targets_; MockDatastore* datastore_ = nullptr; - id delegate_ = nullptr; + WatchStreamCallback* callback_ = nullptr; }; class MockWriteStream : public WriteStream { @@ -248,11 +248,11 @@ int sent_mutations_count() const { credentials_{credentials} { } -std::shared_ptr MockDatastore::CreateWatchStream(id delegate) { +std::shared_ptr MockDatastore::CreateWatchStream(WatchStreamCallback* callback) { watch_stream_ = std::make_shared( worker_queue_, credentials_, [[FSTSerializerBeta alloc] initWithDatabaseID:&database_info_->database_id()], - grpc_connection(), delegate, this); + grpc_connection(), callback, this); return watch_stream_; } diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 9dbc80383cd..b6b5ae00487 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -308,7 +308,7 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { namespace firestore { namespace remote { -TestTargetMetadataProvider CreateSingleResultProvider(DocumentKey document_key, +TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider(DocumentKey document_key, const std::vector &listen_targets, const std::vector &limbo_targets) { TestTargetMetadataProvider metadata_provider; @@ -332,12 +332,12 @@ TestTargetMetadataProvider CreateSingleResultProvider(DocumentKey document_key, return metadata_provider; } -TestTargetMetadataProvider CreateSingleResultProvider(DocumentKey document_key, +TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider(DocumentKey document_key, const std::vector &targets) { return CreateSingleResultProvider(document_key, targets, /*limbo_targets=*/{}); } -TestTargetMetadataProvider CreateEmptyResultProvider(DocumentKey document_key, +TestTargetMetadataProvider TestTargetMetadataProvider::CreateEmptyResultProvider(const DocumentKey& document_key, const std::vector &targets) { TestTargetMetadataProvider metadata_provider; FSTQuery *query = [FSTQuery queryWithPath:document_key.path()]; @@ -381,8 +381,9 @@ RemoteEvent FSTTestAddedRemoteEvent(FSTMaybeDocument *doc, HARD_ASSERT(![doc isKindOfClass:[FSTDocument class]] || ![(FSTDocument *)doc hasLocalMutations], "Docs from remote updates shouldn't have local changes."); DocumentWatchChange change{addedToTargets, {}, doc.key, doc}; - WatchChangeAggregator aggregator{ - TestTargetMetadataProvider::CreateEmptyResultProvider(doc.key, addedToTargets)}; + auto metadataProvider = + TestTargetMetadataProvider::CreateEmptyResultProvider(doc.key, addedToTargets); + WatchChangeAggregator aggregator{&metadataProvider}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } @@ -415,8 +416,9 @@ RemoteEvent FSTTestUpdateRemoteEventWithLimboTargets( std::vector listens = updatedInTargets; listens.insert(listens.end(), removedFromTargets.begin(), removedFromTargets.end()); - WatchChangeAggregator aggregator{ - TestTargetMetadataProvider::CreateSingleResultProvider(doc.key, listens, limboTargets)}; + auto metadataProvider = + TestTargetMetadataProvider::CreateSingleResultProvider(doc.key, listens, limboTargets); + WatchChangeAggregator aggregator{&metadataProvider}; aggregator.HandleDocumentChange(change); return aggregator.CreateRemoteEvent(doc.version); } From 6db2ee9db82a66af50539aafc51eef25087ebf04 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 17:30:07 -0500 Subject: [PATCH 090/107] style.sh --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 2 ++ Firestore/Example/Tests/Util/FSTHelpers.h | 31 +++++++++---------- Firestore/Example/Tests/Util/FSTHelpers.mm | 15 ++++----- .../firebase/firestore/remote/remote_store.h | 13 +++++--- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 03ed9562b4e..22172c8f959 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -19,6 +19,8 @@ #import #import +#include + #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTLocalWriteResult.h" #import "Firestore/Source/Local/FSTPersistence.h" diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index 60d1241fa77..6e6f57158ab 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -151,7 +151,7 @@ namespace firestore { namespace remote { class TestTargetMetadataProvider : public TargetMetadataProvider { - public: + public: /** * Creates a `TestTargetMetadataProvider` that behaves as if there's an established listen for * each of the given targets, where each target has previously seen query results containing just @@ -161,32 +161,31 @@ class TestTargetMetadataProvider : public TargetMetadataProvider { * just the `document_key` and that the provided targets will be returned as active from the * `GetQueryDataForTarget` target. */ - static TestTargetMetadataProvider CreateSingleResultProvider(model::DocumentKey document_key, - const std::vector &targets); - static TestTargetMetadataProvider CreateSingleResultProvider(model::DocumentKey document_key, - const std::vector &targets, - const std::vector &limbo_targets); + static TestTargetMetadataProvider CreateSingleResultProvider( + model::DocumentKey document_key, const std::vector &targets); + static TestTargetMetadataProvider CreateSingleResultProvider( + model::DocumentKey document_key, + const std::vector &targets, + const std::vector &limbo_targets); /** * Creates an `TestTargetMetadataProvider` that behaves as if there's an established listen for * each of the given targets, where each target has not seen any previous document. * - * Internally this means that the `GetRemoteKeysForTarget` callback for these targets will return an - * empty set of document keys and that the provided targets will be returned as active from the + * Internally this means that the `GetRemoteKeysForTarget` callback for these targets will return + * an empty set of document keys and that the provided targets will be returned as active from the * `GetQueryDataForTarget` target. */ - static TestTargetMetadataProvider CreateEmptyResultProvider(const model::DocumentKey& document_key, - const std::vector &targets); + static TestTargetMetadataProvider CreateEmptyResultProvider( + const model::DocumentKey &document_key, const std::vector &targets); /** Sets or replaces the local state for the provided query data. */ - void SetSyncedKeys(model::DocumentKeySet keys, FSTQueryData* query_data); + void SetSyncedKeys(model::DocumentKeySet keys, FSTQueryData *query_data); - model::DocumentKeySet GetRemoteKeysForTarget( - model::TargetId target_id) const override; - FSTQueryData* GetQueryDataForTarget( - model::TargetId target_id) const override; + model::DocumentKeySet GetRemoteKeysForTarget(model::TargetId target_id) const override; + FSTQueryData *GetQueryDataForTarget(model::TargetId target_id) const override; - private: + private: std::unordered_map synced_keys_; std::unordered_map query_data_; }; diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index b6b5ae00487..6ee7720c4ac 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -308,9 +308,10 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { namespace firestore { namespace remote { -TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider(DocumentKey document_key, - const std::vector &listen_targets, - const std::vector &limbo_targets) { +TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider( + DocumentKey document_key, + const std::vector &listen_targets, + const std::vector &limbo_targets) { TestTargetMetadataProvider metadata_provider; FSTQuery *query = [FSTQuery queryWithPath:document_key.path()]; @@ -332,13 +333,13 @@ MaybeDocumentMap FSTTestDocUpdates(NSArray *docs) { return metadata_provider; } -TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider(DocumentKey document_key, - const std::vector &targets) { +TestTargetMetadataProvider TestTargetMetadataProvider::CreateSingleResultProvider( + DocumentKey document_key, const std::vector &targets) { return CreateSingleResultProvider(document_key, targets, /*limbo_targets=*/{}); } -TestTargetMetadataProvider TestTargetMetadataProvider::CreateEmptyResultProvider(const DocumentKey& document_key, - const std::vector &targets) { +TestTargetMetadataProvider TestTargetMetadataProvider::CreateEmptyResultProvider( + const DocumentKey &document_key, const std::vector &targets) { TestTargetMetadataProvider metadata_provider; FSTQuery *query = [FSTQuery queryWithPath:document_key.path()]; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index ef6f3f3a923..615adca48b2 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -69,23 +69,26 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)rejectListenWithTargetID: (const firebase::firestore::model::TargetId)targetID - error:(NSError*)error; + error: + (NSError*)error; // NOLINT(readability/casting) /** * Applies the result of a successful write of a mutation batch to the sync * engine, emitting snapshots in any views that the mutation applies to, and * removing the batch from the mutation queue. */ -- (void)applySuccessfulWriteWithResult:(FSTMutationBatchResult*)batchResult; +- (void)applySuccessfulWriteWithResult: + (FSTMutationBatchResult*)batchResult; // NOLINT(readability/casting) /** * Rejects the batch, removing the batch from the mutation queue, recomputing * the local view of any documents affected by the batch and then, emitting * snapshots with the reverted value. */ -- (void)rejectFailedWriteWithBatchID: - (firebase::firestore::model::BatchId)batchID - error:(NSError*)error; +- (void) + rejectFailedWriteWithBatchID:(firebase::firestore::model::BatchId)batchID + error: + (NSError*)error; // NOLINT(readability/casting) /** * Returns the set of remote document keys for the given target ID. This list From 463b65243b3808b3325d39460b09d3700c9335a2 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 17:33:32 -0500 Subject: [PATCH 091/107] accidental --- .../xcschemes/Firestore_FuzzTests_iOS.xcscheme | 14 +------------- .../xcschemes/Firestore_Tests_iOS.xcscheme | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme index 64f6e6851e7..763229ed44c 100644 --- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_FuzzTests_iOS.xcscheme @@ -7,11 +7,8 @@ buildImplicitDependencies = "YES"> + buildForTesting = "YES"> - - - - From dba5e70b2f2a59a75b5639fc3bafd072d0717710 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 17:57:20 -0500 Subject: [PATCH 092/107] small fixes --- .../firebase/firestore/remote/remote_store.h | 14 +- .../firebase/firestore/remote/remote_store.mm | 125 +++++++++--------- .../firebase/firestore/remote/watch_stream.h | 3 +- 3 files changed, 76 insertions(+), 66 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 615adca48b2..4d9180fe365 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -135,7 +135,10 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { return *watch_stream_; } - void ListenToTarget(FSTQueryData* query_data); + /** Listens to the target identified by the given `FSTQueryData`. */ + void Listen(FSTQueryData* query_data); + + /** Stops listening to the target with the given target ID. */ void StopListening(model::TargetId target_id); model::DocumentKeySet GetRemoteKeysForTarget( @@ -183,10 +186,6 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { */ FSTLocalStore* local_store_ = nil; - OnlineStateTracker online_state_tracker_; - - std::unique_ptr watch_change_aggregator_; - /** * A mapping of watched targets that the client cares about tracking and the * user has explicitly called a 'listen' for this target. @@ -198,13 +197,16 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { */ std::unordered_map listen_targets_; - std::shared_ptr watch_stream_; + OnlineStateTracker online_state_tracker_; /** * Set to true by `EnableNetwork` and false by `DisableNetworkInternal` and * indicates the user-preferred network state. */ bool is_network_enabled_ = false; + + std::shared_ptr watch_stream_; + std::unique_ptr watch_change_aggregator_; }; } // namespace remote diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index fbd4fd6b7ec..f40a5e7b31d 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -59,40 +59,28 @@ watch_stream_ = datastore->CreateWatchStream(this); } -void RemoteStore::StartWatchStream() { - HARD_ASSERT(ShouldStartWatchStream(), - "StartWatchStream called when ShouldStartWatchStream: is false."); - watch_change_aggregator_ = absl::make_unique(this); - watch_stream_->Start(); - - online_state_tracker_.HandleWatchStreamStart(); -} - -void RemoteStore::ListenToTarget(FSTQueryData* query_data) { +void RemoteStore::Listen(FSTQueryData* query_data) { TargetId targetKey = query_data.targetID; HARD_ASSERT(listen_targets_.find(targetKey) == listen_targets_.end(), - "listenToQuery called with duplicate target id: %s", targetKey); + "Listen called with duplicate target id: %s", targetKey); + // Mark this as something the client is currently listening for. listen_targets_[targetKey] = query_data; if (ShouldStartWatchStream()) { + // The listen will be sent in `OnWatchStreamOpen` StartWatchStream(); } else if (watch_stream_->IsOpen()) { SendWatchRequest(query_data); } } -void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { - watch_change_aggregator_->RecordPendingTargetRequest(query_data.targetID); - watch_stream_->WatchQuery(query_data); -} - void RemoteStore::StopListening(TargetId target_id) { size_t num_erased = listen_targets_.erase(target_id); HARD_ASSERT(num_erased == 1, - "stopListeningToTargetID: target not currently watched: %s", - target_id); + "StopListening: target not currently watched: %s", target_id); + // The watch stream might not be started if we're in a disconnected state if (watch_stream_->IsOpen()) { SendUnwatchRequest(target_id); } @@ -100,24 +88,58 @@ if (watch_stream_->IsOpen()) { watch_stream_->MarkIdle(); } else if (CanUseNetwork()) { - // Revert to OnlineState::Unknown if the watch stream is not open and we + // Revert to `OnlineState::Unknown` if the watch stream is not open and we // have no listeners, since without any listens to send we cannot confirm - // if the stream is healthy and upgrade to OnlineState::Online. + // if the stream is healthy and upgrade to `OnlineState::Online`. online_state_tracker_.UpdateState(OnlineState::Unknown); } } } +FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { + auto found = listen_targets_.find(target_id); + return found != listen_targets_.end() ? found->second : nil; +} + +DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { + return [sync_engine_ remoteKeysForTarget:target_id]; +} + +void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { + // We need to increment the the expected number of pending responses we're due + // from watch so we wait for the ack to process any messages from this target. + watch_change_aggregator_->RecordPendingTargetRequest(query_data.targetID); + watch_stream_->WatchQuery(query_data); +} + void RemoteStore::SendUnwatchRequest(TargetId target_id) { + // We need to increment the expected number of pending responses we're due + // from watch so we wait for the removal on the server before we process any + // messages from this target. watch_change_aggregator_->RecordPendingTargetRequest(target_id); watch_stream_->UnwatchTargetId(target_id); } +void RemoteStore::StartWatchStream() { + HARD_ASSERT(ShouldStartWatchStream(), + "StartWatchStream called when ShouldStartWatchStream is false."); + watch_change_aggregator_ = absl::make_unique(this); + watch_stream_->Start(); + + online_state_tracker_.HandleWatchStreamStart(); +} + bool RemoteStore::ShouldStartWatchStream() const { return CanUseNetwork() && !watch_stream_->IsStarted() && !listen_targets_.empty(); } +bool RemoteStore::CanUseNetwork() const { + // PORTING NOTE: This method exists mostly because web also has to take into + // account primary vs. secondary state. + return is_network_enabled_; +} + void RemoteStore::CleanUpWatchStreamState() { watch_change_aggregator_.reset(); } @@ -129,6 +151,29 @@ } } +void RemoteStore::OnWatchStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWatchStream(), + "Watch stream was stopped gracefully while still needed."); + } + + CleanUpWatchStreamState(); + + // If we still need the watch stream, retry the connection. + if (ShouldStartWatchStream()) { + online_state_tracker_.HandleWatchStreamFailure(status); + + StartWatchStream(); + } else { + // We don't need to restart the watch stream because there are no active + // targets. The online state is set to unknown because there is no active + // attempt at establishing a connection. + online_state_tracker_.UpdateState(OnlineState::Unknown); + } +} + void RemoteStore::OnWatchStreamChange(const WatchChange& change, const SnapshotVersion& snapshot_version) { // Mark the connection as Online because we got a message from the server. @@ -159,34 +204,11 @@ if (snapshot_version != SnapshotVersion::None() && snapshot_version >= [local_store_ lastRemoteSnapshotVersion]) { // We have received a target change with a global snapshot if the snapshot - // version is not equal to SnapshotVersion.None(). + // version is not equal to `SnapshotVersion::None()`. RaiseWatchSnapshot(snapshot_version); } } -void RemoteStore::OnWatchStreamClose(const Status& status) { - if (status.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's - // desirable. - HARD_ASSERT(!ShouldStartWatchStream(), - "Watch stream was stopped gracefully while still needed."); - } - - CleanUpWatchStreamState(); - - // If we still need the watch stream, retry the connection. - if (ShouldStartWatchStream()) { - online_state_tracker_.HandleWatchStreamFailure(status); - - StartWatchStream(); - } else { - // We don't need to restart the watch stream because there are no active - // targets. The online state is set to unknown because there is no active - // attempt at establishing a connection. - online_state_tracker_.UpdateState(OnlineState::Unknown); - } -} - void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { HARD_ASSERT(snapshot_version != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); @@ -269,21 +291,6 @@ } } -bool RemoteStore::CanUseNetwork() const { - // PORTING NOTE: This method exists mostly because web also has to take into - // account primary vs. secondary state. - return is_network_enabled_; -} - -DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { - return [sync_engine_ remoteKeysForTarget:target_id]; -} - -FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { - auto found = listen_targets_.find(target_id); - return found != listen_targets_.end() ? found->second : nil; -} - } // namespace remote } // namespace firestore } // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.h b/Firestore/core/src/firebase/firestore/remote/watch_stream.h index f5d29ba488a..b6136cfbb4d 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.h +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.h @@ -43,7 +43,8 @@ namespace firebase { namespace firestore { namespace remote { -/** An interface defining the events that can be emitted by the `WatchStream`. +/** + * An interface defining the events that can be emitted by the `WatchStream`. */ class WatchStreamCallback { public: From 97229a887a8a1cbbc6093f1132c26942599dc5a8 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 19:14:17 -0500 Subject: [PATCH 093/107] initial --- Firestore/Source/Remote/FSTRemoteStore.mm | 195 +----------------- .../firebase/firestore/remote/remote_store.h | 72 +++++++ .../firebase/firestore/remote/remote_store.mm | 174 ++++++++++++++++ 3 files changed, 247 insertions(+), 194 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 47623dc53a6..048c5be1c8a 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -73,41 +73,15 @@ NS_ASSUME_NONNULL_BEGIN -/** - * The maximum number of pending writes to allow. - * TODO(bjornick): Negotiate this value with the backend. - */ -static const int kMaxPendingWrites = 10; - #pragma mark - FSTRemoteStore @interface FSTRemoteStore () -#pragma mark Watch Stream - -/** - * A list of up to kMaxPendingWrites writes that we have fetched from the LocalStore via - * fillWritePipeline and have or will send to the write stream. - * - * Whenever writePipeline is not empty, the RemoteStore will attempt to start or restart the write - * stream. When the stream is established, the writes in the pipeline will be sent in order. - * - * Writes remain in writePipeline until they are acknowledged by the backend and thus will - * automatically be re-sent if the stream is interrupted / restarted before they're acknowledged. - * - * Write responses from the backend are linked to their originating request purely based on - * order, and so we can just remove writes from the front of the writePipeline as we receive - * responses. - */ -@property(nonatomic, strong, readonly) NSMutableArray *writePipeline; -@end - @implementation FSTRemoteStore { /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; std::unique_ptr _remoteStore; - std::shared_ptr _writeStream; } - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore @@ -116,15 +90,10 @@ - (instancetype)initWithLocalStore:(FSTLocalStore *)localStore onlineStateHandler:(std::function)onlineStateHandler { if (self = [super init]) { _datastore = std::move(datastore); - - _writePipeline = [NSMutableArray array]; - _datastore->Start(); _remoteStore = absl::make_unique(localStore, _datastore.get(), queue, std::move(onlineStateHandler)); - _writeStream = _datastore->CreateWriteStream(self); - _remoteStore->set_is_network_enabled(false); } return self; @@ -218,21 +187,6 @@ - (void)stopListeningToTargetID:(TargetId)targetID { #pragma mark Write Stream -/** - * Returns YES if the network is enabled, the write stream has not yet been started and there are - * pending writes. - */ -- (BOOL)shouldStartWriteStream { - return _remoteStore->CanUseNetwork() && !_writeStream->IsStarted() && - self.writePipeline.count > 0; -} - -- (void)startWriteStream { - HARD_ASSERT([self shouldStartWriteStream], - "startWriteStream: called when shouldStartWriteStream: is false."); - _writeStream->Start(); -} - /** * Attempts to fill our write pipeline with writes from the LocalStore. * @@ -242,154 +196,7 @@ - (void)startWriteStream { * Starts the write stream if necessary. */ - (void)fillWritePipeline { - BatchId lastBatchIDRetrieved = - self.writePipeline.count == 0 ? kBatchIdUnknown : self.writePipeline.lastObject.batchID; - while ([self canAddToWritePipeline]) { - FSTMutationBatch *batch = - [_remoteStore->local_store() nextMutationBatchAfterBatchID:lastBatchIDRetrieved]; - if (!batch) { - if (self.writePipeline.count == 0) { - _writeStream->MarkIdle(); - } - break; - } - [self addBatchToWritePipeline:batch]; - lastBatchIDRetrieved = batch.batchID; - } - - if ([self shouldStartWriteStream]) { - [self startWriteStream]; - } -} - -/** - * Returns YES if we can add to the write pipeline (i.e. it is not full and the network is enabled). - */ -- (BOOL)canAddToWritePipeline { - return _remoteStore->CanUseNetwork() && self.writePipeline.count < kMaxPendingWrites; -} - -/** - * Queues additional writes to be sent to the write stream, sending them immediately if the write - * stream is established. - */ -- (void)addBatchToWritePipeline:(FSTMutationBatch *)batch { - HARD_ASSERT([self canAddToWritePipeline], "addBatchToWritePipeline called when pipeline is full"); - - [self.writePipeline addObject:batch]; - - if (_writeStream->IsOpen() && _writeStream->handshake_complete()) { - _writeStream->WriteMutations(batch.mutations); - } -} - -- (void)writeStreamDidOpen { - _writeStream->WriteHandshake(); -} - -/** - * Handles a successful handshake response from the server, which is our cue to send any pending - * writes. - */ -- (void)writeStreamDidCompleteHandshake { - // Record the stream token. - [_remoteStore->local_store() setLastStreamToken:_writeStream->GetLastStreamToken()]; - - // Send the write pipeline now that the stream is established. - for (FSTMutationBatch *write in self.writePipeline) { - _writeStream->WriteMutations(write.mutations); - } -} - -/** Handles a successful StreamingWriteResponse from the server that contains a mutation result. */ -- (void)writeStreamDidReceiveResponseWithVersion:(const SnapshotVersion &)commitVersion - mutationResults:(NSArray *)results { - // This is a response to a write containing mutations and should be correlated to the first - // write in our write pipeline. - NSMutableArray *writePipeline = self.writePipeline; - FSTMutationBatch *batch = writePipeline[0]; - [writePipeline removeObjectAtIndex:0]; - - FSTMutationBatchResult *batchResult = - [FSTMutationBatchResult resultWithBatch:batch - commitVersion:commitVersion - mutationResults:results - streamToken:_writeStream->GetLastStreamToken()]; - [_remoteStore->sync_engine() applySuccessfulWriteWithResult:batchResult]; - - // It's possible that with the completion of this mutation another slot has freed up. - [self fillWritePipeline]; -} - -/** - * Handles the closing of the StreamingWrite RPC, either because of an error or because the RPC - * has been terminated by the client or the server. - */ -- (void)writeStreamWasInterruptedWithError:(const Status &)error { - if (error.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's desirable. - HARD_ASSERT(![self shouldStartWriteStream], - "Write stream was stopped gracefully while still needed."); - } - - // If the write stream closed due to an error, invoke the error callbacks if there are pending - // writes. - if (!error.ok() && self.writePipeline.count > 0) { - if (_writeStream->handshake_complete()) { - // This error affects the actual writes. - [self handleWriteError:error]; - } else { - // If there was an error before the handshake finished, it's possible that the server is - // unable to process the stream token we're sending. (Perhaps it's too old?) - [self handleHandshakeError:error]; - } - } - - // The write stream might have been started by refilling the write pipeline for failed writes - if ([self shouldStartWriteStream]) { - [self startWriteStream]; - } -} - -- (void)handleHandshakeError:(const Status &)error { - HARD_ASSERT(!error.ok(), "Handling write error with status OK."); - // Reset the token if it's a permanent error, signaling the write stream is - // no longer valid. Note that the handshake does not count as a write: see - // comments on `Datastore::IsPermanentWriteError` for details. - if (Datastore::IsPermanentError(error)) { - NSString *token = [_writeStream->GetLastStreamToken() base64EncodedStringWithOptions:0]; - LOG_DEBUG("FSTRemoteStore %s error before completed handshake; resetting stream token %s: " - "error code: '%s', details: '%s'", - (__bridge void *)self, token, error.code(), error.error_message()); - _writeStream->SetLastStreamToken(nil); - [_remoteStore->local_store() setLastStreamToken:nil]; - } else { - // Some other error, don't reset stream token. Our stream logic will just retry with exponential - // backoff. - } -} - -- (void)handleWriteError:(const Status &)error { - HARD_ASSERT(!error.ok(), "Handling write error with status OK."); - // Only handle permanent errors here. If it's transient, just let the retry logic kick in. - if (!Datastore::IsPermanentWriteError(error)) { - return; - } - - // If this was a permanent error, the request itself was the problem so it's not going to - // succeed if we resend it. - FSTMutationBatch *batch = self.writePipeline[0]; - [self.writePipeline removeObjectAtIndex:0]; - - // In this case it's also unlikely that the server itself is melting down--this was just a - // bad request so inhibit backoff on the next restart. - _writeStream->InhibitBackoff(); - - [_remoteStore->sync_engine() rejectFailedWriteWithBatchID:batch.batchID - error:util::MakeNSError(error)]; - - // It's possible that with the completion of this mutation another slot has freed up. - [self fillWritePipeline]; + _remoteStore->FillWritePipeline(); } - (FSTTransaction *)transaction { diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 4d9180fe365..e3e7e5934cb 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -25,6 +25,7 @@ #include #include +#include #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" @@ -38,6 +39,7 @@ #include "Firestore/core/src/firebase/firestore/util/status.h" @class FSTLocalStore; +@class FSTMutationBatch; @class FSTMutationBatchResult; @class FSTQueryData; @@ -151,6 +153,25 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { const model::SnapshotVersion& snapshot_version) override; void OnWatchStreamClose(const util::Status& status) override; + void OnWriteStreamOpen() override; +/** + * Handles the closing of the StreamingWrite RPC, either because of an error or + * because the RPC has been terminated by the client or the server. + */ + void OnWriteStreamClose(const util::Status& status) override; + + /** + * Handles a successful handshake response from the server, which is our cue to + * send any pending writes. + */ + void OnWriteStreamHandshakeComplete() override; + + /** + * Handles a successful StreamingWriteResponse from the server that contains a + * mutation result. + */ + void OnWriteStreamResponse(model::SnapshotVersion commit_version, std::vector mutation_results) override; + // TODO(varconst): make the following methods private. bool CanUseNetwork() const; @@ -165,6 +186,12 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void CleanUpWatchStreamState(); + /** + * Returns true if the network is enabled, the write stream has not yet been + * started and there are pending writes. + */ + bool ShouldStartWriteStream() const; + private: void SendWatchRequest(FSTQueryData* query_data); void SendUnwatchRequest(model::TargetId target_id); @@ -178,6 +205,31 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { /** Process a target error and passes the error along to `SyncEngine`. */ void ProcessTargetError(const WatchTargetChange& change); + /** + * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. + * + * Called internally to bootstrap or refill the write pipeline and by `FSTSyncEngine` + * whenever there are new mutations to process. + * + * Starts the write stream if necessary. + */ + void FillWritePipeline(); + + /** + * Returns true if we can add to the write pipeline (i.e. it is not full and the + * network is enabled). + */ + bool CanAddToWritePipeline() const; + + /** + * Queues additional writes to be sent to the write stream, sending them + * immediately if the write stream is established. + */ + void AddToWritePipeline(FSTMutationBatch* batch); + + void HandleHandshakeError(const util::Status& status); + void HandleWriteError(const util::Status& status); + id sync_engine_ = nil; /** @@ -206,7 +258,27 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { bool is_network_enabled_ = false; std::shared_ptr watch_stream_; + std::shared_ptr write_stream_; std::unique_ptr watch_change_aggregator_; + + /** + * A list of up to `kMaxPendingWrites` writes that we have fetched from the + * `LocalStore` via `FillWritePipeline` and have or will send to the write + * stream. + * + * Whenever `write_pipeline_` is not empty, the `RemoteStore` will attempt to + * start or restart the write stream. When the stream is established, the + * writes in the pipeline will be sent in order. + * + * Writes remain in `write_pipeline_` until they are acknowledged by the + * backend and thus will automatically be re-sent if the stream is interrupted + * / restarted before they're acknowledged. + * + * Write responses from the backend are linked to their originating request + * purely based on order, and so we can just remove writes from the front of + * the `write_pipeline_` as we receive responses. + */ + std::vector write_pipeline_; }; } // namespace remote diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index f40a5e7b31d..6abe0aafd1e 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -48,6 +48,16 @@ namespace firestore { namespace remote { +namespace { + +/** + * The maximum number of pending writes to allow. + * TODO(bjornick): Negotiate this value with the backend. + */ +constexpr int kMaxPendingWrites = 10; + +} // namespace + RemoteStore::RemoteStore( FSTLocalStore* local_store, Datastore* datastore, @@ -57,6 +67,7 @@ online_state_tracker_{worker_queue, std::move(online_state_handler)} { // Create streams (but note they're not started yet) watch_stream_ = datastore->CreateWatchStream(this); + write_stream_ = datastore->CreateWriteStream(this); } void RemoteStore::Listen(FSTQueryData* query_data) { @@ -291,6 +302,169 @@ } } +bool RemoteStore::ShouldStartWriteStream() const { + return CanUseNetwork() && !write_stream_->IsStarted() && + !write_pipeline_.empty(); +} + +void RemoteStore::StartWriteStream() { + HARD_ASSERT(ShouldStartWriteStream() "StartWriteStream called when " + "ShouldStartWriteStream is false."); + write_stream_->Start(); +} + +void RemoteStore::FillWritePipeline() { + BatchId last_batch_id_retrieved = write_pipeline_.empty() + ? kBatchIdUnknown + : write_pipeline_.back().batchID; + while (CanAddToWritePipeline()) { + FSTMutationBatch* batch = + [local_store_ nextMutationBatchAfterBatchID:last_batch_id_retrieved]; + if (!batch) { + if (write_pipeline_.empty()) { + write_stream_->MarkIdle(); + } + break; + } + AddBatchToWritePipeline(batch); + last_batch_id_retrieved = batch.batchID; + } + + if (ShouldStartWriteStream()) { + StartWriteStream(); + } +} + +bool RemoteStore::CanAddToWritePipeline() const { + return CanUseNetwork() && write_pipeline_.size() < kMaxPendingWrites; +} + +void RemoteStore::AddToWritePipeline(FSTMutationBatch* batch) { + HARD_ASSERT(CanAddToWritePipeline(), + "AddToWritePipeline called when pipeline is full"); + + write_pipeline_.push_back(batch); + + if (write_stream_->IsOpen() && write_stream_->handshake_complete()) { + write_stream_->WriteMutations(batch.mutations); + } +} + +void RemoteStore::OnWriteStreamOpen() { + write_stream_->WriteHandshake(); +} + +void RemoteStore::OnWriteStreamHandshakeComplete() { + // Record the stream token. + [local_store_ setLastStreamToken:write_stream_->GetLastStreamToken()]; + + // Send the write pipeline now that the stream is established. + for (FSTMutationBatch* write : write_pipeline_) { + write_stream_->WriteMutations(write.mutations); + } +} + +void RemoteStore::OnWriteStreamResponse( + SnapshotVersion commit_version, + std::vector mutation_results) { + // This is a response to a write containing mutations and should be correlated + // to the first write in our write pipeline. + FSTMutationBatch* batch = write_pipeline_.front(); + write_pipeline_.erase(write_pipeline_.begin()); + + FSTMutationBatchResult* batchResult = [FSTMutationBatchResult + resultWithBatch:batch + commitVersion:commit_version + mutationResults:std::move(mutation_results) + streamToken:write_stream_->GetLastStreamToken()]; + [sync_engine_ applySuccessfulWriteWithResult:batchResult]; + + // It's possible that with the completion of this mutation another slot has + // freed up. + FillWritePipeline(); +} + +/** + * Handles the closing of the StreamingWrite RPC, either because of an error or + * because the RPC has been terminated by the client or the server. + */ + void RemoteStore::OnWriteStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWriteStream(), + "Write stream was stopped gracefully while still needed."); + } + + // If the write stream closed due to an error, invoke the error callbacks if + // there are pending writes. + if (!status.ok() && !write_pipeline_.empty()) { + if (write_stream_->handshake_complete()) { + // This error affects the actual writes. + HandleWriteError(status); + } else { + // If there was an error before the handshake finished, it's possible that + // the server is unable to process the stream token we're sending. + // (Perhaps it's too old?) + HandleHandshakeError(status); + } + } + + // The write stream might have been started by refilling the write pipeline + // for failed writes + if (ShouldStartWriteStream()) { + StartWriteStream(); + } +} + +void RemoteStore::HandleHandshakeError(const Status& status) { + HARD_ASSERT(!error.ok(), "Handling write error with status OK."); + + // Reset the token if it's a permanent error, signaling the write stream is + // no longer valid. Note that the handshake does not count as a write: see + // comments on `Datastore::IsPermanentWriteError` for details. + if (Datastore::IsPermanentError(error)) { + NSString* token = + [write_stream_->GetLastStreamToken() base64EncodedStringWithOptions:0]; + LOG_DEBUG("RemoteStore %s error before completed handshake; resetting " + "stream token %s: " + "error code: '%s', details: '%s'", + (__bridge void*)self, token, error.code(), error.error_message()); + write_stream_->SetLastStreamToken(nil); + [local_store_ setLastStreamToken:nil]; + } else { + // Some other error, don't reset stream token. Our stream logic will just + // retry with exponential backoff. + } +} + +void RemoteStore::HandleWriteError(const Status& status) { + HARD_ASSERT(!error.ok(), "Handling write error with status OK."); + + // Only handle permanent errors here. If it's transient, just let the retry + // logic kick in. + if (!Datastore::IsPermanentWriteError(error)) { + return; + } + + // If this was a permanent error, the request itself was the problem so it's + // not going to succeed if we resend it. + FSTMutationBatch* batch = write_pipeline_.front() + write_pipeline_.erase(write_pipeline_.front()); + + // In this case it's also unlikely that the server itself is melting + // down--this was just a bad request so inhibit backoff on the next restart. + write_stream_->InhibitBackoff(); + + [sync_engine_ + rejectFailedWriteWithBatchID:batch.batchID + error:util::MakeNSError(error)]; + + // It's possible that with the completion of this mutation another slot has + // freed up. + FillWritePipeline(); +} + } // namespace remote } // namespace firestore } // namespace firebase From 5266f7cd8de89ebbf31a0024719a30586ad6ca4c Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 31 Jan 2019 19:19:06 -0500 Subject: [PATCH 094/107] initial cont. --- Firestore/Source/Remote/FSTRemoteStore.mm | 12 ++-- .../firebase/firestore/remote/remote_store.h | 63 +++++++++++-------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 048c5be1c8a..2e49459f4fe 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -75,7 +75,7 @@ #pragma mark - FSTRemoteStore -@interface FSTRemoteStore () +@interface FSTRemoteStore () @implementation FSTRemoteStore { /** The client-side proxy for interacting with the backend. */ @@ -115,7 +115,7 @@ - (void)enableNetwork { if (_remoteStore->CanUseNetwork()) { // Load any saved stream token from persistent storage - _writeStream->SetLastStreamToken([_remoteStore->local_store() lastStreamToken]); + _remoteStore->write_stream().SetLastStreamToken([_remoteStore->local_store() lastStreamToken]); if (_remoteStore->ShouldStartWatchStream()) { _remoteStore->StartWatchStream(); @@ -139,12 +139,12 @@ - (void)disableNetwork { /** Disables the network, setting the OnlineState to the specified targetOnlineState. */ - (void)disableNetworkInternal { _remoteStore->watch_stream().Stop(); - _writeStream->Stop(); + _remoteStore->write_stream().Stop(); - if (self.writePipeline.count > 0) { + if (!_remoteStore->write_pipeline().empty()) { LOG_DEBUG("Stopping write stream with %s pending writes", - (unsigned long)self.writePipeline.count); - [self.writePipeline removeAllObjects]; + _remoteStore->write_pipeline().size()); + _remoteStore->write_pipeline().clear(); } _remoteStore->CleanUpWatchStreamState(); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index e3e7e5934cb..b26cc57f0d8 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -114,6 +114,7 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { std::function online_state_handler); // TODO(varconst): remove the getters and setters + id sync_engine() { return sync_engine_; } @@ -136,6 +137,11 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { WatchStream& watch_stream() { return *watch_stream_; } + WriteStream& write_stream() { + return *write_stream_; + } + + std::vector& write_pipeline() { return write_pipeline_; } /** Listens to the target identified by the given `FSTQueryData`. */ void Listen(FSTQueryData* query_data); @@ -154,23 +160,26 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void OnWatchStreamClose(const util::Status& status) override; void OnWriteStreamOpen() override; -/** - * Handles the closing of the StreamingWrite RPC, either because of an error or - * because the RPC has been terminated by the client or the server. - */ + + /** + * Handles the closing of the StreamingWrite RPC, either because of an error + * or because the RPC has been terminated by the client or the server. + */ void OnWriteStreamClose(const util::Status& status) override; /** - * Handles a successful handshake response from the server, which is our cue to - * send any pending writes. - */ + * Handles a successful handshake response from the server, which is our cue + * to send any pending writes. + */ void OnWriteStreamHandshakeComplete() override; /** * Handles a successful StreamingWriteResponse from the server that contains a * mutation result. */ - void OnWriteStreamResponse(model::SnapshotVersion commit_version, std::vector mutation_results) override; + void OnWriteStreamResponse( + model::SnapshotVersion commit_version, + std::vector mutation_results) override; // TODO(varconst): make the following methods private. @@ -186,12 +195,6 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void CleanUpWatchStreamState(); - /** - * Returns true if the network is enabled, the write stream has not yet been - * started and there are pending writes. - */ - bool ShouldStartWriteStream() const; - private: void SendWatchRequest(FSTQueryData* query_data); void SendUnwatchRequest(model::TargetId target_id); @@ -206,25 +209,31 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void ProcessTargetError(const WatchTargetChange& change); /** - * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. - * - * Called internally to bootstrap or refill the write pipeline and by `FSTSyncEngine` - * whenever there are new mutations to process. - * - * Starts the write stream if necessary. - */ + * Returns true if the network is enabled, the write stream has not yet been + * started and there are pending writes. + */ + bool ShouldStartWriteStream() const; + + /** + * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. + * + * Called internally to bootstrap or refill the write pipeline and by + * `FSTSyncEngine` whenever there are new mutations to process. + * + * Starts the write stream if necessary. + */ void FillWritePipeline(); /** - * Returns true if we can add to the write pipeline (i.e. it is not full and the - * network is enabled). - */ + * Returns true if we can add to the write pipeline (i.e. it is not full and + * the network is enabled). + */ bool CanAddToWritePipeline() const; /** - * Queues additional writes to be sent to the write stream, sending them - * immediately if the write stream is established. - */ + * Queues additional writes to be sent to the write stream, sending them + * immediately if the write stream is established. + */ void AddToWritePipeline(FSTMutationBatch* batch); void HandleHandshakeError(const util::Status& status); From 53f00fc3c5c39504aeb4eadad1dc7b8d2bf16ccb Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 15:27:07 -0500 Subject: [PATCH 095/107] Compiles! --- .../Example/Tests/Local/FSTLocalStoreTests.mm | 2 +- .../Tests/SpecTests/FSTMockDatastore.h | 4 +- .../Tests/SpecTests/FSTMockDatastore.mm | 27 ++++----- .../Example/Tests/SpecTests/FSTSpecTests.mm | 2 +- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 3 +- .../SpecTests/FSTSyncEngineTestDriver.mm | 4 +- Firestore/Source/Model/FSTMutationBatch.h | 5 +- Firestore/Source/Model/FSTMutationBatch.mm | 23 ++++--- Firestore/Source/Remote/FSTRemoteStore.mm | 5 +- Firestore/Source/Remote/FSTStream.h | 60 ------------------- .../src/firebase/firestore/remote/datastore.h | 3 +- .../firebase/firestore/remote/datastore.mm | 4 +- .../firestore/remote/remote_objc_bridge.h | 20 +------ .../firestore/remote/remote_objc_bridge.mm | 31 ++-------- .../firebase/firestore/remote/remote_store.h | 25 ++++---- .../firebase/firestore/remote/remote_store.mm | 30 +++++----- .../firebase/firestore/remote/write_stream.h | 42 ++++++++++++- .../firebase/firestore/remote/write_stream.mm | 12 ++-- 18 files changed, 123 insertions(+), 179 deletions(-) delete mode 100644 Firestore/Source/Remote/FSTStream.h diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 22172c8f959..7b0071bc6bb 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -153,7 +153,7 @@ - (void)acknowledgeMutationWithVersion:(FSTTestSnapshotVersion)documentVersion { transformResults:nil]; FSTMutationBatchResult *result = [FSTMutationBatchResult resultWithBatch:batch commitVersion:version - mutationResults:@[ mutationResult ] + mutationResults:{ mutationResult} streamToken:nil]; _lastChanges = [self.localStore acknowledgeBatchWithResult:result]; } diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h index 59afab20fa1..c4d2a893ca4 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h @@ -40,7 +40,7 @@ class MockDatastore : public Datastore { auth::CredentialsProvider* credentials); std::shared_ptr CreateWatchStream(WatchStreamCallback* callback) override; - std::shared_ptr CreateWriteStream(id delegate) override; + std::shared_ptr CreateWriteStream(WriteStreamCallback* callback) override; /** * A count of the total number of requests sent to the watch stream since the beginning of the @@ -82,7 +82,7 @@ class MockDatastore : public Datastore { int WritesSent() const; /** Injects a write ack as though it had come from the backend in response to a write. */ - void AckWrite(const model::SnapshotVersion& version, NSArray* results); + void AckWrite(const model::SnapshotVersion& version, std::vector results); /** Injects a stream failure as though it had come from the backend. */ void FailWrite(const util::Status& error); diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index 3d7214c246e..8c1d689fe0b 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -25,7 +25,6 @@ #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Remote/FSTStream.h" #include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.h" @@ -161,18 +160,18 @@ void WriteWatchChange(const WatchChange& change, SnapshotVersion snap) { CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate, + WriteStreamCallback* callback, MockDatastore* datastore) - : WriteStream{worker_queue, credentials_provider, serializer, grpc_connection, delegate}, + : WriteStream{worker_queue, credentials_provider, serializer, grpc_connection, callback}, datastore_{datastore}, - delegate_{delegate} { + callback_{callback} { } void Start() override { HARD_ASSERT(!open_, "Trying to start already started write stream"); open_ = true; sent_mutations_ = {}; - [delegate_ writeStreamDidOpen]; + callback_->OnWriteStreamOpen(); } void Stop() override { @@ -194,7 +193,7 @@ bool IsOpen() const override { void WriteHandshake() override { datastore_->IncrementWriteStreamRequests(); SetHandshakeComplete(); - [delegate_ writeStreamDidCompleteHandshake]; + callback_->OnWriteStreamHandshakeComplete(); } void WriteMutations(NSArray* mutations) override { @@ -203,14 +202,14 @@ void WriteMutations(NSArray* mutations) override { } /** Injects a write ack as though it had come from the backend in response to a write. */ - void AckWrite(const SnapshotVersion& commitVersion, NSArray* results) { - [delegate_ writeStreamDidReceiveResponseWithVersion:commitVersion mutationResults:results]; + void AckWrite(const SnapshotVersion& commitVersion, std::vector results) { + callback_->OnWriteStreamResponse(commitVersion, std::move(results)); } /** Injects a failed write response as though it had come from the backend. */ void FailStream(const Status& error) { open_ = false; - [delegate_ writeStreamWasInterruptedWithError:error]; + callback_->OnWriteStreamClose(error); } /** @@ -236,7 +235,7 @@ int sent_mutations_count() const { bool open_ = false; std::queue*> sent_mutations_; MockDatastore* datastore_ = nullptr; - id delegate_ = nullptr; + WriteStreamCallback* callback_ = nullptr; }; MockDatastore::MockDatastore(const core::DatabaseInfo& database_info, @@ -257,11 +256,11 @@ int sent_mutations_count() const { return watch_stream_; } -std::shared_ptr MockDatastore::CreateWriteStream(id delegate) { +std::shared_ptr MockDatastore::CreateWriteStream(WriteStreamCallback* callback) { write_stream_ = std::make_shared( worker_queue_, credentials_, [[FSTSerializerBeta alloc] initWithDatabaseID:&database_info_->database_id()], - grpc_connection(), delegate, this); + grpc_connection(), callback, this); return write_stream_; } @@ -290,8 +289,8 @@ int sent_mutations_count() const { return write_stream_->sent_mutations_count(); } -void MockDatastore::AckWrite(const SnapshotVersion& version, NSArray* results) { - write_stream_->AckWrite(version, results); +void MockDatastore::AckWrite(const SnapshotVersion& version, std::vector results) { + write_stream_->AckWrite(version, std::move(results)); } void MockDatastore::FailWrite(const Status& error) { diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index 266cda72610..d0148727810 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -363,7 +363,7 @@ - (void)doWriteAck:(NSDictionary *)spec { FSTMutationResult *mutationResult = [[FSTMutationResult alloc] initWithVersion:version transformResults:nil]; - [self.driver receiveWriteAckWithVersion:version mutationResults:@[ mutationResult ]]; + [self.driver receiveWriteAckWithVersion:version mutationResults:{ mutationResult}]; } - (void)doFailWrite:(NSDictionary *)spec { diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index b3b2a1d2a5c..12da1d63657 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -18,6 +18,7 @@ #include #include +#include #import "Firestore/Source/Remote/FSTRemoteStore.h" @@ -197,7 +198,7 @@ typedef std::unordered_map *)mutationResults; + mutationResults:(std::vector )mutationResults; /** * A count of the mutations written to the write stream by the FSTSyncEngine, but not yet diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 8d7b7a236da..55acd5fbf2a 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -273,12 +273,12 @@ - (void)changeUser:(const User &)user { - (FSTOutstandingWrite *)receiveWriteAckWithVersion:(const SnapshotVersion &)commitVersion mutationResults: - (NSArray *)mutationResults { + (std::vector)mutationResults { FSTOutstandingWrite *write = [self currentOutstandingWrites].firstObject; [[self currentOutstandingWrites] removeObjectAtIndex:0]; [self validateNextWriteSent:write.write]; - _workerQueue->EnqueueBlocking([&] { _datastore->AckWrite(commitVersion, mutationResults); }); + _workerQueue->EnqueueBlocking([&] { _datastore->AckWrite(commitVersion, std::move(mutationResults)); }); return write; } diff --git a/Firestore/Source/Model/FSTMutationBatch.h b/Firestore/Source/Model/FSTMutationBatch.h index 0aace1d323f..5bbe5a637d5 100644 --- a/Firestore/Source/Model/FSTMutationBatch.h +++ b/Firestore/Source/Model/FSTMutationBatch.h @@ -17,6 +17,7 @@ #import #include +#include #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_key_set.h" @@ -102,13 +103,13 @@ NS_ASSUME_NONNULL_BEGIN */ + (instancetype)resultWithBatch:(FSTMutationBatch *)batch commitVersion:(firebase::firestore::model::SnapshotVersion)commitVersion - mutationResults:(NSArray *)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken; - (const firebase::firestore::model::SnapshotVersion &)commitVersion; +- (const std::vector&) mutationResults; @property(nonatomic, strong, readonly) FSTMutationBatch *batch; -@property(nonatomic, strong, readonly) NSArray *mutationResults; @property(nonatomic, strong, readonly, nullable) NSData *streamToken; - (const firebase::firestore::model::DocumentVersionMap &)docVersions; diff --git a/Firestore/Source/Model/FSTMutationBatch.mm b/Firestore/Source/Model/FSTMutationBatch.mm index aad425f3f62..54b136de792 100644 --- a/Firestore/Source/Model/FSTMutationBatch.mm +++ b/Firestore/Source/Model/FSTMutationBatch.mm @@ -82,9 +82,9 @@ - (FSTMaybeDocument *_Nullable)applyToRemoteDocument:(FSTMaybeDocument *_Nullabl "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), maybeDoc.key.ToString()); - HARD_ASSERT(mutationBatchResult.mutationResults.count == self.mutations.count, + HARD_ASSERT(mutationBatchResult.mutationResults.size() == self.mutations.count, "Mismatch between mutations length (%s) and results length (%s)", - self.mutations.count, mutationBatchResult.mutationResults.count); + self.mutations.count, mutationBatchResult.mutationResults.size()); for (NSUInteger i = 0; i < self.mutations.count; i++) { FSTMutation *mutation = self.mutations[i]; @@ -130,25 +130,26 @@ - (DocumentKeySet)keys { @interface FSTMutationBatchResult () - (instancetype)initWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(NSArray *)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken docVersions:(DocumentVersionMap)docVersions NS_DESIGNATED_INITIALIZER; @end @implementation FSTMutationBatchResult { SnapshotVersion _commitVersion; + std::vector _mutationResults; DocumentVersionMap _docVersions; } - (instancetype)initWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(NSArray *)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken docVersions:(DocumentVersionMap)docVersions { if (self = [super init]) { _batch = batch; _commitVersion = std::move(commitVersion); - _mutationResults = mutationResults; + _mutationResults = std::move(mutationResults); _streamToken = streamToken; _docVersions = std::move(docVersions); } @@ -159,17 +160,21 @@ - (instancetype)initWithBatch:(FSTMutationBatch *)batch return _commitVersion; } +- (const std::vector&)mutationResults { + return _mutationResults; +} + - (const DocumentVersionMap &)docVersions { return _docVersions; } + (instancetype)resultWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(NSArray *)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken { - HARD_ASSERT(batch.mutations.count == mutationResults.count, + HARD_ASSERT(batch.mutations.count == mutationResults.size(), "Mutations sent %s must equal results received %s", batch.mutations.count, - mutationResults.count); + mutationResults.size()); DocumentVersionMap docVersions; NSArray *mutations = batch.mutations; @@ -186,7 +191,7 @@ + (instancetype)resultWithBatch:(FSTMutationBatch *)batch return [[FSTMutationBatchResult alloc] initWithBatch:batch commitVersion:std::move(commitVersion) - mutationResults:mutationResults + mutationResults:std::move(mutationResults) streamToken:streamToken docVersions:std::move(docVersions)]; } diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 2e49459f4fe..c63082aebe8 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -28,7 +28,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Remote/FSTStream.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" @@ -75,8 +74,6 @@ #pragma mark - FSTRemoteStore -@interface FSTRemoteStore () - @implementation FSTRemoteStore { /** The client-side proxy for interacting with the backend. */ std::shared_ptr _datastore; @@ -178,7 +175,7 @@ - (void)credentialDidChange { #pragma mark Watch Stream - (void)listenToTargetWithQueryData:(FSTQueryData *)queryData { - _remoteStore->ListenToTarget(queryData); + _remoteStore->Listen(queryData); } - (void)stopListeningToTargetID:(TargetId)targetID { diff --git a/Firestore/Source/Remote/FSTStream.h b/Firestore/Source/Remote/FSTStream.h deleted file mode 100644 index 211a82154f5..00000000000 --- a/Firestore/Source/Remote/FSTStream.h +++ /dev/null @@ -1,60 +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 - -#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" -#include "Firestore/core/src/firebase/firestore/remote/watch_change.h" -#include "Firestore/core/src/firebase/firestore/util/status.h" - -@class FSTMutationResult; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTWriteStreamDelegate - -@protocol FSTWriteStreamDelegate - -/** Called by the FSTWriteStream when it is ready to accept outbound request messages. */ -- (void)writeStreamDidOpen; - -/** - * Called by the FSTWriteStream upon a successful handshake response from the server, which is the - * receiver's cue to send any pending writes. - */ -- (void)writeStreamDidCompleteHandshake; - -/** - * Called by the FSTWriteStream upon receiving a StreamingWriteResponse from the server that - * contains mutation results. - */ -- (void)writeStreamDidReceiveResponseWithVersion: - (const firebase::firestore::model::SnapshotVersion &)commitVersion - mutationResults:(NSArray *)results; - -/** - * Called when the FSTWriteStream's underlying RPC is interrupted for whatever reason, usually - * because of an error, but possibly due to an idle timeout. The error passed to this method may be - * nil, in which case the stream was closed without attributable fault. - * - * NOTE: This will not be called after `stop` is called on the stream. See "Starting and Stopping" - * on FSTStream for details. - */ -- (void)writeStreamWasInterruptedWithError:(const firebase::firestore::util::Status &)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.h b/Firestore/core/src/firebase/firestore/remote/datastore.h index 9e2268ea571..1c9c592977a 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.h +++ b/Firestore/core/src/firebase/firestore/remote/datastore.h @@ -45,7 +45,6 @@ #include "grpcpp/support/status.h" #import "Firestore/Source/Core/FSTTypes.h" -#import "Firestore/Source/Remote/FSTStream.h" namespace firebase { namespace firestore { @@ -91,7 +90,7 @@ class Datastore : public std::enable_shared_from_this { * shared channel. */ virtual std::shared_ptr CreateWriteStream( - id delegate); + WriteStreamCallback* callback); void CommitMutations(NSArray* mutations, FSTVoidErrorBlock completion); diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.mm b/Firestore/core/src/firebase/firestore/remote/datastore.mm index 1bf2376d8f8..d393f17ad30 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.mm +++ b/Firestore/core/src/firebase/firestore/remote/datastore.mm @@ -158,10 +158,10 @@ void LogGrpcCallFinished(absl::string_view rpc_name, } std::shared_ptr Datastore::CreateWriteStream( - id delegate) { + WriteStreamCallback* callback) { return std::make_shared(worker_queue_, credentials_, serializer_bridge_.GetSerializer(), - &grpc_connection_, delegate); + &grpc_connection_, callback); } void Datastore::CommitMutations(NSArray* mutations, diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h index e5cefba467a..63f23e03781 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h @@ -39,7 +39,6 @@ #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" -#import "Firestore/Source/Remote/FSTStream.h" namespace firebase { namespace firestore { @@ -125,7 +124,7 @@ class WriteStreamSerializer { GCFSWriteResponse* ParseResponse(const grpc::ByteBuffer& message, util::Status* out_status) const; model::SnapshotVersion ToCommitVersion(GCFSWriteResponse* proto) const; - NSArray* ToMutationResults( + std::vector ToMutationResults( GCFSWriteResponse* proto) const; /** Creates a pretty-printed description of the proto for debugging. */ @@ -172,23 +171,6 @@ class DatastoreSerializer { FSTSerializerBeta* serializer_; }; -/** A C++ bridge that invokes methods on an `FSTWriteStreamDelegate`. */ -class WriteStreamDelegate { - public: - explicit WriteStreamDelegate(id delegate) - : delegate_{delegate} { - } - - void NotifyDelegateOnOpen(); - void NotifyDelegateOnHandshakeComplete(); - void NotifyDelegateOnCommit(const model::SnapshotVersion& commit_version, - NSArray* results); - void NotifyDelegateOnClose(const util::Status& status); - - private: - __weak id delegate_; -}; - } // namespace bridge } // namespace remote } // namespace firestore diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm index 406f9199f6d..cccd0e47170 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm @@ -208,16 +208,16 @@ bool IsLoggingEnabled() { return [serializer_ decodedVersion:proto.commitTime]; } -NSArray* WriteStreamSerializer::ToMutationResults( +std::vector WriteStreamSerializer::ToMutationResults( GCFSWriteResponse* response) const { NSMutableArray* responses = response.writeResultsArray; - NSMutableArray* results = - [NSMutableArray arrayWithCapacity:responses.count]; + std::vector results; + results.reserve(responses.count); const model::SnapshotVersion commitVersion = ToCommitVersion(response); for (GCFSWriteResult* proto in responses) { - [results addObject:[serializer_ decodedMutationResult:proto - commitVersion:commitVersion]]; + results.push_back([serializer_ decodedMutationResult:proto + commitVersion:commitVersion]); }; return results; } @@ -300,27 +300,6 @@ bool IsLoggingEnabled() { return [serializer_ decodedMaybeDocumentFromBatch:response]; } -// WriteStreamDelegate - -void WriteStreamDelegate::NotifyDelegateOnOpen() { - [delegate_ writeStreamDidOpen]; -} - -void WriteStreamDelegate::NotifyDelegateOnHandshakeComplete() { - [delegate_ writeStreamDidCompleteHandshake]; -} - -void WriteStreamDelegate::NotifyDelegateOnCommit( - const SnapshotVersion& commit_version, - NSArray* results) { - [delegate_ writeStreamDidReceiveResponseWithVersion:commit_version - mutationResults:results]; -} - -void WriteStreamDelegate::NotifyDelegateOnClose(const Status& status) { - [delegate_ writeStreamWasInterruptedWithError:status]; -} - } // namespace bridge } // namespace remote } // namespace firestore diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index b26cc57f0d8..6a00a091a4e 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -35,6 +35,7 @@ #include "Firestore/core/src/firebase/firestore/remote/remote_event.h" #include "Firestore/core/src/firebase/firestore/remote/watch_change.h" #include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" +#include "Firestore/core/src/firebase/firestore/remote/write_stream.h" #include "Firestore/core/src/firebase/firestore/util/async_queue.h" #include "Firestore/core/src/firebase/firestore/util/status.h" @@ -106,7 +107,7 @@ namespace firebase { namespace firestore { namespace remote { -class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { +class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, public WriteStreamCallback { public: RemoteStore(FSTLocalStore* local_store, Datastore* datastore, @@ -195,6 +196,16 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { void CleanUpWatchStreamState(); + /** + * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. + * + * Called internally to bootstrap or refill the write pipeline and by + * `FSTSyncEngine` whenever there are new mutations to process. + * + * Starts the write stream if necessary. + */ + void FillWritePipeline(); + private: void SendWatchRequest(FSTQueryData* query_data); void SendUnwatchRequest(model::TargetId target_id); @@ -208,22 +219,14 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback { /** Process a target error and passes the error along to `SyncEngine`. */ void ProcessTargetError(const WatchTargetChange& change); + void StartWriteStream(); + /** * Returns true if the network is enabled, the write stream has not yet been * started and there are pending writes. */ bool ShouldStartWriteStream() const; - /** - * Attempts to fill our write pipeline with writes from the `FSTLocalStore`. - * - * Called internally to bootstrap or refill the write pipeline and by - * `FSTSyncEngine` whenever there are new mutations to process. - * - * Starts the write stream if necessary. - */ - void FillWritePipeline(); - /** * Returns true if we can add to the write pipeline (i.e. it is not full and * the network is enabled). diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 6abe0aafd1e..8d3d42414d8 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -20,16 +20,20 @@ #import "Firestore/Source/Local/FSTLocalStore.h" #import "Firestore/Source/Local/FSTQueryData.h" +#import "Firestore/Source/Model/FSTMutationBatch.h" +#include "Firestore/core/src/firebase/firestore/model/mutation_batch.h" #include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" +#include "Firestore/core/src/firebase/firestore/util/log.h" #include "absl/memory/memory.h" +using firebase::firestore::model::BatchId; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::OnlineState; using firebase::firestore::model::SnapshotVersion; -using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::TargetId; +using firebase::firestore::model::kBatchIdUnknown; using firebase::firestore::remote::Datastore; using firebase::firestore::remote::WatchStream; using firebase::firestore::remote::DocumentWatchChange; @@ -48,16 +52,12 @@ namespace firestore { namespace remote { -namespace { - /** * The maximum number of pending writes to allow. * TODO(bjornick): Negotiate this value with the backend. */ constexpr int kMaxPendingWrites = 10; -} // namespace - RemoteStore::RemoteStore( FSTLocalStore* local_store, Datastore* datastore, @@ -308,7 +308,7 @@ } void RemoteStore::StartWriteStream() { - HARD_ASSERT(ShouldStartWriteStream() "StartWriteStream called when " + HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " "ShouldStartWriteStream is false."); write_stream_->Start(); } @@ -326,7 +326,7 @@ } break; } - AddBatchToWritePipeline(batch); + AddToWritePipeline(batch); last_batch_id_retrieved = batch.batchID; } @@ -418,18 +418,18 @@ } void RemoteStore::HandleHandshakeError(const Status& status) { - HARD_ASSERT(!error.ok(), "Handling write error with status OK."); + HARD_ASSERT(!status.ok(), "Handling write error with status OK."); // Reset the token if it's a permanent error, signaling the write stream is // no longer valid. Note that the handshake does not count as a write: see // comments on `Datastore::IsPermanentWriteError` for details. - if (Datastore::IsPermanentError(error)) { + if (Datastore::IsPermanentError(status)) { NSString* token = [write_stream_->GetLastStreamToken() base64EncodedStringWithOptions:0]; LOG_DEBUG("RemoteStore %s error before completed handshake; resetting " "stream token %s: " "error code: '%s', details: '%s'", - (__bridge void*)self, token, error.code(), error.error_message()); + this, token, status.code(), status.error_message()); write_stream_->SetLastStreamToken(nil); [local_store_ setLastStreamToken:nil]; } else { @@ -439,18 +439,18 @@ } void RemoteStore::HandleWriteError(const Status& status) { - HARD_ASSERT(!error.ok(), "Handling write error with status OK."); + HARD_ASSERT(!status.ok(), "Handling write error with status OK."); // Only handle permanent errors here. If it's transient, just let the retry // logic kick in. - if (!Datastore::IsPermanentWriteError(error)) { + if (!Datastore::IsPermanentWriteError(status)) { return; } // If this was a permanent error, the request itself was the problem so it's // not going to succeed if we resend it. - FSTMutationBatch* batch = write_pipeline_.front() - write_pipeline_.erase(write_pipeline_.front()); + FSTMutationBatch* batch = write_pipeline_.front(); + write_pipeline_.erase(write_pipeline_.begin()); // In this case it's also unlikely that the server itself is melting // down--this was just a bad request so inhibit backoff on the next restart. @@ -458,7 +458,7 @@ [sync_engine_ rejectFailedWriteWithBatchID:batch.batchID - error:util::MakeNSError(error)]; + error:util::MakeNSError(status)]; // It's possible that with the completion of this mutation another slot has // freed up. diff --git a/Firestore/core/src/firebase/firestore/remote/write_stream.h b/Firestore/core/src/firebase/firestore/remote/write_stream.h index 8e34e3eac25..6350a5e7405 100644 --- a/Firestore/core/src/firebase/firestore/remote/write_stream.h +++ b/Firestore/core/src/firebase/firestore/remote/write_stream.h @@ -24,7 +24,9 @@ #import #include #include +#include +#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h" #include "Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.h" #include "Firestore/core/src/firebase/firestore/remote/stream.h" @@ -37,10 +39,46 @@ #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" +@class FSTMutationResult; + namespace firebase { namespace firestore { namespace remote { +class WriteStreamCallback { + public: + /** + * Called by the `WriteStream` when it is ready to accept outbound request + * messages. + */ + virtual void OnWriteStreamOpen() = 0; + + /** + * Called by the `WriteStream` upon a successful handshake response from the + * server, which is the receiver's cue to send any pending writes. + */ + virtual void OnWriteStreamHandshakeComplete() = 0; + + /** + * Called by the `WriteStream` upon receiving a StreamingWriteResponse from + * the server that contains mutation results. + */ + virtual void OnWriteStreamResponse( + model::SnapshotVersion commit_version, + std::vector results) = 0; + + /** + * Called when the `WriteStream`'s underlying RPC is interrupted for whatever + * reason, usually because of an error, but possibly due to an idle timeout. + * The status passed to this method may be "ok", in which case the stream was + * closed without attributable fault. + * + * NOTE: This will not be called after `Stop` is called on the stream. See + * "Starting and Stopping" on `Stream` for details. + */ + virtual void OnWriteStreamClose(const util::Status& status) = 0; +}; + /** * A Stream that implements the Write RPC. * @@ -65,7 +103,7 @@ class WriteStream : public Stream { auth::CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate); + WriteStreamCallback* callback); void SetLastStreamToken(NSData* token); /** @@ -115,7 +153,7 @@ class WriteStream : public Stream { } bridge::WriteStreamSerializer serializer_bridge_; - bridge::WriteStreamDelegate delegate_bridge_; + WriteStreamCallback* callback_ = nullptr; bool handshake_complete_ = false; }; diff --git a/Firestore/core/src/firebase/firestore/remote/write_stream.mm b/Firestore/core/src/firebase/firestore/remote/write_stream.mm index 17f46a53e04..044401a38d5 100644 --- a/Firestore/core/src/firebase/firestore/remote/write_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/write_stream.mm @@ -36,11 +36,11 @@ CredentialsProvider* credentials_provider, FSTSerializerBeta* serializer, GrpcConnection* grpc_connection, - id delegate) + WriteStreamCallback* callback) : Stream{async_queue, credentials_provider, grpc_connection, TimerId::WriteStreamConnectionBackoff, TimerId::WriteStreamIdle}, serializer_bridge_{serializer}, - delegate_bridge_{delegate} { + callback_{callback} { } void WriteStream::SetLastStreamToken(NSData* token) { @@ -97,11 +97,11 @@ } void WriteStream::NotifyStreamOpen() { - delegate_bridge_.NotifyDelegateOnOpen(); + callback_->OnWriteStreamOpen(); } void WriteStream::NotifyStreamClose(const Status& status) { - delegate_bridge_.NotifyDelegateOnClose(status); + callback_->OnWriteStreamClose(status); // Delegate's logic might depend on whether handshake was completed, so only // reset it after notifying. handshake_complete_ = false; @@ -124,14 +124,14 @@ if (!handshake_complete()) { // The first response is the handshake response handshake_complete_ = true; - delegate_bridge_.NotifyDelegateOnHandshakeComplete(); + callback_->OnWriteStreamHandshakeComplete(); } else { // A successful first write response means the stream is healthy. // Note that we could consider a successful handshake healthy, however, the // write itself might be causing an error we want to back off from. backoff_.Reset(); - delegate_bridge_.NotifyDelegateOnCommit( + callback_->OnWriteStreamResponse( serializer_bridge_.ToCommitVersion(response), serializer_bridge_.ToMutationResults(response)); } From 1858aaeedb014ce477f6b0a7c91d51e1ede03d20 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 15:47:45 -0500 Subject: [PATCH 096/107] all tests pass --- .../Example/App/GoogleService-Info.plist | 42 ++++++++++++------- .../Firestore_IntegrationTests_iOS.xcscheme | 2 + .../xcschemes/Firestore_Tests_iOS.xcscheme | 1 + Firestore/Source/Remote/FSTRemoteStore.mm | 4 ++ .../firebase/firestore/remote/remote_store.h | 12 +++--- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/Firestore/Example/App/GoogleService-Info.plist b/Firestore/Example/App/GoogleService-Info.plist index 3f7547fb48d..0e35ab4a3d9 100644 --- a/Firestore/Example/App/GoogleService-Info.plist +++ b/Firestore/Example/App/GoogleService-Info.plist @@ -2,27 +2,39 @@ - API_KEY - correct_api_key - TRACKING_ID - correct_tracking_id + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 CLIENT_ID - correct_client_id + 174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11.apps.googleusercontent.com REVERSED_CLIENT_ID - correct_reversed_client_id - GOOGLE_APP_ID - 1:123:ios:123abc + com.googleusercontent.apps.174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11 + API_KEY + AIzaSyB_QJO1AARQzdvEgzb-o8wQ9eag5V8ZVCI GCM_SENDER_ID - correct_gcm_sender_id + 174583568604 PLIST_VERSION 1 BUNDLE_ID - com.google.FirebaseSDKTests + com.firebase.FirestoreExample PROJECT_ID - abc-xyz-123 - DATABASE_URL - https://abc-xyz-123.firebaseio.com + varconst-9 STORAGE_BUCKET - project-id-123.storage.firebase.com + varconst-9.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:174583568604:ios:0459a01df1082630 + DATABASE_URL + https://varconst-9.firebaseio.com - + \ No newline at end of file diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme index 4e6f82845e2..2d22568f77b 100644 --- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme @@ -26,6 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableAddressSanitizer = "YES" + enableASanStackUseAfterReturn = "YES" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index c63082aebe8..9d86bd9ee29 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -196,6 +196,10 @@ - (void)fillWritePipeline { _remoteStore->FillWritePipeline(); } +- (void)addBatchToWritePipeline:(FSTMutationBatch *)batch { + _remoteStore->AddToWritePipeline(batch); +} + - (FSTTransaction *)transaction { return [FSTTransaction transactionWithDatastore:_datastore.get()]; } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 6a00a091a4e..83a210169ae 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -206,6 +206,12 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, p */ void FillWritePipeline(); + /** + * Queues additional writes to be sent to the write stream, sending them + * immediately if the write stream is established. + */ + void AddToWritePipeline(FSTMutationBatch* batch); + private: void SendWatchRequest(FSTQueryData* query_data); void SendUnwatchRequest(model::TargetId target_id); @@ -233,12 +239,6 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, p */ bool CanAddToWritePipeline() const; - /** - * Queues additional writes to be sent to the write stream, sending them - * immediately if the write stream is established. - */ - void AddToWritePipeline(FSTMutationBatch* batch); - void HandleHandshakeError(const util::Status& status); void HandleWriteError(const util::Status& status); From 4589e1f83f87cdb6e464a3696fec07e832b94a02 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 15:49:57 -0500 Subject: [PATCH 097/107] style.sh --- Firestore/Example/Tests/Local/FSTLocalStoreTests.mm | 2 +- Firestore/Example/Tests/SpecTests/FSTMockDatastore.h | 1 + Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm | 3 ++- Firestore/Example/Tests/SpecTests/FSTSpecTests.mm | 2 +- .../Example/Tests/SpecTests/FSTSyncEngineTestDriver.h | 6 +++--- .../Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm | 3 ++- Firestore/Source/Model/FSTMutationBatch.h | 4 ++-- Firestore/Source/Model/FSTMutationBatch.mm | 10 +++++----- .../core/src/firebase/firestore/remote/datastore.mm | 2 +- .../firebase/firestore/remote/remote_objc_bridge.mm | 2 +- .../core/src/firebase/firestore/remote/remote_store.h | 8 ++++++-- .../core/src/firebase/firestore/remote/remote_store.mm | 9 ++++----- 12 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 7b0071bc6bb..026db12ad05 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -153,7 +153,7 @@ - (void)acknowledgeMutationWithVersion:(FSTTestSnapshotVersion)documentVersion { transformResults:nil]; FSTMutationBatchResult *result = [FSTMutationBatchResult resultWithBatch:batch commitVersion:version - mutationResults:{ mutationResult} + mutationResults:{mutationResult} streamToken:nil]; _lastChanges = [self.localStore acknowledgeBatchWithResult:result]; } diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h index c4d2a893ca4..c9555cd9455 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.h @@ -18,6 +18,7 @@ #include #include +#include #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h" #include "Firestore/core/src/firebase/firestore/model/types.h" diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index 8c1d689fe0b..34c3d10295b 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -289,7 +289,8 @@ int sent_mutations_count() const { return write_stream_->sent_mutations_count(); } -void MockDatastore::AckWrite(const SnapshotVersion& version, std::vector results) { +void MockDatastore::AckWrite(const SnapshotVersion& version, + std::vector results) { write_stream_->AckWrite(version, std::move(results)); } diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index d0148727810..24f0fd4a7ee 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -363,7 +363,7 @@ - (void)doWriteAck:(NSDictionary *)spec { FSTMutationResult *mutationResult = [[FSTMutationResult alloc] initWithVersion:version transformResults:nil]; - [self.driver receiveWriteAckWithVersion:version mutationResults:{ mutationResult}]; + [self.driver receiveWriteAckWithVersion:version mutationResults:{mutationResult}]; } - (void)doFailWrite:(NSDictionary *)spec { diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 12da1d63657..780291a7888 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -196,9 +196,9 @@ typedef std::unordered_map )mutationResults; +- (FSTOutstandingWrite *) + receiveWriteAckWithVersion:(const firebase::firestore::model::SnapshotVersion &)commitVersion + mutationResults:(std::vector)mutationResults; /** * A count of the mutations written to the write stream by the FSTSyncEngine, but not yet diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 55acd5fbf2a..7554689ba6b 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -278,7 +278,8 @@ - (FSTOutstandingWrite *)receiveWriteAckWithVersion:(const SnapshotVersion &)com [[self currentOutstandingWrites] removeObjectAtIndex:0]; [self validateNextWriteSent:write.write]; - _workerQueue->EnqueueBlocking([&] { _datastore->AckWrite(commitVersion, std::move(mutationResults)); }); + _workerQueue->EnqueueBlocking( + [&] { _datastore->AckWrite(commitVersion, std::move(mutationResults)); }); return write; } diff --git a/Firestore/Source/Model/FSTMutationBatch.h b/Firestore/Source/Model/FSTMutationBatch.h index 5bbe5a637d5..ac8212db47a 100644 --- a/Firestore/Source/Model/FSTMutationBatch.h +++ b/Firestore/Source/Model/FSTMutationBatch.h @@ -103,11 +103,11 @@ NS_ASSUME_NONNULL_BEGIN */ + (instancetype)resultWithBatch:(FSTMutationBatch *)batch commitVersion:(firebase::firestore::model::SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken; - (const firebase::firestore::model::SnapshotVersion &)commitVersion; -- (const std::vector&) mutationResults; +- (const std::vector &)mutationResults; @property(nonatomic, strong, readonly) FSTMutationBatch *batch; @property(nonatomic, strong, readonly, nullable) NSData *streamToken; diff --git a/Firestore/Source/Model/FSTMutationBatch.mm b/Firestore/Source/Model/FSTMutationBatch.mm index 54b136de792..c76c5e3fd2f 100644 --- a/Firestore/Source/Model/FSTMutationBatch.mm +++ b/Firestore/Source/Model/FSTMutationBatch.mm @@ -130,20 +130,20 @@ - (DocumentKeySet)keys { @interface FSTMutationBatchResult () - (instancetype)initWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken docVersions:(DocumentVersionMap)docVersions NS_DESIGNATED_INITIALIZER; @end @implementation FSTMutationBatchResult { SnapshotVersion _commitVersion; - std::vector _mutationResults; + std::vector _mutationResults; DocumentVersionMap _docVersions; } - (instancetype)initWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken docVersions:(DocumentVersionMap)docVersions { if (self = [super init]) { @@ -160,7 +160,7 @@ - (instancetype)initWithBatch:(FSTMutationBatch *)batch return _commitVersion; } -- (const std::vector&)mutationResults { +- (const std::vector &)mutationResults { return _mutationResults; } @@ -170,7 +170,7 @@ - (instancetype)initWithBatch:(FSTMutationBatch *)batch + (instancetype)resultWithBatch:(FSTMutationBatch *)batch commitVersion:(SnapshotVersion)commitVersion - mutationResults:(std::vector)mutationResults + mutationResults:(std::vector)mutationResults streamToken:(nullable NSData *)streamToken { HARD_ASSERT(batch.mutations.count == mutationResults.size(), "Mutations sent %s must equal results received %s", batch.mutations.count, diff --git a/Firestore/core/src/firebase/firestore/remote/datastore.mm b/Firestore/core/src/firebase/firestore/remote/datastore.mm index d393f17ad30..d7f955abed8 100644 --- a/Firestore/core/src/firebase/firestore/remote/datastore.mm +++ b/Firestore/core/src/firebase/firestore/remote/datastore.mm @@ -158,7 +158,7 @@ void LogGrpcCallFinished(absl::string_view rpc_name, } std::shared_ptr Datastore::CreateWriteStream( - WriteStreamCallback* callback) { + WriteStreamCallback* callback) { return std::make_shared(worker_queue_, credentials_, serializer_bridge_.GetSerializer(), &grpc_connection_, callback); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm index cccd0e47170..c2f0882b807 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_objc_bridge.mm @@ -217,7 +217,7 @@ bool IsLoggingEnabled() { const model::SnapshotVersion commitVersion = ToCommitVersion(response); for (GCFSWriteResult* proto in responses) { results.push_back([serializer_ decodedMutationResult:proto - commitVersion:commitVersion]); + commitVersion:commitVersion]); }; return results; } diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index 83a210169ae..e3b64e2c317 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -107,7 +107,9 @@ namespace firebase { namespace firestore { namespace remote { -class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, public WriteStreamCallback { +class RemoteStore : public TargetMetadataProvider, + public WatchStreamCallback, + public WriteStreamCallback { public: RemoteStore(FSTLocalStore* local_store, Datastore* datastore, @@ -142,7 +144,9 @@ class RemoteStore : public TargetMetadataProvider, public WatchStreamCallback, p return *write_stream_; } - std::vector& write_pipeline() { return write_pipeline_; } + std::vector& write_pipeline() { + return write_pipeline_; + } /** Listens to the target identified by the given `FSTQueryData`. */ void Listen(FSTQueryData* query_data); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 8d3d42414d8..6b433775cfd 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -309,7 +309,7 @@ void RemoteStore::StartWriteStream() { HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " - "ShouldStartWriteStream is false."); + "ShouldStartWriteStream is false."); write_stream_->Start(); } @@ -388,7 +388,7 @@ * Handles the closing of the StreamingWrite RPC, either because of an error or * because the RPC has been terminated by the client or the server. */ - void RemoteStore::OnWriteStreamClose(const Status& status) { +void RemoteStore::OnWriteStreamClose(const Status& status) { if (status.ok()) { // Graceful stop (due to Stop() or idle timeout). Make sure that's // desirable. @@ -456,9 +456,8 @@ // down--this was just a bad request so inhibit backoff on the next restart. write_stream_->InhibitBackoff(); - [sync_engine_ - rejectFailedWriteWithBatchID:batch.batchID - error:util::MakeNSError(status)]; + [sync_engine_ rejectFailedWriteWithBatchID:batch.batchID + error:util::MakeNSError(status)]; // It's possible that with the completion of this mutation another slot has // freed up. From 28e068941f70df43c17ec11b8432e508c056b144 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 16:10:00 -0500 Subject: [PATCH 098/107] android method order --- .../firebase/firestore/remote/remote_store.h | 24 ++-- .../firebase/firestore/remote/remote_store.mm | 113 +++++++++--------- 2 files changed, 70 insertions(+), 67 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index e3b64e2c317..a3ff706ddeb 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -166,18 +166,18 @@ class RemoteStore : public TargetMetadataProvider, void OnWriteStreamOpen() override; - /** - * Handles the closing of the StreamingWrite RPC, either because of an error - * or because the RPC has been terminated by the client or the server. - */ - void OnWriteStreamClose(const util::Status& status) override; - /** * Handles a successful handshake response from the server, which is our cue * to send any pending writes. */ void OnWriteStreamHandshakeComplete() override; + /** + * Handles the closing of the StreamingWrite RPC, either because of an error + * or because the RPC has been terminated by the client or the server. + */ + void OnWriteStreamClose(const util::Status& status) override; + /** * Handles a successful StreamingWriteResponse from the server that contains a * mutation result. @@ -229,6 +229,12 @@ class RemoteStore : public TargetMetadataProvider, /** Process a target error and passes the error along to `SyncEngine`. */ void ProcessTargetError(const WatchTargetChange& change); + /** + * Returns true if we can add to the write pipeline (i.e. it is not full and + * the network is enabled). + */ + bool CanAddToWritePipeline() const; + void StartWriteStream(); /** @@ -237,12 +243,6 @@ class RemoteStore : public TargetMetadataProvider, */ bool ShouldStartWriteStream() const; - /** - * Returns true if we can add to the write pipeline (i.e. it is not full and - * the network is enabled). - */ - bool CanAddToWritePipeline() const; - void HandleHandshakeError(const util::Status& status); void HandleWriteError(const util::Status& status); diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 6b433775cfd..23b722addca 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -70,6 +70,8 @@ write_stream_ = datastore->CreateWriteStream(this); } +// Watch Stream + void RemoteStore::Listen(FSTQueryData* query_data) { TargetId targetKey = query_data.targetID; HARD_ASSERT(listen_targets_.find(targetKey) == listen_targets_.end(), @@ -107,15 +109,6 @@ } } -FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { - auto found = listen_targets_.find(target_id); - return found != listen_targets_.end() ? found->second : nil; -} - -DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { - return [sync_engine_ remoteKeysForTarget:target_id]; -} - void RemoteStore::SendWatchRequest(FSTQueryData* query_data) { // We need to increment the the expected number of pending responses we're due // from watch so we wait for the ack to process any messages from this target. @@ -131,13 +124,9 @@ watch_stream_->UnwatchTargetId(target_id); } -void RemoteStore::StartWatchStream() { - HARD_ASSERT(ShouldStartWatchStream(), - "StartWatchStream called when ShouldStartWatchStream is false."); - watch_change_aggregator_ = absl::make_unique(this); - watch_stream_->Start(); - - online_state_tracker_.HandleWatchStreamStart(); +bool RemoteStore::ShouldStartWriteStream() const { + return CanUseNetwork() && !write_stream_->IsStarted() && + !write_pipeline_.empty(); } bool RemoteStore::ShouldStartWatchStream() const { @@ -145,16 +134,19 @@ !listen_targets_.empty(); } -bool RemoteStore::CanUseNetwork() const { - // PORTING NOTE: This method exists mostly because web also has to take into - // account primary vs. secondary state. - return is_network_enabled_; -} - void RemoteStore::CleanUpWatchStreamState() { watch_change_aggregator_.reset(); } +void RemoteStore::StartWatchStream() { + HARD_ASSERT(ShouldStartWatchStream(), + "StartWatchStream called when ShouldStartWatchStream is false."); + watch_change_aggregator_ = absl::make_unique(this); + watch_stream_->Start(); + + online_state_tracker_.HandleWatchStreamStart(); +} + void RemoteStore::OnWatchStreamOpen() { // Restore any existing watches. for (const auto& kv : listen_targets_) { @@ -162,29 +154,6 @@ } } -void RemoteStore::OnWatchStreamClose(const Status& status) { - if (status.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's - // desirable. - HARD_ASSERT(!ShouldStartWatchStream(), - "Watch stream was stopped gracefully while still needed."); - } - - CleanUpWatchStreamState(); - - // If we still need the watch stream, retry the connection. - if (ShouldStartWatchStream()) { - online_state_tracker_.HandleWatchStreamFailure(status); - - StartWatchStream(); - } else { - // We don't need to restart the watch stream because there are no active - // targets. The online state is set to unknown because there is no active - // attempt at establishing a connection. - online_state_tracker_.UpdateState(OnlineState::Unknown); - } -} - void RemoteStore::OnWatchStreamChange(const WatchChange& change, const SnapshotVersion& snapshot_version) { // Mark the connection as Online because we got a message from the server. @@ -220,6 +189,34 @@ } } +void RemoteStore::OnWatchStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWatchStream(), + "Watch stream was stopped gracefully while still needed."); + } + + CleanUpWatchStreamState(); + + // If we still need the watch stream, retry the connection. + if (ShouldStartWatchStream()) { + online_state_tracker_.HandleWatchStreamFailure(status); + + StartWatchStream(); + } else { + // We don't need to restart the watch stream because there are no active + // targets. The online state is set to unknown because there is no active + // attempt at establishing a connection. + online_state_tracker_.UpdateState(OnlineState::Unknown); + } +} + +bool RemoteStore::CanUseNetwork() const { + // PORTING NOTE: This method exists mostly because web also has to take into + // account primary vs. secondary state. + return is_network_enabled_; +} void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { HARD_ASSERT(snapshot_version != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); @@ -302,16 +299,7 @@ } } -bool RemoteStore::ShouldStartWriteStream() const { - return CanUseNetwork() && !write_stream_->IsStarted() && - !write_pipeline_.empty(); -} - -void RemoteStore::StartWriteStream() { - HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " - "ShouldStartWriteStream is false."); - write_stream_->Start(); -} +// Write Stream void RemoteStore::FillWritePipeline() { BatchId last_batch_id_retrieved = write_pipeline_.empty() @@ -350,6 +338,12 @@ } } +void RemoteStore::StartWriteStream() { + HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " + "ShouldStartWriteStream is false."); + write_stream_->Start(); +} + void RemoteStore::OnWriteStreamOpen() { write_stream_->WriteHandshake(); } @@ -464,6 +458,15 @@ FillWritePipeline(); } +DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { + return [sync_engine_ remoteKeysForTarget:target_id]; +} + +FSTQueryData* RemoteStore::GetQueryDataForTarget(TargetId target_id) const { + auto found = listen_targets_.find(target_id); + return found != listen_targets_.end() ? found->second : nil; +} + } // namespace remote } // namespace firestore } // namespace firebase From c803f6143a140387d9883d2ea887643b737fe520 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 16:22:40 -0500 Subject: [PATCH 099/107] web method order --- .../firebase/firestore/remote/remote_store.mm | 77 ++++++++++--------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 23b722addca..54d41fe10f0 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -124,20 +124,11 @@ watch_stream_->UnwatchTargetId(target_id); } -bool RemoteStore::ShouldStartWriteStream() const { - return CanUseNetwork() && !write_stream_->IsStarted() && - !write_pipeline_.empty(); -} - bool RemoteStore::ShouldStartWatchStream() const { return CanUseNetwork() && !watch_stream_->IsStarted() && !listen_targets_.empty(); } -void RemoteStore::CleanUpWatchStreamState() { - watch_change_aggregator_.reset(); -} - void RemoteStore::StartWatchStream() { HARD_ASSERT(ShouldStartWatchStream(), "StartWatchStream called when ShouldStartWatchStream is false."); @@ -147,6 +138,10 @@ online_state_tracker_.HandleWatchStreamStart(); } +void RemoteStore::CleanUpWatchStreamState() { + watch_change_aggregator_.reset(); +} + void RemoteStore::OnWatchStreamOpen() { // Restore any existing watches. for (const auto& kv : listen_targets_) { @@ -154,6 +149,29 @@ } } +void RemoteStore::OnWatchStreamClose(const Status& status) { + if (status.ok()) { + // Graceful stop (due to Stop() or idle timeout). Make sure that's + // desirable. + HARD_ASSERT(!ShouldStartWatchStream(), + "Watch stream was stopped gracefully while still needed."); + } + + CleanUpWatchStreamState(); + + // If we still need the watch stream, retry the connection. + if (ShouldStartWatchStream()) { + online_state_tracker_.HandleWatchStreamFailure(status); + + StartWatchStream(); + } else { + // We don't need to restart the watch stream because there are no active + // targets. The online state is set to unknown because there is no active + // attempt at establishing a connection. + online_state_tracker_.UpdateState(OnlineState::Unknown); + } +} + void RemoteStore::OnWatchStreamChange(const WatchChange& change, const SnapshotVersion& snapshot_version) { // Mark the connection as Online because we got a message from the server. @@ -189,34 +207,6 @@ } } -void RemoteStore::OnWatchStreamClose(const Status& status) { - if (status.ok()) { - // Graceful stop (due to Stop() or idle timeout). Make sure that's - // desirable. - HARD_ASSERT(!ShouldStartWatchStream(), - "Watch stream was stopped gracefully while still needed."); - } - - CleanUpWatchStreamState(); - - // If we still need the watch stream, retry the connection. - if (ShouldStartWatchStream()) { - online_state_tracker_.HandleWatchStreamFailure(status); - - StartWatchStream(); - } else { - // We don't need to restart the watch stream because there are no active - // targets. The online state is set to unknown because there is no active - // attempt at establishing a connection. - online_state_tracker_.UpdateState(OnlineState::Unknown); - } -} - -bool RemoteStore::CanUseNetwork() const { - // PORTING NOTE: This method exists mostly because web also has to take into - // account primary vs. secondary state. - return is_network_enabled_; -} void RemoteStore::RaiseWatchSnapshot(const SnapshotVersion& snapshot_version) { HARD_ASSERT(snapshot_version != SnapshotVersion::None(), "Can't raise event for unknown SnapshotVersion"); @@ -338,6 +328,11 @@ } } +bool RemoteStore::ShouldStartWriteStream() const { + return CanUseNetwork() && !write_stream_->IsStarted() && + !write_pipeline_.empty(); +} + void RemoteStore::StartWriteStream() { HARD_ASSERT(ShouldStartWriteStream(), "StartWriteStream called when " "ShouldStartWriteStream is false."); @@ -363,6 +358,8 @@ std::vector mutation_results) { // This is a response to a write containing mutations and should be correlated // to the first write in our write pipeline. + HARD_ASSERT(!write_pipeline_.empty(), "Got result for empty write pipeline"); + FSTMutationBatch* batch = write_pipeline_.front(); write_pipeline_.erase(write_pipeline_.begin()); @@ -458,6 +455,12 @@ FillWritePipeline(); } +bool RemoteStore::CanUseNetwork() const { + // PORTING NOTE: This method exists mostly because web also has to take into + // account primary vs. secondary state. + return is_network_enabled_; +} + DocumentKeySet RemoteStore::GetRemoteKeysForTarget(TargetId target_id) const { return [sync_engine_ remoteKeysForTarget:target_id]; } From aa18e6c25d4b6061586c0891f4f17d8fda2c7faf Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 16:25:27 -0500 Subject: [PATCH 100/107] rename --- Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm | 2 +- Firestore/core/src/firebase/firestore/remote/remote_store.h | 2 +- Firestore/core/src/firebase/firestore/remote/remote_store.mm | 2 +- Firestore/core/src/firebase/firestore/remote/write_stream.h | 2 +- Firestore/core/src/firebase/firestore/remote/write_stream.mm | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm index 34c3d10295b..49bf0b71375 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMockDatastore.mm @@ -203,7 +203,7 @@ void WriteMutations(NSArray* mutations) override { /** Injects a write ack as though it had come from the backend in response to a write. */ void AckWrite(const SnapshotVersion& commitVersion, std::vector results) { - callback_->OnWriteStreamResponse(commitVersion, std::move(results)); + callback_->OnWriteStreamMutationResult(commitVersion, std::move(results)); } /** Injects a failed write response as though it had come from the backend. */ diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index a3ff706ddeb..a778209ee02 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -182,7 +182,7 @@ class RemoteStore : public TargetMetadataProvider, * Handles a successful StreamingWriteResponse from the server that contains a * mutation result. */ - void OnWriteStreamResponse( + void OnWriteStreamMutationResult( model::SnapshotVersion commit_version, std::vector mutation_results) override; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 54d41fe10f0..5782f6af9cc 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -353,7 +353,7 @@ } } -void RemoteStore::OnWriteStreamResponse( +void RemoteStore::OnWriteStreamMutationResult( SnapshotVersion commit_version, std::vector mutation_results) { // This is a response to a write containing mutations and should be correlated diff --git a/Firestore/core/src/firebase/firestore/remote/write_stream.h b/Firestore/core/src/firebase/firestore/remote/write_stream.h index 6350a5e7405..8e85bcf1693 100644 --- a/Firestore/core/src/firebase/firestore/remote/write_stream.h +++ b/Firestore/core/src/firebase/firestore/remote/write_stream.h @@ -63,7 +63,7 @@ class WriteStreamCallback { * Called by the `WriteStream` upon receiving a StreamingWriteResponse from * the server that contains mutation results. */ - virtual void OnWriteStreamResponse( + virtual void OnWriteStreamMutationResult( model::SnapshotVersion commit_version, std::vector results) = 0; diff --git a/Firestore/core/src/firebase/firestore/remote/write_stream.mm b/Firestore/core/src/firebase/firestore/remote/write_stream.mm index 044401a38d5..8112742d5cd 100644 --- a/Firestore/core/src/firebase/firestore/remote/write_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/write_stream.mm @@ -131,7 +131,7 @@ // write itself might be causing an error we want to back off from. backoff_.Reset(); - callback_->OnWriteStreamResponse( + callback_->OnWriteStreamMutationResult( serializer_bridge_.ToCommitVersion(response), serializer_bridge_.ToMutationResults(response)); } From ce0d114fe57e4f5a0f3a9e89024cfa2b37556d17 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 16:27:45 -0500 Subject: [PATCH 101/107] undo --- .../Example/App/GoogleService-Info.plist | 42 +++++++------------ .../Firestore_IntegrationTests_iOS.xcscheme | 2 - .../xcschemes/Firestore_Tests_iOS.xcscheme | 1 - 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/Firestore/Example/App/GoogleService-Info.plist b/Firestore/Example/App/GoogleService-Info.plist index 0e35ab4a3d9..3f7547fb48d 100644 --- a/Firestore/Example/App/GoogleService-Info.plist +++ b/Firestore/Example/App/GoogleService-Info.plist @@ -2,39 +2,27 @@ - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-3940256099942544/2934735716 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-3940256099942544/4411468910 + API_KEY + correct_api_key + TRACKING_ID + correct_tracking_id CLIENT_ID - 174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11.apps.googleusercontent.com + correct_client_id REVERSED_CLIENT_ID - com.googleusercontent.apps.174583568604-o3a9bvdn9m31fcqcqha0svo555ekqh11 - API_KEY - AIzaSyB_QJO1AARQzdvEgzb-o8wQ9eag5V8ZVCI + correct_reversed_client_id + GOOGLE_APP_ID + 1:123:ios:123abc GCM_SENDER_ID - 174583568604 + correct_gcm_sender_id PLIST_VERSION 1 BUNDLE_ID - com.firebase.FirestoreExample + com.google.FirebaseSDKTests PROJECT_ID - varconst-9 - STORAGE_BUCKET - varconst-9.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:174583568604:ios:0459a01df1082630 + abc-xyz-123 DATABASE_URL - https://varconst-9.firebaseio.com + https://abc-xyz-123.firebaseio.com + STORAGE_BUCKET + project-id-123.storage.firebase.com - \ No newline at end of file + diff --git a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme index 2d22568f77b..4e6f82845e2 100644 --- a/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme +++ b/Firestore/Example/Firestore.xcodeproj/xcshareddata/xcschemes/Firestore_IntegrationTests_iOS.xcscheme @@ -26,8 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - enableAddressSanitizer = "YES" - enableASanStackUseAfterReturn = "YES" shouldUseLaunchSchemeArgsEnv = "YES"> From 318debc166157f264f6baa4499ccc8078f86352d Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 18:10:42 -0500 Subject: [PATCH 102/107] Review feedback --- Firestore/core/src/firebase/firestore/remote/remote_event.h | 4 +--- Firestore/core/src/firebase/firestore/remote/remote_event.mm | 5 +++++ Firestore/core/src/firebase/firestore/remote/watch_stream.mm | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.h b/Firestore/core/src/firebase/firestore/remote/remote_event.h index dec0dba59ac..8a1fc4ce066 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.h @@ -311,9 +311,7 @@ class RemoteEvent { class WatchChangeAggregator { public: explicit WatchChangeAggregator( - TargetMetadataProvider* target_metadata_provider) - : target_metadata_provider_{target_metadata_provider} { - } + TargetMetadataProvider* target_metadata_provider); /** * Processes and adds the `DocumentWatchChange` to the current set of changes. diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 2a583b2d100..1864cb86484 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -114,6 +114,11 @@ // WatchChangeAggregator +WatchChangeAggregator::WatchChangeAggregator( + TargetMetadataProvider* target_metadata_provider) + : target_metadata_provider_{NOT_NULL(target_metadata_provider)} { + } + void WatchChangeAggregator::HandleDocumentChange( const DocumentWatchChange& document_change) { for (TargetId target_id : document_change.updated_target_ids()) { diff --git a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm index c55abf8e3aa..0066809fae3 100644 --- a/Firestore/core/src/firebase/firestore/remote/watch_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/watch_stream.mm @@ -16,6 +16,7 @@ #include "Firestore/core/src/firebase/firestore/remote/watch_stream.h" +#include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/status.h" @@ -40,7 +41,7 @@ : Stream{async_queue, credentials_provider, grpc_connection, TimerId::ListenStreamConnectionBackoff, TimerId::ListenStreamIdle}, serializer_bridge_{serializer}, - callback_{callback} { + callback_{NOT_NULL(callback)} { } void WatchStream::WatchQuery(FSTQueryData* query) { From 924b4553b099ba71578e07eb6ab759402f15ed62 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 18:11:27 -0500 Subject: [PATCH 103/107] Review feedback --- Firestore/core/src/firebase/firestore/remote/write_stream.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firestore/core/src/firebase/firestore/remote/write_stream.mm b/Firestore/core/src/firebase/firestore/remote/write_stream.mm index 8112742d5cd..db778509fda 100644 --- a/Firestore/core/src/firebase/firestore/remote/write_stream.mm +++ b/Firestore/core/src/firebase/firestore/remote/write_stream.mm @@ -40,7 +40,7 @@ : Stream{async_queue, credentials_provider, grpc_connection, TimerId::WriteStreamConnectionBackoff, TimerId::WriteStreamIdle}, serializer_bridge_{serializer}, - callback_{callback} { + callback_{NOT_NULL(callback)} { } void WriteStream::SetLastStreamToken(NSData* token) { From af88702dacbd6c08ca748e6458fbd1c225faced1 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 18:56:54 -0500 Subject: [PATCH 104/107] style.sh --- .../core/src/firebase/firestore/remote/remote_event.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_event.mm b/Firestore/core/src/firebase/firestore/remote/remote_event.mm index 1864cb86484..65bb82b0339 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_event.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_event.mm @@ -115,9 +115,9 @@ // WatchChangeAggregator WatchChangeAggregator::WatchChangeAggregator( - TargetMetadataProvider* target_metadata_provider) - : target_metadata_provider_{NOT_NULL(target_metadata_provider)} { - } + TargetMetadataProvider* target_metadata_provider) + : target_metadata_provider_{NOT_NULL(target_metadata_provider)} { +} void WatchChangeAggregator::HandleDocumentChange( const DocumentWatchChange& document_change) { From 33da7537744a3d1618d0e2589a6f0465a645424f Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 1 Feb 2019 19:08:33 -0500 Subject: [PATCH 105/107] fix weird bug --- Firestore/Example/Tests/Integration/FSTDatastoreTests.mm | 2 +- Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index f057cb5deab..ec43e8ba7eb 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -219,7 +219,7 @@ - (void)testStreamingWrite { FSTRemoteStoreEventCapture *capture = [[FSTRemoteStoreEventCapture alloc] initWithTestCase:self]; [capture expectWriteEventWithDescription:@"write mutations"]; - _remoteStore.syncEngine = capture; + [_remoteStore setSyncEngine:capture]; FSTSetMutation *mutation = [self setMutation]; FSTMutationBatch *batch = [[FSTMutationBatch alloc] initWithBatchID:23 diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 8d7b7a236da..299f15703db 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -165,7 +165,7 @@ - (instancetype)initWithPersistence:(id)persistence _syncEngine = [[FSTSyncEngine alloc] initWithLocalStore:_localStore remoteStore:_remoteStore initialUser:initialUser]; - _remoteStore.syncEngine = _syncEngine; + [_remoteStore setSyncEngine:_syncEngine]; _eventManager = [FSTEventManager eventManagerWithSyncEngine:_syncEngine]; // Set up internal event tracking for the spec tests. From 217a47fbbf5a56e31f7fa0c67f72862e5aea9dce Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 6 Feb 2019 19:16:46 -0500 Subject: [PATCH 106/107] Review feedback --- .../src/firebase/firestore/remote/remote_store.h | 15 --------------- .../src/firebase/firestore/remote/remote_store.mm | 7 ++----- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.h b/Firestore/core/src/firebase/firestore/remote/remote_store.h index a778209ee02..6d0d0bfcf6f 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.h +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.h @@ -165,23 +165,8 @@ class RemoteStore : public TargetMetadataProvider, void OnWatchStreamClose(const util::Status& status) override; void OnWriteStreamOpen() override; - - /** - * Handles a successful handshake response from the server, which is our cue - * to send any pending writes. - */ void OnWriteStreamHandshakeComplete() override; - - /** - * Handles the closing of the StreamingWrite RPC, either because of an error - * or because the RPC has been terminated by the client or the server. - */ void OnWriteStreamClose(const util::Status& status) override; - - /** - * Handles a successful StreamingWriteResponse from the server that contains a - * mutation result. - */ void OnWriteStreamMutationResult( model::SnapshotVersion commit_version, std::vector mutation_results) override; diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 5782f6af9cc..53c672fd7ec 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -54,7 +54,7 @@ /** * The maximum number of pending writes to allow. - * TODO(bjornick): Negotiate this value with the backend. + * TODO(b/35853402): Negotiate this value with the backend. */ constexpr int kMaxPendingWrites = 10; @@ -375,10 +375,6 @@ FillWritePipeline(); } -/** - * Handles the closing of the StreamingWrite RPC, either because of an error or - * because the RPC has been terminated by the client or the server. - */ void RemoteStore::OnWriteStreamClose(const Status& status) { if (status.ok()) { // Graceful stop (due to Stop() or idle timeout). Make sure that's @@ -390,6 +386,7 @@ // If the write stream closed due to an error, invoke the error callbacks if // there are pending writes. if (!status.ok() && !write_pipeline_.empty()) { + // TODO: handle UNAUTHENTICATED status, see go/firestore-client-errors if (write_stream_->handshake_complete()) { // This error affects the actual writes. HandleWriteError(status); From fa1082ea5e72a44f12958b2027e6507cb487c1f7 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 6 Feb 2019 19:54:29 -0500 Subject: [PATCH 107/107] Fix --- Firestore/core/src/firebase/firestore/remote/remote_store.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Firestore/core/src/firebase/firestore/remote/remote_store.mm b/Firestore/core/src/firebase/firestore/remote/remote_store.mm index 53c672fd7ec..3779086aeba 100644 --- a/Firestore/core/src/firebase/firestore/remote/remote_store.mm +++ b/Firestore/core/src/firebase/firestore/remote/remote_store.mm @@ -386,7 +386,8 @@ // If the write stream closed due to an error, invoke the error callbacks if // there are pending writes. if (!status.ok() && !write_pipeline_.empty()) { - // TODO: handle UNAUTHENTICATED status, see go/firestore-client-errors + // TODO(varconst): handle UNAUTHENTICATED status, see + // go/firestore-client-errors if (write_stream_->handshake_complete()) { // This error affects the actual writes. HandleWriteError(status);