Skip to content

Add a type parameter to Persistence #1047

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 31 commits into from
Jul 31, 2018
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2c93300
Cherry pick sequence number starting point
Jul 23, 2018
96d732c
Working on typed transactions
Jul 23, 2018
59121ba
Start plumbing in sequence number
Jul 24, 2018
4b75267
Back out sequence number changes
Jul 25, 2018
29505fc
[AUTOMATED]: Prettier Code Styling
Jul 25, 2018
d03f608
Fix tests
Jul 25, 2018
e7efc7b
[AUTOMATED]: Prettier Code Styling
Jul 25, 2018
fd1359a
Fix lint
Jul 25, 2018
9a76422
[AUTOMATED]: Prettier Code Styling
Jul 25, 2018
a7b46dd
Merge branch 'master' into typed_transactions
Jul 25, 2018
3abdbbe
Uncomment line
Jul 25, 2018
5b66917
Fix the merge conflicts
Jul 25, 2018
a2848ff
MemoryPersistenceTransaction -> MemoryTransaction
Jul 26, 2018
70e8e51
[AUTOMATED]: Prettier Code Styling
Jul 26, 2018
ca4bc5d
Review updates
Jul 27, 2018
7909aef
Style
Jul 27, 2018
1bd431e
Merge branch 'master' into typed_transactions
Jul 27, 2018
9fc2b89
Lint and style
Jul 27, 2018
d4f1dcc
Review feedback
Jul 30, 2018
a94c026
[AUTOMATED]: Prettier Code Styling
Jul 30, 2018
fa05379
Merge branch 'master' into typed_transactions
Jul 30, 2018
068a4af
Revert some unintentional import churn
Jul 30, 2018
8e46ab9
Line 44 should definitely be empty
Jul 30, 2018
091038c
Checkpoint before adding helper function for stores
Jul 30, 2018
f0ed2dd
Use a helper for casting PersistenceTransaction to IndexedDbTransaction
Jul 30, 2018
ca53e31
[AUTOMATED]: Prettier Code Styling
Jul 30, 2018
4193323
Remove errant generic type
Jul 30, 2018
1a39850
Lint
Jul 30, 2018
80a2459
Merge branch 'master' into typed_transactions
Jul 30, 2018
7d14f14
Merge branch 'master' into typed_transactions
Jul 31, 2018
9e570c8
Fix typo
Jul 31, 2018
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
8 changes: 5 additions & 3 deletions packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { IndexedDbPersistence } from '../local/indexeddb_persistence';
import { LocalStore } from '../local/local_store';
import { MemoryPersistence } from '../local/memory_persistence';
import { NoOpGarbageCollector } from '../local/no_op_garbage_collector';
import { Persistence } from '../local/persistence';
import { Persistence, PersistenceTransaction } from '../local/persistence';
import {
DocumentKeySet,
documentKeySet,
Expand Down Expand Up @@ -76,8 +76,10 @@ export class FirestoreClient {
// undefined checks.
private eventMgr: EventManager;
private garbageCollector: GarbageCollector;
private persistence: Persistence;
private localStore: LocalStore;
// Note that localStore will end up with the same type parameter as
// persistence because the LocalStore constructor enforces this.
Copy link
Contributor

Choose a reason for hiding this comment

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

obsolete

private persistence: Persistence<PersistenceTransaction>;
private localStore: LocalStore<PersistenceTransaction>;
private remoteStore: RemoteStore;
private syncEngine: SyncEngine;

Expand Down
4 changes: 2 additions & 2 deletions packages/firestore/src/core/sync_engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { ObjectMap } from '../util/obj_map';
import { Deferred } from '../util/promise';
import { SortedMap } from '../util/sorted_map';
import { isNullOrUndefined } from '../util/types';

import { PersistenceTransaction } from '../local/persistence';
import { Query } from './query';
import { SnapshotVersion } from './snapshot_version';
import { TargetIdGenerator } from './target_id_generator';
Expand Down Expand Up @@ -143,7 +143,7 @@ export class SyncEngine implements RemoteSyncer {
private targetIdGenerator = TargetIdGenerator.forSyncEngine();

constructor(
private localStore: LocalStore,
private localStore: LocalStore<PersistenceTransaction>,
private remoteStore: RemoteStore,
private currentUser: User
) {
Expand Down
55 changes: 27 additions & 28 deletions packages/firestore/src/local/indexeddb_mutation_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ import {
} from './indexeddb_schema';
import { LocalSerializer } from './local_serializer';
import { MutationQueue } from './mutation_queue';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { SimpleDb, SimpleDbStore } from './simple_db';
import { IndexedDbTransaction } from './indexeddb_persistence';

/** A mutation queue for a specific user, backed by IndexedDB. */
export class IndexedDbMutationQueue implements MutationQueue {
export class IndexedDbMutationQueue
implements MutationQueue<IndexedDbTransaction> {
/**
* Next value to use when assigning sequential IDs to each mutation batch.
*
Expand Down Expand Up @@ -87,7 +88,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
return new IndexedDbMutationQueue(userId, serializer);
}

start(transaction: PersistenceTransaction): PersistencePromise<void> {
start(transaction: IndexedDbTransaction): PersistencePromise<void> {
return IndexedDbMutationQueue.loadNextBatchIdFromDb(transaction)
.next(nextBatchId => {
this.nextBatchId = nextBatchId;
Expand Down Expand Up @@ -129,7 +130,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
* are no mutations returns 0. Note that batch IDs are global.
*/
static loadNextBatchIdFromDb(
txn: PersistenceTransaction
txn: IndexedDbTransaction
): PersistencePromise<BatchId> {
let maxBatchId = BATCHID_UNKNOWN;
return mutationsStore(txn)
Expand All @@ -152,7 +153,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
.next(() => maxBatchId + 1);
}

checkEmpty(transaction: PersistenceTransaction): PersistencePromise<boolean> {
checkEmpty(transaction: IndexedDbTransaction): PersistencePromise<boolean> {
let empty = true;
const range = IDBKeyRange.bound(
this.keyForBatchId(Number.NEGATIVE_INFINITY),
Expand All @@ -167,19 +168,19 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getNextBatchId(
transaction: PersistenceTransaction
transaction: IndexedDbTransaction
): PersistencePromise<BatchId> {
return PersistencePromise.resolve(this.nextBatchId);
}

getHighestAcknowledgedBatchId(
transaction: PersistenceTransaction
transaction: IndexedDbTransaction
): PersistencePromise<BatchId> {
return PersistencePromise.resolve(this.metadata.lastAcknowledgedBatchId);
}

acknowledgeBatch(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
batch: MutationBatch,
streamToken: ProtoByteString
): PersistencePromise<void> {
Expand All @@ -196,21 +197,21 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getLastStreamToken(
transaction: PersistenceTransaction
transaction: IndexedDbTransaction
): PersistencePromise<ProtoByteString> {
return PersistencePromise.resolve(this.metadata.lastStreamToken);
}

setLastStreamToken(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
streamToken: ProtoByteString
): PersistencePromise<void> {
this.metadata.lastStreamToken = convertStreamToken(streamToken);
return mutationQueuesStore(transaction).put(this.metadata);
}

addMutationBatch(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
localWriteTime: Timestamp,
mutations: Mutation[]
): PersistencePromise<MutationBatch> {
Expand Down Expand Up @@ -245,7 +246,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

lookupMutationBatch(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
batchId: BatchId
): PersistencePromise<MutationBatch | null> {
return mutationsStore(transaction)
Expand All @@ -257,7 +258,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getNextMutationBatchAfterBatchId(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
batchId: BatchId
): PersistencePromise<MutationBatch | null> {
// All batches with batchId <= this.metadata.lastAcknowledgedBatchId have
Expand All @@ -283,7 +284,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getAllMutationBatches(
transaction: PersistenceTransaction
transaction: IndexedDbTransaction
): PersistencePromise<MutationBatch[]> {
const range = IDBKeyRange.bound(
this.keyForBatchId(BATCHID_UNKNOWN),
Expand All @@ -297,7 +298,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getAllMutationBatchesThroughBatchId(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
batchId: BatchId
): PersistencePromise<MutationBatch[]> {
const range = IDBKeyRange.bound(
Expand All @@ -312,7 +313,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getAllMutationBatchesAffectingDocumentKey(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
documentKey: DocumentKey
): PersistencePromise<MutationBatch[]> {
// Scan the document-mutation index starting with a prefix starting with
Expand Down Expand Up @@ -363,7 +364,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

getAllMutationBatchesAffectingQuery(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
query: Query
): PersistencePromise<MutationBatch[]> {
assert(
Expand Down Expand Up @@ -439,7 +440,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

removeMutationBatches(
transaction: PersistenceTransaction,
transaction: IndexedDbTransaction,
batches: MutationBatch[]
): PersistencePromise<void> {
const txn = mutationsStore(transaction);
Expand Down Expand Up @@ -477,9 +478,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
return PersistencePromise.waitFor(promises);
}

performConsistencyCheck(
txn: PersistenceTransaction
): PersistencePromise<void> {
performConsistencyCheck(txn: IndexedDbTransaction): PersistencePromise<void> {
return this.checkEmpty(txn).next(empty => {
if (!empty) {
return PersistencePromise.resolve();
Expand Down Expand Up @@ -517,7 +516,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
}

containsKey(
txn: PersistenceTransaction,
txn: IndexedDbTransaction,
key: DocumentKey
): PersistencePromise<boolean> {
const indexKey = DbDocumentMutation.prefixForPath(this.userId, key.path);
Expand Down Expand Up @@ -561,10 +560,10 @@ function convertStreamToken(token: ProtoByteString): string {
* Helper to get a typed SimpleDbStore for the mutations object store.
*/
function mutationsStore(
txn: PersistenceTransaction
txn: IndexedDbTransaction
): SimpleDbStore<DbMutationBatchKey, DbMutationBatch> {
return SimpleDb.getStore<DbMutationBatchKey, DbMutationBatch>(
txn,
txn.simpleDbTransaction,
DbMutationBatch.store
);
}
Expand All @@ -573,10 +572,10 @@ function mutationsStore(
* Helper to get a typed SimpleDbStore for the mutationQueues object store.
*/
function documentMutationsStore(
txn: PersistenceTransaction
txn: IndexedDbTransaction
): SimpleDbStore<DbDocumentMutationKey, DbDocumentMutation> {
return SimpleDb.getStore<DbDocumentMutationKey, DbDocumentMutation>(
txn,
txn.simpleDbTransaction,
DbDocumentMutation.store
);
}
Expand All @@ -585,10 +584,10 @@ function documentMutationsStore(
* Helper to get a typed SimpleDbStore for the mutationQueues object store.
*/
function mutationQueuesStore(
txn: PersistenceTransaction
txn: IndexedDbTransaction
): SimpleDbStore<DbMutationQueueKey, DbMutationQueue> {
return SimpleDb.getStore<DbMutationQueueKey, DbMutationQueue>(
txn,
txn.simpleDbTransaction,
DbMutationQueue.store
);
}
45 changes: 30 additions & 15 deletions packages/firestore/src/local/indexeddb_persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ const UNSUPPORTED_PLATFORM_ERROR_MSG =
' IndexedDB or is known to have an incomplete implementation. Offline' +
' persistence has been disabled.';

export class IndexedDbTransaction {
constructor(readonly simpleDbTransaction: SimpleDbTransaction) {}
}

/**
* An IndexedDB-backed instance of Persistence. Data is stored persistently
* across sessions.
Expand Down Expand Up @@ -88,7 +92,7 @@ const UNSUPPORTED_PLATFORM_ERROR_MSG =
* which acts as an indicator that another tab should go ahead and take the
* owner lease immediately regardless of the current lease timestamp.
*/
export class IndexedDbPersistence implements Persistence {
export class IndexedDbPersistence implements Persistence<IndexedDbTransaction> {
/**
* The name of the main (and currently only) IndexedDB database. this name is
* appended to the prefix provided to the IndexedDbPersistence constructor.
Expand Down Expand Up @@ -162,21 +166,21 @@ export class IndexedDbPersistence implements Persistence {
return this._started;
}

getMutationQueue(user: User): MutationQueue {
getMutationQueue(user: User): MutationQueue<IndexedDbTransaction> {
return IndexedDbMutationQueue.forUser(user, this.serializer);
}

getQueryCache(): QueryCache {
getQueryCache(): QueryCache<IndexedDbTransaction> {
return new IndexedDbQueryCache(this.serializer);
}

getRemoteDocumentCache(): RemoteDocumentCache {
getRemoteDocumentCache(): RemoteDocumentCache<IndexedDbTransaction> {
return new IndexedDbRemoteDocumentCache(this.serializer);
}

runTransaction<T>(
action: string,
operation: (transaction: SimpleDbTransaction) => PersistencePromise<T>
operation: (transaction: IndexedDbTransaction) => PersistencePromise<T>
): Promise<T> {
if (this.persistenceError) {
return Promise.reject(this.persistenceError);
Expand All @@ -186,10 +190,17 @@ export class IndexedDbPersistence implements Persistence {

// Do all transactions as readwrite against all object stores, since we
// are the only reader/writer.
return this.simpleDb.runTransaction('readwrite', ALL_STORES, txn => {
// Verify that we still have the owner lease as part of every transaction.
return this.ensureOwnerLease(txn).next(() => operation(txn));
});
return this.simpleDb.runTransaction(
'readwrite',
ALL_STORES,
simpleDbTxn => {
// Verify that we still have the owner lease as part of every transaction.
const txn = new IndexedDbTransaction(simpleDbTxn);
return this.ensureOwnerLease(txn.simpleDbTransaction).next(() =>
Copy link
Contributor

Choose a reason for hiding this comment

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

simpleDbTxn?

Copy link
Author

Choose a reason for hiding this comment

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

If it's all the same, I'd rather keep the longer name. I think the abbreviation is a little harder to read.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was suggesting you use the existing variable that's in scope.

Copy link
Author

Choose a reason for hiding this comment

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

Ah. That makes more sense. Done.

Copy link
Contributor

Choose a reason for hiding this comment

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

As a general rule if I ever ask somebody to abbreviate a name in code review feedback you can assume my account has been hacked. 😁

operation(txn)
);
}
);
}

static isAvailable(): boolean {
Expand Down Expand Up @@ -326,12 +337,16 @@ export class IndexedDbPersistence implements Persistence {
// would increase the chances of us not refreshing on time if the queue is
// backed up for some reason.
this.ownerLeaseRefreshHandle = setInterval(() => {
const txResult = this.runTransaction('Refresh owner timestamp', txn => {
// NOTE: We don't need to validate the current owner contents, since
// runTransaction does that automatically.
const store = txn.store<DbOwnerKey, DbOwner>(DbOwner.store);
return store.put('owner', new DbOwner(this.ownerId, Date.now()));
});
const txResult = this.simpleDb.runTransaction(
'readwrite',
ALL_STORES,
txn => {
// NOTE: We don't need to validate the current owner contents, since
// runTransaction does that automatically.
const store = txn.store<DbOwnerKey, DbOwner>(DbOwner.store);
return store.put('owner', new DbOwner(this.ownerId, Date.now()));
}
);

txResult.catch(reason => {
// Probably means we lost the lease. Report the error and stop trying to
Expand Down
Loading