Skip to content

Commit e8b53c6

Browse files
committed
Initial implementation
1 parent 06dc136 commit e8b53c6

File tree

3 files changed

+90
-12
lines changed

3 files changed

+90
-12
lines changed

packages/firestore/src/api/database.ts

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { deepEqual, getDefaultEmulatorHostnameAndPort } from '@firebase/util';
2626
import { User } from '../auth/user';
2727
import {
2828
IndexedDbOfflineComponentProvider,
29+
LruGcMemoryOfflineComponentProvider,
2930
MultiTabOfflineComponentProvider,
3031
OfflineComponentProvider,
3132
OnlineComponentProvider
@@ -286,28 +287,65 @@ export function configureFirestore(firestore: Firestore): void {
286287
}
287288

288289
/**
289-
* Attempts to enable persistent storage, if possible.
290+
* Attempts to enable the LRU garbage collector for memory persistence.
290291
*
291292
* Must be called before any other functions (other than
292293
* {@link initializeFirestore}, {@link (getFirestore:1)} or
293294
* {@link clearIndexedDbPersistence}.
294295
*
295-
* If this fails, `enableIndexedDbPersistence()` will reject the promise it
296-
* returns. Note that even after this failure, the {@link Firestore} instance will
297-
* remain usable, however offline persistence will be disabled.
296+
* By default, any documents that are not part of an active query result or
297+
* with no mutation attached to them are removed from memory immediately.
298298
*
299-
* There are several reasons why this can fail, which can be identified by
300-
* the `code` on the error.
301-
*
302-
* * failed-precondition: The app is already open in another browser tab.
303-
* * unimplemented: The browser is incompatible with the offline
304-
* persistence implementation.
299+
* This function changes the default behavior, to enable a least-recent-used
300+
* garbage collector. Documents will be collected when their total size exceeds
301+
* `Settings.cacheSizeBytes`, with least recently used documents get removed first.
305302
*
306303
* @param firestore - The {@link Firestore} instance to enable persistence for.
307-
* @param persistenceSettings - Optional settings object to configure
308-
* persistence.
309304
* @returns A `Promise` that represents successfully enabling persistent storage.
310305
*/
306+
export function enableMemoryLRUGarbageCollection(
307+
firestore: Firestore
308+
): Promise<void> {
309+
firestore = cast(firestore, Firestore);
310+
verifyNotInitialized(firestore);
311+
312+
const client = ensureFirestoreConfigured(firestore);
313+
const settings = firestore._freezeSettings();
314+
315+
const onlineComponentProvider = new OnlineComponentProvider();
316+
const offlineComponentProvider = new LruGcMemoryOfflineComponentProvider(
317+
settings.cacheSizeBytes
318+
);
319+
return setPersistenceProviders(
320+
client,
321+
onlineComponentProvider,
322+
offlineComponentProvider
323+
);
324+
}
325+
326+
/**
327+
* Attempts to enable persistent storage, if possible. //
328+
* //
329+
* Must be called before any other functions (other than //
330+
* {@link initializeFirestore}, {@link (getFirestore:1)} or //
331+
* {@link clearIndexedDbPersistence}. //
332+
* //
333+
* If this fails, `enableIndexedDbPersistence()` will reject the promise it //
334+
* returns. Note that even after this failure, the {@link Firestore} instance will //
335+
* remain usable, however offline persistence will be disabled. //
336+
* //
337+
* There are several reasons why this can fail, which can be identified by //
338+
* the `code` on the error. //
339+
* //
340+
* * failed-precondition: The app is already open in another browser tab. //
341+
* * unimplemented: The browser is incompatible with the offline //
342+
* persistence implementation. //
343+
* //
344+
* @param firestore - The {@link Firestore} instance to enable persistence for. //
345+
* @param persistenceSettings - Optional settings object to configure //
346+
* persistence. //
347+
* @returns A `Promise` that represents successfully enabling persistent storage. //
348+
*/
311349
export function enableIndexedDbPersistence(
312350
firestore: Firestore,
313351
persistenceSettings?: PersistenceSettings

packages/firestore/src/core/component_provider.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { LruParams } from '../local/lru_garbage_collector';
3131
import { LruScheduler } from '../local/lru_garbage_collector_impl';
3232
import {
3333
MemoryEagerDelegate,
34+
MemoryLruDelegate,
3435
MemoryPersistence
3536
} from '../local/memory_persistence';
3637
import { Scheduler, Persistence } from '../local/persistence';
@@ -72,6 +73,7 @@ import {
7273
syncEngineSynchronizeWithChangedDocuments
7374
} from './sync_engine_impl';
7475
import { OnlineStateSource } from './types';
76+
import { hardAssert } from '../util/assert';
7577

7678
export interface ComponentConfiguration {
7779
asyncQueue: AsyncQueue;
@@ -172,6 +174,37 @@ export class MemoryOfflineComponentProvider
172174
}
173175
}
174176

177+
export class LruGcMemoryOfflineComponentProvider extends MemoryOfflineComponentProvider {
178+
constructor(protected readonly cacheSizeBytes: number | undefined) {
179+
super();
180+
}
181+
182+
createGarbageCollectionScheduler(
183+
cfg: ComponentConfiguration,
184+
localStore: LocalStore
185+
): Scheduler | null {
186+
hardAssert(
187+
this.persistence.referenceDelegate instanceof MemoryLruDelegate,
188+
'referenceDelegate is expected to be an instance of MemoryLruDelegate.'
189+
);
190+
191+
const garbageCollector =
192+
this.persistence.referenceDelegate.garbageCollector;
193+
return new LruScheduler(garbageCollector, cfg.asyncQueue, localStore);
194+
}
195+
196+
createPersistence(cfg: ComponentConfiguration): Persistence {
197+
const lruParams =
198+
this.cacheSizeBytes !== undefined
199+
? LruParams.withCacheSize(this.cacheSizeBytes)
200+
: LruParams.DEFAULT;
201+
return new MemoryPersistence(
202+
p => MemoryLruDelegate.factory(p, lruParams),
203+
this.serializer
204+
);
205+
}
206+
}
207+
175208
/**
176209
* Provides all components needed for Firestore with IndexedDB persistence.
177210
*/

packages/firestore/src/local/memory_persistence.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ export class MemoryLruDelegate implements ReferenceDelegate, LruDelegate {
353353
this.garbageCollector = newLruGarbageCollector(this, lruParams);
354354
}
355355

356+
static factory(
357+
persistence: MemoryPersistence,
358+
lruParams: LruParams | null
359+
): MemoryLruDelegate {
360+
return new MemoryLruDelegate(persistence, lruParams!!);
361+
}
362+
356363
// No-ops, present so memory persistence doesn't have to care which delegate
357364
// it has.
358365
onTransactionStarted(): void {}

0 commit comments

Comments
 (0)