Skip to content

Commit 5e3a516

Browse files
author
Greg Soltis
authored
LocalStore uses a SparseArray to track target ids, not a set (#65)
* LocalStore uses a SparseArray to track target ids, not a set, so use that instead of a set in lru code. * Add android robolectric to memory version of the lru tests
1 parent 58c2075 commit 5e3a516

File tree

8 files changed

+26
-19
lines changed

8 files changed

+26
-19
lines changed

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

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

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

17+
import android.util.SparseArray;
1718
import com.google.firebase.firestore.util.Consumer;
18-
import java.util.Set;
1919

2020
/**
2121
* Persistence layers intending to use LRU Garbage collection should implement this interface. This
@@ -37,7 +37,7 @@ interface LruDelegate {
3737
*
3838
* @return the number of targets removed.
3939
*/
40-
int removeTargets(long upperBound, Set<Integer> activeTargetIds);
40+
int removeTargets(long upperBound, SparseArray<?> activeTargetIds);
4141

4242
/**
4343
* Removes all unreferenced documents from the cache that have a sequence number less than or

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

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

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

17+
import android.util.SparseArray;
1718
import com.google.firebase.firestore.core.ListenSequence;
1819
import java.util.Comparator;
1920
import java.util.PriorityQueue;
20-
import java.util.Set;
2121

2222
/** Implements the steps for LRU garbage collection. */
2323
class LruGarbageCollector {
@@ -80,7 +80,7 @@ long nthSequenceNumber(int count) {
8080
* Removes targets with a sequence number equal to or less than the given upper bound, and removes
8181
* document associations with those targets.
8282
*/
83-
int removeTargets(long upperBound, Set<Integer> activeTargetIds) {
83+
int removeTargets(long upperBound, SparseArray<?> activeTargetIds) {
8484
return delegate.removeTargets(upperBound, activeTargetIds);
8585
}
8686

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
import static com.google.firebase.firestore.util.Assert.hardAssert;
1818

19+
import android.util.SparseArray;
1920
import com.google.firebase.firestore.core.ListenSequence;
2021
import com.google.firebase.firestore.model.DocumentKey;
2122
import com.google.firebase.firestore.model.MaybeDocument;
2223
import com.google.firebase.firestore.util.Consumer;
2324
import java.util.HashMap;
2425
import java.util.Map;
25-
import java.util.Set;
2626

2727
/** Provides LRU garbage collection functionality for MemoryPersistence. */
2828
class MemoryLruReferenceDelegate implements ReferenceDelegate, LruDelegate {
@@ -94,7 +94,7 @@ public void setInMemoryPins(ReferenceSet inMemoryPins) {
9494
}
9595

9696
@Override
97-
public int removeTargets(long upperBound, Set<Integer> activeTargetIds) {
97+
public int removeTargets(long upperBound, SparseArray<?> activeTargetIds) {
9898
return persistence.getQueryCache().removeQueries(upperBound, activeTargetIds);
9999
}
100100

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

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

17+
import android.util.SparseArray;
1718
import com.google.firebase.database.collection.ImmutableSortedSet;
1819
import com.google.firebase.firestore.core.Query;
1920
import com.google.firebase.firestore.model.DocumentKey;
@@ -22,7 +23,6 @@
2223
import java.util.HashMap;
2324
import java.util.Iterator;
2425
import java.util.Map;
25-
import java.util.Set;
2626
import javax.annotation.Nullable;
2727

2828
/**
@@ -115,13 +115,13 @@ public void removeQueryData(QueryData queryData) {
115115
*
116116
* @return the number of targets removed
117117
*/
118-
int removeQueries(long upperBound, Set<Integer> activeTargetIds) {
118+
int removeQueries(long upperBound, SparseArray<?> activeTargetIds) {
119119
int removed = 0;
120120
for (Iterator<Map.Entry<Query, QueryData>> it = queries.entrySet().iterator(); it.hasNext(); ) {
121121
Map.Entry<Query, QueryData> entry = it.next();
122122
int targetId = entry.getValue().getTargetId();
123123
long sequenceNumber = entry.getValue().getSequenceNumber();
124-
if (sequenceNumber <= upperBound && !activeTargetIds.contains(targetId)) {
124+
if (sequenceNumber <= upperBound && activeTargetIds.get(targetId) == null) {
125125
it.remove();
126126
removeMatchingKeysForTargetId(targetId);
127127
removed++;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
import static com.google.firebase.firestore.util.Assert.hardAssert;
1818

19+
import android.util.SparseArray;
1920
import com.google.firebase.firestore.core.ListenSequence;
2021
import com.google.firebase.firestore.model.DocumentKey;
2122
import com.google.firebase.firestore.model.ResourcePath;
2223
import com.google.firebase.firestore.util.Consumer;
23-
import java.util.Set;
2424

2525
/** Provides LRU functionality for SQLite persistence. */
2626
class SQLiteLruReferenceDelegate implements ReferenceDelegate, LruDelegate {
@@ -103,7 +103,7 @@ public void removeReference(DocumentKey key) {
103103
}
104104

105105
@Override
106-
public int removeTargets(long upperBound, Set<Integer> activeTargetIds) {
106+
public int removeTargets(long upperBound, SparseArray<?> activeTargetIds) {
107107
return persistence.getQueryCache().removeQueries(upperBound, activeTargetIds);
108108
}
109109

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.google.firebase.firestore.util.Assert.hardAssert;
1919

2020
import android.database.sqlite.SQLiteStatement;
21+
import android.util.SparseArray;
2122
import com.google.firebase.Timestamp;
2223
import com.google.firebase.database.collection.ImmutableSortedSet;
2324
import com.google.firebase.firestore.core.Query;
@@ -26,7 +27,6 @@
2627
import com.google.firebase.firestore.proto.Target;
2728
import com.google.firebase.firestore.util.Consumer;
2829
import com.google.protobuf.InvalidProtocolBufferException;
29-
import java.util.Set;
3030
import javax.annotation.Nullable;
3131

3232
/** Cached Queries backed by SQLite. */
@@ -186,7 +186,7 @@ public void removeQueryData(QueryData queryData) {
186186
* present in `activeTargetIds`. Document associations for the removed targets are also removed.
187187
* Returns the number of targets removed.
188188
*/
189-
int removeQueries(long upperBound, Set<Integer> activeTargetIds) {
189+
int removeQueries(long upperBound, SparseArray<?> activeTargetIds) {
190190
int[] count = new int[1];
191191
// SQLite has a max sql statement size, so there is technically a possibility that including a
192192
// an IN clause in this query to filter `activeTargetIds` could overflow. Rather than deal with
@@ -196,7 +196,7 @@ int removeQueries(long upperBound, Set<Integer> activeTargetIds) {
196196
.forEach(
197197
row -> {
198198
int targetId = row.getInt(0);
199-
if (!activeTargetIds.contains(targetId)) {
199+
if (activeTargetIds.get(targetId) == null) {
200200
removeTarget(targetId);
201201
count[0]++;
202202
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.junit.Assert.assertNull;
2727
import static org.junit.Assert.assertTrue;
2828

29+
import android.util.SparseArray;
2930
import com.google.firebase.Timestamp;
3031
import com.google.firebase.firestore.auth.User;
3132
import com.google.firebase.firestore.core.ListenSequence;
@@ -162,7 +163,7 @@ private void removeDocumentFromTarget(DocumentKey key, int targetId) {
162163
queryCache.removeMatchingKeys(keySet(key), targetId);
163164
}
164165

165-
private int removeTargets(long upperBound, Set<Integer> activeTargetIds) {
166+
private int removeTargets(long upperBound, SparseArray<?> activeTargetIds) {
166167
return persistence.runTransaction(
167168
"Remove queries", () -> garbageCollector.removeTargets(upperBound, activeTargetIds));
168169
}
@@ -283,7 +284,7 @@ public void testSequenceNumbersWithMutationsInQueries() {
283284

284285
@Test
285286
public void testRemoveQueriesUpThroughSequenceNumber() {
286-
Map<Integer, QueryData> activeTargetIds = new HashMap<>();
287+
SparseArray<QueryData> activeTargetIds = new SparseArray<>();
287288
for (int i = 0; i < 100; i++) {
288289
QueryData queryData = addNextQuery();
289290
// Mark odd queries as live so we can test filtering out live queries.
@@ -295,7 +296,7 @@ public void testRemoveQueriesUpThroughSequenceNumber() {
295296
// GC up through 20th query, which is 20%.
296297
// Expect to have GC'd 10 targets, since every other target is live
297298
long upperBound = 20 + initialSequenceNumber;
298-
int removed = removeTargets(upperBound, activeTargetIds.keySet());
299+
int removed = removeTargets(upperBound, activeTargetIds);
299300
assertEquals(10, removed);
300301
// Make sure we removed the even targets with targetID <= 20.
301302
persistence.runTransaction(
@@ -567,8 +568,8 @@ public void testRemoveTargetsThenGC() {
567568
});
568569

569570
// Finally, do the garbage collection, up to but not including the removal of middleTarget
570-
Set<Integer> activeTargetIds = new HashSet<>();
571-
activeTargetIds.add(oldestTarget.getTargetId());
571+
SparseArray<QueryData> activeTargetIds = new SparseArray<>();
572+
activeTargetIds.put(oldestTarget.getTargetId(), oldestTarget);
572573
int targetsRemoved = garbageCollector.removeTargets(upperBound, activeTargetIds);
573574
// Expect to remove newest target
574575
assertEquals(1, targetsRemoved);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

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

17+
import org.junit.runner.RunWith;
18+
import org.robolectric.RobolectricTestRunner;
19+
import org.robolectric.annotation.Config;
20+
21+
@RunWith(RobolectricTestRunner.class)
22+
@Config(manifest = Config.NONE)
1723
public class MemoryLruGarbageCollectorTest extends LruGarbageCollectorTestCase {
1824
@Override
1925
Persistence createPersistence() {

0 commit comments

Comments
 (0)