Skip to content

Clean up IndexedDb initialization #2163

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 2 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 23 additions & 28 deletions packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export class FirestoreClient {
): Promise<LruGarbageCollector> {
// TODO(http://b/33384523): For now we just disable garbage collection
// when persistence is enabled.
const storagePrefix = IndexedDbPersistence.buildStoragePrefix(
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
this.databaseInfo
);
// Opt to use proto3 JSON in case the platform doesn't support Uint8Array.
Expand All @@ -347,36 +347,31 @@ export class FirestoreClient {
);
}

let persistence: IndexedDbPersistence;
const lruParams = settings.lruParams();
if (settings.synchronizeTabs) {
this.sharedClientState = new WebStorageSharedClientState(
this.asyncQueue,
this.platform,
storagePrefix,
this.clientId,
user
);
persistence = await IndexedDbPersistence.createMultiClientIndexedDbPersistence(
storagePrefix,
this.clientId,
this.platform,
this.asyncQueue,

this.sharedClientState = settings.synchronizeTabs
? new WebStorageSharedClientState(
this.asyncQueue,
this.platform,
persistenceKey,
this.clientId,
user
)
: new MemorySharedClientState();

const persistence = await IndexedDbPersistence.createIndexedDbPersistence(
{
allowTabSynchronization: settings.synchronizeTabs,
persistenceKey,
clientId: this.clientId,
platform: this.platform,
queue: this.asyncQueue,
serializer,
lruParams,
{ sequenceNumberSyncer: this.sharedClientState }
);
} else {
this.sharedClientState = new MemorySharedClientState();
persistence = await IndexedDbPersistence.createIndexedDbPersistence(
storagePrefix,
this.clientId,
this.platform,
this.asyncQueue,
serializer,
lruParams
);
}
sequenceNumberSyncer: this.sharedClientState
}
);

