Skip to content

Commit 69104c7

Browse files
authored
Serve OR queries from the index. (#3368)
* Serve or queries from the index. * Update test. * Clean up. * Move LogicUtils to 'util' directory. * Reuse existing code for finding least recent index offset. * Add missing function to MemoryIndexManager * Add license to new file. * Address comments. * Address comments.
1 parent 41e38cb commit 69104c7

File tree

8 files changed

+249
-77
lines changed

8 files changed

+249
-77
lines changed

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

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,10 @@
2020
import androidx.annotation.VisibleForTesting;
2121
import com.google.firebase.firestore.model.Document;
2222
import com.google.firebase.firestore.model.DocumentKey;
23-
import com.google.firebase.firestore.model.FieldIndex;
2423
import com.google.firebase.firestore.model.FieldIndex.IndexOffset;
2524
import com.google.firebase.firestore.util.AsyncQueue;
2625
import com.google.firebase.firestore.util.Logger;
27-
import java.util.Collection;
2826
import java.util.HashSet;
29-
import java.util.Iterator;
3027
import java.util.Map;
3128
import java.util.Set;
3229
import java.util.concurrent.TimeUnit;
@@ -130,8 +127,7 @@ private int writeIndexEntries() {
130127
private int writeEntriesForCollectionGroup(
131128
String collectionGroup, int documentsRemainingUnderCap) {
132129
// Use the earliest offset of all field indexes to query the local cache.
133-
Collection<FieldIndex> fieldIndexes = indexManager.getFieldIndexes(collectionGroup);
134-
IndexOffset existingOffset = getExistingOffset(fieldIndexes);
130+
IndexOffset existingOffset = indexManager.getMinOffset(collectionGroup);
135131

136132
LocalDocumentsResult nextBatch =
137133
localDocumentsView.getNextDocuments(
@@ -159,24 +155,6 @@ private IndexOffset getNewOffset(IndexOffset existingOffset, LocalDocumentsResul
159155
Math.max(lookupResult.getBatchId(), existingOffset.getLargestBatchId()));
160156
}
161157

162-
/** Returns the lowest offset for the provided index group. */
163-
private IndexOffset getExistingOffset(Collection<FieldIndex> fieldIndexes) {
164-
hardAssert(!fieldIndexes.isEmpty(), "Updating collection without indexes");
165-
166-
Iterator<FieldIndex> it = fieldIndexes.iterator();
167-
IndexOffset minOffset = it.next().getIndexState().getOffset();
168-
int minBatchId = minOffset.getLargestBatchId();
169-
while (it.hasNext()) {
170-
IndexOffset newOffset = it.next().getIndexState().getOffset();
171-
if (newOffset.compareTo(minOffset) < 0) {
172-
minOffset = newOffset;
173-
}
174-
minBatchId = Math.max(newOffset.getLargestBatchId(), minBatchId);
175-
}
176-
177-
return IndexOffset.create(minOffset.getReadTime(), minOffset.getDocumentKey(), minBatchId);
178-
}
179-
180158
@VisibleForTesting
181159
void setMaxDocumentsToProcess(int newMax) {
182160
maxDocumentsToProcess = newMax;

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.firebase.firestore.model.Document;
2121
import com.google.firebase.firestore.model.DocumentKey;
2222
import com.google.firebase.firestore.model.FieldIndex;
23+
import com.google.firebase.firestore.model.FieldIndex.IndexOffset;
2324
import com.google.firebase.firestore.model.ResourcePath;
2425
import java.util.Collection;
2526
import java.util.List;
@@ -74,6 +75,18 @@ public interface IndexManager {
7475
/** Returns all configured field indexes. */
7576
Collection<FieldIndex> getFieldIndexes();
7677

78+
/** Returns whether we can serve the given target from an index. */
79+
boolean canServeFromIndex(Target target);
80+
81+
/**
82+
* Iterates over all field indexes that are used to serve the given target, and returns the
83+
* minimum offset of them all. Asserts that the target can be served from index.
84+
*/
85+
IndexOffset getMinOffset(Target target);
86+
87+
/** Returns the minimum offset for the given collection group. */
88+
IndexOffset getMinOffset(String collectionGroup);
89+
7790
/**
7891
* Returns an index that can be used to serve the provided target. Returns {@code null} if no
7992
* index is configured.
@@ -82,7 +95,7 @@ public interface IndexManager {
8295
FieldIndex getFieldIndex(Target target);
8396

8497
/** Returns the documents that match the given target based on the provided index. */
85-
Set<DocumentKey> getDocumentsMatchingTarget(FieldIndex fieldIndex, Target target);
98+
Set<DocumentKey> getDocumentsMatchingTarget(Target target);
8699

87100
/** Returns the next collection group to update. Returns {@code null} if no group exists. */
88101
@Nullable

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.firebase.firestore.model.Document;
2222
import com.google.firebase.firestore.model.DocumentKey;
2323
import com.google.firebase.firestore.model.FieldIndex;
24+
import com.google.firebase.firestore.model.FieldIndex.IndexOffset;
2425
import com.google.firebase.firestore.model.ResourcePath;
2526
import java.util.ArrayList;
2627
import java.util.Collection;
@@ -69,7 +70,7 @@ public FieldIndex getFieldIndex(Target target) {
6970

7071
@Override
7172
@Nullable
72-
public Set<DocumentKey> getDocumentsMatchingTarget(FieldIndex fieldIndex, Target target) {
73+
public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
7374
// Field indices are not supported with memory persistence.
7475
return Collections.emptySet();
7576
}
@@ -82,7 +83,7 @@ public String getNextCollectionGroupToUpdate() {
8283
}
8384

8485
@Override
85-
public void updateCollectionGroup(String collectionGroup, FieldIndex.IndexOffset offset) {
86+
public void updateCollectionGroup(String collectionGroup, IndexOffset offset) {
8687
// Field indices are not supported with memory persistence.
8788
}
8889

@@ -98,6 +99,21 @@ public Collection<FieldIndex> getFieldIndexes() {
9899
return Collections.emptyList();
99100
}
100101

102+
@Override
103+
public boolean canServeFromIndex(Target target) {
104+
return false;
105+
}
106+
107+
@Override
108+
public IndexOffset getMinOffset(Target target) {
109+
return IndexOffset.NONE;
110+
}
111+
112+
@Override
113+
public IndexOffset getMinOffset(String collectionGroup) {
114+
return IndexOffset.NONE;
115+
}
116+
101117
@Override
102118
public void updateIndexEntries(ImmutableSortedMap<DocumentKey, Document> documents) {
103119
// Field indices are not supported with memory persistence.

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,21 @@ public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
105105
*/
106106
private @Nullable ImmutableSortedMap<DocumentKey, Document> performQueryUsingIndex(
107107
Query query, Target target) {
108-
// TODO(orquery): Update this condition when we are able to serve or queries from the index.
109-
if (query.matchesAllDocuments() || query.containsCompositeFilters()) {
108+
if (query.matchesAllDocuments()) {
110109
// Don't use index queries that can be executed by scanning the collection.
111110
return null;
112111
}
113112

114-
FieldIndex fieldIndex = indexManager.getFieldIndex(query.toTarget());
115-
if (fieldIndex == null) {
113+
if (!indexManager.canServeFromIndex(target)) {
116114
return null;
117115
}
118116

119-
Set<DocumentKey> keys = indexManager.getDocumentsMatchingTarget(fieldIndex, target);
117+
Set<DocumentKey> keys = indexManager.getDocumentsMatchingTarget(target);
120118
ImmutableSortedMap<DocumentKey, Document> indexedDocuments =
121119
localDocumentsView.getDocuments(keys);
120+
122121
return appendRemainingResults(
123-
values(indexedDocuments), query, fieldIndex.getIndexState().getOffset());
122+
values(indexedDocuments), query, indexManager.getMinOffset(target));
124123
}
125124

126125
/**
@@ -131,8 +130,7 @@ public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
131130
Query query,
132131
ImmutableSortedSet<DocumentKey> remoteKeys,
133132
SnapshotVersion lastLimboFreeSnapshotVersion) {
134-
// TODO(orquery): Update this condition when we are able to serve or queries from the index.
135-
if (query.matchesAllDocuments() || query.containsCompositeFilters()) {
133+
if (query.matchesAllDocuments()) {
136134
// Don't use index queries that can be executed by scanning the collection.
137135
return null;
138136
}

0 commit comments

Comments
 (0)