16
16
17
17
#include " Firestore/core/src/local/leveldb_document_overlay_cache.h"
18
18
19
- #include < map>
20
19
#include < string>
21
- #include < unordered_set>
22
20
#include < utility>
23
21
24
22
#include " Firestore/core/src/credentials/user.h"
@@ -99,46 +97,28 @@ LevelDbDocumentOverlayCache::GetOverlays(const ResourcePath& collection,
99
97
}
100
98
101
99
DocumentOverlayCache::OverlayByDocumentKeyMap
102
- LevelDbDocumentOverlayCache::GetOverlays (const std::string& collection_group,
100
+ LevelDbDocumentOverlayCache::GetOverlays (absl::string_view collection_group,
103
101
int since_batch_id,
104
102
std::size_t count) const {
105
- // TODO(dconeybe) Implement an index so that this query can be performed
106
- // without requiring a full table scan.
107
-
108
- // Load ALL overlays for the given `collection_group` whose largest_batch_id
109
- // are greater than the given `since_batch_id`. By using a `std::map` keyed
110
- // by largest_batch_id, the loop below can iterate over it ordered by
111
- // largest_batch_id.
112
- std::map<int , std::unordered_set<Overlay, OverlayHash>> overlays_by_batch_id;
113
- ForEachOverlay (
114
- [&](LevelDbDocumentOverlayKey&& key, absl::string_view encoded_mutation) {
115
- if (key.largest_batch_id () <= since_batch_id) {
116
- return ;
117
- }
118
- if (key.document_key ().HasCollectionId (collection_group)) {
119
- overlays_by_batch_id[key.largest_batch_id ()].emplace (
120
- ParseOverlay (key, encoded_mutation));
121
- }
122
- });
123
-
124
- // Trim down the overlays loaded above to respect the given `count`, and
125
- // return them.
126
- //
127
- // Note that, as documented, all overlays for the largest_batch_id that pushes
128
- // the size of the result set above the given `count` will be returned, even
129
- // though this likely means that the size of the result set will be strictly
130
- // greater than the given `count`.
103
+ absl::optional<int > current_batch_id;
131
104
OverlayByDocumentKeyMap result;
132
- for (auto & overlays_by_batch_id_entry : overlays_by_batch_id) {
133
- for (auto & overlay : overlays_by_batch_id_entry.second ) {
134
- DocumentKey document_key = overlay.key ();
135
- result[document_key] = std::move (overlay);
136
- }
137
- if (result.size () >= count) {
138
- break ;
139
- }
140
- }
105
+ ForEachKeyInCollectionGroup (
106
+ collection_group, since_batch_id,
107
+ [&](LevelDbDocumentOverlayKey&& key) -> ForEachKeyAction {
108
+ if (!current_batch_id.has_value ()) {
109
+ current_batch_id = key.largest_batch_id ();
110
+ } else if (current_batch_id.value () != key.largest_batch_id ()) {
111
+ if (result.size () >= count) {
112
+ return ForEachKeyAction::kStop ;
113
+ }
114
+ current_batch_id = key.largest_batch_id ();
115
+ }
141
116
117
+ absl::optional<Overlay> overlay = GetOverlay (key);
118
+ HARD_ASSERT (overlay.has_value ());
119
+ result[std::move (key).document_key ()] = std::move (overlay).value ();
120
+ return ForEachKeyAction::kKeepGoing ;
121
+ });
142
122
return result;
143
123
}
144
124
@@ -157,6 +137,11 @@ int LevelDbDocumentOverlayCache::GetCollectionIndexEntryCount() const {
157
137
LevelDbDocumentOverlayCollectionIndexKey::KeyPrefix (user_id_));
158
138
}
159
139
140
+ int LevelDbDocumentOverlayCache::GetCollectionGroupIndexEntryCount () const {
141
+ return CountEntriesWithKeyPrefix (
142
+ LevelDbDocumentOverlayCollectionGroupIndexKey::KeyPrefix (user_id_));
143
+ }
144
+
160
145
int LevelDbDocumentOverlayCache::CountEntriesWithKeyPrefix (
161
146
const std::string& key_prefix) const {
162
147
int count = 0 ;
@@ -193,6 +178,12 @@ void LevelDbDocumentOverlayCache::SaveOverlay(int largest_batch_id,
193
178
transaction->Put (key.Encode (), serializer_->EncodeMutation (mutation));
194
179
transaction->Put (LevelDbDocumentOverlayLargestBatchIdIndexKey::Key (key), " " );
195
180
transaction->Put (LevelDbDocumentOverlayCollectionIndexKey::Key (key), " " );
181
+
182
+ absl::optional<std::string> collection_group_index_key =
183
+ LevelDbDocumentOverlayCollectionGroupIndexKey::Key (key);
184
+ if (collection_group_index_key.has_value ()) {
185
+ transaction->Put (std::move (collection_group_index_key).value (), " " );
186
+ }
196
187
}
197
188
198
189
void LevelDbDocumentOverlayCache::DeleteOverlay (
@@ -219,19 +210,11 @@ void LevelDbDocumentOverlayCache::DeleteOverlay(
219
210
transaction->Delete (key.Encode ());
220
211
transaction->Delete (LevelDbDocumentOverlayLargestBatchIdIndexKey::Key (key));
221
212
transaction->Delete (LevelDbDocumentOverlayCollectionIndexKey::Key (key));
222
- }
223
213
224
- void LevelDbDocumentOverlayCache::ForEachOverlay (
225
- std::function<void ((LevelDbDocumentOverlayKey && key,
226
- absl::string_view encoded_mutation))> callback) const {
227
- auto it = db_->current_transaction ()->NewIterator ();
228
- const std::string user_key = LevelDbDocumentOverlayKey::KeyPrefix (user_id_);
229
-
230
- for (it->Seek (user_key); it->Valid () && absl::StartsWith (it->key (), user_key);
231
- it->Next ()) {
232
- LevelDbDocumentOverlayKey key;
233
- HARD_ASSERT (key.Decode (it->key ()));
234
- callback (std::move (key), it->value ());
214
+ absl::optional<std::string> collection_group_index_key =
215
+ LevelDbDocumentOverlayCollectionGroupIndexKey::Key (key);
216
+ if (collection_group_index_key.has_value ()) {
217
+ transaction->Delete (std::move (collection_group_index_key).value ());
235
218
}
236
219
}
237
220
@@ -273,6 +256,36 @@ void LevelDbDocumentOverlayCache::ForEachKeyInCollection(
273
256
}
274
257
}
275
258
259
+ void LevelDbDocumentOverlayCache::ForEachKeyInCollectionGroup (
260
+ absl::string_view collection_group,
261
+ int since_batch_id,
262
+ std::function<ForEachKeyAction(LevelDbDocumentOverlayKey&&)> callback)
263
+ const {
264
+ const std::string index_start_key =
265
+ LevelDbDocumentOverlayCollectionGroupIndexKey::KeyPrefix (
266
+ user_id_, collection_group, since_batch_id + 1 );
267
+ const std::string index_key_prefix =
268
+ LevelDbDocumentOverlayCollectionGroupIndexKey::KeyPrefix (
269
+ user_id_, collection_group);
270
+
271
+ auto it = db_->current_transaction ()->NewIterator ();
272
+ for (it->Seek (index_start_key);
273
+ it->Valid () && absl::StartsWith (it->key (), index_key_prefix);
274
+ it->Next ()) {
275
+ LevelDbDocumentOverlayCollectionGroupIndexKey key;
276
+ HARD_ASSERT (key.Decode (it->key ()));
277
+ if (key.collection_group () != collection_group) {
278
+ break ;
279
+ }
280
+ const ForEachKeyAction action =
281
+ callback (std::move (key).ToLevelDbDocumentOverlayKey ());
282
+ if (action == ForEachKeyAction::kStop ) {
283
+ break ;
284
+ }
285
+ HARD_ASSERT (action == ForEachKeyAction::kKeepGoing );
286
+ }
287
+ }
288
+
276
289
absl::optional<Overlay> LevelDbDocumentOverlayCache::GetOverlay (
277
290
const LevelDbDocumentOverlayKey& key) const {
278
291
auto it = db_->current_transaction ()->NewIterator ();
0 commit comments