Skip to content

Index-Free Queries (feature, code still disabled) #2180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b4d70ac
Index-Free: Track readTime in the RemoteDocument store (#2125)
schmidt-sebastian Sep 4, 2019
998152d
Merge branch 'master' into mrschmidt/indexfree-master
schmidt-sebastian Sep 4, 2019
06e6c50
Use Read-Time Index for Multi-Tab (#2128)
schmidt-sebastian Sep 5, 2019
b450295
Master
schmidt-sebastian Sep 5, 2019
330abde
Merge branch 'mrschmidt/indexfree-master' of github.com:firebase/fire…
schmidt-sebastian Sep 5, 2019
6ee3647
Index-free: Add readTime to the MemoryRemoteDocumentCache (#2157)
schmidt-sebastian Sep 6, 2019
d32cbbe
Index-Free: Persist the lastLimboFreeSnapshot version (#2152)
schmidt-sebastian Sep 6, 2019
2fef555
Index-Free: Filter document queries by read time (#2159)
schmidt-sebastian Sep 6, 2019
b3c514a
Add SimpleQueryEngine (#2160)
schmidt-sebastian Sep 6, 2019
0433b82
Merge branch 'master' into mrschmidt/indexfree-master
schmidt-sebastian Sep 9, 2019
5e2a1e5
Port matchesAllDocuments() (#2166)
schmidt-sebastian Sep 10, 2019
55ffe46
Expose operation counts from Persistence layer (take 2) (#2165)
schmidt-sebastian Sep 10, 2019
988cc41
Merge branch 'master' into mrschmidt/indexfree-master
schmidt-sebastian Sep 12, 2019
1e8d007
[AUTOMATED]: Prettier Code Styling
schmidt-sebastian Sep 12, 2019
539ab0d
Add IndexFreeQueryEngine (#2169)
schmidt-sebastian Sep 17, 2019
050c82a
Merge branch 'mrschmidt/indexfree-master' of github.com:firebase/fire…
schmidt-sebastian Sep 17, 2019
7a3a2d1
Index-Free: Port LocalStore tests (#2173)
schmidt-sebastian Sep 17, 2019
1ccb186
Merge branch 'mrschmidt/indexfree-master' of github.com:firebase/fire…
schmidt-sebastian Sep 17, 2019
0618849
Add Query to Target ID Map (#2179)
schmidt-sebastian Sep 17, 2019
ee6a62f
Merge branch 'mrschmidt/indexfree-master' of github.com:firebase/fire…
schmidt-sebastian Sep 17, 2019
0d92213
Merge
schmidt-sebastian Sep 17, 2019
fc3e432
Adding it.skip suppression
schmidt-sebastian Sep 17, 2019
1be914c
Fix typo in IndexFreeQueryEngine
schmidt-sebastian Sep 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 17 additions & 23 deletions packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ import { IndexedDbPersistence } from '../local/indexeddb_persistence';
import { LocalStore } from '../local/local_store';
import { MemoryPersistence } from '../local/memory_persistence';
import { Persistence } from '../local/persistence';
import {
DocumentKeySet,
documentKeySet,
DocumentMap
} from '../model/collections';
import { SimpleQueryEngine } from '../local/simple_query_engine';
import { Document, MaybeDocument, NoDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { Mutation } from '../model/mutation';
Expand All @@ -44,7 +40,7 @@ import {
QueryListener
} from './event_manager';
import { SyncEngine } from './sync_engine';
import { View, ViewDocumentChanges } from './view';
import { View } from './view';

import {
LruGarbageCollector,
Expand Down Expand Up @@ -401,7 +397,9 @@ export class FirestoreClient {
return this.platform
.loadConnection(this.databaseInfo)
.then(async connection => {
this.localStore = new LocalStore(this.persistence, user);
// TODO(index-free): Use IndexFreeQueryEngine/IndexedQueryEngine as appropriate.
const queryEngine = new SimpleQueryEngine();
this.localStore = new LocalStore(this.persistence, queryEngine, user);
if (maybeLruGc) {
// We're running LRU Garbage collection. Set up the scheduler.
this.lruScheduler = new LruScheduler(
Expand Down Expand Up @@ -581,22 +579,18 @@ export class FirestoreClient {

getDocumentsFromLocalCache(query: Query): Promise<ViewSnapshot> {
this.verifyNotTerminated();
return this.asyncQueue
.enqueue(() => {
return this.localStore.executeQuery(query);
})
.then((docs: DocumentMap) => {
const remoteKeys: DocumentKeySet = documentKeySet();

const view = new View(query, remoteKeys);
const viewDocChanges: ViewDocumentChanges = view.computeDocChanges(
docs
);
return view.applyChanges(
viewDocChanges,
/* updateLimboDocuments= */ false
).snapshot!;
});
return this.asyncQueue.enqueue(async () => {
const queryResult = await this.localStore.executeQuery(
query,
/* usePreviousResults= */ true
);
const view = new View(query, queryResult.remoteKeys);
const viewDocChanges = view.computeDocChanges(queryResult.documents);
return view.applyChanges(
viewDocChanges,
/* updateLimboDocuments= */ false
).snapshot!;
});
}

write(mutations: Mutation[]): Promise<void> {
Expand Down
16 changes: 16 additions & 0 deletions packages/firestore/src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,22 @@ export class Query {
);
}

/**
* Returns true if this query does not specify any query constraints that
* could remove results.
*/
matchesAllDocuments(): boolean {
return (
this.filters.length === 0 &&
this.limit === null &&
this.startAt == null &&
this.endAt == null &&
(this.explicitOrderBy.length === 0 ||
(this.explicitOrderBy.length === 1 &&
this.explicitOrderBy[0].field.isKeyField()))
);
}

// TODO(b/29183165): This is used to get a unique string from a query to, for
// example, use as a dictionary key, but the implementation is subject to
// collisions. Make it collision-free.
Expand Down
65 changes: 27 additions & 38 deletions packages/firestore/src/core/sync_engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { Deferred } from '../util/promise';
import { SortedMap } from '../util/sorted_map';

import { ignoreIfPrimaryLeaseLoss } from '../local/indexeddb_persistence';
import { isDocumentChangeMissingError } from '../local/indexeddb_remote_document_cache';
import { ClientId, SharedClientState } from '../local/shared_client_state';
import {
QueryTargetState,
Expand Down Expand Up @@ -244,13 +243,12 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
current: boolean
): Promise<ViewSnapshot> {
const query = queryData.query;
const docs = await this.localStore.executeQuery(query);
const remoteKeys = await this.localStore.remoteDocumentKeys(
queryData.targetId
const queryResult = await this.localStore.executeQuery(
query,
/* usePreviousResults= */ true
);

const view = new View(query, remoteKeys);
const viewDocChanges = view.computeDocChanges(docs);
const view = new View(query, queryResult.remoteKeys);
const viewDocChanges = view.computeDocChanges(queryResult.documents);
const synthesizedTargetChange = TargetChange.createSynthesizedTargetChangeForCurrentChange(
queryData.targetId,
current && this.onlineState !== OnlineState.Offline
Expand Down Expand Up @@ -283,13 +281,12 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
private async synchronizeViewAndComputeSnapshot(
queryView: QueryView
): Promise<ViewChange> {
const docs = await this.localStore.executeQuery(queryView.query);
const remoteKeys = await this.localStore.remoteDocumentKeys(
queryView.targetId
const queryResult = await this.localStore.executeQuery(
queryView.query,
/* usePreviousResults= */ true
);
const viewSnapshot = queryView.view.synchronizeWithPersistedState(
docs,
remoteKeys
queryResult
);
if (this.isPrimary) {
this.updateTrackedLimbos(queryView.targetId, viewSnapshot.limboChanges);
Expand Down Expand Up @@ -787,9 +784,14 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
// The query has a limit and some docs were removed, so we need
// to re-run the query against the local store to make sure we
// didn't lose any good docs that had been past the limit.
return this.localStore.executeQuery(queryView.query).then(docs => {
return queryView.view.computeDocChanges(docs, viewDocChanges);
});
return this.localStore
.executeQuery(queryView.query, /* usePreviousResults= */ false)
.then(({ documents }) => {
return queryView.view.computeDocChanges(
documents,
viewDocChanges
);
});
})
.then((viewDocChanges: ViewDocumentChanges) => {
const targetChange =
Expand Down Expand Up @@ -983,29 +985,16 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
switch (state) {
case 'current':
case 'not-current': {
try {
const changes = await this.localStore.getNewDocumentChanges();
const synthesizedRemoteEvent = RemoteEvent.createSynthesizedRemoteEventForCurrentChange(
targetId,
state === 'current'
);
await this.emitNewSnapsAndNotifyLocalStore(
changes,
synthesizedRemoteEvent
);
break;
// Catch errors thrown by getNewDocumentchanges().
} catch (error) {
if (isDocumentChangeMissingError(error)) {
const activeTargets: TargetId[] = [];
objUtils.forEachNumber(this.queryViewsByTarget, target =>
activeTargets.push(target)
);
await this.synchronizeQueryViewsAndRaiseSnapshots(activeTargets);
} else {
throw error;
}
}
const changes = await this.localStore.getNewDocumentChanges();
const synthesizedRemoteEvent = RemoteEvent.createSynthesizedRemoteEventForCurrentChange(
targetId,
state === 'current'
);
await this.emitNewSnapsAndNotifyLocalStore(
changes,
synthesizedRemoteEvent
);
break;
}
case 'rejected': {
const queryView = this.queryViewsByTarget[targetId];
Expand Down
18 changes: 8 additions & 10 deletions packages/firestore/src/core/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

import { QueryResult } from '../local/local_store';
import {
documentKeySet,
DocumentKeySet,
Expand Down Expand Up @@ -433,21 +434,18 @@ export class View {
* of `syncedDocuments` since secondary clients update their query views
* based purely on synthesized RemoteEvents.
*
* @param localDocs - The documents that match the query according to the
* LocalStore.
* @param remoteKeys - The keys of the documents that match the query
* according to the backend.
* @param queryResult.documents - The documents that match the query according
* to the LocalStore.
* @param queryResult.remoteKeys - The keys of the documents that match the
* query according to the backend.
*
* @return The ViewChange that resulted from this synchronization.
*/
// PORTING NOTE: Multi-tab only.
synchronizeWithPersistedState(
localDocs: MaybeDocumentMap,
remoteKeys: DocumentKeySet
): ViewChange {
this._syncedDocuments = remoteKeys;
synchronizeWithPersistedState(queryResult: QueryResult): ViewChange {
this._syncedDocuments = queryResult.remoteKeys;
this.limboDocuments = documentKeySet();
const docChanges = this.computeDocChanges(localDocs);
const docChanges = this.computeDocChanges(queryResult.documents);
return this.applyChanges(docChanges, /*updateLimboDocuments=*/ true);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/firestore/src/core/view_snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ export class ViewSnapshot {
changes,
mutatedKeys,
fromCache,
true,
false
/* syncStateChanged= */ true,
/* excludesMetadataChanges= */ false
);
}

Expand Down
Loading