Skip to content

Commit 9d64048

Browse files
Add Overlay class
1 parent 5cf9ae8 commit 9d64048

File tree

9 files changed

+162
-129
lines changed

9 files changed

+162
-129
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/local/DocumentOverlayCache.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.firebase.firestore.model.DocumentKey;
1919
import com.google.firebase.firestore.model.ResourcePath;
2020
import com.google.firebase.firestore.model.mutation.Mutation;
21+
import com.google.firebase.firestore.model.mutation.Overlay;
2122
import java.util.Map;
2223

2324
/**
@@ -35,7 +36,7 @@ public interface DocumentOverlayCache {
3536
* for that key.
3637
*/
3738
@Nullable
38-
Mutation getOverlay(DocumentKey key);
39+
Overlay getOverlay(DocumentKey key);
3940

4041
/**
4142
* Saves the given document key to mutation map to persistence as overlays. All overlays will have
@@ -52,6 +53,7 @@ public interface DocumentOverlayCache {
5253
* @param collection The collection path to get the overlays for.
5354
* @param sinceBatchId The minimum batch ID to filter by (exclusive). Only overlays that contain a
5455
* change past `sinceBatchId` are returned.
56+
* @return Mapping of each document key in the collection to its overlay.
5557
*/
56-
Map<DocumentKey, Mutation> getOverlays(ResourcePath collection, int sinceBatchId);
58+
Map<DocumentKey, Overlay> getOverlays(ResourcePath collection, int sinceBatchId);
5759
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalDocumentsView.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.google.firebase.firestore.model.mutation.FieldMask;
3030
import com.google.firebase.firestore.model.mutation.Mutation;
3131
import com.google.firebase.firestore.model.mutation.MutationBatch;
32+
import com.google.firebase.firestore.model.mutation.Overlay;
3233
import com.google.firebase.firestore.model.mutation.PatchMutation;
3334
import java.util.HashMap;
3435
import java.util.HashSet;
@@ -42,7 +43,6 @@
4243
* in remoteDocumentCache or local mutations for the document). The view is computed by applying the
4344
* mutations in the MutationQueue to the RemoteDocumentCache.
4445
*/
45-
// TODO: Turn this into the UnifiedDocumentCache / whatever.
4646
class LocalDocumentsView {
4747

4848
private final RemoteDocumentCache remoteDocumentCache;
@@ -88,14 +88,14 @@ IndexManager getIndexManager() {
8888
* for it.
8989
*/
9090
Document getDocument(DocumentKey key) {
91-
Mutation overlay = documentOverlayCache.getOverlay(key);
91+
Overlay overlay = documentOverlayCache.getOverlay(key);
9292
// Only read from remote document cache if overlay is a patch.
9393
MutableDocument document =
94-
(overlay == null || overlay instanceof PatchMutation)
94+
(overlay == null || overlay.getMutation() instanceof PatchMutation)
9595
? remoteDocumentCache.get(key)
9696
: MutableDocument.newInvalidDocument(key);
9797
if (overlay != null) {
98-
overlay.applyToLocalView(document, null, Timestamp.now());
98+
overlay.getMutation().applyToLocalView(document, null, Timestamp.now());
9999
}
100100

101101
return document;
@@ -125,18 +125,18 @@ ImmutableSortedMap<DocumentKey, Document> getLocalViewOfDocuments(
125125
ImmutableSortedMap<DocumentKey, Document> results = emptyDocumentMap();
126126
Map<DocumentKey, MutableDocument> recalculateDocuments = new HashMap<>();
127127
for (Map.Entry<DocumentKey, MutableDocument> entry : docs.entrySet()) {
128-
Mutation overlay = documentOverlayCache.getOverlay(entry.getKey());
128+
Overlay overlay = documentOverlayCache.getOverlay(entry.getKey());
129129
// Recalculate an overlay if the document's existence state is changed due to a remote
130130
// event *and* the overlay is a PatchMutation. This is because document existence state
131131
// can change if some patch mutation's preconditions are met.
132132
// NOTE: we recalculate when `overlay` is null as well, because there might be a patch
133133
// mutation whose precondition does not match before the change (hence overlay==null),
134134
// but would now match.
135135
if (existenceStateChanged.contains(entry.getKey())
136-
&& (overlay == null || overlay instanceof PatchMutation)) {
136+
&& (overlay == null || overlay.getMutation() instanceof PatchMutation)) {
137137
recalculateDocuments.put(entry.getKey(), docs.get(entry.getKey()));
138138
} else if (overlay != null) {
139-
overlay.applyToLocalView(entry.getValue(), null, Timestamp.now());
139+
overlay.getMutation().applyToLocalView(entry.getValue(), null, Timestamp.now());
140140
}
141141
}
142142

@@ -260,11 +260,11 @@ private ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingCollection
260260
Query query, IndexOffset offset) {
261261
Map<DocumentKey, MutableDocument> remoteDocuments =
262262
remoteDocumentCache.getAll(query.getPath(), offset);
263-
Map<DocumentKey, Mutation> overlays = documentOverlayCache.getOverlays(query.getPath(), -1);
263+
Map<DocumentKey, Overlay> overlays = documentOverlayCache.getOverlays(query.getPath(), -1);
264264

265265
// As documents might match the query because of their overlay we need to include documents
266266
// for all overlays in the initial document set.
267-
for (Map.Entry<DocumentKey, Mutation> entry : overlays.entrySet()) {
267+
for (Map.Entry<DocumentKey, Overlay> entry : overlays.entrySet()) {
268268
if (!remoteDocuments.containsKey(entry.getKey())) {
269269
remoteDocuments.put(entry.getKey(), MutableDocument.newInvalidDocument(entry.getKey()));
270270
}
@@ -273,9 +273,9 @@ private ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingCollection
273273
// Apply the overlays and match against the query.
274274
ImmutableSortedMap<DocumentKey, Document> results = emptyDocumentMap();
275275
for (Map.Entry<DocumentKey, MutableDocument> docEntry : remoteDocuments.entrySet()) {
276-
Mutation overlay = overlays.get(docEntry.getKey());
276+
Overlay overlay = overlays.get(docEntry.getKey());
277277
if (overlay != null) {
278-
overlay.applyToLocalView(docEntry.getValue(), null, Timestamp.now());
278+
overlay.getMutation().applyToLocalView(docEntry.getValue(), null, Timestamp.now());
279279
}
280280
// Finally, insert the documents that still match the query
281281
if (query.matches(docEntry.getValue())) {

firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryDocumentOverlayCache.java

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
package com.google.firebase.firestore.local;
1616

17-
import android.util.Pair;
1817
import androidx.annotation.Nullable;
1918
import com.google.firebase.firestore.model.DocumentKey;
2019
import com.google.firebase.firestore.model.ResourcePath;
2120
import com.google.firebase.firestore.model.mutation.Mutation;
21+
import com.google.firebase.firestore.model.mutation.Overlay;
2222
import java.util.HashMap;
2323
import java.util.HashSet;
2424
import java.util.Map;
@@ -28,17 +28,13 @@
2828
public class MemoryDocumentOverlayCache implements DocumentOverlayCache {
2929
// A map sorted by DocumentKey, whose value is a pair of the largest batch id for the overlay
3030
// and the overlay itself.
31-
private final TreeMap<DocumentKey, Pair<Integer, Mutation>> overlays = new TreeMap<>();
31+
private final TreeMap<DocumentKey, Overlay> overlays = new TreeMap<>();
3232
private final Map<Integer, Set<DocumentKey>> overlayByBatchId = new HashMap<>();
3333

3434
@Nullable
3535
@Override
36-
public Mutation getOverlay(DocumentKey key) {
37-
Pair<Integer, Mutation> overlay = overlays.get(key);
38-
if (overlay != null) {
39-
return overlay.second;
40-
}
41-
return null;
36+
public Overlay getOverlay(DocumentKey key) {
37+
return overlays.get(key);
4238
}
4339

4440
private void saveOverlay(int largestBatchId, @Nullable Mutation mutation) {
@@ -47,12 +43,12 @@ private void saveOverlay(int largestBatchId, @Nullable Mutation mutation) {
4743
}
4844

4945
// Remove the association of the overlay to its batch id.
50-
Pair<Integer, Mutation> existing = this.overlays.get(mutation.getKey());
46+
Overlay existing = this.overlays.get(mutation.getKey());
5147
if (existing != null) {
52-
overlayByBatchId.get(existing.first).remove(mutation.getKey());
48+
overlayByBatchId.get(existing.getLargestBatchId()).remove(mutation.getKey());
5349
}
5450

55-
overlays.put(mutation.getKey(), new Pair<>(largestBatchId, mutation));
51+
overlays.put(mutation.getKey(), Overlay.create(largestBatchId, mutation));
5652

5753
// Create the associate of this overlay to the given largestBatchId.
5854
if (overlayByBatchId.get(largestBatchId) == null) {
@@ -80,15 +76,15 @@ public void removeOverlaysForBatchId(int batchId) {
8076
}
8177

8278
@Override
83-
public Map<DocumentKey, Mutation> getOverlays(ResourcePath collection, int sinceBatchId) {
84-
Map<DocumentKey, Mutation> result = new HashMap<>();
79+
public Map<DocumentKey, Overlay> getOverlays(ResourcePath collection, int sinceBatchId) {
80+
Map<DocumentKey, Overlay> result = new HashMap<>();
8581

8682
int immediateChildrenPathLength = collection.length() + 1;
8783
DocumentKey prefix = DocumentKey.fromPath(collection.append(""));
88-
Map<DocumentKey, Pair<Integer, Mutation>> view = overlays.tailMap(prefix);
84+
Map<DocumentKey, Overlay> view = overlays.tailMap(prefix);
8985

90-
for (Map.Entry<DocumentKey, Pair<Integer, Mutation>> entry : view.entrySet()) {
91-
DocumentKey key = entry.getKey();
86+
for (Overlay overlay : view.values()) {
87+
DocumentKey key = overlay.getKey();
9288
if (!collection.isPrefixOf(key.getPath())) {
9389
break;
9490
}
@@ -97,9 +93,8 @@ public Map<DocumentKey, Mutation> getOverlays(ResourcePath collection, int since
9793
continue;
9894
}
9995

100-
Pair<Integer, Mutation> batchIdToOverlay = entry.getValue();
101-
if (batchIdToOverlay.first > sinceBatchId) {
102-
result.put(entry.getKey(), batchIdToOverlay.second);
96+
if (overlay.getLargestBatchId() > sinceBatchId) {
97+
result.put(overlay.getKey(), overlay);
10398
}
10499
}
105100

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteDocumentOverlayCache.java

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.firebase.firestore.model.DocumentKey;
2222
import com.google.firebase.firestore.model.ResourcePath;
2323
import com.google.firebase.firestore.model.mutation.Mutation;
24+
import com.google.firebase.firestore.model.mutation.Overlay;
2425
import com.google.firestore.v1.Write;
2526
import com.google.protobuf.InvalidProtocolBufferException;
2627
import java.util.HashMap;
@@ -39,23 +40,14 @@ public SQLiteDocumentOverlayCache(SQLitePersistence db, LocalSerializer serializ
3940

4041
@Nullable
4142
@Override
42-
public Mutation getOverlay(DocumentKey key) {
43+
public Overlay getOverlay(DocumentKey key) {
4344
String collectionPath = EncodedPath.encode(key.getPath().popLast());
4445
String documentId = key.getPath().getLastSegment();
4546
return db.query(
46-
"SELECT overlay_mutation FROM document_overlays WHERE uid = ? AND collection_path = ? AND document_id = ?")
47+
"SELECT overlay_mutation, largest_batch_id FROM document_overlays "
48+
+ "WHERE uid = ? AND collection_path = ? AND document_id = ?")
4749
.binding(uid, collectionPath, documentId)
48-
.firstValue(
49-
row -> {
50-
if (row == null) return null;
51-
52-
try {
53-
Write mutation = Write.parseFrom(row.getBlob(0));
54-
return serializer.decodeMutation(mutation);
55-
} catch (InvalidProtocolBufferException e) {
56-
throw fail("Overlay failed to parse: %s", e);
57-
}
58-
});
50+
.firstValue(this::decodeOverlay);
5951
}
6052

6153
private void saveOverlay(int largestBatchId, DocumentKey key, @Nullable Mutation mutation) {
@@ -90,28 +82,31 @@ public void removeOverlaysForBatchId(int batchId) {
9082
}
9183

9284
@Override
93-
public Map<DocumentKey, Mutation> getOverlays(ResourcePath collection, int sinceBatchId) {
85+
public Map<DocumentKey, Overlay> getOverlays(ResourcePath collection, int sinceBatchId) {
9486
String collectionPath = EncodedPath.encode(collection);
9587

96-
Map<DocumentKey, Mutation> result = new HashMap<>();
97-
88+
Map<DocumentKey, Overlay> result = new HashMap<>();
9889
db.query(
99-
"SELECT document_id, overlay_mutation FROM document_overlays "
90+
"SELECT overlay_mutation, largest_batch_id FROM document_overlays "
10091
+ "WHERE uid = ? AND collection_path = ? AND largest_batch_id > ?")
10192
.binding(uid, collectionPath, sinceBatchId)
10293
.forEach(
10394
row -> {
104-
try {
105-
String documentId = row.getString(0);
106-
Write write = Write.parseFrom(row.getBlob(1));
107-
Mutation mutation = serializer.decodeMutation(write);
108-
109-
result.put(DocumentKey.fromPath(collection.append(documentId)), mutation);
110-
} catch (InvalidProtocolBufferException e) {
111-
throw fail("Overlay failed to parse: %s", e);
112-
}
95+
Overlay overlay = decodeOverlay(row);
96+
result.put(overlay.getKey(), overlay);
11397
});
11498

11599
return result;
116100
}
101+
102+
private Overlay decodeOverlay(android.database.Cursor row) {
103+
try {
104+
Write write = Write.parseFrom(row.getBlob(0));
105+
int largestBatchId = row.getInt(1);
106+
Mutation mutation = serializer.decodeMutation(write);
107+
return Overlay.create(largestBatchId, mutation);
108+
} catch (InvalidProtocolBufferException e) {
109+
throw fail("Overlay failed to parse: %s", e);
110+
}
111+
}
117112
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteSchema.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ private void removeMutationBatch(String uid, int batchId) {
297297
mutationDeleter.bindString(1, uid);
298298
mutationDeleter.bindLong(2, batchId);
299299
int deleted = mutationDeleter.executeUpdateDelete();
300-
hardAssert(deleted != 0, "Mutatiohn batch (%s, %d) did not exist", uid, batchId);
300+
hardAssert(deleted != 0, "Mutation batch (%s, %d) did not exist", uid, batchId);
301301

302302
// Delete all index entries for this batch
303303
db.execSQL(
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.model.mutation;
16+
17+
import com.google.auto.value.AutoValue;
18+
import com.google.firebase.firestore.model.DocumentKey;
19+
20+
/**
21+
* Representation of an overlay computed by Firestore.
22+
*
23+
* <p>Holds information about a mutation and the largest batch id in Firestore when the mutation was
24+
* created.
25+
*/
26+
@AutoValue
27+
public abstract class Overlay {
28+
public static Overlay create(int largestBatchId, Mutation mutation) {
29+
return new AutoValue_Overlay(largestBatchId, mutation);
30+
}
31+
32+
public abstract int getLargestBatchId();
33+
34+
public abstract Mutation getMutation();
35+
36+
public DocumentKey getKey() {
37+
return getMutation().getKey();
38+
}
39+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/util/Util.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,11 @@ public static <K, V> Map<K, V> firstNEntries(Map<K, V> data, int n, Comparator<V
392392
if (data.size() <= n) {
393393
return data;
394394
} else {
395-
List<Map.Entry<K, V>> sortedVlaues = new ArrayList<>(data.entrySet());
396-
Collections.sort(sortedVlaues, (l, r) -> comp.compare(l.getValue(), r.getValue()));
395+
List<Map.Entry<K, V>> sortedValues = new ArrayList<>(data.entrySet());
396+
Collections.sort(sortedValues, (l, r) -> comp.compare(l.getValue(), r.getValue()));
397397
Map<K, V> result = new HashMap<>();
398398
for (int i = 0; i < n; ++i) {
399-
result.put(sortedVlaues.get(i).getKey(), sortedVlaues.get(i).getValue());
399+
result.put(sortedValues.get(i).getKey(), sortedValues.get(i).getValue());
400400
}
401401
return result;
402402
}

0 commit comments

Comments
 (0)