Skip to content

Commit 8def2aa

Browse files
author
Greg Soltis
authored
Port Memory remote document cache to C++ (#2176)
* Port Memory remote document cache to C++
1 parent 943141e commit 8def2aa

File tree

4 files changed

+206
-74
lines changed

4 files changed

+206
-74
lines changed

Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#import "Firestore/Source/Local/FSTRemoteDocumentCache.h"
2222

23+
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2324
#include "Firestore/core/src/firebase/firestore/model/types.h"
2425

2526
NS_ASSUME_NONNULL_BEGIN

Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm

Lines changed: 10 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
#import "Firestore/Source/Local/FSTMemoryPersistence.h"
2323
#import "Firestore/Source/Model/FSTDocument.h"
2424

25+
#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h"
2526
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2627
#include "Firestore/core/src/firebase/firestore/model/document_map.h"
2728

29+
using firebase::firestore::local::MemoryRemoteDocumentCache;
2830
using firebase::firestore::model::DocumentKey;
2931
using firebase::firestore::model::DocumentKeySet;
3032
using firebase::firestore::model::ListenSequenceNumber;
@@ -33,104 +35,38 @@
3335

3436
NS_ASSUME_NONNULL_BEGIN
3537

36-
/**
37-
* Returns an estimate of the number of bytes used to store the given
38-
* document key in memory. This is only an estimate and includes the size
39-
* of the segments of the path, but not any object overhead or path separators.
40-
*/
41-
static size_t FSTDocumentKeyByteSize(const DocumentKey &key) {
42-
size_t count = 0;
43-
for (const auto &segment : key.path()) {
44-
count += segment.size();
45-
}
46-
return count;
47-
}
48-
49-
@interface FSTMemoryRemoteDocumentCache ()
50-
51-
@end
52-
5338
@implementation FSTMemoryRemoteDocumentCache {
54-
/** Underlying cache of documents. */
55-
MaybeDocumentMap _docs;
39+
MemoryRemoteDocumentCache _cache;
5640
}
5741

5842
- (void)addEntry:(FSTMaybeDocument *)document {
59-
_docs = _docs.insert(document.key, document);
43+
_cache.AddEntry(document);
6044
}
6145

6246
- (void)removeEntryForKey:(const DocumentKey &)key {
63-
_docs = _docs.erase(key);
47+
_cache.RemoveEntry(key);
6448
}
6549

6650
- (nullable FSTMaybeDocument *)entryForKey:(const DocumentKey &)key {
67-
auto found = _docs.find(key);
68-
return found != _docs.end() ? found->second : nil;
51+
return _cache.Get(key);
6952
}
7053

7154
- (MaybeDocumentMap)entriesForKeys:(const DocumentKeySet &)keys {
72-
MaybeDocumentMap results;
73-
for (const DocumentKey &key : keys) {
74-
// Make sure each key has a corresponding entry, which is null in case the document is not
75-
// found.
76-
results = results.insert(key, [self entryForKey:key]);
77-
}
78-
return results;
55+
return _cache.GetAll(keys);
7956
}
8057

8158
- (DocumentMap)documentsMatchingQuery:(FSTQuery *)query {
82-
DocumentMap result;
83-
84-
// Documents are ordered by key, so we can use a prefix scan to narrow down the documents
85-
// we need to match the query against.
86-
DocumentKey prefix{query.path.Append("")};
87-
for (auto it = _docs.lower_bound(prefix); it != _docs.end(); ++it) {
88-
const DocumentKey &key = it->first;
89-
if (!query.path.IsPrefixOf(key.path())) {
90-
break;
91-
}
92-
FSTMaybeDocument *maybeDoc = nil;
93-
auto found = _docs.find(key);
94-
if (found != _docs.end()) {
95-
maybeDoc = found->second;
96-
}
97-
if (![maybeDoc isKindOfClass:[FSTDocument class]]) {
98-
continue;
99-
}
100-
FSTDocument *doc = static_cast<FSTDocument *>(maybeDoc);
101-
if ([query matchesDocument:doc]) {
102-
result = result.insert(key, doc);
103-
}
104-
}
105-
106-
return result;
59+
return _cache.GetMatchingDocuments(query);
10760
}
10861

10962
- (std::vector<DocumentKey>)removeOrphanedDocuments:
11063
(FSTMemoryLRUReferenceDelegate *)referenceDelegate
11164
throughSequenceNumber:(ListenSequenceNumber)upperBound {
112-
std::vector<DocumentKey> removed;
113-
MaybeDocumentMap updatedDocs = _docs;
114-
for (const auto &kv : _docs) {
115-
const DocumentKey &docKey = kv.first;
116-
if (![referenceDelegate isPinnedAtSequenceNumber:upperBound document:docKey]) {
117-
updatedDocs = updatedDocs.erase(docKey);
118-
removed.push_back(docKey);
119-
}
120-
}
121-
_docs = updatedDocs;
122-
return removed;
65+
return _cache.RemoveOrphanedDocuments(referenceDelegate, upperBound);
12366
}
12467

12568
- (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer {
126-
size_t count = 0;
127-
for (const auto &kv : _docs) {
128-
const DocumentKey &key = kv.first;
129-
FSTMaybeDocument *doc = kv.second;
130-
count += FSTDocumentKeyByteSize(key);
131-
count += [[serializer encodedMaybeDocument:doc] serializedSize];
132-
}
133-
return count;
69+
return _cache.CalculateByteSize(serializer);
13470
}
13571

13672
@end
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_
18+
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_
19+
20+
#if !defined(__OBJC__)
21+
#error "For now, this file must only be included by ObjC source files."
22+
#endif // !defined(__OBJC__)
23+
24+
#import <Foundation/Foundation.h>
25+
26+
#include <vector>
27+
28+
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
29+
#include "Firestore/core/src/firebase/firestore/model/document_key_set.h"
30+
#include "Firestore/core/src/firebase/firestore/model/document_map.h"
31+
#include "Firestore/core/src/firebase/firestore/model/types.h"
32+
33+
@class FSTLocalSerializer;
34+
@class FSTMaybeDocument;
35+
@class FSTMemoryLRUReferenceDelegate;
36+
@class FSTQuery;
37+
38+
NS_ASSUME_NONNULL_BEGIN
39+
40+
namespace firebase {
41+
namespace firestore {
42+
namespace local {
43+
44+
class MemoryRemoteDocumentCache {
45+
public:
46+
void AddEntry(FSTMaybeDocument *document);
47+
void RemoveEntry(const model::DocumentKey &key);
48+
49+
FSTMaybeDocument *_Nullable Get(const model::DocumentKey &key);
50+
model::MaybeDocumentMap GetAll(const model::DocumentKeySet &keys);
51+
model::DocumentMap GetMatchingDocuments(FSTQuery *query);
52+
53+
std::vector<model::DocumentKey> RemoveOrphanedDocuments(
54+
FSTMemoryLRUReferenceDelegate *reference_delegate,
55+
model::ListenSequenceNumber upper_bound);
56+
57+
size_t CalculateByteSize(FSTLocalSerializer *serializer);
58+
59+
private:
60+
/** Underlying cache of documents. */
61+
model::MaybeDocumentMap docs_;
62+
};
63+
64+
} // namespace local
65+
} // namespace firestore
66+
} // namespace firebase
67+
68+
NS_ASSUME_NONNULL_END
69+
70+
#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_REMOTE_DOCUMENT_CACHE_H_
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/core/src/firebase/firestore/local/memory_remote_document_cache.h"
18+
19+
#import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h"
20+
#import "Firestore/Source/Core/FSTQuery.h"
21+
#import "Firestore/Source/Local/FSTMemoryPersistence.h"
22+
23+
using firebase::firestore::model::DocumentKey;
24+
using firebase::firestore::model::DocumentKeySet;
25+
using firebase::firestore::model::DocumentMap;
26+
using firebase::firestore::model::ListenSequenceNumber;
27+
using firebase::firestore::model::MaybeDocumentMap;
28+
29+
namespace firebase {
30+
namespace firestore {
31+
namespace local {
32+
33+
namespace {
34+
/**
35+
* Returns an estimate of the number of bytes used to store the given
36+
* document key in memory. This is only an estimate and includes the size
37+
* of the segments of the path, but not any object overhead or path separators.
38+
*/
39+
size_t DocumentKeyByteSize(const DocumentKey &key) {
40+
size_t count = 0;
41+
for (const auto &segment : key.path()) {
42+
count += segment.size();
43+
}
44+
return count;
45+
}
46+
} // namespace
47+
48+
void MemoryRemoteDocumentCache::AddEntry(FSTMaybeDocument *document) {
49+
docs_ = docs_.insert(document.key, document);
50+
}
51+
52+
void MemoryRemoteDocumentCache::RemoveEntry(const DocumentKey &key) {
53+
docs_ = docs_.erase(key);
54+
}
55+
56+
FSTMaybeDocument *_Nullable MemoryRemoteDocumentCache::Get(
57+
const DocumentKey &key) {
58+
auto found = docs_.find(key);
59+
return found != docs_.end() ? found->second : nil;
60+
}
61+
62+
MaybeDocumentMap MemoryRemoteDocumentCache::GetAll(const DocumentKeySet &keys) {
63+
MaybeDocumentMap results;
64+
for (const DocumentKey &key : keys) {
65+
// Make sure each key has a corresponding entry, which is null in case the
66+
// document is not found.
67+
// TODO(http://b/32275378): Don't conflate missing / deleted.
68+
results = results.insert(key, Get(key));
69+
}
70+
return results;
71+
}
72+
73+
DocumentMap MemoryRemoteDocumentCache::GetMatchingDocuments(FSTQuery *query) {
74+
DocumentMap results;
75+
76+
// Documents are ordered by key, so we can use a prefix scan to narrow down
77+
// the documents we need to match the query against.
78+
DocumentKey prefix{query.path.Append("")};
79+
for (auto it = docs_.lower_bound(prefix); it != docs_.end(); ++it) {
80+
const DocumentKey &key = it->first;
81+
if (!query.path.IsPrefixOf(key.path())) {
82+
break;
83+
}
84+
FSTMaybeDocument *maybeDoc = it->second;
85+
if (![maybeDoc isKindOfClass:[FSTDocument class]]) {
86+
continue;
87+
}
88+
FSTDocument *doc = static_cast<FSTDocument *>(maybeDoc);
89+
if ([query matchesDocument:doc]) {
90+
results = results.insert(key, doc);
91+
}
92+
}
93+
return results;
94+
}
95+
96+
std::vector<DocumentKey> MemoryRemoteDocumentCache::RemoveOrphanedDocuments(
97+
FSTMemoryLRUReferenceDelegate *reference_delegate,
98+
ListenSequenceNumber upper_bound) {
99+
std::vector<DocumentKey> removed;
100+
MaybeDocumentMap updated_docs = docs_;
101+
for (const auto &kv : docs_) {
102+
const DocumentKey &key = kv.first;
103+
if (![reference_delegate isPinnedAtSequenceNumber:upper_bound
104+
document:key]) {
105+
updated_docs = updated_docs.erase(key);
106+
removed.push_back(key);
107+
}
108+
}
109+
docs_ = updated_docs;
110+
return removed;
111+
}
112+
113+
size_t MemoryRemoteDocumentCache::CalculateByteSize(
114+
FSTLocalSerializer *serializer) {
115+
size_t count = 0;
116+
for (const auto &kv : docs_) {
117+
count += DocumentKeyByteSize(kv.first);
118+
count += [[serializer encodedMaybeDocument:kv.second] serializedSize];
119+
}
120+
return count;
121+
}
122+
123+
} // namespace local
124+
} // namespace firestore
125+
} // namespace firebase

0 commit comments

Comments
 (0)