From fd33c967896a5d82805cb9c286f155fd3cac78a1 Mon Sep 17 00:00:00 2001 From: Greg Soltis Date: Mon, 10 Dec 2018 14:35:52 -0800 Subject: [PATCH 1/4] Port Memory remote document cache to C++ --- .../Local/FSTMemoryRemoteDocumentCache.h | 34 +++++ .../Local/FSTMemoryRemoteDocumentCache.mm | 131 ++++++++++++------ 2 files changed, 119 insertions(+), 46 deletions(-) diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h index 453fcce7845..3c79eabd647 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h @@ -20,6 +20,8 @@ #import "Firestore/Source/Local/FSTRemoteDocumentCache.h" +#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/types.h" NS_ASSUME_NONNULL_BEGIN @@ -37,4 +39,36 @@ NS_ASSUME_NONNULL_BEGIN @end +namespace firebase { +namespace firestore { +namespace local { + +class MemoryRemoteDocumentCache { + public: + MemoryRemoteDocumentCache(); + + void AddEntry(FSTMaybeDocument *document); + + void RemoveEntry(const model::DocumentKey &key); + + FSTMaybeDocument *_Nullable Find(const model::DocumentKey &key); + + model::MaybeDocumentMap FindAll(const model::DocumentKeySet &keys); + + model::DocumentMap GetMatchingDocuments(FSTQuery *query); + + std::vector RemoveOrphanedDocuments( + FSTMemoryLRUReferenceDelegate *reference_delegate, model::ListenSequenceNumber upper_bound); + + size_t ByteSize(FSTLocalSerializer *serializer); + + private: + /** Underlying cache of documents. */ + model::MaybeDocumentMap docs_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm index 22373f8e8d8..2cb4a25959c 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm @@ -15,6 +15,7 @@ */ #import "Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h" +#import #import #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" @@ -25,6 +26,7 @@ #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" +using firebase::firestore::local::MemoryRemoteDocumentCache; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::DocumentKeySet; using firebase::firestore::model::ListenSequenceNumber; @@ -33,106 +35,143 @@ NS_ASSUME_NONNULL_BEGIN +@implementation FSTMemoryRemoteDocumentCache { + MemoryRemoteDocumentCache _cache; +} + +- (instancetype)init { + if (self = [super init]) { + } + return self; +} + +- (void)addEntry:(FSTMaybeDocument *)document { + _cache.AddEntry(document); +} + +- (void)removeEntryForKey:(const DocumentKey &)key { + _cache.RemoveEntry(key); +} + +- (nullable FSTMaybeDocument *)entryForKey:(const DocumentKey &)key { + return _cache.Find(key); +} + +- (MaybeDocumentMap)entriesForKeys:(const DocumentKeySet &)keys { + return _cache.FindAll(keys); +} + +- (DocumentMap)documentsMatchingQuery:(FSTQuery *)query { + return _cache.GetMatchingDocuments(query); +} + +- (std::vector)removeOrphanedDocuments: + (FSTMemoryLRUReferenceDelegate *)referenceDelegate + throughSequenceNumber:(ListenSequenceNumber)upperBound { + return _cache.RemoveOrphanedDocuments(referenceDelegate, upperBound); +} + +- (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer { + return _cache.ByteSize(serializer); +} + +@end + +namespace firebase { +namespace firestore { +namespace local { + +namespace { /** * Returns an estimate of the number of bytes used to store the given * document key in memory. This is only an estimate and includes the size * of the segments of the path, but not any object overhead or path separators. */ -static size_t FSTDocumentKeyByteSize(const DocumentKey &key) { +static size_t DocumentKeyByteSize(const DocumentKey &key) { size_t count = 0; for (const auto &segment : key.path()) { count += segment.size(); } return count; } +} // namespace -@interface FSTMemoryRemoteDocumentCache () - -@end - -@implementation FSTMemoryRemoteDocumentCache { - /** Underlying cache of documents. */ - MaybeDocumentMap _docs; +MemoryRemoteDocumentCache::MemoryRemoteDocumentCache() { } -- (void)addEntry:(FSTMaybeDocument *)document { - _docs = _docs.insert(document.key, document); +void MemoryRemoteDocumentCache::AddEntry(FSTMaybeDocument *document) { + docs_ = docs_.insert(document.key, document); } -- (void)removeEntryForKey:(const DocumentKey &)key { - _docs = _docs.erase(key); +void MemoryRemoteDocumentCache::RemoveEntry(const DocumentKey &key) { + docs_ = docs_.erase(key); } -- (nullable FSTMaybeDocument *)entryForKey:(const DocumentKey &)key { - auto found = _docs.find(key); - return found != _docs.end() ? found->second : nil; +FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Find(const DocumentKey &key) { + auto found = docs_.find(key); + return found != docs_.end() ? found->second : nil; } -- (MaybeDocumentMap)entriesForKeys:(const DocumentKeySet &)keys { +model::MaybeDocumentMap MemoryRemoteDocumentCache::FindAll(const model::DocumentKeySet &keys) { MaybeDocumentMap results; for (const DocumentKey &key : keys) { // Make sure each key has a corresponding entry, which is null in case the document is not // found. - results = results.insert(key, [self entryForKey:key]); + // TODO(http://b/32275378): Don't conflate missing / deleted. + results = results.insert(key, Find(key)); } return results; } -- (DocumentMap)documentsMatchingQuery:(FSTQuery *)query { - DocumentMap result; +DocumentMap MemoryRemoteDocumentCache::GetMatchingDocuments(FSTQuery *query) { + DocumentMap results; // Documents are ordered by key, so we can use a prefix scan to narrow down the documents // we need to match the query against. - DocumentKey prefix{query.path.Append("")}; - for (auto it = _docs.lower_bound(prefix); it != _docs.end(); ++it) { + DocumentKey prefix = DocumentKey{query.path.Append("")}; + for (auto it = docs_.lower_bound(prefix); it != docs_.end(); it++) { const DocumentKey &key = it->first; if (!query.path.IsPrefixOf(key.path())) { break; } - FSTMaybeDocument *maybeDoc = nil; - auto found = _docs.find(key); - if (found != _docs.end()) { - maybeDoc = found->second; - } + FSTMaybeDocument *maybeDoc = it->second; if (![maybeDoc isKindOfClass:[FSTDocument class]]) { continue; } FSTDocument *doc = static_cast(maybeDoc); if ([query matchesDocument:doc]) { - result = result.insert(key, doc); + results = results.insert(key, doc); } } - - return result; + return results; } -- (std::vector)removeOrphanedDocuments: - (FSTMemoryLRUReferenceDelegate *)referenceDelegate - throughSequenceNumber:(ListenSequenceNumber)upperBound { +std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( + FSTMemoryLRUReferenceDelegate *reference_delegate, ListenSequenceNumber upper_bound) { std::vector removed; - MaybeDocumentMap updatedDocs = _docs; - for (const auto &kv : _docs) { - const DocumentKey &docKey = kv.first; - if (![referenceDelegate isPinnedAtSequenceNumber:upperBound document:docKey]) { - updatedDocs = updatedDocs.erase(docKey); - removed.push_back(docKey); + MaybeDocumentMap updated_docs = docs_; + for (const auto &kv : docs_) { + const DocumentKey &key = kv.first; + if (![reference_delegate isPinnedAtSequenceNumber:upper_bound document:key]) { + updated_docs = updated_docs.erase(key); + removed.push_back(key); } } - _docs = updatedDocs; + docs_ = updated_docs; return removed; } -- (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer { +size_t MemoryRemoteDocumentCache::ByteSize(FSTLocalSerializer *serializer) { size_t count = 0; - for (const auto &kv : _docs) { - const DocumentKey &key = kv.first; - FSTMaybeDocument *doc = kv.second; - count += FSTDocumentKeyByteSize(key); - count += [[serializer encodedMaybeDocument:doc] serializedSize]; + for (const auto &kv : docs_) { + count += DocumentKeyByteSize(kv.first); + count += [[serializer encodedMaybeDocument:kv.second] serializedSize]; } return count; } -@end +} // namespace local +} // namespace firestore +} // namespace firebase NS_ASSUME_NONNULL_END From 672e95205f70e50737cc646daeac593b90c011a7 Mon Sep 17 00:00:00 2001 From: Greg Soltis Date: Wed, 12 Dec 2018 11:02:23 -0800 Subject: [PATCH 2/4] Checkpoint before file move --- .../Local/FSTMemoryRemoteDocumentCache.h | 8 ++--- .../Local/FSTMemoryRemoteDocumentCache.mm | 30 +++++++------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h index 3c79eabd647..6e803c9f4d4 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h @@ -45,22 +45,20 @@ namespace local { class MemoryRemoteDocumentCache { public: - MemoryRemoteDocumentCache(); - void AddEntry(FSTMaybeDocument *document); void RemoveEntry(const model::DocumentKey &key); - FSTMaybeDocument *_Nullable Find(const model::DocumentKey &key); + FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key); - model::MaybeDocumentMap FindAll(const model::DocumentKeySet &keys); + model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys); model::DocumentMap GetMatchingDocuments(FSTQuery *query); std::vector RemoveOrphanedDocuments( FSTMemoryLRUReferenceDelegate *reference_delegate, model::ListenSequenceNumber upper_bound); - size_t ByteSize(FSTLocalSerializer *serializer); + size_t CalculateByteSize(FSTLocalSerializer *serializer); private: /** Underlying cache of documents. */ diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm index 2cb4a25959c..f3a7c8a7cb1 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm @@ -15,7 +15,6 @@ */ #import "Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h" -#import #import #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" @@ -39,12 +38,6 @@ @implementation FSTMemoryRemoteDocumentCache { MemoryRemoteDocumentCache _cache; } -- (instancetype)init { - if (self = [super init]) { - } - return self; -} - - (void)addEntry:(FSTMaybeDocument *)document { _cache.AddEntry(document); } @@ -54,11 +47,11 @@ - (void)removeEntryForKey:(const DocumentKey &)key { } - (nullable FSTMaybeDocument *)entryForKey:(const DocumentKey &)key { - return _cache.Find(key); + return _cache.Get(key); } - (MaybeDocumentMap)entriesForKeys:(const DocumentKeySet &)keys { - return _cache.FindAll(keys); + return _cache.GetAll(keys); } - (DocumentMap)documentsMatchingQuery:(FSTQuery *)query { @@ -72,7 +65,7 @@ - (DocumentMap)documentsMatchingQuery:(FSTQuery *)query { } - (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer { - return _cache.ByteSize(serializer); + return _cache.CalculateByteSize(serializer); } @end @@ -96,9 +89,6 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { } } // namespace -MemoryRemoteDocumentCache::MemoryRemoteDocumentCache() { -} - void MemoryRemoteDocumentCache::AddEntry(FSTMaybeDocument *document) { docs_ = docs_.insert(document.key, document); } @@ -107,18 +97,18 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { docs_ = docs_.erase(key); } -FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Find(const DocumentKey &key) { +FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get(const DocumentKey &key) { auto found = docs_.find(key); return found != docs_.end() ? found->second : nil; } -model::MaybeDocumentMap MemoryRemoteDocumentCache::FindAll(const model::DocumentKeySet &keys) { +MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet &keys) { MaybeDocumentMap results; for (const DocumentKey &key : keys) { // Make sure each key has a corresponding entry, which is null in case the document is not // found. // TODO(http://b/32275378): Don't conflate missing / deleted. - results = results.insert(key, Find(key)); + results = results.insert(key, Get(key)); } return results; } @@ -128,8 +118,8 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { // Documents are ordered by key, so we can use a prefix scan to narrow down the documents // we need to match the query against. - DocumentKey prefix = DocumentKey{query.path.Append("")}; - for (auto it = docs_.lower_bound(prefix); it != docs_.end(); it++) { + DocumentKey prefix{query.path.Append("")}; + for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { const DocumentKey &key = it->first; if (!query.path.IsPrefixOf(key.path())) { break; @@ -146,7 +136,7 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { return results; } -std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( +std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( FSTMemoryLRUReferenceDelegate *reference_delegate, ListenSequenceNumber upper_bound) { std::vector removed; MaybeDocumentMap updated_docs = docs_; @@ -161,7 +151,7 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { return removed; } -size_t MemoryRemoteDocumentCache::ByteSize(FSTLocalSerializer *serializer) { +size_t MemoryRemoteDocumentCache::CalculateByteSize(FSTLocalSerializer *serializer) { size_t count = 0; for (const auto &kv : docs_) { count += DocumentKeyByteSize(kv.first); From 000b86f4e8124fec77da4777c1ac898dc70af170 Mon Sep 17 00:00:00 2001 From: Greg Soltis Date: Wed, 12 Dec 2018 11:53:39 -0800 Subject: [PATCH 3/4] Move MemoryRemoteDocumentCache into its own files --- .../Local/FSTMemoryRemoteDocumentCache.h | 31 ----- .../Local/FSTMemoryRemoteDocumentCache.mm | 95 +------------ .../local/memory_remote_document_cache.h | 71 ++++++++++ .../local/memory_remote_document_cache.mm | 125 ++++++++++++++++++ 4 files changed, 197 insertions(+), 125 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h create mode 100644 Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h index 6e803c9f4d4..1f0884fe33a 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h @@ -21,7 +21,6 @@ #import "Firestore/Source/Local/FSTRemoteDocumentCache.h" #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/types.h" NS_ASSUME_NONNULL_BEGIN @@ -39,34 +38,4 @@ NS_ASSUME_NONNULL_BEGIN @end -namespace firebase { -namespace firestore { -namespace local { - -class MemoryRemoteDocumentCache { - public: - void AddEntry(FSTMaybeDocument *document); - - void RemoveEntry(const model::DocumentKey &key); - - FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key); - - model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys); - - model::DocumentMap GetMatchingDocuments(FSTQuery *query); - - std::vector RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate *reference_delegate, model::ListenSequenceNumber upper_bound); - - size_t CalculateByteSize(FSTLocalSerializer *serializer); - - private: - /** Underlying cache of documents. */ - model::MaybeDocumentMap docs_; -}; - -} // namespace local -} // namespace firestore -} // namespace firebase - NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm index f3a7c8a7cb1..4f4070141aa 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm @@ -22,6 +22,7 @@ #import "Firestore/Source/Local/FSTMemoryPersistence.h" #import "Firestore/Source/Model/FSTDocument.h" +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" #include "Firestore/core/src/firebase/firestore/model/document_map.h" @@ -70,98 +71,4 @@ - (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer { @end -namespace firebase { -namespace firestore { -namespace local { - -namespace { -/** - * Returns an estimate of the number of bytes used to store the given - * document key in memory. This is only an estimate and includes the size - * of the segments of the path, but not any object overhead or path separators. - */ -static size_t DocumentKeyByteSize(const DocumentKey &key) { - size_t count = 0; - for (const auto &segment : key.path()) { - count += segment.size(); - } - return count; -} -} // namespace - -void MemoryRemoteDocumentCache::AddEntry(FSTMaybeDocument *document) { - docs_ = docs_.insert(document.key, document); -} - -void MemoryRemoteDocumentCache::RemoveEntry(const DocumentKey &key) { - docs_ = docs_.erase(key); -} - -FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get(const DocumentKey &key) { - auto found = docs_.find(key); - return found != docs_.end() ? found->second : nil; -} - -MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet &keys) { - MaybeDocumentMap results; - for (const DocumentKey &key : keys) { - // Make sure each key has a corresponding entry, which is null in case the document is not - // found. - // TODO(http://b/32275378): Don't conflate missing / deleted. - results = results.insert(key, Get(key)); - } - return results; -} - -DocumentMap MemoryRemoteDocumentCache::GetMatchingDocuments(FSTQuery *query) { - DocumentMap results; - - // Documents are ordered by key, so we can use a prefix scan to narrow down the documents - // we need to match the query against. - DocumentKey prefix{query.path.Append("")}; - for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { - const DocumentKey &key = it->first; - if (!query.path.IsPrefixOf(key.path())) { - break; - } - FSTMaybeDocument *maybeDoc = it->second; - if (![maybeDoc isKindOfClass:[FSTDocument class]]) { - continue; - } - FSTDocument *doc = static_cast(maybeDoc); - if ([query matchesDocument:doc]) { - results = results.insert(key, doc); - } - } - return results; -} - -std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate *reference_delegate, ListenSequenceNumber upper_bound) { - std::vector removed; - MaybeDocumentMap updated_docs = docs_; - for (const auto &kv : docs_) { - const DocumentKey &key = kv.first; - if (![reference_delegate isPinnedAtSequenceNumber:upper_bound document:key]) { - updated_docs = updated_docs.erase(key); - removed.push_back(key); - } - } - docs_ = updated_docs; - return removed; -} - -size_t MemoryRemoteDocumentCache::CalculateByteSize(FSTLocalSerializer *serializer) { - size_t count = 0; - for (const auto &kv : docs_) { - count += DocumentKeyByteSize(kv.first); - count += [[serializer encodedMaybeDocument:kv.second] serializedSize]; - } - return count; -} - -} // namespace local -} // namespace firestore -} // namespace firebase - NS_ASSUME_NONNULL_END diff --git a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h new file mode 100644 index 00000000000..2a16db18ac9 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ +#define FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ + +#if !defined(__OBJC__) +#error "For now, this file must only be included by ObjC source files." +#endif // !defined(__OBJC__) + +#import + +#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/document_map.h" +#include "Firestore/core/src/firebase/firestore/model/types.h" + + +@class FSTLocalSerializer; +@class FSTMaybeDocument; +@class FSTMemoryLRUReferenceDelegate; +@class FSTQuery; + +NS_ASSUME_NONNULL_BEGIN + +namespace firebase { +namespace firestore { +namespace local { + +class MemoryRemoteDocumentCache { + public: + void AddEntry(FSTMaybeDocument *document); + + void RemoveEntry(const model::DocumentKey &key); + + FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key); + + model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys); + + model::DocumentMap GetMatchingDocuments(FSTQuery *query); + + std::vector RemoveOrphanedDocuments( + FSTMemoryLRUReferenceDelegate *reference_delegate, model::ListenSequenceNumber upper_bound); + + size_t CalculateByteSize(FSTLocalSerializer *serializer); + + private: + /** Underlying cache of documents. */ + model::MaybeDocumentMap docs_; +}; + +} // namespace local +} // namespace firestore +} // namespace firebase + +NS_ASSUME_NONNULL_END + +#endif // FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ diff --git a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm new file mode 100644 index 00000000000..7b0d2913a9a --- /dev/null +++ b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm @@ -0,0 +1,125 @@ +/* + * 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. + */ + +#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.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/document_map.h" + +#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" +#import "Firestore/Source/Core/FSTQuery.h" +#import "Firestore/Source/Local/FSTMemoryPersistence.h" + +using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::DocumentKeySet; +using firebase::firestore::model::DocumentMap; +using firebase::firestore::model::ListenSequenceNumber; +using firebase::firestore::model::MaybeDocumentMap; + +namespace firebase { +namespace firestore { +namespace local { + +namespace { +/** + * Returns an estimate of the number of bytes used to store the given + * document key in memory. This is only an estimate and includes the size + * of the segments of the path, but not any object overhead or path separators. + */ +static size_t DocumentKeyByteSize(const DocumentKey &key) { + size_t count = 0; + for (const auto &segment : key.path()) { + count += segment.size(); + } + return count; +} +} // namespace + +void MemoryRemoteDocumentCache::AddEntry(FSTMaybeDocument *document) { + docs_ = docs_.insert(document.key, document); +} + +void MemoryRemoteDocumentCache::RemoveEntry(const DocumentKey &key) { + docs_ = docs_.erase(key); +} + +FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get(const DocumentKey &key) { + auto found = docs_.find(key); + return found != docs_.end() ? found->second : nil; +} + +MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet &keys) { + MaybeDocumentMap results; + for (const DocumentKey &key : keys) { + // Make sure each key has a corresponding entry, which is null in case the document is not + // found. + // TODO(http://b/32275378): Don't conflate missing / deleted. + results = results.insert(key, Get(key)); + } + return results; +} + +DocumentMap MemoryRemoteDocumentCache::GetMatchingDocuments(FSTQuery *query) { + DocumentMap results; + + // Documents are ordered by key, so we can use a prefix scan to narrow down the documents + // we need to match the query against. + DocumentKey prefix{query.path.Append("")}; + for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { + const DocumentKey &key = it->first; + if (!query.path.IsPrefixOf(key.path())) { + break; + } + FSTMaybeDocument *maybeDoc = it->second; + if (![maybeDoc isKindOfClass:[FSTDocument class]]) { + continue; + } + FSTDocument *doc = static_cast(maybeDoc); + if ([query matchesDocument:doc]) { + results = results.insert(key, doc); + } + } + return results; +} + +std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( + FSTMemoryLRUReferenceDelegate *reference_delegate, ListenSequenceNumber upper_bound) { + std::vector removed; + MaybeDocumentMap updated_docs = docs_; + for (const auto &kv : docs_) { + const DocumentKey &key = kv.first; + if (![reference_delegate isPinnedAtSequenceNumber:upper_bound document:key]) { + updated_docs = updated_docs.erase(key); + removed.push_back(key); + } + } + docs_ = updated_docs; + return removed; +} + +size_t MemoryRemoteDocumentCache::CalculateByteSize(FSTLocalSerializer *serializer) { + size_t count = 0; + for (const auto &kv : docs_) { + count += DocumentKeyByteSize(kv.first); + count += [[serializer encodedMaybeDocument:kv.second] serializedSize]; + } + return count; +} + +} // namespace local +} // namespace firestore +} // namespace firebase \ No newline at end of file From 39518504b40c34849ee95a2684682111741cd510 Mon Sep 17 00:00:00 2001 From: Greg Soltis Date: Wed, 12 Dec 2018 16:21:14 -0800 Subject: [PATCH 4/4] Style cleanup and linting --- .../local/memory_remote_document_cache.h | 15 +++++------ .../local/memory_remote_document_cache.mm | 26 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h index 2a16db18ac9..4c23ef54103 100644 --- a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h +++ b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ -#define FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ #if !defined(__OBJC__) #error "For now, this file must only be included by ObjC source files." @@ -23,12 +23,13 @@ #import +#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/document_map.h" #include "Firestore/core/src/firebase/firestore/model/types.h" - @class FSTLocalSerializer; @class FSTMaybeDocument; @class FSTMemoryLRUReferenceDelegate; @@ -43,17 +44,15 @@ namespace local { class MemoryRemoteDocumentCache { public: void AddEntry(FSTMaybeDocument *document); - void RemoveEntry(const model::DocumentKey &key); FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key); - model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys); - model::DocumentMap GetMatchingDocuments(FSTQuery *query); std::vector RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate *reference_delegate, model::ListenSequenceNumber upper_bound); + FSTMemoryLRUReferenceDelegate *reference_delegate, + model::ListenSequenceNumber upper_bound); size_t CalculateByteSize(FSTLocalSerializer *serializer); @@ -68,4 +67,4 @@ class MemoryRemoteDocumentCache { NS_ASSUME_NONNULL_END -#endif // FIRESTORE_CORE_SRC_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_ diff --git a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm index 7b0d2913a9a..b7535309e83 100644 --- a/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm +++ b/Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.mm @@ -16,10 +16,6 @@ #include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.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/document_map.h" - #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTMemoryPersistence.h" @@ -40,7 +36,7 @@ * document key in memory. This is only an estimate and includes the size * of the segments of the path, but not any object overhead or path separators. */ -static size_t DocumentKeyByteSize(const DocumentKey &key) { +size_t DocumentKeyByteSize(const DocumentKey &key) { size_t count = 0; for (const auto &segment : key.path()) { count += segment.size(); @@ -57,7 +53,8 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { docs_ = docs_.erase(key); } -FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get(const DocumentKey &key) { +FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get( + const DocumentKey &key) { auto found = docs_.find(key); return found != docs_.end() ? found->second : nil; } @@ -65,8 +62,8 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet &keys) { MaybeDocumentMap results; for (const DocumentKey &key : keys) { - // Make sure each key has a corresponding entry, which is null in case the document is not - // found. + // Make sure each key has a corresponding entry, which is null in case the + // document is not found. // TODO(http://b/32275378): Don't conflate missing / deleted. results = results.insert(key, Get(key)); } @@ -76,8 +73,8 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { DocumentMap MemoryRemoteDocumentCache::GetMatchingDocuments(FSTQuery *query) { DocumentMap results; - // Documents are ordered by key, so we can use a prefix scan to narrow down the documents - // we need to match the query against. + // Documents are ordered by key, so we can use a prefix scan to narrow down + // the documents we need to match the query against. DocumentKey prefix{query.path.Append("")}; for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) { const DocumentKey &key = it->first; @@ -97,12 +94,14 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { } std::vector MemoryRemoteDocumentCache::RemoveOrphanedDocuments( - FSTMemoryLRUReferenceDelegate *reference_delegate, ListenSequenceNumber upper_bound) { + FSTMemoryLRUReferenceDelegate *reference_delegate, + ListenSequenceNumber upper_bound) { std::vector removed; MaybeDocumentMap updated_docs = docs_; for (const auto &kv : docs_) { const DocumentKey &key = kv.first; - if (![reference_delegate isPinnedAtSequenceNumber:upper_bound document:key]) { + if (![reference_delegate isPinnedAtSequenceNumber:upper_bound + document:key]) { updated_docs = updated_docs.erase(key); removed.push_back(key); } @@ -111,7 +110,8 @@ static size_t DocumentKeyByteSize(const DocumentKey &key) { return removed; } -size_t MemoryRemoteDocumentCache::CalculateByteSize(FSTLocalSerializer *serializer) { +size_t MemoryRemoteDocumentCache::CalculateByteSize( + FSTLocalSerializer *serializer) { size_t count = 0; for (const auto &kv : docs_) { count += DocumentKeyByteSize(kv.first);