Skip to content

Commit ea58129

Browse files
Use subclass
1 parent ea52b91 commit ea58129

File tree

2 files changed

+129
-173
lines changed

2 files changed

+129
-173
lines changed

packages/firestore/src/core/component_provider.ts

Lines changed: 119 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@ import { IndexFreeQueryEngine } from '../local/index_free_query_engine';
4040
import { IndexedDbPersistence } from '../local/indexeddb_persistence';
4141
import {
4242
MemoryEagerDelegate,
43-
MemoryPersistence,
44-
MemoryReferenceDelegate
43+
MemoryLruDelegate,
44+
MemoryPersistence
4545
} from '../local/memory_persistence';
4646

47+
const MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE =
48+
'You are using the memory-only build of Firestore. Persistence support is ' +
49+
'only available via the @firebase/firestore bundle or the ' +
50+
'firebase-firestore.js build.';
51+
4752
export interface ComponentConfiguration {
4853
asyncQueue: AsyncQueue;
4954
databaseInfo: DatabaseInfo;
@@ -74,19 +79,52 @@ export interface ComponentProvider {
7479
}
7580

7681
/**
77-
* Provides all components needed for Firestore with IndexedDB persistence.
82+
* Provides all components needed for Firestore with in-memory persistence.
83+
* Uses EagerGC garbage collection.
7884
*/
79-
export class IndexedDbComponentProvider implements ComponentProvider {
80-
persistence!: IndexedDbPersistence;
85+
export class MemoryComponentProvider {
86+
persistence!: Persistence;
8187
sharedClientState!: SharedClientState;
8288
localStore!: LocalStore;
8389
syncEngine!: SyncEngine;
84-
gcScheduler!: GarbageCollectionScheduler;
90+
gcScheduler!: GarbageCollectionScheduler | null;
8591
remoteStore!: RemoteStore;
8692
eventManager!: EventManager;
8793

88-
initialize(cfg: ComponentConfiguration): Promise<void> {
89-
return initializeComponentProvider(this, cfg);
94+
async initialize(cfg: ComponentConfiguration): Promise<void> {
95+
this.sharedClientState = this.createSharedClientState(cfg);
96+
this.persistence = this.createPersistence(cfg);
97+
await this.persistence.start();
98+
this.gcScheduler = this.createGarbageCollectionScheduler(cfg);
99+
this.localStore = this.createLocalStore(cfg);
100+
this.remoteStore = this.createRemoteStore(cfg);
101+
this.syncEngine = this.createSyncEngine(cfg);
102+
this.eventManager = this.createEventManager(cfg);
103+
104+
this.sharedClientState.onlineStateHandler = onlineState =>
105+
this.syncEngine.applyOnlineStateChange(
106+
onlineState,
107+
OnlineStateSource.SharedClientState
108+
);
109+
this.remoteStore.syncEngine = this.syncEngine;
110+
this.sharedClientState.syncEngine = this.syncEngine;
111+
112+
await this.sharedClientState.start();
113+
await this.remoteStore.start();
114+
await this.localStore.start();
115+
116+
// NOTE: This will immediately call the listener, so we make sure to
117+
// set it after localStore / remoteStore are started.
118+
await this.persistence.setPrimaryStateListener(async isPrimary => {
119+
await this.syncEngine.applyPrimaryState(isPrimary);
120+
if (this.gcScheduler) {
121+
if (isPrimary && !this.gcScheduler.started) {
122+
this.gcScheduler.start(this.localStore);
123+
} else if (!isPrimary) {
124+
this.gcScheduler.stop();
125+
}
126+
}
127+
});
90128
}
91129

92130
createEventManager(cfg: ComponentConfiguration): EventManager {
@@ -96,9 +134,7 @@ export class IndexedDbComponentProvider implements ComponentProvider {
96134
createGarbageCollectionScheduler(
97135
cfg: ComponentConfiguration
98136
): GarbageCollectionScheduler | null {
99-
const garbageCollector = this.persistence.referenceDelegate
100-
.garbageCollector;
101-
return new LruScheduler(garbageCollector, cfg.asyncQueue);
137+
return null;
102138
}
103139

104140
createLocalStore(cfg: ComponentConfiguration): LocalStore {
@@ -111,26 +147,10 @@ export class IndexedDbComponentProvider implements ComponentProvider {
111147

112148
createPersistence(cfg: ComponentConfiguration): Persistence {
113149
debugAssert(
114-
cfg.persistenceSettings.durable,
115-
'Can only start durable persistence'
116-
);
117-
118-
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
119-
cfg.databaseInfo
150+
!cfg.persistenceSettings.durable,
151+
'Can only start memory persistence'
120152
);
121-
const serializer = cfg.platform.newSerializer(cfg.databaseInfo.databaseId);
122-
return IndexedDbPersistence.createIndexedDbPersistence({
123-
allowTabSynchronization: cfg.persistenceSettings.synchronizeTabs,
124-
persistenceKey,
125-
clientId: cfg.clientId,
126-
platform: cfg.platform,
127-
queue: cfg.asyncQueue,
128-
serializer,
129-
lruParams: LruParams.withCacheSize(
130-
cfg.persistenceSettings.cacheSizeBytes
131-
),
132-
sequenceNumberSyncer: this.sharedClientState
133-
});
153+
return new MemoryPersistence(cfg.clientId, MemoryEagerDelegate.factory);
134154
}
135155

136156
createRemoteStore(cfg: ComponentConfiguration): RemoteStore {
@@ -148,29 +168,6 @@ export class IndexedDbComponentProvider implements ComponentProvider {
148168
}
149169

150170
createSharedClientState(cfg: ComponentConfiguration): SharedClientState {
151-
debugAssert(
152-
cfg.persistenceSettings.durable,
153-
'Can only start durable persistence'
154-
);
155-
156-
if (cfg.persistenceSettings.synchronizeTabs) {
157-
if (!WebStorageSharedClientState.isAvailable(cfg.platform)) {
158-
throw new FirestoreError(
159-
Code.UNIMPLEMENTED,
160-
'IndexedDB persistence is only available on platforms that support LocalStorage.'
161-
);
162-
}
163-
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
164-
cfg.databaseInfo
165-
);
166-
return new WebStorageSharedClientState(
167-
cfg.asyncQueue,
168-
cfg.platform,
169-
persistenceKey,
170-
cfg.clientId,
171-
cfg.initialUser
172-
);
173-
}
174171
return new MemorySharedClientState();
175172
}
176173

@@ -185,137 +182,101 @@ export class IndexedDbComponentProvider implements ComponentProvider {
185182
}
186183

187184
clearPersistence(databaseInfo: DatabaseInfo): Promise<void> {
188-
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
189-
databaseInfo
185+
throw new FirestoreError(
186+
Code.FAILED_PRECONDITION,
187+
MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE
190188
);
191-
return IndexedDbPersistence.clearPersistence(persistenceKey);
192189
}
193190
}
194191

195-
const MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE =
196-
'You are using the memory-only build of Firestore. Persistence support is ' +
197-
'only available via the @firebase/firestore bundle or the ' +
198-
'firebase-firestore.js build.';
199-
200192
/**
201193
* Provides all components needed for Firestore with in-memory persistence.
194+
* Uses LRU garbage collection.
202195
*/
203-
export class MemoryComponentProvider implements ComponentProvider {
204-
persistence!: Persistence;
205-
sharedClientState!: SharedClientState;
206-
localStore!: LocalStore;
207-
syncEngine!: SyncEngine;
208-
gcScheduler!: null;
209-
remoteStore!: RemoteStore;
210-
eventManager!: EventManager;
211-
212-
constructor(
213-
readonly referenceDelegateFactory: (
214-
p: MemoryPersistence
215-
) => MemoryReferenceDelegate = MemoryEagerDelegate.factory
216-
) {}
217-
218-
initialize(cfg: ComponentConfiguration): Promise<void> {
219-
return initializeComponentProvider(this, cfg);
220-
}
221-
222-
createEventManager(cfg: ComponentConfiguration): EventManager {
223-
return new EventManager(this.syncEngine);
196+
export class MemoryLruComponentProvider extends MemoryComponentProvider {
197+
createPersistence(cfg: ComponentConfiguration): Persistence {
198+
debugAssert(
199+
!cfg.persistenceSettings.durable,
200+
'Can only start memory persistence'
201+
);
202+
return new MemoryPersistence(
203+
cfg.clientId,
204+
p => new MemoryLruDelegate(p, LruParams.DEFAULT)
205+
);
224206
}
207+
}
225208

209+
/**
210+
* Provides all components needed for Firestore with IndexedDB persistence.
211+
*/
212+
export class IndexedDbComponentProvider extends MemoryComponentProvider {
226213
createGarbageCollectionScheduler(
227214
cfg: ComponentConfiguration
228215
): GarbageCollectionScheduler | null {
229-
return null;
230-
}
231-
232-
createLocalStore(cfg: ComponentConfiguration): LocalStore {
233-
return new LocalStore(
234-
this.persistence,
235-
new IndexFreeQueryEngine(),
236-
cfg.initialUser
216+
debugAssert(
217+
this.persistence instanceof IndexedDbPersistence,
218+
'IndexedDbComponentProvider should provide IndexedDBPersistence'
237219
);
220+
const garbageCollector = this.persistence.referenceDelegate
221+
.garbageCollector;
222+
return new LruScheduler(garbageCollector, cfg.asyncQueue);
238223
}
239224

240225
createPersistence(cfg: ComponentConfiguration): Persistence {
241226
debugAssert(
242-
!cfg.persistenceSettings.durable,
243-
'Can only start memory persistence'
227+
cfg.persistenceSettings.durable,
228+
'Can only start durable persistence'
244229
);
245-
return new MemoryPersistence(cfg.clientId, this.referenceDelegateFactory);
246-
}
247230

248-
createRemoteStore(cfg: ComponentConfiguration): RemoteStore {
249-
return new RemoteStore(
250-
this.localStore,
251-
cfg.datastore,
252-
cfg.asyncQueue,
253-
onlineState =>
254-
this.syncEngine.applyOnlineStateChange(
255-
onlineState,
256-
OnlineStateSource.RemoteStore
257-
),
258-
cfg.platform.newConnectivityMonitor()
231+
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
232+
cfg.databaseInfo
259233
);
234+
const serializer = cfg.platform.newSerializer(cfg.databaseInfo.databaseId);
235+
return IndexedDbPersistence.createIndexedDbPersistence({
236+
allowTabSynchronization: cfg.persistenceSettings.synchronizeTabs,
237+
persistenceKey,
238+
clientId: cfg.clientId,
239+
platform: cfg.platform,
240+
queue: cfg.asyncQueue,
241+
serializer,
242+
lruParams: LruParams.withCacheSize(
243+
cfg.persistenceSettings.cacheSizeBytes
244+
),
245+
sequenceNumberSyncer: this.sharedClientState
246+
});
260247
}
261248

262249
createSharedClientState(cfg: ComponentConfiguration): SharedClientState {
263-
return new MemorySharedClientState();
264-
}
265-
266-
createSyncEngine(cfg: ComponentConfiguration): SyncEngine {
267-
return new SyncEngine(
268-
this.localStore,
269-
this.remoteStore,
270-
this.sharedClientState,
271-
cfg.initialUser,
272-
cfg.maxConcurrentLimboResolutions
250+
debugAssert(
251+
cfg.persistenceSettings.durable,
252+
'Can only start durable persistence'
273253
);
274-
}
275254

276-
clearPersistence(): never {
277-
throw new FirestoreError(
278-
Code.FAILED_PRECONDITION,
279-
MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE
280-
);
255+
if (cfg.persistenceSettings.synchronizeTabs) {
256+
if (!WebStorageSharedClientState.isAvailable(cfg.platform)) {
257+
throw new FirestoreError(
258+
Code.UNIMPLEMENTED,
259+
'IndexedDB persistence is only available on platforms that support LocalStorage.'
260+
);
261+
}
262+
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
263+
cfg.databaseInfo
264+
);
265+
return new WebStorageSharedClientState(
266+
cfg.asyncQueue,
267+
cfg.platform,
268+
persistenceKey,
269+
cfg.clientId,
270+
cfg.initialUser
271+
);
272+
}
273+
return new MemorySharedClientState();
281274
}
282-
}
283-
284-
async function initializeComponentProvider(
285-
target: MemoryComponentProvider | IndexedDbComponentProvider,
286-
cfg: ComponentConfiguration
287-
): Promise<void> {
288-
target.sharedClientState = target.createSharedClientState(cfg);
289-
target.persistence = target.createPersistence(cfg);
290-
await target.persistence.start();
291-
target.gcScheduler = target.createGarbageCollectionScheduler(cfg);
292-
target.localStore = target.createLocalStore(cfg);
293-
target.remoteStore = target.createRemoteStore(cfg);
294-
target.syncEngine = target.createSyncEngine(cfg);
295-
target.eventManager = target.createEventManager(cfg);
296275

297-
target.sharedClientState.onlineStateHandler = onlineState =>
298-
target.syncEngine.applyOnlineStateChange(
299-
onlineState,
300-
OnlineStateSource.SharedClientState
276+
clearPersistence(databaseInfo: DatabaseInfo): Promise<void> {
277+
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
278+
databaseInfo
301279
);
302-
target.remoteStore.syncEngine = target.syncEngine;
303-
target.sharedClientState.syncEngine = target.syncEngine;
304-
305-
await target.sharedClientState.start();
306-
await target.remoteStore.start();
307-
await target.localStore.start();
308-
309-
// NOTE: This will immediately call the listener, so we make sure to
310-
// set it after localStore / remoteStore are started.
311-
await target.persistence.setPrimaryStateListener(async isPrimary => {
312-
await target.syncEngine.applyPrimaryState(isPrimary);
313-
if (target.gcScheduler) {
314-
if (isPrimary && !target.gcScheduler.started) {
315-
target.gcScheduler.start(target.localStore);
316-
} else if (!isPrimary) {
317-
target.gcScheduler.stop();
318-
}
319-
}
320-
});
280+
return IndexedDbPersistence.clearPersistence(persistenceKey);
281+
}
321282
}

0 commit comments

Comments
 (0)