Skip to content

Firestore: enable/disablePersistentCacheIndexAutoCreation() added, but hidden for now #7542

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 40 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
9e96412
enable/disablePersistentCacheIndexAutoCreation() implemented, but hidden
dconeybe Aug 10, 2023
9a63921
Firestore: testing_hooks.ts: move some logic into testing_hooks_spi.ts
dconeybe Aug 10, 2023
0b92504
Merge remote-tracking branch 'origin/dconeybe/TestingHooksSpi' into C…
dconeybe Aug 10, 2023
f3489a6
api fixes
dconeybe Aug 10, 2023
6caf745
add testing_hooks.ts to externs.json so that _TestingHooksExistenceFi…
dconeybe Aug 10, 2023
dc3f741
Merge remote-tracking branch 'origin/master' into TestingHooksSpi
dconeybe Aug 10, 2023
0b4eb3b
doc minor fix
dconeybe Aug 10, 2023
5a1d318
Merge remote-tracking branch 'origin/dconeybe/TestingHooksSpi' into C…
dconeybe Aug 10, 2023
b1ebeec
persistent_cache_index_manager.test.ts: add "Auto" to "Indexing" in a…
dconeybe Aug 10, 2023
168d922
minor tweaks
dconeybe Aug 11, 2023
929fe25
Merge branch 'TestingHooksSpi' into ClientSideIndexAutoCreation
dconeybe Aug 11, 2023
9ded338
minor tweaks
dconeybe Aug 11, 2023
ab8fd36
testing_hooks.ts: add registerCallback()
dconeybe Aug 11, 2023
fadb79b
rework testing hooks
dconeybe Aug 11, 2023
c681d3d
run_tests_in_ci.js rewrite
dconeybe Aug 12, 2023
c4822ce
run_tests_in_ci.js: set `process.exitCode=1` instead of calling `proc…
dconeybe Aug 14, 2023
526b561
run_tests_in_ci.js: revert local modifications
dconeybe Aug 14, 2023
78bbbc0
Merge remote-tracking branch 'remotes/origin/dconeybe/RunTestsInCiJsT…
dconeybe Aug 14, 2023
24dc0fa
undo changes to run_tests_in_ci.js because they aren't part of this PR
dconeybe Aug 15, 2023
92c698d
Merge remote-tracking branch 'origin/master' into TestingHooksSpi
dconeybe Aug 15, 2023
e550a5c
empty commit to trigger github actions
dconeybe Aug 15, 2023
2a65b2c
Merge branch 'TestingHooksSpi' into ClientSideIndexAutoCreation
dconeybe Aug 15, 2023
92a6de0
firestore_client.ts: remove unused import of `debugCast`
dconeybe Aug 15, 2023
037fc58
Merge remote-tracking branch 'origin/master' into TestingHooksSpi
dconeybe Aug 16, 2023
90ec00d
Merge remote-tracking branch 'origin/dconeybe/TestingHooksSpi' into C…
dconeybe Aug 16, 2023
4a3f01c
enabled -> isEnabled
dconeybe Aug 16, 2023
e74f00c
query_context.ts: make `amount` parameter of the incrementDocumentRea…
dconeybe Aug 16, 2023
a5ed920
target_index_matcher.ts: make suggested change to inline comment abou…
dconeybe Aug 16, 2023
0107d40
Merge remote-tracking branch 'origin/master' into ClientSideIndexAuto…
dconeybe Aug 16, 2023
c6b1c9c
Merge remote-tracking branch 'origin/master' into ClientSideIndexAuto…
dconeybe Aug 22, 2023
51e017d
remove testing hooks (still need to update the tests and other code t…
dconeybe Aug 22, 2023
2a14ce6
remove testing hooks from tests, except for persistent_cache_index_ma…
dconeybe Aug 22, 2023
35c670f
Remove leading underscores from exports from persistent_cache_index_m…
dconeybe Aug 22, 2023
36fb48b
Merge remote-tracking branch 'origin/master' into ClientSideIndexAuto…
dconeybe Aug 23, 2023
5e0144a
improve getDocumentsMatchingQuery() to not consider creating an index…
dconeybe Aug 23, 2023
dac9991
persistent_cache_index_manager.ts: prettier fix
dconeybe Aug 23, 2023
4835585
yarn lint:fix
dconeybe Aug 23, 2023
d84308f
yarn changeset
dconeybe Aug 23, 2023
62d28ba
query_engine.ts: remove superfluous log message, as requested in code…
dconeybe Aug 24, 2023
bedfda0
yarn prettier
dconeybe Aug 24, 2023
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
6 changes: 6 additions & 0 deletions packages/firestore/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ export type {
} from './api/credentials';
export { EmptyAuthCredentialsProvider as _EmptyAuthCredentialsProvider } from './api/credentials';
export { EmptyAppCheckTokenProvider as _EmptyAppCheckTokenProvider } from './api/credentials';
export {
PersistentCacheIndexManager as _PersistentCacheIndexManager,
getPersistentCacheIndexManager as _getPersistentCacheIndexManager,
enablePersistentCacheIndexAutoCreation as _enablePersistentCacheIndexAutoCreation,
disablePersistentCacheIndexAutoCreation as _disablePersistentCacheIndexAutoCreation
} from './api/persistent_cache_index_manager';
export {
ExistenceFilterMismatchCallback as _TestingHooksExistenceFilterMismatchCallback,
TestingHooks as _TestingHooks
Expand Down
166 changes: 166 additions & 0 deletions packages/firestore/src/api/persistent_cache_index_manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* @license
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
firestoreClientSetPersistentCacheIndexAutoCreationEnabled,
FirestoreClient,
TestingHooks as FirestoreClientTestingHooks
} from '../core/firestore_client';
import { cast } from '../util/input_validation';
import { logDebug, logWarn } from '../util/log';
import { testingHooksSpi } from '../util/testing_hooks_spi';

import { ensureFirestoreConfigured, Firestore } from './database';

/**
* A `PersistentCacheIndexManager` which you can config persistent cache indexes
* used for local query execution.
*
* To use, call `getPersistentCacheIndexManager()` to get an instance.
*
* TODO(CSI) Remove @internal to make the API publicly available.
* @internal
*/
export class PersistentCacheIndexManager {
readonly type: 'PersistentCacheIndexManager' = 'PersistentCacheIndexManager';

/** @hideconstructor */
constructor(readonly _client: FirestoreClient) {}
}

/**
* Returns the PersistentCache Index Manager used by the given `Firestore`
* object.
*
* @return The `PersistentCacheIndexManager` instance, or `null` if local
* persistent storage is not in use.
*
* TODO(CSI) Remove @internal to make the API publicly available.
* @internal
*/
export function getPersistentCacheIndexManager(
firestore: Firestore
): PersistentCacheIndexManager | null {
firestore = cast(firestore, Firestore);

const cachedInstance = persistentCacheIndexManagerByFirestore.get(firestore);
if (cachedInstance) {
return cachedInstance;
}

const client = ensureFirestoreConfigured(firestore);
if (client._uninitializedComponentsProvider?._offlineKind !== 'persistent') {
return null;
}

const instance = new PersistentCacheIndexManager(client);
persistentCacheIndexManagerByFirestore.set(firestore, instance);
return instance;
}

/**
* Enables SDK to create persistent cache indexes automatically for local query
* execution when SDK believes cache indexes can help improves performance.
*
* This feature is disabled by default.
*
* TODO(CSI) Remove @internal to make the API publicly available.
* @internal
*/
export function enablePersistentCacheIndexAutoCreation(
indexManager: PersistentCacheIndexManager
): void {
setPersistentCacheIndexAutoCreationEnabled(indexManager, true);
}

/**
* Stops creating persistent cache indexes automatically for local query
* execution. The indexes which have been created by calling
* `enablePersistentCacheIndexAutoCreation()` still take effect.
*
* TODO(CSI) Remove @internal to make the API publicly available.
* @internal
*/
export function disablePersistentCacheIndexAutoCreation(
indexManager: PersistentCacheIndexManager
): void {
setPersistentCacheIndexAutoCreationEnabled(indexManager, false);
}

function setPersistentCacheIndexAutoCreationEnabled(
indexManager: PersistentCacheIndexManager,
isEnabled: boolean
): void {
indexManager._client.verifyNotTerminated();

const promise = firestoreClientSetPersistentCacheIndexAutoCreationEnabled(
indexManager._client,
isEnabled
);

promise
.then(_ =>
logDebug(
`setting persistent cache index auto creation ` +
`isEnabled=${isEnabled} succeeded`
)
)
.catch(error =>
logWarn(
`setting persistent cache index auto creation ` +
`isEnabled=${isEnabled} failed`,
error
)
);

testingHooksSpi?.notifyPersistentCacheIndexAutoCreationToggle(promise);
}

/**
* Maps `Firestore` instances to their corresponding
* `PersistentCacheIndexManager` instances.
*
* Use a `WeakMap` so that the mapping will be automatically dropped when the
* `Firestore` instance is garbage collected. This emulates a private member
* as described in https://goo.gle/454yvug.
*/
const persistentCacheIndexManagerByFirestore = new WeakMap<
Firestore,
PersistentCacheIndexManager
>();

/**
* Test-only hooks into the SDK for use exclusively by integration tests.
*/
export class TestingHooks {
private constructor() {
throw new Error('creating instances is not supported');
}

static setIndexAutoCreationSettings(
indexManager: PersistentCacheIndexManager,
settings: {
indexAutoCreationMinCollectionSize?: number;
relativeIndexReadCostPerDocument?: number;
}
): Promise<void> {
return FirestoreClientTestingHooks.setPersistentCacheIndexAutoCreationSettings(
indexManager._client,
settings
);
}
}
53 changes: 52 additions & 1 deletion packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import {
CredentialsProvider
} from '../api/credentials';
import { User } from '../auth/user';
import { IndexType } from '../local/index_manager';
import { LocalStore } from '../local/local_store';
import {
localStoreConfigureFieldIndexes,
localStoreExecuteQuery,
localStoreGetNamedQuery,
localStoreHandleUserChange,
localStoreReadDocument
localStoreReadDocument,
localStoreSetIndexAutoCreationEnabled,
TestingHooks as LocalStoreTestingHooks
} from '../local/local_store_impl';
import { Persistence } from '../local/persistence';
import { Document } from '../model/document';
Expand Down Expand Up @@ -828,3 +831,51 @@ export function firestoreClientSetIndexConfiguration(
);
});
}

export function firestoreClientSetPersistentCacheIndexAutoCreationEnabled(
client: FirestoreClient,
isEnabled: boolean
): Promise<void> {
return client.asyncQueue.enqueue(async () => {
return localStoreSetIndexAutoCreationEnabled(
await getLocalStore(client),
isEnabled
);
});
}

/**
* Test-only hooks into the SDK for use exclusively by integration tests.
*/
export class TestingHooks {
private constructor() {
throw new Error('creating instances is not supported');
}

static getQueryIndexType(
client: FirestoreClient,
query: Query
): Promise<IndexType> {
return client.asyncQueue.enqueue(async () => {
const localStore = await getLocalStore(client);
return LocalStoreTestingHooks.getQueryIndexType(localStore, query);
});
}

static setPersistentCacheIndexAutoCreationSettings(
client: FirestoreClient,
settings: {
indexAutoCreationMinCollectionSize?: number;
relativeIndexReadCostPerDocument?: number;
}
): Promise<void> {
const settingsCopy = { ...settings };
return client.asyncQueue.enqueue(async () => {
const localStore = await getLocalStore(client);
LocalStoreTestingHooks.setIndexAutoCreationSettings(
localStore,
settingsCopy
);
});
}
}
19 changes: 19 additions & 0 deletions packages/firestore/src/local/index_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ export const enum IndexType {
FULL
}

export function displayNameForIndexType(indexType: IndexType): string {
switch (indexType) {
case IndexType.NONE:
return 'NONE';
case IndexType.PARTIAL:
return 'PARTIAL';
case IndexType.FULL:
return 'FULL';
default:
return `[unknown IndexType: ${indexType}]`;
}
}

/**
* Represents a set of indexes that are used to execute queries efficiently.
*
Expand Down Expand Up @@ -92,6 +105,12 @@ export interface IndexManager {
index: FieldIndex
): PersistencePromise<void>;

/** Creates a full matched field index which serves the given target. */
createTargetIndexes(
transaction: PersistenceTransaction,
target: Target
): PersistencePromise<void>;

/**
* Returns a list of field indexes that correspond to the specified collection
* group.
Expand Down
20 changes: 20 additions & 0 deletions packages/firestore/src/local/indexeddb_index_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,26 @@ export class IndexedDbIndexManager implements IndexManager {
);
}

createTargetIndexes(
transaction: PersistenceTransaction,
target: Target
): PersistencePromise<void> {
return PersistencePromise.forEach(
this.getSubTargets(target),
(subTarget: Target) => {
return this.getIndexType(transaction, subTarget).next(type => {
if (type === IndexType.NONE || type === IndexType.PARTIAL) {
const targetIndexMatcher = new TargetIndexMatcher(subTarget);
return this.addFieldIndex(
transaction,
targetIndexMatcher.buildTargetIndex()
);
}
});
}
);
}

getDocumentsMatchingTarget(
transaction: PersistenceTransaction,
target: Target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
} from './local_serializer';
import { PersistencePromise } from './persistence_promise';
import { PersistenceTransaction } from './persistence_transaction';
import { QueryContext } from './query_context';
import { RemoteDocumentCache } from './remote_document_cache';
import { RemoteDocumentChangeBuffer } from './remote_document_change_buffer';
import { SimpleDbStore } from './simple_db';
Expand Down Expand Up @@ -279,7 +280,8 @@ class IndexedDbRemoteDocumentCacheImpl implements IndexedDbRemoteDocumentCache {
transaction: PersistenceTransaction,
query: Query,
offset: IndexOffset,
mutatedDocs: OverlayMap
mutatedDocs: OverlayMap,
context?: QueryContext
): PersistencePromise<MutableDocumentMap> {
const collection = query.path;
const startKey = [
Expand All @@ -300,6 +302,7 @@ class IndexedDbRemoteDocumentCacheImpl implements IndexedDbRemoteDocumentCache {
return remoteDocumentsStore(transaction)
.loadAll(IDBKeyRange.bound(startKey, endKey, true))
.next(dbRemoteDocs => {
context?.incrementDocumentReadCount(dbRemoteDocs.length);
let results = mutableDocumentMap();
for (const dbRemoteDoc of dbRemoteDocs) {
const document = this.maybeDecodeDocument(
Expand Down
Loading