@powersync/service-module-mongodb-storage 0.0.0-dev-20260803144812 → 0.0.0-dev-20260929095716
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 +129 -7
- package/dist/storage/MongoBucketStorage.d.ts +42 -5
- package/dist/storage/MongoBucketStorage.js +404 -215
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +39 -14
- package/dist/storage/implementation/MongoBucketBatch.js +169 -98
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +21 -79
- package/dist/storage/implementation/MongoCompactor.js +27 -238
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoIdSequence.d.ts +10 -1
- package/dist/storage/implementation/MongoIdSequence.js +14 -1
- package/dist/storage/implementation/MongoIdSequence.js.map +1 -1
- package/dist/storage/implementation/MongoOpIdAllocator.d.ts +27 -0
- package/dist/storage/implementation/MongoOpIdAllocator.js +97 -0
- package/dist/storage/implementation/MongoOpIdAllocator.js.map +1 -0
- 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 +35 -2
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +2 -1
- package/dist/storage/implementation/MongoPersistedReplicationStream.js +7 -4
- package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +3 -3
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +10 -8
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js +8 -4
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +32 -11
- package/dist/storage/implementation/MongoSyncBucketStorage.js +95 -31
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +26 -2
- package/dist/storage/implementation/MongoSyncRulesLock.js +59 -10
- 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 +57 -14
- 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 +28 -1
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +35 -0
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +11 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +227 -221
- 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 +66 -17
- 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 +14 -2
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +261 -194
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +83 -25
- package/dist/storage/implementation/v3/MongoCompactorV3.js +702 -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 +92 -32
- 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 +77 -45
- 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 +108 -0
- package/dist/storage/implementation/v3/compact-utils.js +223 -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 +90 -6
- 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 +15 -7
- package/dist/storage/implementation/v3/source-table-utils.js +49 -57
- 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.d.ts +4 -2
- package/dist/utils/test-utils.js +7 -4
- 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 +545 -277
- package/src/storage/implementation/MongoBucketBatch.ts +258 -124
- package/src/storage/implementation/MongoCompactor.ts +37 -346
- package/src/storage/implementation/MongoIdSequence.ts +21 -1
- package/src/storage/implementation/MongoOpIdAllocator.ts +105 -0
- package/src/storage/implementation/MongoParameterCompactor.ts +388 -102
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +46 -1
- package/src/storage/implementation/MongoPersistedReplicationStream.ts +12 -4
- package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +48 -29
- package/src/storage/implementation/MongoStorageProvider.ts +16 -4
- package/src/storage/implementation/MongoSyncBucketStorage.ts +133 -40
- package/src/storage/implementation/MongoSyncRulesLock.ts +78 -12
- 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 +76 -20
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +4 -0
- package/src/storage/implementation/db.ts +36 -2
- package/src/storage/implementation/models.ts +39 -0
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +272 -254
- 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 +88 -28
- 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 +339 -247
- package/src/storage/implementation/v3/MongoCompactorV3.ts +955 -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 +112 -42
- package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +94 -51
- 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 +329 -0
- package/src/storage/implementation/v3/compaction-constants.ts +5 -0
- package/src/storage/implementation/v3/models.ts +97 -4
- 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 +82 -76
- package/src/storage/storage-index.ts +2 -0
- package/src/types/types.ts +42 -7
- package/src/utils/test-utils.ts +9 -5
- 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 +794 -205
- package/test/src/chunk_compaction_config.test.ts +38 -0
- package/test/src/cleanup-stopped-sync-configs.test.ts +59 -26
- package/test/src/compact-utils.test.ts +251 -0
- package/test/src/concurrent_writers.test.ts +599 -0
- package/test/src/connection_config.test.ts +159 -0
- package/test/src/helpers/MemoryObjectStorage.ts +14 -6
- package/test/src/helpers/concurrentWriter.mjs +29 -0
- package/test/src/helpers/s3TestFactory.ts +12 -12
- package/test/src/object_storage_usage.test.ts +268 -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 +280 -24
- package/test/src/storage_compacting.test.ts +1097 -253
- package/test/src/storage_object_storage_inline_threshold.test.ts +3 -3
- package/test/src/storage_s3_checksums.test.ts +6 -7
- package/test/src/storage_s3_compaction_lifecycle.test.ts +143 -17
- package/test/src/storage_s3_reading.test.ts +294 -6
- package/test/src/storage_s3_writing.test.ts +4 -3
- package/test/src/storage_sync.test.ts +412 -80
- package/test/src/storeCurrentData.test.ts +5 -5
- package/test/src/util.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,18 +6,31 @@ import { ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
|
6
6
|
* at the end of the transaction.
|
|
7
7
|
*/
|
|
8
8
|
export class MongoIdSequence {
|
|
9
|
+
ranges;
|
|
9
10
|
_last;
|
|
10
|
-
constructor(last) {
|
|
11
|
+
constructor(last, ranges) {
|
|
12
|
+
this.ranges = ranges;
|
|
11
13
|
if (typeof last != 'bigint') {
|
|
12
14
|
throw new ReplicationAssertionError(`BigInt required, got ${last} ${typeof last}`);
|
|
13
15
|
}
|
|
14
16
|
this._last = last;
|
|
15
17
|
}
|
|
16
18
|
next() {
|
|
19
|
+
if (this.ranges != null) {
|
|
20
|
+
const next = this.ranges.find((range) => range.end > this._last);
|
|
21
|
+
if (next == null) {
|
|
22
|
+
throw new OpIdRangeExhausted();
|
|
23
|
+
}
|
|
24
|
+
this._last = this._last + 1n < next.start ? next.start : this._last + 1n;
|
|
25
|
+
return this._last;
|
|
26
|
+
}
|
|
17
27
|
return ++this._last;
|
|
18
28
|
}
|
|
19
29
|
last() {
|
|
20
30
|
return this._last;
|
|
21
31
|
}
|
|
22
32
|
}
|
|
33
|
+
/** Abort the transaction before reserving more IDs and retrying its evaluation. */
|
|
34
|
+
export class OpIdRangeExhausted extends Error {
|
|
35
|
+
}
|
|
23
36
|
//# sourceMappingURL=MongoIdSequence.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoIdSequence.js","sourceRoot":"","sources":["../../../src/storage/implementation/MongoIdSequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,OAAO,eAAe;
|
|
1
|
+
{"version":3,"file":"MongoIdSequence.js","sourceRoot":"","sources":["../../../src/storage/implementation/MongoIdSequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IAKP;IAJX,KAAK,CAAS;IAEtB,YACE,IAAY,EACK,MAA6B;QAA7B,WAAM,GAAN,MAAM,CAAuB;QAE9C,IAAI,OAAO,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,yBAAyB,CAAC,wBAAwB,IAAI,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC;QACrF,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;YACjE,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACjB,MAAM,IAAI,kBAAkB,EAAE,CAAC;YACjC,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACzE,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAQD,mFAAmF;AACnF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;CAAG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { VersionedPowerSyncMongo } from './db.js';
|
|
2
|
+
import { MongoIdSequence } from './MongoIdSequence.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared by writers of one stream and lease owner in this process. Reservations
|
|
5
|
+
* use short majority writes, never the publication session. A crashed owner
|
|
6
|
+
* abandons its unused ranges; the global sequence is an allocation watermark.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MongoOpIdAllocator {
|
|
9
|
+
private readonly db;
|
|
10
|
+
private ranges;
|
|
11
|
+
private reserving?;
|
|
12
|
+
constructor(db: VersionedPowerSyncMongo);
|
|
13
|
+
discard(): void;
|
|
14
|
+
sequence(persistedOp: bigint): MongoIdSequence;
|
|
15
|
+
committed(lastOp: bigint): void;
|
|
16
|
+
/** Top up between transactions, retaining every unused ID in existing ranges. */
|
|
17
|
+
ensureCapacity(): Promise<void>;
|
|
18
|
+
reserve(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Atomically reserve a range of operation IDs in the global sequence.
|
|
21
|
+
*
|
|
22
|
+
* We continue using the range across multiple batches, until the range is exhausted,
|
|
23
|
+
* so we don't "waste" large segements in long-running processes with small batches.
|
|
24
|
+
* However, we can't return unused portions back to the database if we don't use them.
|
|
25
|
+
*/
|
|
26
|
+
private reserveRange;
|
|
27
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
3
|
+
import { MongoIdSequence } from './MongoIdSequence.js';
|
|
4
|
+
const RESERVATION_SIZE = 65536n;
|
|
5
|
+
const LOW_WATER_MARK = 16384n;
|
|
6
|
+
const MAX_OP_ID = (1n << 63n) - 1n;
|
|
7
|
+
/**
|
|
8
|
+
* Shared by writers of one stream and lease owner in this process. Reservations
|
|
9
|
+
* use short majority writes, never the publication session. A crashed owner
|
|
10
|
+
* abandons its unused ranges; the global sequence is an allocation watermark.
|
|
11
|
+
*/
|
|
12
|
+
export class MongoOpIdAllocator {
|
|
13
|
+
db;
|
|
14
|
+
ranges = [];
|
|
15
|
+
reserving;
|
|
16
|
+
constructor(db) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
}
|
|
19
|
+
discard() {
|
|
20
|
+
this.ranges = [];
|
|
21
|
+
}
|
|
22
|
+
sequence(persistedOp) {
|
|
23
|
+
// The stream is fenced before reading this head. Another writer may have
|
|
24
|
+
// committed since this allocator was last used, including in another process.
|
|
25
|
+
// Never reuse reserved IDs below that durable head.
|
|
26
|
+
return new MongoIdSequence(persistedOp, this.ranges.slice());
|
|
27
|
+
}
|
|
28
|
+
committed(lastOp) {
|
|
29
|
+
this.ranges = this.ranges
|
|
30
|
+
.filter((range) => range.end > lastOp)
|
|
31
|
+
.map((range) => ({ start: range.start > lastOp ? range.start : lastOp + 1n, end: range.end }));
|
|
32
|
+
}
|
|
33
|
+
/** Top up between transactions, retaining every unused ID in existing ranges. */
|
|
34
|
+
async ensureCapacity() {
|
|
35
|
+
const remaining = this.ranges.reduce((total, range) => total + range.end - range.start + 1n, 0n);
|
|
36
|
+
if (remaining < LOW_WATER_MARK) {
|
|
37
|
+
await this.reserve();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async reserve() {
|
|
41
|
+
if (this.reserving != null) {
|
|
42
|
+
return this.reserving;
|
|
43
|
+
}
|
|
44
|
+
this.reserving = this.reserveRange();
|
|
45
|
+
try {
|
|
46
|
+
await this.reserving;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
this.reserving = undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Atomically reserve a range of operation IDs in the global sequence.
|
|
54
|
+
*
|
|
55
|
+
* We continue using the range across multiple batches, until the range is exhausted,
|
|
56
|
+
* so we don't "waste" large segements in long-running processes with small batches.
|
|
57
|
+
* However, we can't return unused portions back to the database if we don't use them.
|
|
58
|
+
*/
|
|
59
|
+
async reserveRange() {
|
|
60
|
+
try {
|
|
61
|
+
// Return the previous watermark so an unchanged value at the limit can be
|
|
62
|
+
// distinguished from a successful reservation ending near the limit.
|
|
63
|
+
const previous = await this.db.op_id_sequence.findOneAndUpdate({ _id: 'main' }, [
|
|
64
|
+
{
|
|
65
|
+
$set: {
|
|
66
|
+
op_id: {
|
|
67
|
+
$let: {
|
|
68
|
+
vars: { current: { $ifNull: ['$op_id', 0n] } },
|
|
69
|
+
in: {
|
|
70
|
+
$cond: [
|
|
71
|
+
{ $lte: ['$$current', MAX_OP_ID - RESERVATION_SIZE] },
|
|
72
|
+
{ $add: ['$$current', RESERVATION_SIZE] },
|
|
73
|
+
'$$current'
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
], { upsert: true, returnDocument: 'before', writeConcern: { w: 'majority' } });
|
|
81
|
+
const last = previous?.op_id ?? 0n;
|
|
82
|
+
if (last > MAX_OP_ID - RESERVATION_SIZE) {
|
|
83
|
+
// Not expected to ever happen, unless the sequence was manually modified
|
|
84
|
+
throw new ReplicationAssertionError('Operation ID sequence exhausted');
|
|
85
|
+
}
|
|
86
|
+
this.ranges.push({ start: last + 1n, end: last + RESERVATION_SIZE });
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// Concurrent first reservations may race to insert the sequence document - retry in that case.
|
|
90
|
+
if (error instanceof mongo.MongoServerError && error.code === 11000) {
|
|
91
|
+
return this.reserveRange();
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=MongoOpIdAllocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MongoOpIdAllocator.js","sourceRoot":"","sources":["../../../src/storage/implementation/MongoOpIdAllocator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,OAAO,EAAE,eAAe,EAAa,MAAM,sBAAsB,CAAC;AAElE,MAAM,gBAAgB,GAAG,MAAO,CAAC;AACjC,MAAM,cAAc,GAAG,MAAO,CAAC;AAC/B,MAAM,SAAS,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;AAEnC;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IAIA;IAHrB,MAAM,GAAgB,EAAE,CAAC;IACzB,SAAS,CAAiB;IAElC,YAA6B,EAA2B;QAA3B,OAAE,GAAF,EAAE,CAAyB;IAAG,CAAC;IAE5D,OAAO;QACL,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,WAAmB;QAC1B,yEAAyE;QACzE,8EAA8E;QAC9E,oDAAoD;QACpD,OAAO,IAAI,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;aACtB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC;aACrC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACnG,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,cAAc;QAClB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QACjG,IAAI,SAAS,GAAG,cAAc,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,YAAY;QACxB,IAAI,CAAC;YACH,0EAA0E;YAC1E,qEAAqE;YACrE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,gBAAgB,CAC5D,EAAE,GAAG,EAAE,MAAM,EAAE,EACf;gBACE;oBACE,IAAI,EAAE;wBACJ,KAAK,EAAE;4BACL,IAAI,EAAE;gCACJ,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;gCAC9C,EAAE,EAAE;oCACF,KAAK,EAAE;wCACL,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,SAAS,GAAG,gBAAgB,CAAC,EAAE;wCACrD,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAE;wCACzC,WAAW;qCACZ;iCACF;6BACF;yBACF;qBACF;iBACF;aACF,EACD,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,CAC5E,CAAC;YACF,MAAM,IAAI,GAAG,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,GAAG,SAAS,GAAG,gBAAgB,EAAE,CAAC;gBACxC,yEAAyE;gBACzE,MAAM,IAAI,yBAAyB,CAAC,iCAAiC,CAAC,CAAC;YACzE,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,GAAG,gBAAgB,EAAE,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,+FAA+F;YAC/F,IAAI,KAAK,YAAY,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACpE,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;YAC7B,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,23 +1,96 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
-
import {
|
|
2
|
+
import { Logger } from '@powersync/lib-services-framework';
|
|
3
|
+
import { bson, CompactOptions, InternalOpId } from '@powersync/service-core';
|
|
3
4
|
import type { VersionedPowerSyncMongo } from './db.js';
|
|
5
|
+
type ParameterCompactionReadDocument = {
|
|
6
|
+
_id: InternalOpId;
|
|
7
|
+
key: mongo.Document;
|
|
8
|
+
lookup: bson.Binary;
|
|
9
|
+
bucket_parameters?: unknown[] | null;
|
|
10
|
+
};
|
|
11
|
+
export type ParameterCompactionResult = {
|
|
12
|
+
collections: number;
|
|
13
|
+
scannedEntries: number;
|
|
14
|
+
deletedEntries: number;
|
|
15
|
+
};
|
|
4
16
|
/**
|
|
5
17
|
* Compacts parameter lookup data (the bucket_parameters collection).
|
|
6
18
|
*
|
|
7
|
-
*
|
|
19
|
+
* Both storage versions persist a per-stream compaction cursor, so a run only scans entries in the
|
|
20
|
+
* un-compacted operation-id range. V1 scans its shared collection using only the `_id` index, so it
|
|
21
|
+
* additionally filters by stream in code.
|
|
22
|
+
*
|
|
23
|
+
* The cursor is a single value covering every collection of the stream, so it can only be advanced
|
|
24
|
+
* to a boundary that all collections have passed. To keep it moving during a long pass, collections
|
|
25
|
+
* are processed in lock-step rather than one after another - see {@link compactCollections}.
|
|
8
26
|
*
|
|
9
27
|
* For background, see the `/docs/storage/parameter-lookups.md` file.
|
|
10
28
|
*/
|
|
11
|
-
export declare class MongoParameterCompactor {
|
|
29
|
+
export declare abstract class MongoParameterCompactor {
|
|
30
|
+
#private;
|
|
12
31
|
protected readonly db: VersionedPowerSyncMongo;
|
|
13
|
-
protected readonly
|
|
32
|
+
protected readonly replicationStreamId: number;
|
|
14
33
|
protected readonly checkpoint: InternalOpId;
|
|
15
34
|
protected readonly options: CompactOptions;
|
|
16
|
-
protected readonly
|
|
17
|
-
|
|
35
|
+
protected readonly parameterCompactionBatchSize: number;
|
|
36
|
+
protected readonly parameterCompactionPersistIntervalMs: number;
|
|
37
|
+
protected readonly logger: Logger;
|
|
38
|
+
protected readonly signal?: AbortSignal;
|
|
39
|
+
constructor(db: VersionedPowerSyncMongo, replicationStreamId: number, checkpoint: InternalOpId, options: CompactOptions, parameterCompactionBatchSize?: number, parameterCompactionPersistIntervalMs?: number);
|
|
18
40
|
compact(): Promise<void>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The exclusive operation-id boundary through which this stream's parameter indexes have all
|
|
43
|
+
* been compacted.
|
|
44
|
+
*/
|
|
45
|
+
protected readCompactedBefore(): Promise<InternalOpId>;
|
|
46
|
+
protected persistCompactedBefore(compactedBefore: InternalOpId): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Commits the checkpoint-change invalidation fence before the first delete of this pass.
|
|
49
|
+
*
|
|
50
|
+
* Checkpoint change detection finds changed lookups by querying parameter entries in
|
|
51
|
+
* (lastCheckpoint, nextCheckpoint]. Compaction physically removes entries in that range, so a
|
|
52
|
+
* checkpoint that can no longer see the full history must instead invalidate all parameter
|
|
53
|
+
* buckets. The fence records the boundary below which that history may be missing.
|
|
54
|
+
*
|
|
55
|
+
* The fence must be committed before the first delete: MongoDB snapshot ordering then
|
|
56
|
+
* guarantees that a checkpoint snapshot which observes a deletion also observes the fence.
|
|
57
|
+
*
|
|
58
|
+
* This deliberately isn't the same value as the compaction cursor. If the pass fails halfway,
|
|
59
|
+
* the fence only causes conservative invalidation, while an advanced cursor would skip
|
|
60
|
+
* deletion work that never completed.
|
|
61
|
+
*/
|
|
62
|
+
private ensureInvalidationFence;
|
|
63
|
+
protected abstract getCollections(): Promise<mongo.Collection<mongo.Document>[]>;
|
|
64
|
+
protected abstract shouldCompactDocument(doc: ParameterCompactionReadDocument): boolean;
|
|
65
|
+
/** Deletes history preceding a batch for several identities sharing a lookup. */
|
|
66
|
+
protected abstract leadingHistoryDeleteFilter(lookup: bson.Binary, keys: mongo.Document[], before: InternalOpId): mongo.Document;
|
|
67
|
+
/**
|
|
68
|
+
* Processes every collection of the stream, in lock-step: each turn takes one batch from the
|
|
69
|
+
* collection that has processed the least so far.
|
|
70
|
+
*
|
|
71
|
+
* The persisted cursor is the minimum position over all collections, which is exactly the
|
|
72
|
+
* boundary that all of them have passed, so it can be advanced periodically during the pass.
|
|
73
|
+
* Always picking the collection that is furthest behind also keeps each of them within one batch
|
|
74
|
+
* of that boundary, bounding the work an interrupted pass has to repeat.
|
|
75
|
+
*
|
|
76
|
+
* V1 storage always has a single collection; V3 has a collection per defined index. So in V1 the
|
|
77
|
+
* ame process collapses to compacting the single collection in order, while V3 can alternate between
|
|
78
|
+
* collections.
|
|
79
|
+
*/
|
|
80
|
+
private compactCollections;
|
|
81
|
+
/**
|
|
82
|
+
* The boundary that every scope has processed past, capped at the target checkpoint, and the
|
|
83
|
+
* scope sitting on it.
|
|
84
|
+
*
|
|
85
|
+
* The frontier is the furthest the cursor may be advanced. The scope is the one that has
|
|
86
|
+
* processed the least, or null once all of them have reached the target checkpoint.
|
|
87
|
+
*/
|
|
88
|
+
private frontier;
|
|
89
|
+
/**
|
|
90
|
+
* Reads and processes one batch from the scope, and advances its position past that batch.
|
|
91
|
+
*/
|
|
92
|
+
private compactBatch;
|
|
93
|
+
/** Deletes documents by `_id`, chunked to bound the command size. Returns the number deleted. */
|
|
94
|
+
private deleteByIds;
|
|
23
95
|
}
|
|
96
|
+
export {};
|