Skip to content

Commit 90e30d4

Browse files
Schema migration that drops held write acks
1 parent 4625e84 commit 90e30d4

10 files changed

+321
-56
lines changed

packages/firestore/src/core/firestore_client.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -293,17 +293,15 @@ export class FirestoreClient {
293293
// TODO(http://b/33384523): For now we just disable garbage collection
294294
// when persistence is enabled.
295295
this.garbageCollector = new NoOpGarbageCollector();
296-
const storagePrefix = IndexedDbPersistence.buildStoragePrefix(
297-
this.databaseInfo
298-
);
296+
299297
// Opt to use proto3 JSON in case the platform doesn't support Uint8Array.
300298
const serializer = new JsonProtoSerializer(this.databaseInfo.databaseId, {
301299
useProto3Json: true
302300
});
303301

304302
return Promise.resolve().then(() => {
305303
const persistence: IndexedDbPersistence = new IndexedDbPersistence(
306-
storagePrefix,
304+
this.databaseInfo,
307305
this.clientId,
308306
this.platform,
309307
this.asyncQueue,
@@ -322,6 +320,9 @@ export class FirestoreClient {
322320
);
323321
}
324322

323+
const storagePrefix = IndexedDbPersistence.buildStoragePrefix(
324+
this.databaseInfo
325+
);
325326
this.sharedClientState = settings.experimentalTabSynchronization
326327
? new WebStorageSharedClientState(
327328
this.asyncQueue,

packages/firestore/src/local/indexeddb_persistence.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,18 @@ export class IndexedDbPersistence implements Persistence {
204204
private queryCache: IndexedDbQueryCache;
205205
private remoteDocumentCache: IndexedDbRemoteDocumentCache;
206206

207+
private readonly persistenceKey: string;
208+
207209
constructor(
208-
private readonly persistenceKey: string,
210+
private readonly databaseInfo: DatabaseInfo,
209211
private readonly clientId: ClientId,
210212
platform: Platform,
211213
private readonly queue: AsyncQueue,
212214
serializer: JsonProtoSerializer,
213215
synchronizeTabs: boolean
214216
) {
215-
this.dbName = persistenceKey + IndexedDbPersistence.MAIN_DATABASE;
217+
this.persistenceKey = IndexedDbPersistence.buildStoragePrefix(databaseInfo);
218+
this.dbName = this.persistenceKey + IndexedDbPersistence.MAIN_DATABASE;
216219
this.serializer = new LocalSerializer(serializer);
217220
this.document = platform.document;
218221
this.window = platform.window;
@@ -241,7 +244,12 @@ export class IndexedDbPersistence implements Persistence {
241244
assert(!this.started, 'IndexedDbPersistence double-started!');
242245
assert(this.window !== null, "Expected 'window' to be defined");
243246

244-
return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb)
247+
return SimpleDb.openOrCreate(
248+
this.databaseInfo.databaseId,
249+
this.dbName,
250+
SCHEMA_VERSION,
251+
createOrUpgradeDb
252+
)
245253
.then(db => {
246254
this.simpleDb = db;
247255
})

packages/firestore/src/local/indexeddb_schema.ts

+74-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ import { encode, EncodedResourcePath } from './encoded_resource_path';
2424
import { SimpleDbTransaction } from './simple_db';
2525
import { PersistencePromise } from './persistence_promise';
2626
import { SnapshotVersion } from '../core/snapshot_version';
27+
import { BATCHID_UNKNOWN } from '../model/mutation_batch';
28+
import { IndexedDbMutationQueue } from './indexeddb_mutation_queue';
29+
import { LocalSerializer } from './local_serializer';
30+
import { JsonProtoSerializer } from '../remote/serializer';
31+
import { IndexedDbTransaction } from './indexeddb_persistence';
32+
import { DatabaseId } from '../core/database_info';
2733

2834
/**
2935
* Schema Version for the Web client:
@@ -35,8 +41,11 @@ import { SnapshotVersion } from '../core/snapshot_version';
3541
* to limbo resolution. Addresses
3642
* https://github.com/firebase/firebase-ios-sdk/issues/1548
3743
* 4. Multi-Tab Support.
44+
* 5. Removal of held write acks (not yet active).
3845
*/
3946
export const SCHEMA_VERSION = 4;
47+
// TODO(mrschmidt): As SCHEMA_VERSION becomes 5, uncomment the assert in
48+
// `createOrUpgradeDb`.
4049

4150
/**
4251
* Performs database creation and schema upgrades.
@@ -47,14 +56,15 @@ export const SCHEMA_VERSION = 4;
4756
*/
4857
export function createOrUpgradeDb(
4958
db: IDBDatabase,
59+
databaseId: DatabaseId,
5060
txn: SimpleDbTransaction,
5161
fromVersion: number,
5262
toVersion: number
5363
): PersistencePromise<void> {
54-
assert(
55-
fromVersion < toVersion && fromVersion >= 0 && toVersion <= SCHEMA_VERSION,
56-
'Unexpected schema upgrade from v${fromVersion} to v{toVersion}.'
57-
);
64+
// assert(
65+
// fromVersion < toVersion && fromVersion >= 0 && toVersion <= SCHEMA_VERSION,
66+
// `Unexpected schema upgrade from v${fromVersion} to v{toVersion}.`
67+
// );
5868

5969
if (fromVersion < 1 && toVersion >= 1) {
6070
createPrimaryClientStore(db);
@@ -94,6 +104,10 @@ export function createOrUpgradeDb(
94104
});
95105
}
96106

107+
if (fromVersion < 5 && toVersion >= 5) {
108+
p = p.next(() => removeAcknowledgedMutations(db, databaseId, txn));
109+
}
110+
97111
return p;
98112
}
99113

@@ -295,6 +309,62 @@ function upgradeMutationBatchSchemaAndMigrateData(
295309
});
296310
}
297311

312+
function removeAcknowledgedMutations(
313+
db: IDBDatabase,
314+
databaseId: DatabaseId,
315+
txn: SimpleDbTransaction
316+
): PersistencePromise<void> {
317+
const queuesStore = txn.store<DbMutationQueueKey, DbMutationQueue>(
318+
DbMutationQueue.store
319+
);
320+
const mutationsStore = txn.store<DbMutationBatchKey, DbMutationBatch>(
321+
DbMutationBatch.store
322+
);
323+
const serializer = new LocalSerializer(
324+
new JsonProtoSerializer(databaseId, {
325+
useProto3Json: true
326+
})
327+
);
328+
329+
const indexedDbTransaction = new IndexedDbTransaction(txn);
330+
return queuesStore.loadAll().next(queues => {
331+
let p = PersistencePromise.resolve();
332+
for (const queue of queues) {
333+
p = p.next(() => {
334+
const mutationQueue = new IndexedDbMutationQueue(
335+
queue.userId,
336+
serializer
337+
);
338+
const range = IDBKeyRange.bound(
339+
[queue.userId, BATCHID_UNKNOWN],
340+
[queue.userId, queue.lastAcknowledgedBatchId]
341+
);
342+
343+
return mutationsStore
344+
.loadAll(DbMutationBatch.userMutationsIndex, range)
345+
.next(dbBatches => {
346+
let removeP = PersistencePromise.resolve();
347+
for (const dbBatch of dbBatches) {
348+
assert(
349+
dbBatch.userId === queue.userId,
350+
`Cannot process batch ${dbBatch.batchId} from unexpected user`
351+
);
352+
const batch = serializer.fromDbMutationBatch(dbBatch);
353+
removeP = removeP.next(() =>
354+
mutationQueue.removeMutationBatch(indexedDbTransaction, batch)
355+
);
356+
}
357+
return removeP;
358+
})
359+
.next(() =>
360+
mutationQueue.performConsistencyCheck(indexedDbTransaction)
361+
);
362+
});
363+
}
364+
return p;
365+
});
366+
}
367+
298368
/**
299369
* An object to be stored in the 'documentMutations' store in IndexedDb.
300370
*

packages/firestore/src/local/simple_db.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { SCHEMA_VERSION } from './indexeddb_schema';
2222
import { AnyJs } from '../util/misc';
2323
import { Deferred } from '../util/promise';
2424
import { Code, FirestoreError } from '../util/error';
25+
import { DatabaseId } from '../core/database_info';
2526

2627
const LOG_TAG = 'SimpleDb';
2728

@@ -35,10 +36,12 @@ const LOG_TAG = 'SimpleDb';
3536
export class SimpleDb {
3637
/** Opens the specified database, creating or upgrading it if necessary. */
3738
static openOrCreate(
39+
databaseId: DatabaseId,
3840
name: string,
3941
version: number,
4042
runUpgrade: (
4143
db: IDBDatabase,
44+
databaseId: DatabaseId,
4245
txn: SimpleDbTransaction,
4346
fromVersion: number,
4447
toVersion: number
@@ -87,12 +90,14 @@ export class SimpleDb {
8790
// we wrap that in a SimpleDbTransaction to allow use of our friendlier
8891
// API for schema migration operations.
8992
const txn = new SimpleDbTransaction(request.transaction);
90-
runUpgrade(db, txn, event.oldVersion, SCHEMA_VERSION).next(() => {
91-
debug(
92-
LOG_TAG,
93-
'Database upgrade to version ' + SCHEMA_VERSION + ' complete'
94-
);
95-
});
93+
runUpgrade(db, databaseId, txn, event.oldVersion, SCHEMA_VERSION).next(
94+
() => {
95+
debug(
96+
LOG_TAG,
97+
'Database upgrade to version ' + SCHEMA_VERSION + ' complete'
98+
);
99+
}
100+
);
96101
};
97102
}).toPromise();
98103
}

packages/firestore/test/unit/local/encoded_resource_path.test.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from '../../../src/local/simple_db';
2525
import { ResourcePath } from '../../../src/model/path';
2626
import { path } from '../../util/helpers';
27+
import { INDEXEDDB_TEST_DATABASE_ID } from './persistence_test_helpers';
2728

2829
let db: SimpleDb;
2930
const sep = '\u0001\u0001';
@@ -39,10 +40,15 @@ describe('EncodedResourcePath', () => {
3940
beforeEach(() => {
4041
return SimpleDb.delete(dbName)
4142
.then(() => {
42-
return SimpleDb.openOrCreate(dbName, 1, db => {
43-
db.createObjectStore('test');
44-
return PersistencePromise.resolve();
45-
});
43+
return SimpleDb.openOrCreate(
44+
INDEXEDDB_TEST_DATABASE_ID,
45+
dbName,
46+
1,
47+
db => {
48+
db.createObjectStore('test');
49+
return PersistencePromise.resolve();
50+
}
51+
);
4652
})
4753
.then(simpleDb => {
4854
db = simpleDb;

0 commit comments

Comments
 (0)