Skip to content

Commit c637f67

Browse files
Change removeMutationBatch to remove a single batch
1 parent 3e98afa commit c637f67

File tree

6 files changed

+93
-129
lines changed

6 files changed

+93
-129
lines changed

packages/firestore/src/local/indexeddb_mutation_queue.ts

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -473,44 +473,42 @@ export class IndexedDbMutationQueue implements MutationQueue {
473473
return PersistencePromise.waitFor(promises).next(() => results);
474474
}
475475

476-
removeMutationBatches(
476+
removeMutationBatch(
477477
transaction: PersistenceTransaction,
478-
batches: MutationBatch[]
478+
batch: MutationBatch
479479
): PersistencePromise<void> {
480480
const mutationStore = mutationsStore(transaction);
481481
const indexTxn = documentMutationsStore(transaction);
482482
const promises: Array<PersistencePromise<void>> = [];
483483

484-
for (const batch of batches) {
485-
const range = IDBKeyRange.only(batch.batchId);
486-
let numDeleted = 0;
487-
const removePromise = mutationStore.iterate(
488-
{ range },
489-
(key, value, control) => {
490-
numDeleted++;
491-
return control.delete();
492-
}
493-
);
494-
promises.push(
495-
removePromise.next(() => {
496-
assert(
497-
numDeleted === 1,
498-
'Dangling document-mutation reference found: Missing batch ' +
499-
batch.batchId
500-
);
501-
})
502-
);
503-
for (const mutation of batch.mutations) {
504-
const indexKey = DbDocumentMutation.key(
505-
this.userId,
506-
mutation.key.path,
507-
batch.batchId
484+
const range = IDBKeyRange.only(batch.batchId);
485+
let numDeleted = 0;
486+
const removePromise = mutationStore.iterate(
487+
{ range },
488+
(key, value, control) => {
489+
numDeleted++;
490+
return control.delete();
491+
}
492+
);
493+
promises.push(
494+
removePromise.next(() => {
495+
assert(
496+
numDeleted === 1,
497+
'Dangling document-mutation reference found: Missing batch ' +
498+
batch.batchId
508499
);
509-
this.removeCachedMutationKeys(batch.batchId);
510-
promises.push(indexTxn.delete(indexKey));
511-
if (this.garbageCollector !== null) {
512-
this.garbageCollector.addPotentialGarbageKey(mutation.key);
513-
}
500+
})
501+
);
502+
for (const mutation of batch.mutations) {
503+
const indexKey = DbDocumentMutation.key(
504+
this.userId,
505+
mutation.key.path,
506+
batch.batchId
507+
);
508+
this.removeCachedMutationKeys(batch.batchId);
509+
promises.push(indexTxn.delete(indexKey));
510+
if (this.garbageCollector !== null) {
511+
this.garbageCollector.addPotentialGarbageKey(mutation.key);
514512
}
515513
}
516514
return PersistencePromise.waitFor(promises);

packages/firestore/src/local/local_store.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,11 @@ export class LocalStore {
302302
}
303303
})
304304
.next(ackedBatches => {
305-
if (ackedBatches.length > 0) {
306-
return this.mutationQueue.removeMutationBatches(txn, ackedBatches);
307-
} else {
308-
return PersistencePromise.resolve();
309-
}
305+
let p = PersistencePromise.resolve();
306+
ackedBatches.forEach(batch => {
307+
p = p.next(() => this.mutationQueue.removeMutationBatch(txn, batch));
308+
});
309+
return p;
310310
});
311311
}
312312

@@ -979,16 +979,17 @@ export class LocalStore {
979979
batches: MutationBatch[]
980980
): PersistencePromise<DocumentKeySet> {
981981
let affectedDocs = documentKeySet();
982+
983+
let p = PersistencePromise.resolve();
982984
for (const batch of batches) {
983985
for (const mutation of batch.mutations) {
984986
const key = mutation.key;
985987
affectedDocs = affectedDocs.add(key);
986988
}
989+
p = p.next(() => this.mutationQueue.removeMutationBatch(txn, batch));
987990
}
988991

989-
return this.mutationQueue
990-
.removeMutationBatches(txn, batches)
991-
.next(() => affectedDocs);
992+
return p.next(() => affectedDocs);
992993
}
993994

994995
private applyWriteToRemoteDocuments(

packages/firestore/src/local/memory_mutation_queue.ts

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -328,73 +328,45 @@ export class MemoryMutationQueue implements MutationQueue {
328328
return result;
329329
}
330330

331-
removeMutationBatches(
331+
removeMutationBatch(
332332
transaction: PersistenceTransaction,
333-
batches: MutationBatch[]
333+
batch: MutationBatch
334334
): PersistencePromise<void> {
335-
const batchCount = batches.length;
336-
assert(batchCount > 0, 'Should not remove mutations when none exist.');
337-
338-
const firstBatchId = batches[0].batchId;
339-
const queueCount = this.mutationQueue.length;
340-
341335
// Find the position of the first batch for removal. This need not be the
342336
// first entry in the queue.
343-
const startIndex = this.indexOfExistingBatchId(firstBatchId, 'removed');
337+
const batchIndex = this.indexOfExistingBatchId(batch.batchId, 'removed');
344338
assert(
345-
this.mutationQueue[startIndex].batchId === firstBatchId,
339+
this.mutationQueue[batchIndex].batchId === batch.batchId,
346340
'Removed batches must exist in the queue'
347341
);
348342

349-
// Check that removed batches are contiguous (while excluding tombstones).
350-
let batchIndex = 1;
351-
let queueIndex = startIndex + 1;
352-
while (batchIndex < batchCount && queueIndex < queueCount) {
353-
const batch = this.mutationQueue[queueIndex];
354-
if (batch.isTombstone()) {
355-
queueIndex++;
356-
continue;
357-
}
358-
359-
assert(
360-
batch.batchId === batches[batchIndex].batchId,
361-
'Removed batches must be contiguous in the queue'
362-
);
363-
batchIndex++;
364-
queueIndex++;
365-
}
366-
367343
// Only actually remove batches if removing at the front of the queue.
368344
// Previously rejected batches may have left tombstones in the queue, so
369345
// expand the removal range to include any tombstones.
370-
if (startIndex === 0) {
371-
for (; queueIndex < queueCount; queueIndex++) {
346+
if (batchIndex === 0) {
347+
let queueIndex = 1;
348+
for (; queueIndex < this.mutationQueue.length; queueIndex++) {
372349
const batch = this.mutationQueue[queueIndex];
373350
if (!batch.isTombstone()) {
374351
break;
375352
}
376353
}
377-
const length = queueIndex - startIndex;
378-
this.mutationQueue.splice(startIndex, length);
354+
this.mutationQueue.splice(0, queueIndex);
379355
} else {
380-
// Mark the tombstones
381-
for (let i = startIndex; i < queueIndex; i++) {
382-
this.mutationQueue[i] = this.mutationQueue[i].toTombstone();
383-
}
356+
this.mutationQueue[batchIndex] = this.mutationQueue[
357+
batchIndex
358+
].toTombstone();
384359
}
385360

386361
let references = this.batchesByDocumentKey;
387-
for (const batch of batches) {
388-
const batchId = batch.batchId;
389-
for (const mutation of batch.mutations) {
390-
const key = mutation.key;
391-
if (this.garbageCollector !== null) {
392-
this.garbageCollector.addPotentialGarbageKey(key);
393-
}
394-
395-
const ref = new DocReference(key, batchId);
396-
references = references.delete(ref);
362+
for (const mutation of batch.mutations) {
363+
const key = mutation.key;
364+
if (this.garbageCollector !== null) {
365+
this.garbageCollector.addPotentialGarbageKey(key);
397366
}
367+
368+
const ref = new DocReference(key, batch.batchId);
369+
references = references.delete(ref);
398370
}
399371
this.batchesByDocumentKey = references;
400372
return PersistencePromise.resolve();

packages/firestore/src/local/mutation_queue.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,21 +197,17 @@ export interface MutationQueue extends GarbageSource {
197197
): PersistencePromise<MutationBatch[]>;
198198

199199
/**
200-
* Removes the given mutation batches from the queue. This is useful in two
200+
* Removes the given mutation batch from the queue. This is useful in two
201201
* circumstances:
202202
*
203-
* + Removing applied mutations from the head of the queue
204-
* + Removing rejected mutations from anywhere in the queue
205-
*
206-
* In both cases, the array of mutations to remove must be a contiguous range
207-
* of batchIds. This is most easily accomplished by loading mutations with
208-
* getAllMutationBatchesThroughBatchId()
203+
* + Removing an applied mutation from the head of the queue
204+
* + Removing a rejected mutation from anywhere in the queue
209205
*
210206
* Multi-Tab Note: This operation should only be called by the primary client.
211207
*/
212-
removeMutationBatches(
208+
removeMutationBatch(
213209
transaction: PersistenceTransaction,
214-
batches: MutationBatch[]
210+
batch: MutationBatch
215211
): PersistencePromise<void>;
216212

217213
/**

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

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function genericMutationQueueTests(): void {
127127
for (let i = 0; i < holes.length; i++) {
128128
const index = holes[i] - i;
129129
const batch = batches[index];
130-
await mutationQueue.removeMutationBatches([batch]);
130+
await mutationQueue.removeMutationBatch(batch);
131131

132132
batches.splice(index, 1);
133133
removed.push(batch);
@@ -146,10 +146,10 @@ function genericMutationQueueTests(): void {
146146
const batch2 = await addMutationBatch();
147147
expect(await mutationQueue.countBatches()).to.equal(2);
148148

149-
await mutationQueue.removeMutationBatches([batch2]);
149+
await mutationQueue.removeMutationBatch(batch2);
150150
expect(await mutationQueue.countBatches()).to.equal(1);
151151

152-
await mutationQueue.removeMutationBatches([batch1]);
152+
await mutationQueue.removeMutationBatch(batch1);
153153
expect(await mutationQueue.countBatches()).to.equal(0);
154154
});
155155

@@ -181,18 +181,18 @@ function genericMutationQueueTests(): void {
181181
batch2.batchId
182182
);
183183

184-
await mutationQueue.removeMutationBatches([batch1]);
184+
await mutationQueue.removeMutationBatch(batch1);
185185
expect(await mutationQueue.getHighestAcknowledgedBatchId()).to.equal(
186186
batch2.batchId
187187
);
188188

189-
await mutationQueue.removeMutationBatches([batch2]);
189+
await mutationQueue.removeMutationBatch(batch2);
190190
expect(await mutationQueue.getHighestAcknowledgedBatchId()).to.equal(
191191
batch2.batchId
192192
);
193193

194194
// Batch 3 never acknowledged.
195-
await mutationQueue.removeMutationBatches([batch3]);
195+
await mutationQueue.removeMutationBatch(batch3);
196196
expect(await mutationQueue.getHighestAcknowledgedBatchId()).to.equal(
197197
batch2.batchId
198198
);
@@ -206,7 +206,7 @@ function genericMutationQueueTests(): void {
206206
);
207207

208208
await mutationQueue.acknowledgeBatch(batch1, emptyByteString());
209-
await mutationQueue.removeMutationBatches([batch1]);
209+
await mutationQueue.removeMutationBatch(batch1);
210210

211211
expect(await mutationQueue.countBatches()).to.equal(0);
212212
expect(await mutationQueue.getHighestAcknowledgedBatchId()).to.equal(
@@ -226,7 +226,8 @@ function genericMutationQueueTests(): void {
226226
batch2.batchId
227227
);
228228

229-
await mutationQueue.removeMutationBatches([batch1, batch2]);
229+
await mutationQueue.removeMutationBatch(batch1);
230+
await mutationQueue.removeMutationBatch(batch2);
230231
expect(await mutationQueue.getHighestAcknowledgedBatchId()).to.equal(
231232
batch2.batchId
232233
);
@@ -461,16 +462,17 @@ function genericMutationQueueTests(): void {
461462
await addMutationBatch('foo/baz')
462463
];
463464

464-
await mutationQueue.removeMutationBatches([batches[0]]);
465+
await mutationQueue.removeMutationBatch(batches[0]);
465466
expectSetToEqual(await mutationQueue.collectGarbage(gc), []);
466467

467-
await mutationQueue.removeMutationBatches([batches[1]]);
468+
await mutationQueue.removeMutationBatch(batches[1]);
468469
expectSetToEqual(await mutationQueue.collectGarbage(gc), [key('foo/ba')]);
469470

470-
await mutationQueue.removeMutationBatches([batches[5]]);
471+
await mutationQueue.removeMutationBatch(batches[5]);
471472
expectSetToEqual(await mutationQueue.collectGarbage(gc), [key('foo/baz')]);
472473

473-
await mutationQueue.removeMutationBatches([batches[2], batches[3]]);
474+
await mutationQueue.removeMutationBatch(batches[2]);
475+
await mutationQueue.removeMutationBatch(batches[3]);
474476
expectSetToEqual(await mutationQueue.collectGarbage(gc), [
475477
key('foo/bar'),
476478
key('foo/bar2')
@@ -479,7 +481,8 @@ function genericMutationQueueTests(): void {
479481
batches.push(await addMutationBatch('foo/bar/suffix/baz'));
480482
expectSetToEqual(await mutationQueue.collectGarbage(gc), []);
481483

482-
await mutationQueue.removeMutationBatches([batches[4], batches[6]]);
484+
await mutationQueue.removeMutationBatch(batches[4]);
485+
await mutationQueue.removeMutationBatch(batches[6]);
483486
expectSetToEqual(await mutationQueue.collectGarbage(gc), [
484487
key('foo/bar/suffix/baz')
485488
]);
@@ -509,11 +512,11 @@ function genericMutationQueueTests(): void {
509512
);
510513
});
511514

512-
it('can removeMutationBatches()', async () => {
515+
it('can removeMutationBatch()', async () => {
513516
const batches = await createBatches(10);
514517
const last = batches[batches.length - 1];
515518

516-
await mutationQueue.removeMutationBatches([batches[0]]);
519+
await mutationQueue.removeMutationBatch(batches[0]);
517520
batches.splice(0, 1);
518521
expect(await mutationQueue.countBatches()).to.equal(9);
519522

@@ -525,11 +528,9 @@ function genericMutationQueueTests(): void {
525528
expectEqualArrays(found, batches);
526529
expect(found.length).to.equal(9);
527530

528-
await mutationQueue.removeMutationBatches([
529-
batches[0],
530-
batches[1],
531-
batches[2]
532-
]);
531+
await mutationQueue.removeMutationBatch(batches[0]);
532+
await mutationQueue.removeMutationBatch(batches[1]);
533+
await mutationQueue.removeMutationBatch(batches[2]);
533534
batches.splice(0, 3);
534535
expect(await mutationQueue.countBatches()).to.equal(6);
535536

@@ -539,7 +540,7 @@ function genericMutationQueueTests(): void {
539540
expectEqualArrays(found, batches);
540541
expect(found.length).to.equal(6);
541542

542-
await mutationQueue.removeMutationBatches([batches[batches.length - 1]]);
543+
await mutationQueue.removeMutationBatch(batches[batches.length - 1]);
543544
batches.splice(batches.length - 1, 1);
544545
expect(await mutationQueue.countBatches()).to.equal(5);
545546

@@ -549,11 +550,11 @@ function genericMutationQueueTests(): void {
549550
expectEqualArrays(found, batches);
550551
expect(found.length).to.equal(5);
551552

552-
await mutationQueue.removeMutationBatches([batches[3]]);
553+
await mutationQueue.removeMutationBatch(batches[3]);
553554
batches.splice(3, 1);
554555
expect(await mutationQueue.countBatches()).to.equal(4);
555556

556-
await mutationQueue.removeMutationBatches([batches[1]]);
557+
await mutationQueue.removeMutationBatch(batches[1]);
557558
batches.splice(1, 1);
558559
expect(await mutationQueue.countBatches()).to.equal(3);
559560

@@ -564,10 +565,10 @@ function genericMutationQueueTests(): void {
564565
expect(found.length).to.equal(3);
565566
expect(await mutationQueue.checkEmpty()).to.equal(false);
566567

567-
await mutationQueue.removeMutationBatches(batches);
568-
found = await mutationQueue.getAllMutationBatchesThroughBatchId(
569-
last.batchId
570-
);
568+
for (const batch of batches) {
569+
await mutationQueue.removeMutationBatch(batch);
570+
}
571+
found = await mutationQueue.getAllMutationBatches();
571572
expectEqualArrays(found, []);
572573
expect(found.length).to.equal(0);
573574
expect(await mutationQueue.checkEmpty()).to.equal(true);

0 commit comments

Comments
 (0)