@powersync/service-module-mongodb-storage 0.0.0-dev-20260602073133 → 0.0.0-dev-20260909133214
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 +177 -5
- 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 +71 -18
- package/dist/storage/MongoBucketStorage.js +516 -202
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +71 -29
- package/dist/storage/implementation/MongoBucketBatch.js +140 -66
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoChecksums.d.ts +41 -13
- package/dist/storage/implementation/MongoChecksums.js +36 -121
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +28 -90
- package/dist/storage/implementation/MongoCompactor.js +87 -481
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoHydrationState.d.ts +11 -0
- package/dist/storage/implementation/MongoHydrationState.js +49 -0
- package/dist/storage/implementation/MongoHydrationState.js.map +1 -0
- package/dist/storage/implementation/MongoParameterCompactor.d.ts +82 -8
- package/dist/storage/implementation/MongoParameterCompactor.js +312 -76
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +21 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +93 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -0
- package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +36 -0
- package/dist/storage/implementation/MongoPersistedReplicationStream.js +90 -0
- package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -0
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +25 -0
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +125 -0
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -0
- package/dist/storage/implementation/MongoStorageProvider.js +41 -4
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +81 -37
- package/dist/storage/implementation/MongoSyncBucketStorage.js +159 -86
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.js +23 -11
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +11 -8
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js +159 -33
- 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 +28 -0
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js +2 -0
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js.map +1 -0
- package/dist/storage/implementation/common/PersistedBatch.d.ts +34 -2
- package/dist/storage/implementation/common/PersistedBatch.js +63 -10
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +1 -1
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
- package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +2 -2
- package/dist/storage/implementation/createMongoSyncBucketStorage.js +4 -4
- package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +4 -1
- package/dist/storage/implementation/db.js +31 -16
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +55 -13
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +15 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +135 -107
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +4 -4
- package/dist/storage/implementation/v1/MongoChecksumsV1.js +119 -7
- package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +47 -7
- package/dist/storage/implementation/v1/MongoCompactorV1.js +478 -8
- 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 +33 -27
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +146 -73
- 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/v1/VersionedPowerSyncMongoV1.d.ts +2 -1
- package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +3 -0
- package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -1
- package/dist/storage/implementation/v1/models.d.ts +10 -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/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/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 +16 -5
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +393 -262
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +30 -9
- package/dist/storage/implementation/v3/MongoChecksumsV3.js +161 -20
- package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +108 -18
- package/dist/storage/implementation/v3/MongoCompactorV3.js +1115 -47
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +12 -3
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +13 -8
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +54 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +319 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +61 -36
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +353 -161
- 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 +8 -3
- package/dist/storage/implementation/v3/PersistedBatchV3.js +131 -29
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +3 -3
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js +13 -11
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +26 -14
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +73 -29
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
- package/dist/storage/implementation/v3/bucket-format.d.ts +13 -0
- package/dist/storage/implementation/v3/bucket-format.js +79 -0
- package/dist/storage/implementation/v3/bucket-format.js.map +1 -0
- package/dist/storage/implementation/v3/chunking.d.ts +10 -0
- package/dist/storage/implementation/v3/chunking.js +30 -0
- package/dist/storage/implementation/v3/chunking.js.map +1 -0
- 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 +187 -23
- package/dist/storage/implementation/v3/models.js +11 -28
- package/dist/storage/implementation/v3/models.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +20 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +48 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +33 -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 +68 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +154 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +37 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +167 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +67 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +439 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
- package/dist/storage/implementation/v3/source-table-utils.d.ts +63 -0
- package/dist/storage/implementation/v3/source-table-utils.js +206 -0
- package/dist/storage/implementation/v3/source-table-utils.js.map +1 -0
- package/dist/storage/storage-index.d.ts +5 -4
- package/dist/storage/storage-index.js +5 -4
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/types/types.d.ts +71 -3
- package/dist/types/types.js +58 -2
- package/dist/types/types.js.map +1 -1
- package/dist/utils/test-utils.d.ts +1 -2
- package/dist/utils/test-utils.js +7 -1
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.d.ts +9 -2
- package/dist/utils/util.js +131 -5
- package/dist/utils/util.js.map +1 -1
- package/package.json +13 -19
- package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
- package/src/storage/MongoBucketStorage.ts +728 -242
- package/src/storage/implementation/MongoBucketBatch.ts +196 -91
- package/src/storage/implementation/MongoChecksums.ts +93 -153
- package/src/storage/implementation/MongoCompactor.ts +106 -631
- package/src/storage/implementation/MongoHydrationState.ts +61 -0
- package/src/storage/implementation/MongoParameterCompactor.ts +392 -87
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +122 -0
- package/src/storage/implementation/MongoPersistedReplicationStream.ts +118 -0
- package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +156 -0
- package/src/storage/implementation/MongoStorageProvider.ts +48 -4
- package/src/storage/implementation/MongoSyncBucketStorage.ts +226 -118
- package/src/storage/implementation/MongoSyncRulesLock.ts +28 -12
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +194 -52
- package/src/storage/implementation/SyncRuleStateUpdate.ts +13 -6
- package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +31 -0
- package/src/storage/implementation/common/PersistedBatch.ts +83 -15
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +1 -1
- package/src/storage/implementation/createMongoSyncBucketStorage.ts +21 -7
- package/src/storage/implementation/db.ts +40 -22
- package/src/storage/implementation/models.ts +58 -14
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +174 -125
- package/src/storage/implementation/v1/MongoChecksumsV1.ts +154 -12
- package/src/storage/implementation/v1/MongoCompactorV1.ts +594 -25
- package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +25 -9
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +226 -129
- package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
- package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +11 -1
- package/src/storage/implementation/v1/models.ts +12 -1
- package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
- package/src/storage/implementation/v3/CompactionLease.ts +152 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +502 -324
- package/src/storage/implementation/v3/MongoChecksumsV3.ts +250 -32
- package/src/storage/implementation/v3/MongoCompactorV3.ts +1439 -70
- package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +19 -9
- package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +473 -0
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +453 -211
- package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +169 -45
- package/src/storage/implementation/v3/SourceRecordStoreV3.ts +12 -12
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +99 -38
- package/src/storage/implementation/v3/bucket-format.ts +99 -0
- package/src/storage/implementation/v3/chunking.ts +40 -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 +228 -58
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +62 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +44 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +182 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +230 -0
- package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +573 -0
- package/src/storage/implementation/v3/source-table-utils.ts +398 -0
- package/src/storage/storage-index.ts +14 -4
- package/src/types/types.ts +76 -2
- package/src/utils/test-utils.ts +8 -3
- package/src/utils/util.ts +188 -7
- package/test/src/__snapshots__/storage.test.ts.snap +4 -54
- package/test/src/__snapshots__/storage_sync.test.ts.snap +652 -645
- package/test/src/cleanup-stopped-sync-configs.test.ts +698 -0
- package/test/src/compact-utils.test.ts +226 -0
- package/test/src/helpers/MemoryObjectStorage.ts +61 -0
- package/test/src/helpers/s3TestFactory.ts +69 -0
- package/test/src/object_storage_lifecycle.test.ts +59 -0
- package/test/src/object_storage_usage.test.ts +255 -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/setup.ts +6 -1
- package/test/src/storage.test.ts +478 -13
- package/test/src/storage_compacting.test.ts +2516 -107
- package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
- package/test/src/storage_s3_checksums.test.ts +190 -0
- package/test/src/storage_s3_compaction_lifecycle.test.ts +543 -0
- package/test/src/storage_s3_reading.test.ts +768 -0
- package/test/src/storage_s3_writing.test.ts +136 -0
- package/test/src/storage_sync.test.ts +1507 -76
- package/test/src/storeCurrentData.test.ts +227 -0
- package/test/src/util.ts +3 -2
- package/tsconfig.json +1 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/storage/implementation/BucketDefinitionMapping.d.ts +0 -15
- package/dist/storage/implementation/BucketDefinitionMapping.js +0 -58
- package/dist/storage/implementation/BucketDefinitionMapping.js.map +0 -1
- package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -14
- package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -67
- package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +0 -29
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +0 -76
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +0 -1
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +0 -13
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +0 -2
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +0 -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/MongoParameterLookupV3.d.ts +0 -4
- package/dist/storage/implementation/v3/MongoParameterLookupV3.js +0 -9
- package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +0 -1
- package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -48
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
- package/src/storage/implementation/BucketDefinitionMapping.ts +0 -75
- package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -82
- package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +0 -101
- package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +0 -15
- package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
- package/src/storage/implementation/v3/MongoParameterLookupV3.ts +0 -11
- package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -68
|
@@ -2,6 +2,7 @@ import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
|
2
2
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
3
3
|
import {
|
|
4
4
|
BaseObserver,
|
|
5
|
+
logger as defaultLogger,
|
|
5
6
|
DO_NOT_LOG,
|
|
6
7
|
Logger,
|
|
7
8
|
ReplicationAbortedError,
|
|
@@ -11,13 +12,15 @@ import {
|
|
|
11
12
|
BroadcastIterable,
|
|
12
13
|
CHECKPOINT_INVALIDATE_ALL,
|
|
13
14
|
CheckpointChanges,
|
|
15
|
+
CompactInitialReplicationOptions,
|
|
16
|
+
CompactInitialReplicationResults,
|
|
14
17
|
GetCheckpointChangesOptions,
|
|
15
18
|
InternalOpId,
|
|
16
19
|
mergeAsyncIterables,
|
|
17
|
-
PopulateChecksumCacheOptions,
|
|
18
|
-
PopulateChecksumCacheResults,
|
|
19
20
|
ReplicationCheckpoint,
|
|
21
|
+
ReplicationStreamStorageIds,
|
|
20
22
|
storage,
|
|
23
|
+
SyncRuleState,
|
|
21
24
|
utils,
|
|
22
25
|
WatchWriteCheckpointOptions
|
|
23
26
|
} from '@powersync/service-core';
|
|
@@ -25,21 +28,42 @@ import { HydratedSyncConfig, ParameterLookupRows, ScopedParameterLookup } from '
|
|
|
25
28
|
import * as bson from 'bson';
|
|
26
29
|
import { LRUCache } from 'lru-cache';
|
|
27
30
|
import * as timers from 'timers/promises';
|
|
28
|
-
import {
|
|
31
|
+
import { DEFAULT_CLEAR_BATCH_THROTTLE_RATE } from '../../types/types.js';
|
|
29
32
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
30
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
MongoGetCheckpointChangesOptions,
|
|
35
|
+
MongoSyncBucketStorageCheckpoint
|
|
36
|
+
} from './common/MongoSyncBucketStorageCheckpoint.js';
|
|
37
|
+
import { DEFAULT_INLINE_THRESHOLD_BYTES } from './common/PersistedBatch.js';
|
|
31
38
|
import type { VersionedPowerSyncMongo } from './db.js';
|
|
32
39
|
import { StorageConfig } from './models.js';
|
|
33
40
|
import { MongoBucketBatchOptions } from './MongoBucketBatch.js';
|
|
34
41
|
import { MongoChecksumOptions, MongoChecksums } from './MongoChecksums.js';
|
|
35
42
|
import { MongoCompactOptions, MongoCompactor } from './MongoCompactor.js';
|
|
36
43
|
import { MongoParameterCompactor } from './MongoParameterCompactor.js';
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
44
|
+
import { MongoParsedSyncConfigSet } from './MongoParsedSyncConfigSet.js';
|
|
45
|
+
import { MongoPersistedReplicationStream } from './MongoPersistedReplicationStream.js';
|
|
46
|
+
import { MongoCheckpointAPIOptions, MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js';
|
|
47
|
+
import { ObjectStorage } from './v3/object-storage/ObjectStorage.js';
|
|
39
48
|
|
|
40
49
|
export interface MongoSyncBucketStorageOptions {
|
|
41
|
-
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'
|
|
50
|
+
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'>;
|
|
51
|
+
readPreference?: mongo.ReadPreference;
|
|
52
|
+
checksumCacheTtlMs?: number;
|
|
53
|
+
clearBatchThrottleRate?: number;
|
|
42
54
|
storageConfig: StorageConfig;
|
|
55
|
+
objectStorage?: ObjectStorage;
|
|
56
|
+
inlineThresholdBytes?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The stream state read for a checkpoint. All fields must come from the same snapshot.
|
|
61
|
+
*/
|
|
62
|
+
export interface MongoCheckpointState {
|
|
63
|
+
checkpoint: InternalOpId;
|
|
64
|
+
lsn: string | null;
|
|
65
|
+
/** See {@link MongoSyncBucketStorageCheckpoint.parameterChangesInvalidBefore}. */
|
|
66
|
+
parameterChangesInvalidBefore: InternalOpId;
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
interface InternalCheckpointChanges extends CheckpointChanges {
|
|
@@ -47,13 +71,6 @@ interface InternalCheckpointChanges extends CheckpointChanges {
|
|
|
47
71
|
invalidateWriteCheckpoints: boolean;
|
|
48
72
|
}
|
|
49
73
|
|
|
50
|
-
interface WriterSyncState {
|
|
51
|
-
lastCheckpointLsn: string | null;
|
|
52
|
-
resumeFromLsn: string | null;
|
|
53
|
-
keepaliveOp: InternalOpId | null;
|
|
54
|
-
syncConfigId?: bson.ObjectId | null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
74
|
/**
|
|
58
75
|
* Only keep checkpoints around for a minute, before fetching a fresh one.
|
|
59
76
|
*
|
|
@@ -70,34 +87,68 @@ export abstract class MongoSyncBucketStorage
|
|
|
70
87
|
implements storage.SyncRulesBucketStorage
|
|
71
88
|
{
|
|
72
89
|
readonly db: VersionedPowerSyncMongo;
|
|
90
|
+
|
|
73
91
|
[DO_NOT_LOG] = true;
|
|
74
92
|
|
|
75
93
|
readonly checksums: MongoChecksums;
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
readonly objectStorage?: ObjectStorage;
|
|
96
|
+
readonly inlineThresholdBytes: number;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Canonical parsed sync config sets, keyed by defaultSchema.
|
|
100
|
+
*
|
|
101
|
+
* Entries are never evicted: each parse options value maps to exactly one parsed set for
|
|
102
|
+
* the lifetime of this storage instance, so parsed source objects and mappings always
|
|
103
|
+
* stay associated.
|
|
104
|
+
*/
|
|
105
|
+
private readonly parsedSyncConfigSets = new Map<string, MongoParsedSyncConfigSet>();
|
|
78
106
|
private writeCheckpointAPI: MongoWriteCheckpointAPI;
|
|
79
107
|
public readonly logger: Logger;
|
|
80
108
|
public readonly storageConfig: StorageConfig;
|
|
109
|
+
public readonly readPreference: mongo.ReadPreference | undefined;
|
|
110
|
+
public readonly clearBatchThrottleRate: number;
|
|
81
111
|
#storageInitialized = false;
|
|
82
112
|
|
|
83
113
|
constructor(
|
|
84
114
|
public readonly factory: MongoBucketStorage,
|
|
85
|
-
public readonly
|
|
86
|
-
|
|
87
|
-
public readonly
|
|
115
|
+
public readonly replicationStreamId: number,
|
|
116
|
+
public readonly replicationStream: MongoPersistedReplicationStream,
|
|
117
|
+
public readonly replicationStreamName: string,
|
|
88
118
|
writeCheckpointMode: storage.WriteCheckpointMode | undefined,
|
|
89
119
|
options: MongoSyncBucketStorageOptions
|
|
90
120
|
) {
|
|
91
121
|
super();
|
|
92
122
|
this.storageConfig = options.storageConfig;
|
|
123
|
+
this.objectStorage = options.objectStorage;
|
|
124
|
+
// Keep small chunks inline in MongoDB rather than offloading them to S3.
|
|
125
|
+
// Configurable via object_storage.inline_threshold_bytes.
|
|
126
|
+
this.inlineThresholdBytes = options.inlineThresholdBytes ?? DEFAULT_INLINE_THRESHOLD_BYTES;
|
|
127
|
+
this.readPreference = options.readPreference;
|
|
128
|
+
this.clearBatchThrottleRate = options.clearBatchThrottleRate ?? DEFAULT_CLEAR_BATCH_THROTTLE_RATE;
|
|
93
129
|
this.db = factory.db.versioned(this.storageConfig);
|
|
94
130
|
this.checksums = this.createMongoChecksums(options);
|
|
95
|
-
this.writeCheckpointAPI =
|
|
131
|
+
this.writeCheckpointAPI = this.createWriteCheckpointAPI({
|
|
96
132
|
db: this.db,
|
|
97
|
-
mode: writeCheckpointMode ?? storage.WriteCheckpointMode.MANAGED,
|
|
98
|
-
|
|
133
|
+
writeCheckpointMode: { mode: writeCheckpointMode ?? storage.WriteCheckpointMode.MANAGED },
|
|
134
|
+
replicationStreamId
|
|
99
135
|
});
|
|
100
|
-
|
|
136
|
+
|
|
137
|
+
// Include both replication stream name and sync config version labels in log prefix.
|
|
138
|
+
// Examples:
|
|
139
|
+
// No sync config with a label: [stream]
|
|
140
|
+
// All sync configs have a label: [stream][v5,v6]
|
|
141
|
+
// Mixed: [stream][?,v6]
|
|
142
|
+
const hasVersionLabel = replicationStream.syncConfigContent.some((config) => config.version_label != null);
|
|
143
|
+
const versionLabels = hasVersionLabel
|
|
144
|
+
? replicationStream.syncConfigContent.map((config) => config.version_label ?? '?')
|
|
145
|
+
: [];
|
|
146
|
+
this.logger =
|
|
147
|
+
versionLabels.length == 0
|
|
148
|
+
? replicationStream.logger
|
|
149
|
+
: defaultLogger.child({
|
|
150
|
+
prefix: `[${replicationStreamName}][${versionLabels.join(',')}] `
|
|
151
|
+
});
|
|
101
152
|
}
|
|
102
153
|
|
|
103
154
|
/**
|
|
@@ -108,58 +159,66 @@ export abstract class MongoSyncBucketStorage
|
|
|
108
159
|
abstract createMongoCompactor(options: MongoCompactOptions): MongoCompactor;
|
|
109
160
|
|
|
110
161
|
protected abstract createMongoChecksums(options: MongoSyncBucketStorageOptions): MongoChecksums;
|
|
162
|
+
protected createWriteCheckpointAPI(options: MongoCheckpointAPIOptions): MongoWriteCheckpointAPI {
|
|
163
|
+
return new MongoWriteCheckpointAPI(options);
|
|
164
|
+
}
|
|
165
|
+
|
|
111
166
|
protected abstract createMongoParameterCompactor(
|
|
112
167
|
checkpoint: InternalOpId,
|
|
113
168
|
options: storage.CompactOptions
|
|
114
169
|
): MongoParameterCompactor;
|
|
115
170
|
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
/** MongoDB parameter compaction uses a persisted operation-id cursor. */
|
|
172
|
+
public supportsIncrementalParameterCompaction(): boolean {
|
|
173
|
+
return true;
|
|
118
174
|
}
|
|
119
175
|
|
|
120
|
-
get
|
|
121
|
-
return this.
|
|
176
|
+
get writeCheckpointMode() {
|
|
177
|
+
return this.writeCheckpointAPI.writeCheckpointMode;
|
|
122
178
|
}
|
|
123
179
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
};
|
|
180
|
+
/**
|
|
181
|
+
* Persisted storage ids of all sync configs in this replication stream. Parse-free.
|
|
182
|
+
*/
|
|
183
|
+
get storageIds(): ReplicationStreamStorageIds {
|
|
184
|
+
return this.replicationStream.storageIds;
|
|
130
185
|
}
|
|
131
186
|
|
|
132
|
-
setWriteCheckpointMode(
|
|
133
|
-
this.writeCheckpointAPI.setWriteCheckpointMode(
|
|
187
|
+
setWriteCheckpointMode(config: storage.WriteCheckpointModeConfig): void {
|
|
188
|
+
this.writeCheckpointAPI.setWriteCheckpointMode(config);
|
|
134
189
|
}
|
|
135
190
|
|
|
136
|
-
|
|
137
|
-
|
|
191
|
+
createManagedWriteCheckpoints(
|
|
192
|
+
checkpoints: storage.ManagedWriteCheckpointOptions[]
|
|
193
|
+
): Promise<storage.CreateManagedWriteCheckpointsResult> {
|
|
194
|
+
return this.writeCheckpointAPI.createManagedWriteCheckpoints(checkpoints);
|
|
138
195
|
}
|
|
139
196
|
|
|
140
197
|
lastWriteCheckpoint(filters: storage.SyncStorageLastWriteCheckpointFilters): Promise<bigint | null> {
|
|
141
198
|
return this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
142
199
|
...filters,
|
|
143
|
-
sync_rules_id: this.
|
|
200
|
+
sync_rules_id: this.replicationStreamId
|
|
144
201
|
});
|
|
145
202
|
}
|
|
146
203
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
|
|
204
|
+
getParsedSyncConfigSet(options: storage.ParseSyncConfigOptions): MongoParsedSyncConfigSet {
|
|
205
|
+
let parsed = this.parsedSyncConfigSets.get(options.defaultSchema);
|
|
206
|
+
if (parsed == null) {
|
|
207
|
+
parsed = this.replicationStream.parsed(options);
|
|
208
|
+
this.parsedSyncConfigSets.set(options.defaultSchema, parsed);
|
|
151
209
|
}
|
|
210
|
+
return parsed;
|
|
211
|
+
}
|
|
152
212
|
|
|
153
|
-
|
|
213
|
+
getParsedSyncRules(options: storage.ParseSyncConfigOptions): HydratedSyncConfig {
|
|
214
|
+
return this.getParsedSyncConfigSet(options).hydratedSyncConfig;
|
|
154
215
|
}
|
|
155
216
|
|
|
156
217
|
async getCheckpoint(): Promise<storage.ReplicationCheckpoint> {
|
|
157
218
|
return (await this.getCheckpointInternal()) ?? new EmptyReplicationCheckpoint();
|
|
158
219
|
}
|
|
159
220
|
|
|
160
|
-
protected abstract fetchCheckpointState(
|
|
161
|
-
session: mongo.ClientSession
|
|
162
|
-
): Promise<{ checkpoint: bigint; lsn: string | null } | null>;
|
|
221
|
+
protected abstract fetchCheckpointState(session: mongo.ClientSession): Promise<MongoCheckpointState | null>;
|
|
163
222
|
|
|
164
223
|
async getCheckpointInternal(): Promise<storage.ReplicationCheckpoint | null> {
|
|
165
224
|
return await this.db.client.withSession({ snapshot: true }, async (session) => {
|
|
@@ -169,10 +228,21 @@ export abstract class MongoSyncBucketStorage
|
|
|
169
228
|
}
|
|
170
229
|
|
|
171
230
|
const snapshotTime = (session as any).snapshotTime as bson.Timestamp | undefined;
|
|
231
|
+
const clusterTime = session.clusterTime;
|
|
172
232
|
if (snapshotTime == null) {
|
|
173
233
|
throw new ServiceAssertionError('Missing snapshotTime in getCheckpoint()');
|
|
174
234
|
}
|
|
175
|
-
|
|
235
|
+
if (clusterTime == null) {
|
|
236
|
+
throw new ServiceAssertionError('Missing clusterTime in getCheckpoint()');
|
|
237
|
+
}
|
|
238
|
+
return new MongoReplicationCheckpoint(
|
|
239
|
+
this,
|
|
240
|
+
state.checkpoint,
|
|
241
|
+
state.lsn,
|
|
242
|
+
snapshotTime,
|
|
243
|
+
clusterTime,
|
|
244
|
+
state.parameterChangesInvalidBefore
|
|
245
|
+
);
|
|
176
246
|
});
|
|
177
247
|
}
|
|
178
248
|
|
|
@@ -183,37 +253,43 @@ export abstract class MongoSyncBucketStorage
|
|
|
183
253
|
return;
|
|
184
254
|
}
|
|
185
255
|
|
|
186
|
-
await this.db.initializeStreamStorage(this.
|
|
256
|
+
await this.db.initializeStreamStorage(this.replicationStreamId);
|
|
187
257
|
await this.initializeVersionStorage();
|
|
188
258
|
this.#storageInitialized = true;
|
|
189
259
|
}
|
|
190
260
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const state = await this.getWriterSyncState();
|
|
261
|
+
/**
|
|
262
|
+
* Create the version-specific writer. Implementations fetch their own resume state
|
|
263
|
+
* (e.g. resume LSN, v1 keepalive op) and construct the batch from
|
|
264
|
+
* {@link writerBatchOptions} plus the version-specific fields.
|
|
265
|
+
*/
|
|
266
|
+
protected abstract createWriterImpl(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch>;
|
|
198
267
|
|
|
199
|
-
|
|
268
|
+
/**
|
|
269
|
+
* The version-independent part of the batch options.
|
|
270
|
+
*/
|
|
271
|
+
protected writerBatchOptions(options: storage.CreateWriterOptions): Omit<MongoBucketBatchOptions, 'resumeFromLsn'> {
|
|
272
|
+
return {
|
|
200
273
|
logger: options.logger ?? this.logger,
|
|
201
274
|
db: this.db,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
slotName: this.slot_name,
|
|
206
|
-
lastCheckpointLsn: state.lastCheckpointLsn,
|
|
207
|
-
resumeFromLsn: state.resumeFromLsn,
|
|
208
|
-
keepaliveOp: state.keepaliveOp,
|
|
275
|
+
parsedSyncConfig: this.getParsedSyncConfigSet(options),
|
|
276
|
+
replicationStreamId: this.replicationStreamId,
|
|
277
|
+
replicationStreamName: this.replicationStreamName,
|
|
209
278
|
storeCurrentData: options.storeCurrentData,
|
|
210
279
|
skipExistingRows: options.skipExistingRows ?? false,
|
|
211
280
|
markRecordUnavailable: options.markRecordUnavailable,
|
|
212
281
|
hooks: options.hooks,
|
|
213
|
-
|
|
214
|
-
|
|
282
|
+
tracer: options.tracer,
|
|
283
|
+
signal: options.signal,
|
|
284
|
+
objectStorage: this.objectStorage,
|
|
285
|
+
inlineThresholdBytes: this.inlineThresholdBytes
|
|
215
286
|
};
|
|
216
|
-
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async createWriter(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
|
|
290
|
+
await this.initializeStorage();
|
|
291
|
+
|
|
292
|
+
const writer = await this.createWriterImpl(options);
|
|
217
293
|
this.iterateListeners((cb) => cb.batchStarted?.(writer));
|
|
218
294
|
return writer;
|
|
219
295
|
}
|
|
@@ -243,24 +319,31 @@ export abstract class MongoSyncBucketStorage
|
|
|
243
319
|
}
|
|
244
320
|
|
|
245
321
|
protected abstract getBucketDataBatchImpl(
|
|
246
|
-
checkpoint:
|
|
322
|
+
checkpoint: MongoReplicationCheckpoint,
|
|
247
323
|
dataBuckets: storage.BucketDataRequest[],
|
|
248
324
|
options?: storage.BucketDataBatchOptions
|
|
249
|
-
): AsyncIterable<storage.SyncBucketDataChunk>;
|
|
325
|
+
): AsyncIterable<storage.SyncBucketDataChunk | storage.SyncBucketDataBatchEnd>;
|
|
250
326
|
|
|
251
327
|
async *getBucketDataBatch(
|
|
252
|
-
checkpoint:
|
|
328
|
+
checkpoint: storage.ReplicationCheckpoint,
|
|
253
329
|
dataBuckets: storage.BucketDataRequest[],
|
|
254
330
|
options?: storage.BucketDataBatchOptions
|
|
255
|
-
): AsyncIterable<storage.SyncBucketDataChunk> {
|
|
256
|
-
yield* this.getBucketDataBatchImpl(checkpoint, dataBuckets, options);
|
|
331
|
+
): AsyncIterable<storage.SyncBucketDataChunk | storage.SyncBucketDataBatchEnd> {
|
|
332
|
+
yield* this.getBucketDataBatchImpl(checkpoint as MongoReplicationCheckpoint, dataBuckets, options);
|
|
257
333
|
}
|
|
258
334
|
|
|
259
335
|
async getChecksums(
|
|
260
|
-
checkpoint:
|
|
261
|
-
buckets: storage.BucketChecksumRequest[]
|
|
336
|
+
checkpoint: storage.ReplicationCheckpoint,
|
|
337
|
+
buckets: storage.BucketChecksumRequest[],
|
|
338
|
+
options?: storage.BucketChecksumOptions
|
|
262
339
|
): Promise<utils.ChecksumMap> {
|
|
263
|
-
|
|
340
|
+
const mongoCheckpoint = checkpoint as MongoReplicationCheckpoint;
|
|
341
|
+
const snapshotTime = mongoCheckpoint.snapshotTime; // May be undefined in tests
|
|
342
|
+
return this.checksums.getChecksums(checkpoint.checkpoint, buckets, {
|
|
343
|
+
snapshotTime,
|
|
344
|
+
clusterTime: mongoCheckpoint.clusterTime,
|
|
345
|
+
readPreference: options?.requestHint == 'bulk' ? this.readPreference : undefined
|
|
346
|
+
});
|
|
264
347
|
}
|
|
265
348
|
|
|
266
349
|
clearChecksumCache() {
|
|
@@ -277,9 +360,9 @@ export abstract class MongoSyncBucketStorage
|
|
|
277
360
|
await this.db.notifyCheckpoint();
|
|
278
361
|
}
|
|
279
362
|
|
|
280
|
-
protected abstract getStatusImpl(): Promise<storage.
|
|
363
|
+
protected abstract getStatusImpl(): Promise<storage.ReplicationStreamStatus>;
|
|
281
364
|
|
|
282
|
-
async getStatus(): Promise<storage.
|
|
365
|
+
async getStatus(): Promise<storage.ReplicationStreamStatus> {
|
|
283
366
|
return this.getStatusImpl();
|
|
284
367
|
}
|
|
285
368
|
|
|
@@ -292,6 +375,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
292
375
|
protected abstract clearBucketState(signal?: AbortSignal): Promise<void>;
|
|
293
376
|
|
|
294
377
|
protected abstract clearSourceTables(signal?: AbortSignal): Promise<void>;
|
|
378
|
+
protected async clearCustomCheckpointRequests(_signal?: AbortSignal): Promise<void> {}
|
|
295
379
|
protected abstract clearSyncRuleState(): Promise<void>;
|
|
296
380
|
|
|
297
381
|
async clear(options?: storage.ClearStorageOptions): Promise<void> {
|
|
@@ -308,32 +392,16 @@ export abstract class MongoSyncBucketStorage
|
|
|
308
392
|
await this.clearSourceRecords(signal);
|
|
309
393
|
await this.clearBucketState(signal);
|
|
310
394
|
await this.clearSourceTables(signal);
|
|
395
|
+
await this.clearCustomCheckpointRequests(signal);
|
|
311
396
|
|
|
312
397
|
this.#storageInitialized = false;
|
|
313
398
|
}
|
|
314
399
|
|
|
315
|
-
protected async clearDeleteMany(
|
|
316
|
-
label: string,
|
|
317
|
-
operation: () => Promise<mongo.DeleteResult>,
|
|
318
|
-
signal?: AbortSignal
|
|
319
|
-
): Promise<void> {
|
|
320
|
-
await retryOnMongoMaxTimeMSExpired(operation, {
|
|
321
|
-
signal,
|
|
322
|
-
abortMessage: 'Aborted clearing data',
|
|
323
|
-
retryDelayMs: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS / 5,
|
|
324
|
-
onRetry: () => {
|
|
325
|
-
this.logger.info(
|
|
326
|
-
`Cleared batch of ${label} in ${lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS}ms, continuing...`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
400
|
async reportError(e: any): Promise<void> {
|
|
333
401
|
const message = String(e.message ?? 'Replication failure');
|
|
334
402
|
await this.db.sync_rules.updateOne(
|
|
335
403
|
{
|
|
336
|
-
_id: this.
|
|
404
|
+
_id: this.replicationStreamId
|
|
337
405
|
},
|
|
338
406
|
{
|
|
339
407
|
$set: {
|
|
@@ -347,32 +415,29 @@ export abstract class MongoSyncBucketStorage
|
|
|
347
415
|
async compact(options?: storage.CompactOptions) {
|
|
348
416
|
let maxOpId = options?.maxOpId;
|
|
349
417
|
if (maxOpId == null) {
|
|
418
|
+
// For PROCESSING streams, this will be undefined.
|
|
350
419
|
const checkpoint = await this.getCheckpointInternal();
|
|
351
420
|
maxOpId = checkpoint?.checkpoint ?? undefined;
|
|
352
421
|
}
|
|
353
422
|
await this.createMongoCompactor({ ...options, maxOpId, logger: this.logger }).compact();
|
|
354
423
|
|
|
355
|
-
if (maxOpId != null && options?.compactParameterData) {
|
|
356
|
-
|
|
424
|
+
if (maxOpId != null && options?.compactParameterData && this.replicationStream.state == SyncRuleState.ACTIVE) {
|
|
425
|
+
// Use the stream-scoped logger, matching bucket compaction above.
|
|
426
|
+
await this.createMongoParameterCompactor(maxOpId, { ...options, logger: this.logger }).compact();
|
|
357
427
|
}
|
|
358
428
|
}
|
|
359
429
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const compactor = this.createMongoCompactor({
|
|
364
|
-
...options,
|
|
365
|
-
memoryLimitMB: 0,
|
|
366
|
-
logger: this.logger
|
|
367
|
-
});
|
|
430
|
+
abstract compactInitialReplication(
|
|
431
|
+
options: CompactInitialReplicationOptions
|
|
432
|
+
): Promise<CompactInitialReplicationResults>;
|
|
368
433
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
434
|
+
/**
|
|
435
|
+
* The highest op id persisted for this stream, whether or not covered by a checkpoint.
|
|
436
|
+
*
|
|
437
|
+
* Used as the default `maxOpId` for {@link compactInitialReplication}, which runs after
|
|
438
|
+
* initial replication but before the first checkpoint exists.
|
|
439
|
+
*/
|
|
440
|
+
protected abstract fetchPersistedOpHead(): Promise<InternalOpId | null>;
|
|
376
441
|
|
|
377
442
|
private async *watchActiveCheckpoint(signal: AbortSignal): AsyncIterable<ReplicationCheckpoint> {
|
|
378
443
|
if (signal.aborted) {
|
|
@@ -413,7 +478,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
413
478
|
for await (const nextCheckpoint of iter) {
|
|
414
479
|
if (nextCheckpoint.lsn != null && !queriedInitialWriteCheckpoint) {
|
|
415
480
|
writeCheckpoint = await this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
416
|
-
sync_rules_id: this.
|
|
481
|
+
sync_rules_id: this.replicationStreamId,
|
|
417
482
|
user_id: options.user_id,
|
|
418
483
|
heads: {
|
|
419
484
|
'1': nextCheckpoint.lsn
|
|
@@ -446,7 +511,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
446
511
|
let updatedWriteCheckpoint = updates.updatedWriteCheckpoints.get(options.user_id) ?? null;
|
|
447
512
|
if (updates.invalidateWriteCheckpoints) {
|
|
448
513
|
updatedWriteCheckpoint = await this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
449
|
-
sync_rules_id: this.
|
|
514
|
+
sync_rules_id: this.replicationStreamId,
|
|
450
515
|
user_id: options.user_id,
|
|
451
516
|
heads: {
|
|
452
517
|
'1': nextCheckpoint.lsn!
|
|
@@ -550,13 +615,31 @@ export abstract class MongoSyncBucketStorage
|
|
|
550
615
|
}
|
|
551
616
|
|
|
552
617
|
protected abstract getParameterBucketChangesImpl(
|
|
553
|
-
options:
|
|
618
|
+
options: MongoGetCheckpointChangesOptions
|
|
554
619
|
): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>>;
|
|
555
620
|
|
|
556
621
|
private async getParameterBucketChanges(
|
|
557
622
|
options: GetCheckpointChangesOptions
|
|
558
623
|
): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
|
|
559
|
-
|
|
624
|
+
const nextCheckpoint = requireMongoCheckpoint(options.nextCheckpoint);
|
|
625
|
+
if (options.lastCheckpoint.checkpoint < nextCheckpoint.parameterChangesInvalidBefore) {
|
|
626
|
+
// Parameter compaction may have deleted parameter entries in the range we'd have to query
|
|
627
|
+
// to find the individual changed lookups. Invalidate all parameter buckets instead.
|
|
628
|
+
//
|
|
629
|
+
// The fence is committed before the first delete of a compaction pass, and captured in the
|
|
630
|
+
// same snapshot as the checkpoint, so a checkpoint that could miss a deleted entry always
|
|
631
|
+
// observes the fence as well.
|
|
632
|
+
return {
|
|
633
|
+
invalidateParameterBuckets: true,
|
|
634
|
+
updatedParameterLookups: new Set<string>()
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
// The query below runs at the checkpoint snapshot, which still sees entries deleted by a
|
|
638
|
+
// compaction pass that started after the snapshot.
|
|
639
|
+
return this.getParameterBucketChangesImpl({
|
|
640
|
+
lastCheckpoint: options.lastCheckpoint,
|
|
641
|
+
nextCheckpoint
|
|
642
|
+
});
|
|
560
643
|
}
|
|
561
644
|
|
|
562
645
|
private checkpointChangesCache = new LRUCache<
|
|
@@ -566,6 +649,9 @@ export abstract class MongoSyncBucketStorage
|
|
|
566
649
|
>({
|
|
567
650
|
max: 50,
|
|
568
651
|
maxSize: 12 * 1024 * 1024,
|
|
652
|
+
// When we have more fetches than the cache size, complete the fetches instead
|
|
653
|
+
// of failing with Error('evicted').
|
|
654
|
+
ignoreFetchAbort: true,
|
|
569
655
|
sizeCalculation: (value: InternalCheckpointChanges) => {
|
|
570
656
|
const paramSize = [...value.updatedParameterLookups].reduce<number>((a, b) => a + b.length, 0);
|
|
571
657
|
const bucketSize = [...value.updatedDataBuckets].reduce<number>((a, b) => a + b.length, 0);
|
|
@@ -578,7 +664,10 @@ export abstract class MongoSyncBucketStorage
|
|
|
578
664
|
});
|
|
579
665
|
|
|
580
666
|
async getCheckpointChanges(options: GetCheckpointChangesOptions): Promise<InternalCheckpointChanges> {
|
|
581
|
-
|
|
667
|
+
// The invalidation fence is part of the identity: the same checkpoint pair read before and
|
|
668
|
+
// after a compaction pass produces different results (specific lookups vs. invalidate-all).
|
|
669
|
+
const fence = requireMongoCheckpoint(options.nextCheckpoint).parameterChangesInvalidBefore;
|
|
670
|
+
const key = `${options.lastCheckpoint.checkpoint}_${options.lastCheckpoint.lsn}__${options.nextCheckpoint.checkpoint}_${options.nextCheckpoint.lsn}_${fence}`;
|
|
582
671
|
const result = await this.checkpointChangesCache.fetch(key, { context: { options } });
|
|
583
672
|
return result!;
|
|
584
673
|
}
|
|
@@ -596,14 +685,29 @@ export abstract class MongoSyncBucketStorage
|
|
|
596
685
|
}
|
|
597
686
|
}
|
|
598
687
|
|
|
599
|
-
|
|
688
|
+
/**
|
|
689
|
+
* We don't support any other constructions of ReplicationCheckpoint.
|
|
690
|
+
*/
|
|
691
|
+
function requireMongoCheckpoint(checkpoint: ReplicationCheckpoint): MongoReplicationCheckpoint {
|
|
692
|
+
if (!(checkpoint instanceof MongoReplicationCheckpoint)) {
|
|
693
|
+
throw new ServiceAssertionError(
|
|
694
|
+
`Checkpoint changes require a checkpoint from getCheckpointInternal(), got ${checkpoint.constructor.name}`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
return checkpoint;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
class MongoReplicationCheckpoint implements MongoSyncBucketStorageCheckpoint {
|
|
600
701
|
#storage: MongoSyncBucketStorage;
|
|
601
702
|
|
|
602
703
|
constructor(
|
|
603
704
|
storage: MongoSyncBucketStorage,
|
|
604
705
|
public readonly checkpoint: InternalOpId,
|
|
605
706
|
public readonly lsn: string | null,
|
|
606
|
-
public snapshotTime: mongo.Timestamp
|
|
707
|
+
public snapshotTime: mongo.Timestamp,
|
|
708
|
+
public clusterTime: mongo.ClusterTime,
|
|
709
|
+
/** Captured in the same snapshot as the checkpoint. */
|
|
710
|
+
public readonly parameterChangesInvalidBefore: InternalOpId
|
|
607
711
|
) {
|
|
608
712
|
this.#storage = storage;
|
|
609
713
|
}
|
|
@@ -613,11 +717,15 @@ class MongoReplicationCheckpoint implements ReplicationCheckpoint {
|
|
|
613
717
|
}
|
|
614
718
|
}
|
|
615
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Used when no checkpoint has been persisted yet. This has no snapshot or invalidation fence, so
|
|
722
|
+
* it cannot be used for checkpoint change detection - see {@link requireMongoCheckpoint}.
|
|
723
|
+
*/
|
|
616
724
|
class EmptyReplicationCheckpoint implements ReplicationCheckpoint {
|
|
617
725
|
readonly checkpoint: InternalOpId = 0n;
|
|
618
726
|
readonly lsn: string | null = null;
|
|
619
727
|
|
|
620
|
-
async getParameterSets(_lookups: ScopedParameterLookup[]): Promise<ParameterLookupRows[]> {
|
|
728
|
+
async getParameterSets(_lookups: ScopedParameterLookup[], _limit: number): Promise<ParameterLookupRows[]> {
|
|
621
729
|
return [];
|
|
622
730
|
}
|
|
623
731
|
}
|