Skip to content

Commit 1b326fb

Browse files
authored
Fix checksum calculations in large buckets with > 4m rows (#282)
* Convert checksums to long when aggregating. * Fix the compactor. * Changeset.
1 parent a905dfb commit 1b326fb

File tree

6 files changed

+23
-6
lines changed

6 files changed

+23
-6
lines changed

.changeset/popular-keys-switch.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@powersync/service-module-mongodb-storage': patch
3+
'@powersync/service-core': patch
4+
'@powersync/service-image': patch
5+
---
6+
7+
[MongoDB Storage] Fix checksum calculations in buckets with more than 4 million operations

modules/module-mongodb-storage/src/storage/implementation/MongoCompactor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ export class MongoCompactor {
317317
let numberOfOpsToClear = 0;
318318
for await (let op of query.stream()) {
319319
if (op.op == 'MOVE' || op.op == 'REMOVE' || op.op == 'CLEAR') {
320-
checksum = utils.addChecksums(checksum, op.checksum);
320+
checksum = utils.addChecksums(checksum, Number(op.checksum));
321321
lastOpId = op._id;
322322
numberOfOpsToClear += 1;
323323
if (op.op != 'CLEAR') {
@@ -358,7 +358,7 @@ export class MongoCompactor {
358358
{
359359
_id: lastOpId!,
360360
op: 'CLEAR',
361-
checksum: checksum,
361+
checksum: BigInt(checksum),
362362
data: null,
363363
target_op: targetOp
364364
},

modules/module-mongodb-storage/src/storage/implementation/MongoSyncBucketStorage.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,10 @@ export class MongoSyncBucketStorage
473473
{
474474
$group: {
475475
_id: '$_id.b',
476-
checksum_total: { $sum: '$checksum' },
476+
// Historically, checksum may be stored as 'int' or 'double'.
477+
// More recently, this should be a 'long'.
478+
// $toLong ensures that we always sum it as a long, avoiding inaccuracies in the calculations.
479+
checksum_total: { $sum: { $toLong: '$checksum' } },
477480
count: { $sum: 1 },
478481
has_clear_op: {
479482
$max: {

modules/module-mongodb-storage/src/storage/implementation/PersistedBatch.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export class PersistedBatch {
9797
remaining_buckets.set(key, b);
9898
}
9999

100-
const dchecksum = utils.hashDelete(replicaIdToSubkey(options.table.id, options.sourceKey));
100+
const dchecksum = BigInt(utils.hashDelete(replicaIdToSubkey(options.table.id, options.sourceKey)));
101101

102102
for (const k of options.evaluated) {
103103
const key = currentBucketKey(k);
@@ -133,7 +133,7 @@ export class PersistedBatch {
133133
source_key: options.sourceKey,
134134
table: k.table,
135135
row_id: k.id,
136-
checksum: checksum,
136+
checksum: BigInt(checksum),
137137
data: recordData
138138
}
139139
}

modules/module-mongodb-storage/src/storage/implementation/models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export interface BucketDataDocument {
5656
source_key?: ReplicaId;
5757
table?: string;
5858
row_id?: string;
59-
checksum: number;
59+
checksum: bigint;
6060
data: string | null;
6161
target_op?: bigint | null;
6262
}

modules/module-mongodb-storage/test/src/storage_sync.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,12 @@ describe('sync - mongodb', () => {
117117
has_more: false,
118118
next_after: '4'
119119
});
120+
121+
// Test that the checksum type is correct.
122+
// Specifically, test that it never persisted as double.
123+
const checksumTypes = await factory.db.bucket_data
124+
.aggregate([{ $group: { _id: { $type: '$checksum' }, count: { $sum: 1 } } }])
125+
.toArray();
126+
expect(checksumTypes).toEqual([{ _id: 'long', count: 4 }]);
120127
});
121128
});

0 commit comments

Comments
 (0)