@powersync/service-module-mongodb-storage 0.20.0 → 0.22.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 +62 -0
- package/dist/storage/MongoBucketStorage.d.ts +36 -3
- package/dist/storage/MongoBucketStorage.js +372 -207
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +17 -5
- package/dist/storage/implementation/MongoBucketBatch.js +44 -17
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +19 -79
- package/dist/storage/implementation/MongoCompactor.js +27 -238
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParameterCompactor.d.ts +83 -10
- package/dist/storage/implementation/MongoParameterCompactor.js +309 -96
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +9 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +29 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +4 -2
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js +7 -3
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +27 -11
- package/dist/storage/implementation/MongoSyncBucketStorage.js +78 -31
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.js +21 -9
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/MongoWriteBatch.d.ts +49 -0
- package/dist/storage/implementation/MongoWriteBatch.js +149 -0
- package/dist/storage/implementation/MongoWriteBatch.js.map +1 -0
- package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +9 -7
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js +9 -30
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/SyncRuleStateUpdate.d.ts +11 -5
- package/dist/storage/implementation/SyncRuleStateUpdate.js +14 -6
- package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -1
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +22 -2
- package/dist/storage/implementation/common/PersistedBatch.d.ts +32 -4
- package/dist/storage/implementation/common/PersistedBatch.js +49 -6
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +3 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +3 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +9 -1
- package/dist/storage/implementation/db.js +27 -1
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +31 -0
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +2 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +33 -4
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +38 -6
- package/dist/storage/implementation/v1/MongoCompactorV1.js +247 -20
- package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +16 -2
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -9
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +18 -11
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +65 -16
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +7 -5
- package/dist/storage/implementation/v1/PersistedBatchV1.js +22 -28
- package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/models.js +1 -0
- package/dist/storage/implementation/v1/models.js.map +1 -1
- package/dist/storage/implementation/v3/CompactionLease.d.ts +50 -0
- package/dist/storage/implementation/v3/CompactionLease.js +131 -0
- package/dist/storage/implementation/v3/CompactionLease.js.map +1 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +10 -2
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +100 -26
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +82 -25
- package/dist/storage/implementation/v3/MongoCompactorV3.js +698 -159
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +18 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +23 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +2 -15
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +60 -92
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -1
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +19 -9
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +91 -31
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.d.ts +26 -0
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js +82 -0
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js.map +1 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +14 -8
- package/dist/storage/implementation/v3/PersistedBatchV3.js +76 -42
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +12 -2
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +42 -3
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
- package/dist/storage/implementation/v3/bucket-format.js +2 -0
- package/dist/storage/implementation/v3/bucket-format.js.map +1 -1
- package/dist/storage/implementation/v3/compact-utils.d.ts +107 -0
- package/dist/storage/implementation/v3/compact-utils.js +216 -0
- package/dist/storage/implementation/v3/compact-utils.js.map +1 -0
- package/dist/storage/implementation/v3/compaction-constants.d.ts +5 -0
- package/dist/storage/implementation/v3/compaction-constants.js +6 -0
- package/dist/storage/implementation/v3/compaction-constants.js.map +1 -0
- package/dist/storage/implementation/v3/models.d.ts +84 -4
- package/dist/storage/implementation/v3/models.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +7 -8
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +16 -5
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +14 -11
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +6 -8
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +17 -11
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +38 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +164 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +37 -12
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +197 -25
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/source-table-utils.d.ts +6 -6
- package/dist/storage/implementation/v3/source-table-utils.js +30 -37
- package/dist/storage/implementation/v3/source-table-utils.js.map +1 -1
- package/dist/storage/storage-index.d.ts +2 -1
- package/dist/storage/storage-index.js +1 -0
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/types/types.d.ts +28 -1
- package/dist/types/types.js +28 -7
- package/dist/types/types.js.map +1 -1
- package/dist/utils/test-utils.js +1 -0
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.js +3 -1
- package/dist/utils/util.js.map +1 -1
- package/package.json +10 -9
- package/src/storage/MongoBucketStorage.ts +507 -269
- package/src/storage/implementation/MongoBucketBatch.ts +67 -24
- package/src/storage/implementation/MongoCompactor.ts +35 -346
- package/src/storage/implementation/MongoParameterCompactor.ts +388 -102
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +34 -0
- package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +4 -2
- package/src/storage/implementation/MongoStorageProvider.ts +15 -3
- package/src/storage/implementation/MongoSyncBucketStorage.ts +114 -40
- package/src/storage/implementation/MongoSyncRulesLock.ts +22 -9
- package/src/storage/implementation/MongoWriteBatch.ts +172 -0
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +16 -46
- package/src/storage/implementation/SyncRuleStateUpdate.ts +13 -6
- package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +24 -2
- package/src/storage/implementation/common/PersistedBatch.ts +66 -10
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +4 -0
- package/src/storage/implementation/db.ts +35 -2
- package/src/storage/implementation/models.ts +34 -0
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +46 -6
- package/src/storage/implementation/v1/MongoCompactorV1.ts +327 -40
- package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +25 -9
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +87 -27
- package/src/storage/implementation/v1/PersistedBatchV1.ts +25 -30
- package/src/storage/implementation/v1/models.ts +1 -0
- package/src/storage/implementation/v3/CompactionLease.ts +152 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +138 -34
- package/src/storage/implementation/v3/MongoCompactorV3.ts +958 -225
- package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +34 -0
- package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +100 -109
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +111 -41
- package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +93 -48
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +55 -4
- package/src/storage/implementation/v3/bucket-format.ts +2 -0
- package/src/storage/implementation/v3/compact-utils.ts +320 -0
- package/src/storage/implementation/v3/compaction-constants.ts +5 -0
- package/src/storage/implementation/v3/models.ts +91 -3
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +24 -9
- package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +20 -5
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +26 -14
- package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +229 -0
- package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +279 -29
- package/src/storage/implementation/v3/source-table-utils.ts +39 -41
- package/src/storage/storage-index.ts +2 -0
- package/src/types/types.ts +42 -7
- package/src/utils/test-utils.ts +1 -0
- package/src/utils/util.ts +3 -1
- package/test/src/__snapshots__/storage.test.ts.snap +25 -0
- package/test/src/__snapshots__/storage_sync.test.ts.snap +605 -16
- package/test/src/chunk_compaction_config.test.ts +38 -0
- package/test/src/cleanup-stopped-sync-configs.test.ts +40 -13
- package/test/src/compact-utils.test.ts +226 -0
- package/test/src/helpers/MemoryObjectStorage.ts +14 -6
- package/test/src/object_storage_usage.test.ts +267 -0
- package/test/src/parameter_compacting_v1.test.ts +120 -0
- package/test/src/parameter_compacting_v3.test.ts +192 -0
- package/test/src/parameter_compaction_fence.test.ts +276 -0
- package/test/src/storage.test.ts +273 -22
- package/test/src/storage_compacting.test.ts +968 -246
- package/test/src/storage_s3_checksums.test.ts +3 -4
- package/test/src/storage_s3_compaction_lifecycle.test.ts +138 -12
- package/test/src/storage_s3_reading.test.ts +290 -2
- package/test/src/storage_s3_writing.test.ts +1 -0
- package/test/src/storage_sync.test.ts +336 -41
- package/test/src/util.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,6 +3,8 @@ import { mongo } from '@powersync/lib-service-mongodb';
|
|
|
3
3
|
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
4
4
|
import {
|
|
5
5
|
CheckpointChanges,
|
|
6
|
+
CompactInitialReplicationOptions,
|
|
7
|
+
CompactInitialReplicationResults,
|
|
6
8
|
GetCheckpointChangesOptions,
|
|
7
9
|
InternalOpId,
|
|
8
10
|
internalToExternalOpId,
|
|
@@ -18,12 +20,20 @@ import * as bson from 'bson';
|
|
|
18
20
|
import { mapOpEntry, readSingleBatch, setSessionSnapshotTime } from '../../../utils/util.js';
|
|
19
21
|
import { MongoBucketStorage } from '../../MongoBucketStorage.js';
|
|
20
22
|
import { BucketDataDoc } from '../common/BucketDataDoc.js';
|
|
21
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
MongoGetCheckpointChangesOptions,
|
|
25
|
+
MongoSyncBucketStorageCheckpoint
|
|
26
|
+
} from '../common/MongoSyncBucketStorageCheckpoint.js';
|
|
22
27
|
import { MongoChecksums } from '../MongoChecksums.js';
|
|
23
28
|
import { MongoCompactOptions, MongoCompactor } from '../MongoCompactor.js';
|
|
24
29
|
import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
|
|
25
30
|
import { MongoPersistedReplicationStream } from '../MongoPersistedReplicationStream.js';
|
|
26
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
MongoCheckpointState,
|
|
33
|
+
MongoSyncBucketStorage,
|
|
34
|
+
MongoSyncBucketStorageOptions
|
|
35
|
+
} from '../MongoSyncBucketStorage.js';
|
|
36
|
+
import { MongoCheckpointAPIOptions } from '../MongoWriteCheckpointAPI.js';
|
|
27
37
|
import { loadBucketDataDocument, maxOpId } from './bucket-format.js';
|
|
28
38
|
import {
|
|
29
39
|
BucketDataDocumentV3,
|
|
@@ -36,10 +46,13 @@ import {
|
|
|
36
46
|
import { MongoBucketBatchV3 } from './MongoBucketBatchV3.js';
|
|
37
47
|
import { MongoChecksumsV3 } from './MongoChecksumsV3.js';
|
|
38
48
|
import { MongoCompactorV3 } from './MongoCompactorV3.js';
|
|
49
|
+
import { MongoParameterCompactorV3 } from './MongoParameterCompactorV3.js';
|
|
39
50
|
import { MongoStoppedSyncConfigCleanup } from './MongoStoppedSyncConfigCleanup.js';
|
|
51
|
+
import { MongoWriteCheckpointAPIV3 } from './MongoWriteCheckpointAPIV3.js';
|
|
40
52
|
import { hydrateBucketDataDocuments } from './object-storage/BucketDataObjectStorage.js';
|
|
41
53
|
import { ObjectStorage } from './object-storage/ObjectStorage.js';
|
|
42
54
|
import { ObjectStorageLifecycle } from './object-storage/ObjectStorageLifecycle.js';
|
|
55
|
+
import { ObjectStorageUsage } from './object-storage/ObjectStorageUsage.js';
|
|
43
56
|
import { VersionedPowerSyncMongoV3 } from './VersionedPowerSyncMongoV3.js';
|
|
44
57
|
|
|
45
58
|
export interface MongoSyncBucketStorageContextV3 {
|
|
@@ -188,21 +201,39 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
188
201
|
});
|
|
189
202
|
}
|
|
190
203
|
|
|
204
|
+
protected override createWriteCheckpointAPI(options: MongoCheckpointAPIOptions): MongoWriteCheckpointAPIV3 {
|
|
205
|
+
return new MongoWriteCheckpointAPIV3({
|
|
206
|
+
...options,
|
|
207
|
+
db: this.db,
|
|
208
|
+
syncConfigMapping: () => this.singleSyncConfigMapping()
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
191
212
|
createMongoCompactor(options: MongoCompactOptions): MongoCompactor {
|
|
192
213
|
return new MongoCompactorV3(this, this.db, options);
|
|
193
214
|
}
|
|
194
215
|
|
|
216
|
+
override async compactInitialReplication(
|
|
217
|
+
options: CompactInitialReplicationOptions
|
|
218
|
+
): Promise<CompactInitialReplicationResults> {
|
|
219
|
+
this.logger.info(`Compacting chunks after initial replication...`);
|
|
220
|
+
const start = Date.now();
|
|
221
|
+
const maxOpId = options.maxOpId ?? (await this.fetchPersistedOpHead()) ?? undefined;
|
|
222
|
+
const compactedBuckets = await this.createMongoCompactor({
|
|
223
|
+
...options,
|
|
224
|
+
maxOpId,
|
|
225
|
+
compactChunksOnly: true,
|
|
226
|
+
logger: this.logger
|
|
227
|
+
}).compact();
|
|
228
|
+
this.logger.info(`Compacted chunks after initial replication in ${(Date.now() - start) / 1000}s`);
|
|
229
|
+
return { buckets: compactedBuckets };
|
|
230
|
+
}
|
|
231
|
+
|
|
195
232
|
protected createMongoParameterCompactor(
|
|
196
233
|
checkpoint: InternalOpId,
|
|
197
234
|
options: storage.CompactOptions
|
|
198
235
|
): MongoParameterCompactor {
|
|
199
|
-
return new
|
|
200
|
-
this.db
|
|
201
|
-
.listParameterIndexCollections(this.replicationStreamId)
|
|
202
|
-
.then((collections) =>
|
|
203
|
-
collections.map((c) => c.collection as unknown as lib_mongo.mongo.Collection<lib_mongo.mongo.Document>)
|
|
204
|
-
)
|
|
205
|
-
);
|
|
236
|
+
return new MongoParameterCompactorV3(this.db, this.replicationStreamId, checkpoint, options);
|
|
206
237
|
}
|
|
207
238
|
|
|
208
239
|
protected async fetchPersistedOpHead(): Promise<InternalOpId | null> {
|
|
@@ -214,13 +245,14 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
214
245
|
}
|
|
215
246
|
|
|
216
247
|
protected async createWriterImpl(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
|
|
248
|
+
const batchOptions = this.writerBatchOptions(options);
|
|
217
249
|
const doc = await this.syncRulesCollection.findOne(
|
|
218
250
|
{ _id: this.replicationStreamId },
|
|
219
251
|
{ projection: { resume_lsn: 1 } }
|
|
220
252
|
);
|
|
221
253
|
|
|
222
254
|
return new MongoBucketBatchV3({
|
|
223
|
-
...
|
|
255
|
+
...batchOptions,
|
|
224
256
|
// The stream-level replication position - per-config checkpoint LSNs are consistency
|
|
225
257
|
// markers and do not affect where replication resumes.
|
|
226
258
|
resumeFromLsn: doc?.resume_lsn ?? null,
|
|
@@ -228,16 +260,15 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
228
260
|
});
|
|
229
261
|
}
|
|
230
262
|
|
|
231
|
-
protected async fetchCheckpointState(
|
|
232
|
-
session: mongo.ClientSession
|
|
233
|
-
): Promise<{ checkpoint: bigint; lsn: string | null } | null> {
|
|
263
|
+
protected async fetchCheckpointState(session: mongo.ClientSession): Promise<MongoCheckpointState | null> {
|
|
234
264
|
const doc = await this.syncRulesCollection.findOne(
|
|
235
265
|
this.syncConfigMatch({
|
|
236
266
|
state: { $in: [storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED] }
|
|
237
267
|
}),
|
|
238
268
|
{
|
|
239
269
|
session,
|
|
240
|
-
|
|
270
|
+
// The invalidation fence must be read in the same snapshot as the checkpoint.
|
|
271
|
+
projection: this.syncConfigProjection({ 'parameter_compaction.checkpoint_changes_invalid_before': 1 })
|
|
241
272
|
}
|
|
242
273
|
);
|
|
243
274
|
// Checkpoints are served from the single active config. A PROCESSING config in the same
|
|
@@ -258,7 +289,10 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
258
289
|
}
|
|
259
290
|
return {
|
|
260
291
|
checkpoint: syncConfig.last_checkpoint ?? 0n,
|
|
261
|
-
lsn: syncConfig.last_checkpoint_lsn ?? null
|
|
292
|
+
lsn: syncConfig.last_checkpoint_lsn ?? null,
|
|
293
|
+
// Stream-level state: shared by all sync configs. Defaults to 0n for streams that have
|
|
294
|
+
// never been compacted.
|
|
295
|
+
parameterChangesInvalidBefore: doc?.parameter_compaction?.checkpoint_changes_invalid_before ?? 0n
|
|
262
296
|
};
|
|
263
297
|
}
|
|
264
298
|
|
|
@@ -311,7 +345,8 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
311
345
|
},
|
|
312
346
|
$unset: {
|
|
313
347
|
resume_lsn: 1,
|
|
314
|
-
last_persisted_op: 1
|
|
348
|
+
last_persisted_op: 1,
|
|
349
|
+
parameter_compaction: 1
|
|
315
350
|
}
|
|
316
351
|
},
|
|
317
352
|
{
|
|
@@ -376,6 +411,8 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
376
411
|
for (const collection of await this.db.listBucketDataCollections(this.replicationStreamId)) {
|
|
377
412
|
await collection.drop();
|
|
378
413
|
}
|
|
414
|
+
const usage = new ObjectStorageUsage(this.db, this.replicationStreamId);
|
|
415
|
+
await this.db.client.withSession((session) => session.withTransaction(() => usage.removeStream(session)));
|
|
379
416
|
if (this.objectStorage) {
|
|
380
417
|
const lifecycle = new ObjectStorageLifecycle(this.db, this.replicationStreamId, this.objectStorage);
|
|
381
418
|
await lifecycle.deletePrefix(lifecycle.streamPrefix(), { signal });
|
|
@@ -384,7 +421,7 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
384
421
|
.pendingObjectStorageDeletes(this.replicationStreamId)
|
|
385
422
|
.drop({ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS })
|
|
386
423
|
.catch((error) => {
|
|
387
|
-
if (lib_mongo.
|
|
424
|
+
if (lib_mongo.isMongoNamespaceNotFoundError(error)) {
|
|
388
425
|
return;
|
|
389
426
|
}
|
|
390
427
|
throw error;
|
|
@@ -408,7 +445,7 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
408
445
|
.bucketState(this.replicationStreamId)
|
|
409
446
|
.drop({ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS })
|
|
410
447
|
.catch((error) => {
|
|
411
|
-
if (lib_mongo.
|
|
448
|
+
if (lib_mongo.isMongoNamespaceNotFoundError(error)) {
|
|
412
449
|
return;
|
|
413
450
|
}
|
|
414
451
|
throw error;
|
|
@@ -420,11 +457,23 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
420
457
|
.sourceTables(this.replicationStreamId)
|
|
421
458
|
.drop({ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS })
|
|
422
459
|
.catch((error) => {
|
|
460
|
+
if (lib_mongo.isMongoNamespaceNotFoundError(error)) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
throw error;
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
protected override async clearCustomCheckpointRequests(signal?: AbortSignal): Promise<void> {
|
|
468
|
+
for (const collection of await this.db.listCustomCheckpointRequestCollections(this.replicationStreamId)) {
|
|
469
|
+
signal?.throwIfAborted();
|
|
470
|
+
await collection.drop({ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }).catch((error) => {
|
|
423
471
|
if (lib_mongo.isMongoServerError(error) && error.codeName === 'NamespaceNotFound') {
|
|
424
472
|
return;
|
|
425
473
|
}
|
|
426
474
|
throw error;
|
|
427
475
|
});
|
|
476
|
+
}
|
|
428
477
|
}
|
|
429
478
|
|
|
430
479
|
async cleanupStoppedSyncConfigs(
|
|
@@ -449,7 +498,7 @@ export class MongoSyncBucketStorageV3 extends MongoSyncBucketStorage {
|
|
|
449
498
|
}
|
|
450
499
|
|
|
451
500
|
protected getParameterBucketChangesImpl(
|
|
452
|
-
options:
|
|
501
|
+
options: MongoGetCheckpointChangesOptions
|
|
453
502
|
): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
|
|
454
503
|
return getParameterBucketChangesV3(this.versionContext, options);
|
|
455
504
|
}
|
|
@@ -647,7 +696,7 @@ export async function* getBucketDataBatchV3(
|
|
|
647
696
|
// Hydrate any operations from object storage.
|
|
648
697
|
// In the future we can do this in a more pipelined fashion, but for now we hydrate
|
|
649
698
|
// the entire batch at once.
|
|
650
|
-
await hydrateBucketDataDocuments(docs, ctx.objectStorage, { signal: options?.signal });
|
|
699
|
+
await hydrateBucketDataDocuments(docs, ctx.objectStorage, { signal: options?.signal, tracer: options?.tracer });
|
|
651
700
|
|
|
652
701
|
let currentChunkSizeBytes = 0;
|
|
653
702
|
let currentChunk: utils.SyncBucketData | null = null;
|
|
@@ -784,9 +833,17 @@ export async function getDataBucketChangesV3(
|
|
|
784
833
|
};
|
|
785
834
|
}
|
|
786
835
|
|
|
836
|
+
/**
|
|
837
|
+
* Query the parameter entries changed between the two checkpoints, to determine which parameter
|
|
838
|
+
* lookups need to be re-evaluated.
|
|
839
|
+
*
|
|
840
|
+
* This runs at the next checkpoint's snapshot, so it still sees entries that parameter compaction
|
|
841
|
+
* deleted after that snapshot. Compaction that deleted entries before the snapshot is covered by
|
|
842
|
+
* the invalidation fence, checked before we get here.
|
|
843
|
+
*/
|
|
787
844
|
export async function getParameterBucketChangesV3(
|
|
788
845
|
ctx: MongoSyncBucketStorageContextV3,
|
|
789
|
-
options:
|
|
846
|
+
options: MongoGetCheckpointChangesOptions
|
|
790
847
|
): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
|
|
791
848
|
const limit = 1000;
|
|
792
849
|
const indexIds = ctx.mapping.allParameterIndexIds();
|
|
@@ -816,28 +873,41 @@ export async function getParameterBucketChangesV3(
|
|
|
816
873
|
}
|
|
817
874
|
];
|
|
818
875
|
const [firstCollection, ...remainingCollections] = collections;
|
|
819
|
-
const parameterUpdates = await
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
876
|
+
const parameterUpdates = await ctx.db.client.withSession({ snapshot: true }, async (session) => {
|
|
877
|
+
setSessionSnapshotTime(session, options.nextCheckpoint.snapshotTime);
|
|
878
|
+
return await firstCollection.collection
|
|
879
|
+
.aggregate<{ lookup: bson.Binary; indexId: string }>(
|
|
880
|
+
[
|
|
881
|
+
...pipelineForCollection(firstCollection.indexId),
|
|
882
|
+
...remainingCollections.map((collection) => {
|
|
883
|
+
return {
|
|
884
|
+
$unionWith: {
|
|
885
|
+
coll: collection.collection.collectionName,
|
|
886
|
+
pipeline: pipelineForCollection(collection.indexId)
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
}),
|
|
890
|
+
{
|
|
891
|
+
$limit: limit + 1
|
|
892
|
+
}
|
|
893
|
+
],
|
|
831
894
|
{
|
|
832
|
-
|
|
895
|
+
session,
|
|
896
|
+
readConcern: 'snapshot',
|
|
897
|
+
batchSize: limit + 2,
|
|
898
|
+
maxTimeMS: lib_mongo.db.MONGO_OPERATION_TIMEOUT_MS
|
|
833
899
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
900
|
+
)
|
|
901
|
+
.toArray()
|
|
902
|
+
.catch((e) => {
|
|
903
|
+
// Includes the case where the checkpoint snapshot has expired. Degrading to
|
|
904
|
+
// invalidateParameterBuckets would be safe in itself - it reads nothing - but it gains
|
|
905
|
+
// nothing: the caller responds to that by re-evaluating the parameter queries at this
|
|
906
|
+
// same snapshot, which fails too. The checkpoint has to be refetched instead, which is
|
|
907
|
+
// what the existing sync retry behavior does.
|
|
908
|
+
throw lib_mongo.mapQueryError(e, 'while querying parameter changes');
|
|
909
|
+
});
|
|
910
|
+
});
|
|
841
911
|
|
|
842
912
|
const invalidateParameterUpdates = parameterUpdates.length > limit;
|
|
843
913
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import {
|
|
3
|
+
CustomWriteCheckpointFilters,
|
|
4
|
+
GetCheckpointChangesOptions,
|
|
5
|
+
SingleSyncConfigBucketDefinitionMapping,
|
|
6
|
+
storage
|
|
7
|
+
} from '@powersync/service-core';
|
|
8
|
+
import { EventDefinitionId } from '@powersync/service-sync-rules';
|
|
9
|
+
import { MongoCheckpointAPIOptions, MongoWriteCheckpointAPI } from '../MongoWriteCheckpointAPI.js';
|
|
10
|
+
import { VersionedPowerSyncMongoV3 } from './VersionedPowerSyncMongoV3.js';
|
|
11
|
+
|
|
12
|
+
export type MongoCheckpointAPIV3Options = Omit<MongoCheckpointAPIOptions, 'db'> & {
|
|
13
|
+
db: VersionedPowerSyncMongoV3;
|
|
14
|
+
syncConfigMapping: () => SingleSyncConfigBucketDefinitionMapping;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class MongoWriteCheckpointAPIV3 extends MongoWriteCheckpointAPI {
|
|
18
|
+
declare db: VersionedPowerSyncMongoV3;
|
|
19
|
+
|
|
20
|
+
// Supplied via the constructor or the setWriteCheckpointMode setter.
|
|
21
|
+
private _customWriteCheckpointEventName: string | undefined;
|
|
22
|
+
private readonly syncConfigMapping: () => SingleSyncConfigBucketDefinitionMapping;
|
|
23
|
+
|
|
24
|
+
constructor(options: MongoCheckpointAPIV3Options) {
|
|
25
|
+
super(options);
|
|
26
|
+
this.syncConfigMapping = options.syncConfigMapping;
|
|
27
|
+
// Enforce the CUSTOM-requires-event-name invariant on construction too, not only setWriteCheckpointMode.
|
|
28
|
+
this._customWriteCheckpointEventName = this.requireCustomEventName(options.writeCheckpointMode);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected resolveEventId(): EventDefinitionId {
|
|
32
|
+
const eventName = this._customWriteCheckpointEventName;
|
|
33
|
+
if (!eventName) {
|
|
34
|
+
throw new ServiceAssertionError(`No eventName has been supplied via setWriteCheckpointMode.`);
|
|
35
|
+
}
|
|
36
|
+
return this.syncConfigMapping().eventDefinitionIdByName(eventName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected override async lastCustomWriteCheckpoint(filters: CustomWriteCheckpointFilters): Promise<bigint | null> {
|
|
40
|
+
const { user_id } = filters;
|
|
41
|
+
const eventId = this.resolveEventId();
|
|
42
|
+
|
|
43
|
+
const lastWriteCheckpoint = await this.db
|
|
44
|
+
.customCheckpointRequests({
|
|
45
|
+
eventId,
|
|
46
|
+
replicationStreamId: this.replicationStreamId
|
|
47
|
+
})
|
|
48
|
+
.findOne({
|
|
49
|
+
user_id
|
|
50
|
+
});
|
|
51
|
+
return lastWriteCheckpoint?.checkpoint ?? null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override setWriteCheckpointMode(config: storage.WriteCheckpointModeConfig): void {
|
|
55
|
+
this._customWriteCheckpointEventName = this.requireCustomEventName(config);
|
|
56
|
+
super.setWriteCheckpointMode(config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Validates and returns the event name for the given mode config. Shared by the constructor and
|
|
61
|
+
* {@link setWriteCheckpointMode} so both paths enforce that CUSTOM mode always names its checkpoint event.
|
|
62
|
+
*/
|
|
63
|
+
private requireCustomEventName(config: storage.WriteCheckpointModeConfig): string | undefined {
|
|
64
|
+
if (config.mode != storage.WriteCheckpointMode.CUSTOM) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
if (!config.eventName) {
|
|
68
|
+
throw new ServiceAssertionError(`V3 incremental reprocessing requires an eventName to be supplied.`);
|
|
69
|
+
}
|
|
70
|
+
return config.eventName;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
protected override async getCustomWriteCheckpointChanges(
|
|
74
|
+
options: GetCheckpointChangesOptions
|
|
75
|
+
): Promise<{ invalidateWriteCheckpoints: boolean; updatedWriteCheckpoints: Map<string, bigint> }> {
|
|
76
|
+
const eventId = this.resolveEventId();
|
|
77
|
+
|
|
78
|
+
const limit = 1000;
|
|
79
|
+
const changes = await this.db
|
|
80
|
+
.customCheckpointRequests({
|
|
81
|
+
replicationStreamId: this.replicationStreamId,
|
|
82
|
+
eventId
|
|
83
|
+
})
|
|
84
|
+
.find(
|
|
85
|
+
{
|
|
86
|
+
op_id: { $gt: options.lastCheckpoint.checkpoint, $lte: options.nextCheckpoint.checkpoint }
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
limit: limit + 1,
|
|
90
|
+
// batchSize is 1 more than limit to auto-close the cursor.
|
|
91
|
+
// See https://github.com/mongodb/node-mongodb-native/pull/4580
|
|
92
|
+
batchSize: limit + 2,
|
|
93
|
+
singleBatch: true
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
.toArray();
|
|
97
|
+
const invalidate = changes.length > limit;
|
|
98
|
+
|
|
99
|
+
const updatedWriteCheckpoints = new Map<string, bigint>();
|
|
100
|
+
if (!invalidate) {
|
|
101
|
+
for (let c of changes) {
|
|
102
|
+
updatedWriteCheckpoints.set(c.user_id, c.checkpoint);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
invalidateWriteCheckpoints: invalidate,
|
|
108
|
+
updatedWriteCheckpoints
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|