Skip to content

Commit 4dda69e

Browse files
Review comments
1 parent 34bbd31 commit 4dda69e

File tree

5 files changed

+149
-92
lines changed

5 files changed

+149
-92
lines changed

packages/firestore/src/core/sync_engine.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,10 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
246246
const remoteKeys = await this.localStore.remoteDocumentKeys(
247247
queryData.targetId
248248
);
249-
const docs = await this.localStore.executeQuery(
250-
query,
249+
const docs = await this.localStore.executeQuery(query, {
251250
queryData,
252251
remoteKeys
253-
);
252+
});
254253

255254
const view = new View(query, remoteKeys);
256255
const viewDocChanges = view.computeDocChanges(docs);
@@ -290,11 +289,10 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
290289
const remoteKeys = await this.localStore.remoteDocumentKeys(
291290
queryData.targetId
292291
);
293-
const docs = await this.localStore.executeQuery(
294-
queryData.query,
292+
const docs = await this.localStore.executeQuery(queryData.query, {
295293
queryData,
296294
remoteKeys
297-
);
295+
});
298296
const viewSnapshot = view.synchronizeWithPersistedState(docs, remoteKeys);
299297
if (this.isPrimary) {
300298
this.updateTrackedLimbos(queryData.targetId, viewSnapshot.limboChanges);
@@ -793,7 +791,7 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
793791
// to re-run the query against the local store to make sure we
794792
// didn't lose any good docs that had been past the limit.
795793
return this.localStore
796-
.executeQuery(queryView.query, null, documentKeySet())
794+
.executeQuery(queryView.query, { needsRefill: true })
797795
.then(docs => {
798796
return queryView.view.computeDocChanges(docs, viewDocChanges);
799797
});

packages/firestore/src/local/index_free_query_engine.ts

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,25 @@ import { assert } from '../util/assert';
2828
import { debug, getLogLevel, LogLevel } from '../util/log';
2929
import { SortedSet } from '../util/sorted_set';
3030

31+
// TOOD(b/140938512): Drop SimpleQueryEngine and rename IndexFreeQueryEngine.
32+
3133
/**
3234
* A query engine that takes advantage of the target document mapping in the
3335
* QueryCache. The IndexFreeQueryEngine optimizes query execution by only
34-
* reading the documents previously matched a query plus any documents that were
36+
* reading the documents that previously matched a query plus any documents that were
3537
* edited after the query was last listened to.
3638
*
3739
* There are some cases where Index-Free queries are not guaranteed to produce
38-
* to the same results as full collection scans. In these case, the
39-
* IndexFreeQueryEngine falls back to a full query processing. These cases are:
40+
* the same results as full collection scans. In these cases, the
41+
* IndexFreeQueryEngine falls back to full query processing. These cases are:
4042
*
4143
* - Limit queries where a document that matched the query previously no longer
42-
* matches the query. In this case, we have to scan all local documents since a
43-
* document that was sent to us as part of a different query result may now fall
44-
* into the limit.
44+
* matches the query.
4545
*
46-
* - Limit queries that include edits that occurred after the last remote
47-
* snapshot (both latency-compensated or committed). Even if an edited document
48-
* continues to match the query, an edit may cause a document to sort below
49-
* another document that is in the local cache.
46+
* - Limit queries where a document edit may cause the document to sort below
47+
* another document that is in the local cache.
5048
*
51-
* - Queries where the last snapshot contained Limbo documents. Even though a
52-
* Limbo document is not part of the backend result set, we need to include
53-
* Limbo documents in local views to ensure consistency between different Query
54-
* views. If there exists a previous query snapshot that contained no limbo
55-
* documents, we can instead use the older snapshot version for Index-Free
56-
* processing.
49+
* - Queries that have never been CURRENT or free of Limbo documents.
5750
*/
5851
export class IndexFreeQueryEngine implements QueryEngine {
5952
private localDocumentsView: LocalDocumentsView | undefined;
@@ -89,7 +82,7 @@ export class IndexFreeQueryEngine implements QueryEngine {
8982
return this.executeFullCollectionScan(transaction, query);
9083
}
9184

92-
return this.getSortedPreviousResults(transaction, query, remoteKeys).next(
85+
return this.getSortedDocuments(transaction, query, remoteKeys).next(
9386
previousResults => {
9487
if (
9588
query.hasLimit() &&
@@ -131,21 +124,20 @@ export class IndexFreeQueryEngine implements QueryEngine {
131124
* Returns the documents for the specified remote keys if they still match the
132125
* query, sorted by the query's comparator.
133126
*/
134-
getSortedPreviousResults(
127+
private getSortedDocuments(
135128
transaction: PersistenceTransaction,
136-
query: Query,
129+
sortByQuery: Query,
137130
remoteKeys: DocumentKeySet
138131
): PersistencePromise<SortedSet<Document>> {
139-
// Fetch the documents that matched the query at the last snapshot.
140132
return this.localDocumentsView!.getDocuments(transaction, remoteKeys).next(
141133
previousResults => {
142134
// Sort the documents and re-apply the query filter since previously
143135
// matching documents do not necessarily still match the query.
144136
let results = new SortedSet<Document>((d1, d2) =>
145-
query.docComparator(d1, d2)
137+
sortByQuery.docComparator(d1, d2)
146138
);
147139
previousResults.forEach((_, maybeDoc) => {
148-
if (maybeDoc instanceof Document && query.matches(maybeDoc)) {
140+
if (maybeDoc instanceof Document && sortByQuery.matches(maybeDoc)) {
149141
results = results.add(maybeDoc);
150142
}
151143
});
@@ -166,7 +158,7 @@ export class IndexFreeQueryEngine implements QueryEngine {
166158
* @param limboFreeSnapshotVersion The version of the snapshot when the query
167159
* was last synchronized.
168160
*/
169-
needsRefill(
161+
private needsRefill(
170162
sortedPreviousResults: SortedSet<Document>,
171163
remoteKeys: DocumentKeySet,
172164
limboFreeSnapshotVersion: SnapshotVersion
@@ -177,12 +169,6 @@ export class IndexFreeQueryEngine implements QueryEngine {
177169
return true;
178170
}
179171

180-
// We don't need to find a better match from cache if no documents matched
181-
// the query.
182-
if (sortedPreviousResults.isEmpty()) {
183-
return false;
184-
}
185-
186172
// Limit queries are not eligible for index-free query execution if there is
187173
// a potential that an older document from cache now sorts before a document
188174
// that was previously part of the limit. This, however, can only happen if
@@ -192,14 +178,18 @@ export class IndexFreeQueryEngine implements QueryEngine {
192178
// documents from cache will continue to be "rejected" by this boundary.
193179
// Therefore, we can ignore any modifications that don't affect the last
194180
// document.
195-
const lastDocumentInLimit = sortedPreviousResults.last()!;
181+
const lastDocumentInLimit = sortedPreviousResults.last();
182+
if (!lastDocumentInLimit) {
183+
// We don't need to refill the query if there were already no documents.
184+
return false;
185+
}
196186
return (
197187
lastDocumentInLimit.hasPendingWrites ||
198188
lastDocumentInLimit.version.compareTo(limboFreeSnapshotVersion) > 0
199189
);
200190
}
201191

202-
executeFullCollectionScan(
192+
private executeFullCollectionScan(
203193
transaction: PersistenceTransaction,
204194
query: Query
205195
): PersistencePromise<DocumentMap> {

packages/firestore/src/local/local_store.ts

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -830,54 +830,67 @@ export class LocalStore {
830830
}
831831

832832
/**
833-
* Runs the specified query against all the documents in the local store and
834-
* returns the results.
833+
* Runs the specified query against the local store and returns the results,
834+
* potentially taking advantage of query data from previous executions (such
835+
* as the set of remote keys).
835836
*/
836837
executeQuery(query: Query): Promise<DocumentMap>;
838+
/**
839+
* Performs a full collection scan for the provided query and returns the
840+
* results. Does not take into account metadata from prior executions.
841+
*/
842+
executeQuery(
843+
query: Query,
844+
options: { needsRefill: true }
845+
): Promise<DocumentMap>;
837846
/**
838847
* Runs the specified query against the local store and returns the results,
839848
* potentially taking advantage of the provided query data and the set of
840849
* remote document keys.
841850
*/
842851
executeQuery(
843852
query: Query,
844-
queryData: QueryData | null,
845-
remoteKeys: DocumentKeySet
853+
options: { queryData: QueryData; remoteKeys: DocumentKeySet }
846854
): Promise<DocumentMap>;
847855
executeQuery(
848856
query: Query,
849-
queryData?: QueryData | null,
850-
remoteKeys?: DocumentKeySet
857+
options: {
858+
needsRefill?: boolean;
859+
queryData?: QueryData;
860+
remoteKeys?: DocumentKeySet;
861+
} = {}
851862
): Promise<DocumentMap> {
852-
let cachedQueryData = queryData;
853-
let cachedRemoteKeys = remoteKeys;
863+
const allowLookup = options.needsRefill !== false;
864+
865+
let queryData = options.queryData;
866+
let remoteKeys = options.remoteKeys;
854867

855868
return this.persistence.runTransaction('Execute query', 'readonly', txn => {
856869
return PersistencePromise.resolve()
857870
.next(() => {
858-
// If QueryData is not provided (and not explicitly set to `null`), we
859-
// retrieve the query data and the remote keys from cache.
860-
if (cachedQueryData === undefined) {
861-
return this.getQueryData(txn, query).next(queryData => {
862-
if (queryData) {
863-
return this.queryCache
864-
.getMatchingKeysForTargetId(txn, queryData.targetId)
865-
.next(remoteKeys => {
866-
cachedQueryData = queryData;
867-
cachedRemoteKeys = remoteKeys;
868-
});
869-
}
871+
if (allowLookup && !queryData) {
872+
return this.getQueryData(txn, query).next(result => {
873+
queryData = result || undefined;
870874
});
871875
}
872876
})
873-
.next(() =>
874-
this.queryEngine.getDocumentsMatchingQuery(
877+
.next(() => {
878+
if (allowLookup && queryData && !remoteKeys) {
879+
return this.queryCache
880+
.getMatchingKeysForTargetId(txn, queryData.targetId)
881+
.next(result => {
882+
remoteKeys = result;
883+
});
884+
}
885+
})
886+
.next(() => {
887+
return this.queryEngine.getDocumentsMatchingQuery(
875888
txn,
876889
query,
877-
cachedQueryData || null,
878-
cachedRemoteKeys || documentKeySet()
879-
)
880-
);
890+
queryData || null,
891+
remoteKeys || documentKeySet()
892+
);
893+
});
881894
});
882895
}
883896

0 commit comments

Comments
 (0)