@powersync/service-module-mongodb-storage 0.18.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js +41 -0
- package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js.map +1 -0
- package/dist/storage/MongoBucketStorage.d.ts +5 -1
- package/dist/storage/MongoBucketStorage.js +5 -1
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +3 -0
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoChecksums.d.ts +2 -0
- package/dist/storage/implementation/MongoChecksums.js +3 -2
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +15 -19
- package/dist/storage/implementation/MongoCompactor.js +68 -260
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js +26 -3
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +12 -5
- package/dist/storage/implementation/MongoSyncBucketStorage.js +25 -14
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +2 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js +146 -34
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +2 -0
- package/dist/storage/implementation/common/PersistedBatch.d.ts +6 -0
- package/dist/storage/implementation/common/PersistedBatch.js +15 -8
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +16 -0
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +11 -2
- package/dist/storage/implementation/v1/MongoCompactorV1.js +250 -1
- package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +20 -11
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
- package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +9 -10
- package/dist/storage/implementation/v1/SingleBucketStoreV1.js +2 -8
- package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -1
- package/dist/storage/implementation/v3/BucketDataContextV3.d.ts +13 -0
- package/dist/storage/implementation/v3/BucketDataContextV3.js +23 -0
- package/dist/storage/implementation/v3/BucketDataContextV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +3 -1
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +1 -0
- package/dist/storage/implementation/v3/MongoChecksumsV3.js +59 -103
- package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -2
- package/dist/storage/implementation/v3/MongoCompactorV3.js +354 -219
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +5 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +12 -11
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -1
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +5 -3
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +109 -106
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +5 -2
- package/dist/storage/implementation/v3/PersistedBatchV3.js +53 -15
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +2 -1
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +3 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
- package/dist/storage/implementation/v3/bucket-format.d.ts +10 -1
- package/dist/storage/implementation/v3/bucket-format.js +28 -9
- package/dist/storage/implementation/v3/bucket-format.js.map +1 -1
- package/dist/storage/implementation/v3/chunking.js +3 -1
- package/dist/storage/implementation/v3/chunking.js.map +1 -1
- package/dist/storage/implementation/v3/models.d.ts +38 -1
- package/dist/storage/implementation/v3/models.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +21 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +44 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +30 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.js +12 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +70 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +146 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +42 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +285 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
- package/dist/types/types.d.ts +35 -0
- package/dist/types/types.js +35 -1
- package/dist/types/types.js.map +1 -1
- package/dist/utils/test-utils.js +3 -1
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.d.ts +8 -1
- package/dist/utils/util.js +125 -2
- package/dist/utils/util.js.map +1 -1
- package/package.json +10 -7
- package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
- package/src/storage/MongoBucketStorage.ts +10 -2
- package/src/storage/implementation/MongoBucketBatch.ts +4 -0
- package/src/storage/implementation/MongoChecksums.ts +5 -2
- package/src/storage/implementation/MongoCompactor.ts +90 -314
- package/src/storage/implementation/MongoStorageProvider.ts +32 -3
- package/src/storage/implementation/MongoSyncBucketStorage.ts +34 -24
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +164 -37
- package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +2 -0
- package/src/storage/implementation/common/PersistedBatch.ts +22 -10
- package/src/storage/implementation/models.ts +16 -0
- package/src/storage/implementation/v1/MongoCompactorV1.ts +292 -8
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +54 -40
- package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
- package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +3 -1
- package/src/storage/implementation/v3/MongoChecksumsV3.ts +75 -105
- package/src/storage/implementation/v3/MongoCompactorV3.ts +456 -258
- package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +21 -19
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +123 -126
- package/src/storage/implementation/v3/PersistedBatchV3.ts +69 -16
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +5 -0
- package/src/storage/implementation/v3/bucket-format.ts +36 -9
- package/src/storage/implementation/v3/chunking.ts +3 -1
- package/src/storage/implementation/v3/models.ts +40 -1
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +54 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +29 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +171 -0
- package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +343 -0
- package/src/types/types.ts +42 -1
- package/src/utils/test-utils.ts +3 -1
- package/src/utils/util.ts +182 -4
- package/test/src/__snapshots__/storage_sync.test.ts.snap +1 -583
- package/test/src/cleanup-stopped-sync-configs.test.ts +24 -1
- package/test/src/helpers/MemoryObjectStorage.ts +53 -0
- package/test/src/helpers/s3TestFactory.ts +69 -0
- package/test/src/object_storage_lifecycle.test.ts +59 -0
- package/test/src/setup.ts +6 -1
- package/test/src/storage.test.ts +216 -2
- package/test/src/storage_compacting.test.ts +176 -187
- package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
- package/test/src/storage_s3_checksums.test.ts +191 -0
- package/test/src/storage_s3_compaction_lifecycle.test.ts +417 -0
- package/test/src/storage_s3_reading.test.ts +526 -0
- package/test/src/storage_s3_writing.test.ts +135 -0
- package/test/src/storage_sync.test.ts +95 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/storage/implementation/common/SingleBucketStore.d.ts +0 -54
- package/dist/storage/implementation/common/SingleBucketStore.js +0 -3
- package/dist/storage/implementation/common/SingleBucketStore.js.map +0 -1
- package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -84
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
- package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
- package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -108
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
3
|
import {
|
|
3
4
|
bson,
|
|
4
5
|
BucketChecksum,
|
|
6
|
+
CheckpointChecksumInvalidatedError,
|
|
5
7
|
FetchPartialBucketChecksum,
|
|
6
8
|
InternalOpId,
|
|
7
9
|
isPartialChecksum,
|
|
@@ -179,9 +181,42 @@ export class MongoChecksumsV3 extends MongoChecksums implements DefinitionChecks
|
|
|
179
181
|
requests.set(request.bucket, request);
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
|
|
184
|
+
const aggregate = await this.aggregatePartialChecksums(collection, requests, context);
|
|
185
|
+
const { checksums, startStraddledBuckets } = this.normalizePartialChecksumResults(batch, aggregate);
|
|
186
|
+
|
|
187
|
+
if (startStraddledBuckets.size == 0) {
|
|
188
|
+
return checksums;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// A cached base ends inside a compaction-produced document. Its checksum cannot
|
|
192
|
+
// be safely combined with the document-level checksum, so recalculate this
|
|
193
|
+
// bucket from the beginning. A full result replaces the cached base upstream.
|
|
194
|
+
const fullRequests = batch
|
|
195
|
+
.filter((request) => startStraddledBuckets.has(request.bucket))
|
|
196
|
+
.map((request) => ({ ...request, start: undefined }));
|
|
197
|
+
const fullRequestMap = new Map(fullRequests.map((request) => [request.bucket, request]));
|
|
198
|
+
const fullAggregate = await this.aggregatePartialChecksums(collection, fullRequestMap, context);
|
|
199
|
+
const fullResults = this.normalizePartialChecksumResults(fullRequests, fullAggregate);
|
|
200
|
+
|
|
201
|
+
if (fullResults.startStraddledBuckets.size > 0) {
|
|
202
|
+
throw new ServiceAssertionError(
|
|
203
|
+
`Unexpected start-boundary straddle while recalculating bucket(s) ${[...fullResults.startStraddledBuckets].join(', ')}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
for (const [bucket, checksum] of fullResults.checksums) {
|
|
207
|
+
checksums.set(bucket, checksum);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return checksums;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private async aggregatePartialChecksums(
|
|
214
|
+
collection: lib_mongo.mongo.Collection<BucketDataDocumentV3>,
|
|
215
|
+
requests: Map<string, FetchPartialBucketChecksumByBucket>,
|
|
216
|
+
context: MongoChecksumSessionContext
|
|
217
|
+
): Promise<bson.Document[]> {
|
|
218
|
+
return collection
|
|
219
|
+
.aggregate(this.buildPartialChecksumPipeline(requests), {
|
|
185
220
|
...context.readOptions,
|
|
186
221
|
maxTimeMS: lib_mongo.MONGO_CHECKSUM_TIMEOUT_MS
|
|
187
222
|
})
|
|
@@ -189,8 +224,6 @@ export class MongoChecksumsV3 extends MongoChecksums implements DefinitionChecks
|
|
|
189
224
|
.catch((e) => {
|
|
190
225
|
throw lib_mongo.mapQueryError(e, 'while reading checksums');
|
|
191
226
|
});
|
|
192
|
-
|
|
193
|
-
return this.normalizePartialChecksumResults(batch, aggregate);
|
|
194
227
|
}
|
|
195
228
|
|
|
196
229
|
private buildPartialChecksumPipeline(requests: Map<string, FetchPartialBucketChecksumByBucket>): bson.Document[] {
|
|
@@ -203,128 +236,64 @@ export class MongoChecksumsV3 extends MongoChecksums implements DefinitionChecks
|
|
|
203
236
|
$or: filters
|
|
204
237
|
}
|
|
205
238
|
},
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
bucket_start: {
|
|
209
|
-
$switch: {
|
|
210
|
-
branches: Array.from(requests.entries()).map(([bucket, req]) => ({
|
|
211
|
-
case: { $eq: ['$_id.b', bucket] },
|
|
212
|
-
then: req.start ?? new bson.MinKey()
|
|
213
|
-
})),
|
|
214
|
-
default: new bson.MinKey()
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
bucket_end: {
|
|
218
|
-
$switch: {
|
|
219
|
-
branches: Array.from(requests.entries()).map(([bucket, req]) => ({
|
|
220
|
-
case: { $eq: ['$_id.b', bucket] },
|
|
221
|
-
then: req.end
|
|
222
|
-
})),
|
|
223
|
-
default: new bson.MaxKey()
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
|
-
// Determine if document is fully included within [start, end] range
|
|
239
|
+
// Only document-level metadata is used below. Bucket-data operations may
|
|
240
|
+
// be offloaded, and checksum queries must never inspect the ops array.
|
|
229
241
|
{
|
|
230
242
|
$project: {
|
|
231
243
|
_id: 1,
|
|
232
244
|
min_op: 1,
|
|
233
245
|
checksum: 1,
|
|
234
246
|
count: 1,
|
|
235
|
-
|
|
236
|
-
bucket_start: 1,
|
|
237
|
-
bucket_end: 1,
|
|
238
|
-
is_fully_included: {
|
|
239
|
-
$and: [{ $gt: ['$min_op', '$bucket_start'] }, { $lte: ['$_id.o', '$bucket_end'] }]
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
// Compute included checksum, count, and clear op detection
|
|
244
|
-
{
|
|
245
|
-
$project: {
|
|
246
|
-
_id: 1,
|
|
247
|
-
checksum_total: {
|
|
248
|
-
$cond: {
|
|
249
|
-
if: '$is_fully_included',
|
|
250
|
-
then: '$checksum',
|
|
251
|
-
else: {
|
|
252
|
-
$sum: {
|
|
253
|
-
$map: {
|
|
254
|
-
input: {
|
|
255
|
-
$filter: {
|
|
256
|
-
input: '$ops',
|
|
257
|
-
cond: {
|
|
258
|
-
$and: [{ $gt: ['$$this.o', '$bucket_start'] }, { $lte: ['$$this.o', '$bucket_end'] }]
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
in: '$$this.checksum'
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
count_total: {
|
|
269
|
-
$cond: {
|
|
270
|
-
if: '$is_fully_included',
|
|
271
|
-
then: '$count',
|
|
272
|
-
else: {
|
|
273
|
-
$size: {
|
|
274
|
-
$filter: {
|
|
275
|
-
input: '$ops',
|
|
276
|
-
cond: {
|
|
277
|
-
$and: [{ $gt: ['$$this.o', '$bucket_start'] }, { $lte: ['$$this.o', '$bucket_end'] }]
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
has_clear_op: {
|
|
285
|
-
$max: {
|
|
286
|
-
$map: {
|
|
287
|
-
input: {
|
|
288
|
-
$filter: {
|
|
289
|
-
input: '$ops',
|
|
290
|
-
cond: {
|
|
291
|
-
$and: [{ $gt: ['$$this.o', '$bucket_start'] }, { $lte: ['$$this.o', '$bucket_end'] }]
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
in: { $cond: [{ $eq: ['$$this.op', 'CLEAR'] }, 1, 0] }
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
last_op: { $max: '$_id.o' }
|
|
247
|
+
has_clear_op: 1
|
|
300
248
|
}
|
|
301
249
|
},
|
|
302
|
-
//
|
|
250
|
+
// Aggregate document metadata per bucket. A CLEAR makes the result a full
|
|
251
|
+
// checksum that replaces any cached prefix; storage guarantees that
|
|
252
|
+
// documents preceding the CLEAR have already been removed.
|
|
303
253
|
{
|
|
304
254
|
$group: {
|
|
305
255
|
_id: '$_id.b',
|
|
306
|
-
checksum_total: { $sum: '$
|
|
307
|
-
count: { $sum: '$
|
|
308
|
-
has_clear_op: {
|
|
309
|
-
|
|
256
|
+
checksum_total: { $sum: '$checksum' },
|
|
257
|
+
count: { $sum: '$count' },
|
|
258
|
+
has_clear_op: {
|
|
259
|
+
$max: { $cond: ['$has_clear_op', 1, 0] }
|
|
260
|
+
},
|
|
261
|
+
min_op: { $min: '$min_op' },
|
|
262
|
+
max_op: { $max: '$_id.o' }
|
|
310
263
|
}
|
|
311
|
-
}
|
|
312
|
-
// $sort results
|
|
313
|
-
{ $sort: { _id: 1 } }
|
|
264
|
+
}
|
|
314
265
|
];
|
|
315
266
|
}
|
|
316
267
|
|
|
317
268
|
private normalizePartialChecksumResults(
|
|
318
269
|
batch: FetchPartialBucketChecksumByBucket[],
|
|
319
270
|
aggregate: bson.Document[]
|
|
320
|
-
): PartialChecksumMap {
|
|
271
|
+
): { checksums: PartialChecksumMap; startStraddledBuckets: Set<string> } {
|
|
272
|
+
const requests = new Map(batch.map((request) => [request.bucket, request]));
|
|
273
|
+
const startStraddledBuckets = new Set<string>();
|
|
321
274
|
const partialChecksums = new Map<string, PartialOrFullChecksum>();
|
|
322
|
-
|
|
323
|
-
|
|
275
|
+
|
|
276
|
+
for (const doc of aggregate) {
|
|
277
|
+
const bucket = doc._id as string;
|
|
278
|
+
const request = requests.get(bucket)!;
|
|
279
|
+
|
|
280
|
+
// A maximum beyond end means a matched document straddles the checkpoint.
|
|
281
|
+
// Its document-level checksum includes later operations, so this checkpoint
|
|
282
|
+
// cannot be calculated from document metadata.
|
|
283
|
+
if (doc.max_op > request.end) {
|
|
284
|
+
throw new CheckpointChecksumInvalidatedError(request.end, bucket);
|
|
285
|
+
}
|
|
286
|
+
// The _id filter excludes documents ending at or before start. A minimum
|
|
287
|
+
// at or below start therefore means a matched document straddles it.
|
|
288
|
+
if (request.start != null && doc.min_op <= request.start) {
|
|
289
|
+
startStraddledBuckets.add(bucket);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
324
293
|
partialChecksums.set(bucket, checksumFromAggregate(doc));
|
|
325
294
|
}
|
|
326
295
|
|
|
327
|
-
|
|
296
|
+
const checksums = new Map<string, PartialOrFullChecksum>(
|
|
328
297
|
batch.map((request) => {
|
|
329
298
|
const bucket = request.bucket;
|
|
330
299
|
let partialChecksum = partialChecksums.get(bucket);
|
|
@@ -346,6 +315,7 @@ export class MongoChecksumsV3 extends MongoChecksums implements DefinitionChecks
|
|
|
346
315
|
return [bucket, partialChecksum];
|
|
347
316
|
})
|
|
348
317
|
);
|
|
318
|
+
return { checksums, startStraddledBuckets };
|
|
349
319
|
}
|
|
350
320
|
}
|
|
351
321
|
|