Skip to content

Commit 3c7cc8f

Browse files
authored
Merge 57b5bcb into 7f78362
2 parents 7f78362 + 57b5bcb commit 3c7cc8f

18 files changed

+810
-555
lines changed

packages/firestore/src/api/persistent_cache_index_manager.ts

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
*/
1717

1818
import {
19+
FirestoreClient,
1920
firestoreClientDeleteAllFieldIndexes,
20-
firestoreClientSetPersistentCacheIndexAutoCreationEnabled,
21-
FirestoreClient
21+
firestoreClientDisablePersistentCacheIndexAutoCreation,
22+
firestoreClientEnablePersistentCacheIndexAutoCreation
2223
} from '../core/firestore_client';
2324
import { cast } from '../util/input_validation';
2425
import { logDebug, logWarn } from '../util/log';
@@ -76,7 +77,12 @@ export function getPersistentCacheIndexManager(
7677
export function enablePersistentCacheIndexAutoCreation(
7778
indexManager: PersistentCacheIndexManager
7879
): void {
79-
setPersistentCacheIndexAutoCreationEnabled(indexManager, true);
80+
indexManager._client.verifyNotTerminated();
81+
firestoreClientEnablePersistentCacheIndexAutoCreation(indexManager._client)
82+
.then(_ => logDebug('enablePersistentCacheIndexAutoCreation() succeeded.'))
83+
.catch(error =>
84+
logWarn('enablePersistentCacheIndexAutoCreation() failed', error)
85+
);
8086
}
8187

8288
/**
@@ -87,7 +93,12 @@ export function enablePersistentCacheIndexAutoCreation(
8793
export function disablePersistentCacheIndexAutoCreation(
8894
indexManager: PersistentCacheIndexManager
8995
): void {
90-
setPersistentCacheIndexAutoCreationEnabled(indexManager, false);
96+
indexManager._client.verifyNotTerminated();
97+
firestoreClientDisablePersistentCacheIndexAutoCreation(indexManager._client)
98+
.then(_ => logDebug('disablePersistentCacheIndexAutoCreation() succeeded.'))
99+
.catch(error =>
100+
logWarn('disablePersistentCacheIndexAutoCreation() failed', error)
101+
);
91102
}
92103

93104
/**
@@ -100,41 +111,9 @@ export function deleteAllPersistentCacheIndexes(
100111
indexManager: PersistentCacheIndexManager
101112
): void {
102113
indexManager._client.verifyNotTerminated();
103-
104-
const promise = firestoreClientDeleteAllFieldIndexes(indexManager._client);
105-
106-
promise
107-
.then(_ => logDebug('deleting all persistent cache indexes succeeded'))
108-
.catch(error =>
109-
logWarn('deleting all persistent cache indexes failed', error)
110-
);
111-
}
112-
113-
function setPersistentCacheIndexAutoCreationEnabled(
114-
indexManager: PersistentCacheIndexManager,
115-
isEnabled: boolean
116-
): void {
117-
indexManager._client.verifyNotTerminated();
118-
119-
const promise = firestoreClientSetPersistentCacheIndexAutoCreationEnabled(
120-
indexManager._client,
121-
isEnabled
122-
);
123-
124-
promise
125-
.then(_ =>
126-
logDebug(
127-
`setting persistent cache index auto creation ` +
128-
`isEnabled=${isEnabled} succeeded`
129-
)
130-
)
131-
.catch(error =>
132-
logWarn(
133-
`setting persistent cache index auto creation ` +
134-
`isEnabled=${isEnabled} failed`,
135-
error
136-
)
137-
);
114+
firestoreClientDeleteAllFieldIndexes(indexManager._client)
115+
.then(_ => logDebug('deleteAllPersistentCacheIndexes() succeeded.'))
116+
.catch(error => logWarn('deleteAllPersistentCacheIndexes() failed', error));
138117
}
139118

140119
/**

packages/firestore/src/core/component_provider.ts

Lines changed: 84 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import {
2222
IndexBackfillerScheduler
2323
} from '../local/index_backfiller';
2424
import {
25-
indexedDbStoragePrefix,
26-
IndexedDbPersistence
25+
IndexedDbPersistence,
26+
indexedDbStoragePrefix
2727
} from '../local/indexeddb_persistence';
2828
import { LocalStore } from '../local/local_store';
2929
import { newLocalStore } from '../local/local_store_impl';
@@ -34,7 +34,7 @@ import {
3434
MemoryLruDelegate,
3535
MemoryPersistence
3636
} from '../local/memory_persistence';
37-
import { Scheduler, Persistence } from '../local/persistence';
37+
import { Persistence, Scheduler } from '../local/persistence';
3838
import { QueryEngine } from '../local/query_engine';
3939
import {
4040
ClientId,
@@ -57,6 +57,7 @@ import { JsonProtoSerializer } from '../remote/serializer';
5757
import { hardAssert } from '../util/assert';
5858
import { AsyncQueue } from '../util/async_queue';
5959
import { Code, FirestoreError } from '../util/error';
60+
import { logDebug } from '../util/log';
6061

6162
import { DatabaseInfo } from './database_info';
6263
import { EventManager, newEventManager } from './event_manager';
@@ -90,6 +91,7 @@ export interface ComponentConfiguration {
9091
* cache. Implementations override `initialize()` to provide all components.
9192
*/
9293
export interface OfflineComponentProvider {
94+
asyncQueue: AsyncQueue;
9395
persistence: Persistence;
9496
sharedClientState: SharedClientState;
9597
localStore: LocalStore;
@@ -109,16 +111,23 @@ export interface OfflineComponentProvider {
109111
export class MemoryOfflineComponentProvider
110112
implements OfflineComponentProvider
111113
{
114+
asyncQueue!: AsyncQueue;
112115
persistence!: Persistence;
113116
sharedClientState!: SharedClientState;
114117
localStore!: LocalStore;
115118
gcScheduler!: Scheduler | null;
116-
indexBackfillerScheduler!: Scheduler | null;
119+
indexBackfillerScheduler: Scheduler | null = null;
117120
synchronizeTabs = false;
118121

119122
serializer!: JsonProtoSerializer;
120123

124+
get schedulers(): Scheduler[] {
125+
const schedulers = [this.gcScheduler, this.indexBackfillerScheduler];
126+
return schedulers.filter(scheduler => !!scheduler) as Scheduler[];
127+
}
128+
121129
async initialize(cfg: ComponentConfiguration): Promise<void> {
130+
this.asyncQueue = cfg.asyncQueue;
122131
this.serializer = newSerializer(cfg.databaseInfo.databaseId);
123132
this.sharedClientState = this.createSharedClientState(cfg);
124133
this.persistence = this.createPersistence(cfg);
@@ -128,10 +137,6 @@ export class MemoryOfflineComponentProvider
128137
cfg,
129138
this.localStore
130139
);
131-
this.indexBackfillerScheduler = this.createIndexBackfillerScheduler(
132-
cfg,
133-
this.localStore
134-
);
135140
}
136141

137142
createGarbageCollectionScheduler(
@@ -141,13 +146,6 @@ export class MemoryOfflineComponentProvider
141146
return null;
142147
}
143148

144-
createIndexBackfillerScheduler(
145-
cfg: ComponentConfiguration,
146-
localStore: LocalStore
147-
): Scheduler | null {
148-
return null;
149-
}
150-
151149
createLocalStore(cfg: ComponentConfiguration): LocalStore {
152150
return newLocalStore(
153151
this.persistence,
@@ -166,8 +164,9 @@ export class MemoryOfflineComponentProvider
166164
}
167165

168166
async terminate(): Promise<void> {
169-
this.gcScheduler?.stop();
170-
this.indexBackfillerScheduler?.stop();
167+
for (const scheduler of this.schedulers) {
168+
scheduler.stop();
169+
}
171170
this.sharedClientState.shutdown();
172171
await this.persistence.shutdown();
173172
}
@@ -215,6 +214,8 @@ export class IndexedDbOfflineComponentProvider extends MemoryOfflineComponentPro
215214
indexBackfillerScheduler!: Scheduler | null;
216215
synchronizeTabs = false;
217216

217+
private primaryStateListenerNotified = false;
218+
218219
constructor(
219220
protected readonly onlineComponentProvider: OnlineComponentProvider,
220221
protected readonly cacheSizeBytes: number | undefined,
@@ -237,19 +238,30 @@ export class IndexedDbOfflineComponentProvider extends MemoryOfflineComponentPro
237238
// NOTE: This will immediately call the listener, so we make sure to
238239
// set it after localStore / remoteStore are started.
239240
await this.persistence.setPrimaryStateListener(() => {
240-
if (this.gcScheduler && !this.gcScheduler.started) {
241-
this.gcScheduler.start();
242-
}
243-
if (
244-
this.indexBackfillerScheduler &&
245-
!this.indexBackfillerScheduler.started
246-
) {
247-
this.indexBackfillerScheduler.start();
248-
}
241+
this.primaryStateListenerNotified = true;
242+
this.startSchedulers();
249243
return Promise.resolve();
250244
});
251245
}
252246

247+
private startSchedulers(): void {
248+
if (!this.primaryStateListenerNotified) {
249+
return;
250+
}
251+
252+
for (const scheduler of this.schedulers) {
253+
if (!scheduler.started) {
254+
scheduler.start();
255+
}
256+
}
257+
}
258+
259+
installIndexBackfillerScheduler(scheduler: IndexBackfillerScheduler): void {
260+
hardAssert(!this.indexBackfillerScheduler);
261+
this.indexBackfillerScheduler = scheduler;
262+
this.startSchedulers();
263+
}
264+
253265
createLocalStore(cfg: ComponentConfiguration): LocalStore {
254266
return newLocalStore(
255267
this.persistence,
@@ -268,14 +280,6 @@ export class IndexedDbOfflineComponentProvider extends MemoryOfflineComponentPro
268280
return new LruScheduler(garbageCollector, cfg.asyncQueue, localStore);
269281
}
270282

271-
createIndexBackfillerScheduler(
272-
cfg: ComponentConfiguration,
273-
localStore: LocalStore
274-
): Scheduler | null {
275-
const indexBackfiller = new IndexBackfiller(localStore, this.persistence);
276-
return new IndexBackfillerScheduler(cfg.asyncQueue, indexBackfiller);
277-
}
278-
279283
createPersistence(cfg: ComponentConfiguration): IndexedDbPersistence {
280284
const persistenceKey = indexedDbStoragePrefix(
281285
cfg.databaseInfo.databaseId,
@@ -305,6 +309,30 @@ export class IndexedDbOfflineComponentProvider extends MemoryOfflineComponentPro
305309
}
306310
}
307311

312+
export function indexedDbOfflineComponentProviderInstallFieldIndexPlugin(
313+
componentProvider: IndexedDbOfflineComponentProvider
314+
): void {
315+
if (componentProvider.indexBackfillerScheduler) {
316+
return;
317+
}
318+
319+
logDebug(
320+
'Installing IndexBackfillerScheduler into OfflineComponentProvider ' +
321+
'to support persistent cache indexing.'
322+
);
323+
324+
const indexBackfiller = new IndexBackfiller(
325+
componentProvider.localStore,
326+
componentProvider.persistence
327+
);
328+
const scheduler = new IndexBackfillerScheduler(
329+
componentProvider.asyncQueue,
330+
indexBackfiller
331+
);
332+
333+
componentProvider.installIndexBackfillerScheduler(scheduler);
334+
}
335+
308336
/**
309337
* Provides all components needed for Firestore with multi-tab IndexedDB
310338
* persistence.
@@ -316,6 +344,8 @@ export class IndexedDbOfflineComponentProvider extends MemoryOfflineComponentPro
316344
export class MultiTabOfflineComponentProvider extends IndexedDbOfflineComponentProvider {
317345
synchronizeTabs = true;
318346

347+
private isPrimary: boolean | null = null;
348+
319349
constructor(
320350
protected readonly onlineComponentProvider: OnlineComponentProvider,
321351
protected readonly cacheSizeBytes: number | undefined
@@ -346,27 +376,33 @@ export class MultiTabOfflineComponentProvider extends IndexedDbOfflineComponentP
346376
// NOTE: This will immediately call the listener, so we make sure to
347377
// set it after localStore / remoteStore are started.
348378
await this.persistence.setPrimaryStateListener(async isPrimary => {
379+
this.isPrimary = isPrimary;
380+
349381
await syncEngineApplyPrimaryState(
350382
this.onlineComponentProvider.syncEngine,
351383
isPrimary
352384
);
353-
if (this.gcScheduler) {
354-
if (isPrimary && !this.gcScheduler.started) {
355-
this.gcScheduler.start();
356-
} else if (!isPrimary) {
357-
this.gcScheduler.stop();
358-
}
359-
}
360-
if (this.indexBackfillerScheduler) {
361-
if (isPrimary && !this.indexBackfillerScheduler.started) {
362-
this.indexBackfillerScheduler.start();
363-
} else if (!isPrimary) {
364-
this.indexBackfillerScheduler.stop();
365-
}
366-
}
385+
386+
this.startOrStopSchedulers();
367387
});
368388
}
369389

390+
private startOrStopSchedulers(): void {
391+
for (const scheduler of this.schedulers) {
392+
if (this.isPrimary === true && !scheduler.started) {
393+
scheduler.start();
394+
} else if (this.isPrimary === false) {
395+
scheduler.stop();
396+
}
397+
}
398+
}
399+
400+
installIndexBackfillerScheduler(scheduler: IndexBackfillerScheduler): void {
401+
hardAssert(!this.indexBackfillerScheduler);
402+
this.indexBackfillerScheduler = scheduler;
403+
this.startOrStopSchedulers();
404+
}
405+
370406
createSharedClientState(cfg: ComponentConfiguration): SharedClientState {
371407
const window = getWindow();
372408
if (!WebStorageSharedClientState.isAvailable(window)) {

0 commit comments

Comments
 (0)