Skip to content

Commit 19a3e5c

Browse files
Merge
2 parents 6c67df6 + 339fff1 commit 19a3e5c

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public ImmutableSortedMap<DocumentKey, MaybeDocument> acknowledgeBatch(
208208
() -> {
209209
MutationBatch batch = batchResult.getBatch();
210210
mutationQueue.acknowledgeBatch(batch, batchResult.getStreamToken());
211-
applyBatchResult(batchResult);
211+
applyWriteToRemoteDocuments(batchResult);
212212
mutationQueue.performConsistencyCheck();
213213
return localDocuments.getDocuments(batch.getKeys());
214214
});
@@ -503,7 +503,15 @@ public void releaseQuery(Query query) {
503503
queryCache.updateQueryData(queryData);
504504
}
505505

506-
localViewReferences.removeReferencesForId(queryData.getTargetId());
506+
// References for documents sent via Watch are automatically removed when we delete a
507+
// query's target data from the reference delegate. Since this does not remove references
508+
// for locally mutated documents, we have to remove the target associations for these
509+
// documents manually.
510+
ImmutableSortedSet<DocumentKey> removedReferences =
511+
localViewReferences.removeReferencesForId(queryData.getTargetId());
512+
for (DocumentKey key : removedReferences) {
513+
persistence.getReferenceDelegate().removeReference(key);
514+
}
507515
persistence.getReferenceDelegate().removeTarget(queryData);
508516
targetIds.remove(queryData.getTargetId());
509517
});
@@ -522,7 +530,7 @@ public ImmutableSortedSet<DocumentKey> getRemoteDocumentKeys(int targetId) {
522530
return queryCache.getMatchingKeysForTargetId(targetId);
523531
}
524532

525-
private void applyBatchResult(MutationBatchResult batchResult) {
533+
private void applyWriteToRemoteDocuments(MutationBatchResult batchResult) {
526534
MutationBatch batch = batchResult.getBatch();
527535
Set<DocumentKey> docKeys = batch.getKeys();
528536
for (DocumentKey docKey : docKeys) {

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,27 @@ public void removeReferences(ImmutableSortedSet<DocumentKey> keys, int targetOrB
7777
}
7878
}
7979

80-
/** Clears all references with a given ID. Calls removeReference() for each key removed. */
81-
public void removeReferencesForId(int targetId) {
80+
/**
81+
* Clears all references with a given ID. Calls removeReference() for each key removed.
82+
*
83+
* @return The keys of the documents that were removed.
84+
*/
85+
public ImmutableSortedSet<DocumentKey> removeReferencesForId(int targetId) {
8286
DocumentKey emptyKey = DocumentKey.empty();
8387
DocumentReference startRef = new DocumentReference(emptyKey, targetId);
8488
Iterator<DocumentReference> it = referencesByTarget.iteratorFrom(startRef);
89+
ImmutableSortedSet<DocumentKey> keys = DocumentKey.emptyKeySet();
8590
while (it.hasNext()) {
8691
DocumentReference ref = it.next();
8792
if (ref.getId() == targetId) {
93+
keys = keys.insert(ref.getKey());
8894
removeReference(ref);
8995
} else {
9096
break;
9197
}
9298
}
99+
100+
return keys;
93101
}
94102

95103
/** Clears all references for all IDs. */

firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalStoreTestCase.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,31 @@ public void testHandlesSetMutationThenDocument() {
243243
assertContains(doc("foo/bar", 2, map("foo", "bar"), Document.DocumentState.LOCAL_MUTATIONS));
244244
}
245245

246+
@Test
247+
public void testHandlesSetMutationThenAckThenRelease() {
248+
Query query = Query.atPath(ResourcePath.fromSegments(asList("foo")));
249+
allocateQuery(query);
250+
251+
writeMutation(setMutation("foo/bar", map("foo", "bar")));
252+
assertChanged(doc("foo/bar", 0, map("foo", "bar"), Document.DocumentState.LOCAL_MUTATIONS));
253+
assertContains(doc("foo/bar", 0, map("foo", "bar"), Document.DocumentState.LOCAL_MUTATIONS));
254+
255+
acknowledgeMutation(1);
256+
notifyLocalViewChanges(viewChanges(2, asList("foo/bar"), emptyList()));
257+
258+
assertChanged(doc("foo/bar", 1, map("foo", "bar"), Document.DocumentState.COMMITTED_MUTATIONS));
259+
assertContains(doc("foo/bar", 1, map("foo", "bar"), Document.DocumentState.COMMITTED_MUTATIONS));
260+
261+
releaseQuery(query);
262+
263+
// It has been acknowledged, and should no longer be retained as there is no target and mutation
264+
if (garbageCollectorIsEager()) {
265+
assertNotContains("foo/bar");
266+
} else {
267+
assertContains(doc("foo/bar", 0, map("foo", "bar"), Document.DocumentState.COMMITTED_MUTATIONS));
268+
}
269+
}
270+
246271
@Test
247272
public void testHandlesAckThenRejectThenRemoteEvent() {
248273
// Start a query that requires acks to be held.

0 commit comments

Comments
 (0)