this.persistence = persistence;
return persistence.referenceDelegate.garbageCollector;
});
Expand Down
85 changes: 28 additions & 57 deletions packages/firestore/src/local/indexeddb_persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,6 @@ export class IndexedDbTransaction extends PersistenceTransaction {
* TODO(b/114226234): Remove `synchronizeTabs` section when multi-tab is no
* longer optional.
*/
export interface MultiClientParams {
sequenceNumberSyncer: SequenceNumberSyncer;
}
export class IndexedDbPersistence implements Persistence {
static getStore<Key extends IDBValidKey, Value>(
txn: PersistenceTransaction,
Expand All @@ -191,43 +188,32 @@ export class IndexedDbPersistence implements Persistence {
*/
static MAIN_DATABASE = 'main';

static async createIndexedDbPersistence(
persistenceKey: string,
clientId: ClientId,
platform: Platform,
queue: AsyncQueue,
serializer: JsonProtoSerializer,
lruParams: LruParams
): Promise<IndexedDbPersistence> {
const persistence = new IndexedDbPersistence(
persistenceKey,
clientId,
platform,
queue,
serializer,
lruParams
);
await persistence.start();
return persistence;
}
static async createIndexedDbPersistence(options: {
allowTabSynchronization: boolean;
persistenceKey: string;
clientId: ClientId;
platform: Platform;
lruParams: LruParams;
queue: AsyncQueue;
serializer: JsonProtoSerializer;
sequenceNumberSyncer: SequenceNumberSyncer;
}): Promise<IndexedDbPersistence> {
if (!IndexedDbPersistence.isAvailable()) {
throw new FirestoreError(
Code.UNIMPLEMENTED,
UNSUPPORTED_PLATFORM_ERROR_MSG
);
}

static async createMultiClientIndexedDbPersistence(
persistenceKey: string,
clientId: ClientId,
platform: Platform,
queue: AsyncQueue,
serializer: JsonProtoSerializer,
lruParams: LruParams,
multiClientParams: MultiClientParams
): Promise<IndexedDbPersistence> {
const persistence = new IndexedDbPersistence(
persistenceKey,
clientId,
platform,
queue,
serializer,
lruParams,
multiClientParams
options.allowTabSynchronization,
options.persistenceKey,
options.clientId,
options.platform,
options.lruParams,
options.queue,
options.serializer,
options.sequenceNumberSyncer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems slightly odd and arbitrary for createIndexedDbPersistence() to take an options object but then we flatten that into separate arguments when calling the IndexedDbPersistence constructor.

I don't care very strongly, but it seems like it'd be cleaner to either convert both to options objects or just use plain arguments for both.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with "odd", but I wanted to make this long list of arguments more readable, so I opted for the options object for the external API. If I use an options object in the constructor though, then I would have to declare all fields explicitly again. This is my compromise for the best (and worst) of all worlds.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right! That's a pretty good reason.

);
await persistence.start();
return persistence;
Expand Down Expand Up @@ -262,9 +248,6 @@ export class IndexedDbPersistence implements Persistence {
/** The last time we garbage collected the Remote Document Changelog. */
private lastGarbageCollectionTime = Number.NEGATIVE_INFINITY;

/** Whether to allow shared multi-tab access to the persistence layer. */
private allowTabSynchronization: boolean;

/** A listener to notify on primary state changes. */
private primaryStateListener: PrimaryStateListener = _ => Promise.resolve();

Expand All @@ -274,29 +257,20 @@ export class IndexedDbPersistence implements Persistence {
private readonly webStorage: Storage;
readonly referenceDelegate: IndexedDbLruDelegate;

// Note that `multiClientParams` must be present to enable multi-client support while multi-tab
// is still experimental. When multi-client is switched to always on, `multiClientParams` will
// no longer be optional.
private constructor(
private readonly allowTabSynchronization: boolean,
private readonly persistenceKey: string,
private readonly clientId: ClientId,
platform: Platform,
lruParams: LruParams,
private readonly queue: AsyncQueue,
serializer: JsonProtoSerializer,
lruParams: LruParams,
private readonly multiClientParams?: MultiClientParams
private readonly sequenceNumberSyncer: SequenceNumberSyncer
) {
if (!IndexedDbPersistence.isAvailable()) {
throw new FirestoreError(
Code.UNIMPLEMENTED,
UNSUPPORTED_PLATFORM_ERROR_MSG
);
}
this.referenceDelegate = new IndexedDbLruDelegate(this, lruParams);
this.dbName = persistenceKey + IndexedDbPersistence.MAIN_DATABASE;
this.serializer = new LocalSerializer(serializer);
this.document = platform.document;
this.allowTabSynchronization = multiClientParams !== undefined;
this.queryCache = new IndexedDbQueryCache(
this.referenceDelegate,
this.serializer
Expand Down Expand Up @@ -353,12 +327,9 @@ export class IndexedDbPersistence implements Persistence {
txn => {
return getHighestListenSequenceNumber(txn).next(
highestListenSequenceNumber => {
const sequenceNumberSyncer = this.multiClientParams
? this.multiClientParams.sequenceNumberSyncer
: undefined;
this.listenSequence = new ListenSequence(
highestListenSequenceNumber,
sequenceNumberSyncer
this.sequenceNumberSyncer
);
}
);
Expand Down
30 changes: 10 additions & 20 deletions packages/firestore/test/unit/local/indexeddb_persistence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,16 @@ async function withCustomPersistence(
PlatformSupport.getPlatform(),
new SharedFakeWebStorage()
);
const persistence = await (multiClient
? IndexedDbPersistence.createMultiClientIndexedDbPersistence(
TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
serializer,
LruParams.DEFAULT,
{
sequenceNumberSyncer: MOCK_SEQUENCE_NUMBER_SYNCER
}
)
: IndexedDbPersistence.createIndexedDbPersistence(
TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
serializer,
LruParams.DEFAULT
));
const persistence = await IndexedDbPersistence.createIndexedDbPersistence({
allowTabSynchronization: multiClient,
persistenceKey: TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
serializer,
lruParams: LruParams.DEFAULT,
sequenceNumberSyncer: MOCK_SEQUENCE_NUMBER_SYNCER
});

await fn(persistence, platform, queue);
await persistence.shutdown();
Expand Down
28 changes: 10 additions & 18 deletions packages/firestore/test/unit/local/persistence_test_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,16 @@ export async function testIndexedDbPersistence(
await SimpleDb.delete(prefix + IndexedDbPersistence.MAIN_DATABASE);
}
const platform = PlatformSupport.getPlatform();
return options.synchronizeTabs
? IndexedDbPersistence.createMultiClientIndexedDbPersistence(
TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
JSON_SERIALIZER,
lruParams,
{ sequenceNumberSyncer: MOCK_SEQUENCE_NUMBER_SYNCER }
)
: IndexedDbPersistence.createIndexedDbPersistence(
TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
JSON_SERIALIZER,
lruParams
);
return IndexedDbPersistence.createIndexedDbPersistence({
allowTabSynchronization: !!options.synchronizeTabs,
persistenceKey: TEST_PERSISTENCE_PREFIX,
clientId,
platform,
queue,
serializer: JSON_SERIALIZER,
lruParams,
sequenceNumberSyncer: MOCK_SEQUENCE_NUMBER_SYNCER
});
}

/** Creates and starts a MemoryPersistence instance for testing. */
Expand Down
17 changes: 9 additions & 8 deletions packages/firestore/test/unit/specs/spec_test_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1216,15 +1216,16 @@ class IndexedDbTestRunner extends TestRunner {
gcEnabled: boolean
): Promise<Persistence> {
// TODO(gsoltis): can we or should we disable this test if gc is enabled?
return IndexedDbPersistence.createMultiClientIndexedDbPersistence(
TEST_PERSISTENCE_PREFIX,
this.clientId,
this.platform,
this.queue,
return IndexedDbPersistence.createIndexedDbPersistence({
allowTabSynchronization: true,
persistenceKey: TEST_PERSISTENCE_PREFIX,
clientId: this.clientId,
platform: this.platform,
queue: this.queue,
serializer,
LruParams.DEFAULT,
{ sequenceNumberSyncer: this.sharedClientState }
);
lruParams: LruParams.DEFAULT,
sequenceNumberSyncer: this.sharedClientState
});
}

static destroyPersistence(): Promise<void> {
Expand Down