@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
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
EventDefinitionId,
|
|
4
|
+
HydratedEventDescriptor,
|
|
5
|
+
HydratedSyncConfig,
|
|
6
|
+
SqliteRow,
|
|
7
|
+
SqliteValue
|
|
8
|
+
} from '@powersync/service-sync-rules';
|
|
3
9
|
import * as bson from 'bson';
|
|
4
10
|
|
|
5
11
|
import {
|
|
@@ -12,6 +18,7 @@ import {
|
|
|
12
18
|
ServiceError
|
|
13
19
|
} from '@powersync/lib-services-framework';
|
|
14
20
|
import {
|
|
21
|
+
BucketDefinitionMapping,
|
|
15
22
|
BucketStorageMarkRecordUnavailable,
|
|
16
23
|
deserializeBson,
|
|
17
24
|
InternalOpId,
|
|
@@ -23,14 +30,15 @@ import {
|
|
|
23
30
|
} from '@powersync/service-core';
|
|
24
31
|
import * as timers from 'node:timers/promises';
|
|
25
32
|
import { mongoTableId } from '../../utils/util.js';
|
|
26
|
-
import { BucketDefinitionMapping } from './BucketDefinitionMapping.js';
|
|
27
33
|
import { PersistedBatch } from './common/PersistedBatch.js';
|
|
28
34
|
import { LoadedSourceRecord, SourceRecordStore } from './common/SourceRecordStore.js';
|
|
29
35
|
import type { VersionedPowerSyncMongo } from './db.js';
|
|
30
36
|
import { MAX_ROW_SIZE } from './MongoBucketBatchShared.js';
|
|
31
37
|
import { MongoIdSequence } from './MongoIdSequence.js';
|
|
32
|
-
import {
|
|
38
|
+
import { MongoParsedSyncConfigSet } from './MongoParsedSyncConfigSet.js';
|
|
33
39
|
import { OperationBatch, RecordOperation } from './OperationBatch.js';
|
|
40
|
+
import { ObjectStorage } from './v3/object-storage/ObjectStorage.js';
|
|
41
|
+
import { createObjectStorageUsageWriterId } from './v3/object-storage/ObjectStorageUsage.js';
|
|
34
42
|
|
|
35
43
|
// Currently, we can only have a single flush() at a time, since it locks the op_id sequence.
|
|
36
44
|
// While the MongoDB transaction retry mechanism handles this okay, using an in-process Mutex
|
|
@@ -41,15 +49,25 @@ const replicationMutex = new utils.Mutex();
|
|
|
41
49
|
|
|
42
50
|
export interface MongoBucketBatchOptions {
|
|
43
51
|
db: VersionedPowerSyncMongo;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
/**
|
|
53
|
+
* The parsed sync config set for this batch.
|
|
54
|
+
*
|
|
55
|
+
* The batch derives both the hydrated sync rules and the bucket definition mapping from
|
|
56
|
+
* this single set, so they always come from the same parse. Do not add separate
|
|
57
|
+
* syncRules/mapping options - pairing values from different parses is exactly the bug
|
|
58
|
+
* this shape prevents.
|
|
59
|
+
*/
|
|
60
|
+
parsedSyncConfig: MongoParsedSyncConfigSet;
|
|
61
|
+
replicationStreamId: number;
|
|
62
|
+
replicationStreamName: string;
|
|
63
|
+
syncConfigIds?: bson.ObjectId[];
|
|
64
|
+
/**
|
|
65
|
+
* Seeds the in-memory persisted-op tracking for v1 storage. Not used by v3 storage, which
|
|
66
|
+
* tracks the persisted-op head durably on the replication stream document instead.
|
|
67
|
+
*/
|
|
68
|
+
keepaliveOp?: InternalOpId | null;
|
|
50
69
|
resumeFromLsn: string | null;
|
|
51
70
|
storeCurrentData: boolean;
|
|
52
|
-
mapping: BucketDefinitionMapping;
|
|
53
71
|
/**
|
|
54
72
|
* Set to true for initial replication.
|
|
55
73
|
*/
|
|
@@ -60,6 +78,13 @@ export interface MongoBucketBatchOptions {
|
|
|
60
78
|
|
|
61
79
|
logger: Logger;
|
|
62
80
|
tracer?: PerformanceTracer<'storage' | 'evaluate'>;
|
|
81
|
+
/**
|
|
82
|
+
* Aborts in-flight object storage uploads when replication stops.
|
|
83
|
+
*/
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
|
|
86
|
+
objectStorage?: ObjectStorage;
|
|
87
|
+
inlineThresholdBytes?: number;
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
export abstract class MongoBucketBatch
|
|
@@ -70,35 +95,34 @@ export abstract class MongoBucketBatch
|
|
|
70
95
|
protected logger: Logger;
|
|
71
96
|
|
|
72
97
|
private readonly client: mongo.MongoClient;
|
|
73
|
-
|
|
98
|
+
readonly db: VersionedPowerSyncMongo;
|
|
74
99
|
public readonly session: mongo.ClientSession;
|
|
75
100
|
protected readonly sync_rules: HydratedSyncConfig;
|
|
76
101
|
|
|
77
|
-
protected readonly
|
|
102
|
+
protected readonly replicationStreamId: number;
|
|
78
103
|
|
|
79
|
-
private readonly
|
|
104
|
+
private readonly replicationStreamName: string;
|
|
105
|
+
/**
|
|
106
|
+
* Source-level setting for whether raw row data should be stored in current_data.
|
|
107
|
+
*
|
|
108
|
+
* Some sources always send complete rows (MongoDB, MySQL with binlog_row_image=full),
|
|
109
|
+
* in which case this is false for the whole batch. For sources where it depends on the
|
|
110
|
+
* table (Postgres REPLICA IDENTITY), this is true and the decision is refined per-table
|
|
111
|
+
* via SourceTable.storeCurrentData. The effective per-record value is the conjunction of
|
|
112
|
+
* the two.
|
|
113
|
+
*/
|
|
80
114
|
private readonly storeCurrentData: boolean;
|
|
81
115
|
public readonly skipExistingRows: boolean;
|
|
82
116
|
protected readonly mapping: BucketDefinitionMapping;
|
|
117
|
+
protected readonly objectStorageUsageWriterId = createObjectStorageUsageWriterId();
|
|
83
118
|
|
|
84
119
|
private batch: OperationBatch | null = null;
|
|
85
|
-
|
|
120
|
+
protected write_checkpoint_batch: storage.CustomWriteCheckpointOptions[] = [];
|
|
86
121
|
private markRecordUnavailable: BucketStorageMarkRecordUnavailable | undefined;
|
|
87
122
|
private hooks: storage.StorageHooks | undefined;
|
|
88
123
|
private clearedError = false;
|
|
89
124
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Last LSN received associated with a checkpoint.
|
|
94
|
-
*
|
|
95
|
-
* This could be either:
|
|
96
|
-
* 1. A commit LSN.
|
|
97
|
-
* 2. A keepalive message LSN.
|
|
98
|
-
*/
|
|
99
|
-
protected last_checkpoint_lsn: string | null = null;
|
|
100
|
-
|
|
101
|
-
protected persisted_op: InternalOpId | null = null;
|
|
125
|
+
protected tracer: PerformanceTracer<'storage' | 'evaluate'>;
|
|
102
126
|
|
|
103
127
|
/**
|
|
104
128
|
* Last written op, if any. This may not reflect a consistent checkpoint.
|
|
@@ -106,9 +130,9 @@ export abstract class MongoBucketBatch
|
|
|
106
130
|
public last_flushed_op: InternalOpId | null = null;
|
|
107
131
|
|
|
108
132
|
/**
|
|
109
|
-
*
|
|
133
|
+
* LSN to resume replication from.
|
|
110
134
|
*
|
|
111
|
-
*
|
|
135
|
+
* This is typically the last commit LSN, but there are cases where it differs:
|
|
112
136
|
* 1. After an initial snapshot, we don't have a consistent commit yet, but need to resume from the snapshot LSN.
|
|
113
137
|
* 2. If "no_checkpoint_before_lsn" is set far in advance, it may take a while to reach that point. We
|
|
114
138
|
* may want to resume at incremental points before that.
|
|
@@ -123,34 +147,28 @@ export abstract class MongoBucketBatch
|
|
|
123
147
|
this.options = options;
|
|
124
148
|
this.client = options.db.client;
|
|
125
149
|
this.db = options.db;
|
|
126
|
-
this.
|
|
127
|
-
this.last_checkpoint_lsn = options.lastCheckpointLsn;
|
|
150
|
+
this.replicationStreamId = options.replicationStreamId;
|
|
128
151
|
this.resumeFromLsn = options.resumeFromLsn;
|
|
129
152
|
this.session = this.client.startSession();
|
|
130
|
-
this.
|
|
131
|
-
this.sync_rules = options.
|
|
153
|
+
this.replicationStreamName = options.replicationStreamName;
|
|
154
|
+
this.sync_rules = options.parsedSyncConfig.hydratedSyncConfig;
|
|
132
155
|
this.storeCurrentData = options.storeCurrentData;
|
|
133
|
-
this.mapping = options.mapping;
|
|
156
|
+
this.mapping = options.parsedSyncConfig.mapping;
|
|
134
157
|
this.skipExistingRows = options.skipExistingRows;
|
|
135
158
|
this.markRecordUnavailable = options.markRecordUnavailable;
|
|
136
159
|
this.hooks = options.hooks;
|
|
137
160
|
this.batch = new OperationBatch();
|
|
138
161
|
|
|
139
|
-
this.persisted_op = options.keepaliveOp ?? null;
|
|
140
162
|
this.tracer = options.tracer ?? new PerformanceTracer('MongoDB storage');
|
|
141
163
|
}
|
|
142
164
|
|
|
143
165
|
addCustomWriteCheckpoint(checkpoint: storage.BatchedCustomWriteCheckpointOptions): void {
|
|
144
166
|
this.write_checkpoint_batch.push({
|
|
145
167
|
...checkpoint,
|
|
146
|
-
sync_rules_id: this.
|
|
168
|
+
sync_rules_id: this.replicationStreamId
|
|
147
169
|
});
|
|
148
170
|
}
|
|
149
171
|
|
|
150
|
-
get lastCheckpointLsn() {
|
|
151
|
-
return this.last_checkpoint_lsn;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
172
|
abstract resolveTables(options: storage.ResolveTablesOptions): Promise<storage.ResolveTablesResult>;
|
|
155
173
|
|
|
156
174
|
protected abstract createPersistedBatch(writtenSize: number): PersistedBatch;
|
|
@@ -178,6 +196,11 @@ export abstract class MongoBucketBatch
|
|
|
178
196
|
no_checkpoint_before_lsn?: string
|
|
179
197
|
): Promise<storage.SourceTable[]>;
|
|
180
198
|
|
|
199
|
+
protected abstract batchCreateCustomWriteCheckpoints(session: mongo.ClientSession, opId: InternalOpId): Promise<void>;
|
|
200
|
+
|
|
201
|
+
/** Perform any version-specific setup required before writing custom checkpoints. */
|
|
202
|
+
protected async prepareCustomWriteCheckpoints(): Promise<void> {}
|
|
203
|
+
|
|
181
204
|
async flush(options?: storage.BatchBucketFlushOptions): Promise<storage.FlushedResult | null> {
|
|
182
205
|
let result: storage.FlushedResult | null = null;
|
|
183
206
|
// One flush may be split over multiple transactions.
|
|
@@ -195,25 +218,37 @@ export abstract class MongoBucketBatch
|
|
|
195
218
|
const batch = this.batch;
|
|
196
219
|
let last_op: InternalOpId | null = null;
|
|
197
220
|
let resumeBatch: OperationBatch | null = null;
|
|
221
|
+
let clearedError = false;
|
|
198
222
|
|
|
199
223
|
using _ = this.tracer.span('storage', 'flush');
|
|
200
224
|
|
|
201
225
|
await this.hooks?.beforeBatchFlush?.(this);
|
|
226
|
+
if (this.write_checkpoint_batch.length > 0) {
|
|
227
|
+
// Collection/index creation cannot run inside the replication transaction.
|
|
228
|
+
await this.prepareCustomWriteCheckpoints();
|
|
229
|
+
}
|
|
202
230
|
|
|
203
231
|
await this.withReplicationTransaction(`Flushing ${batch?.length ?? 0} ops`, async (session, opSeq) => {
|
|
232
|
+
clearedError = false;
|
|
204
233
|
if (batch != null) {
|
|
205
|
-
|
|
234
|
+
const result = await this.replicateBatch(session, batch, opSeq, options);
|
|
235
|
+
resumeBatch = result.resumeBatch;
|
|
236
|
+
clearedError ||= result.clearedError;
|
|
206
237
|
}
|
|
207
238
|
|
|
208
239
|
if (this.write_checkpoint_batch.length > 0) {
|
|
209
240
|
this.logger.info(`Writing ${this.write_checkpoint_batch.length} custom write checkpoints`);
|
|
210
|
-
await batchCreateCustomWriteCheckpoints(
|
|
241
|
+
await this.batchCreateCustomWriteCheckpoints(session, opSeq.next());
|
|
211
242
|
this.write_checkpoint_batch = [];
|
|
212
243
|
}
|
|
213
244
|
|
|
214
245
|
last_op = opSeq.last();
|
|
215
246
|
});
|
|
216
247
|
|
|
248
|
+
if (clearedError) {
|
|
249
|
+
this.clearedError = true;
|
|
250
|
+
}
|
|
251
|
+
|
|
217
252
|
// null if done, set if we need another flush
|
|
218
253
|
this.batch = resumeBatch;
|
|
219
254
|
|
|
@@ -221,7 +256,7 @@ export abstract class MongoBucketBatch
|
|
|
221
256
|
throw new ReplicationAssertionError('Unexpected last_op == null');
|
|
222
257
|
}
|
|
223
258
|
|
|
224
|
-
this.
|
|
259
|
+
this.recordPersistedOp(last_op);
|
|
225
260
|
this.last_flushed_op = last_op;
|
|
226
261
|
await this.hooks?.afterBatchFlush?.(this);
|
|
227
262
|
return { flushed_op: last_op };
|
|
@@ -232,11 +267,15 @@ export abstract class MongoBucketBatch
|
|
|
232
267
|
batch: OperationBatch,
|
|
233
268
|
op_seq: MongoIdSequence,
|
|
234
269
|
options?: storage.BucketBatchCommitOptions
|
|
235
|
-
): Promise<OperationBatch | null> {
|
|
270
|
+
): Promise<{ resumeBatch: OperationBatch | null; clearedError: boolean }> {
|
|
236
271
|
let sizes: Map<string, number> | undefined = undefined;
|
|
237
272
|
using _ = this.tracer.span('storage', 'replicate_batch');
|
|
238
|
-
if
|
|
239
|
-
|
|
273
|
+
// Only look up current_data sizes if the batch stores current_data and at least one
|
|
274
|
+
// table in it does too (per-table can disable it, e.g. Postgres REPLICA IDENTITY FULL).
|
|
275
|
+
const anyTableStoresCurrentData =
|
|
276
|
+
this.storeCurrentData && batch.batch.some((r) => r.record.sourceTable.storeCurrentData);
|
|
277
|
+
if (anyTableStoresCurrentData && !this.skipExistingRows) {
|
|
278
|
+
// We skip this step if no tables store current_data, since the sizes will
|
|
240
279
|
// always be small in that case.
|
|
241
280
|
|
|
242
281
|
// With skipExistingRows, we don't load the full documents into memory,
|
|
@@ -249,10 +288,14 @@ export abstract class MongoBucketBatch
|
|
|
249
288
|
// (automatically limited to 48MB(?) per batch by MongoDB). The issue is that it changes
|
|
250
289
|
// the order of processing, which then becomes really tricky to manage.
|
|
251
290
|
// This now takes 2+ queries, but doesn't have any issues with order of operations.
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
291
|
+
// Within this branch this.storeCurrentData is true, so the per-table flag is the
|
|
292
|
+
// effective value - only look up sizes for tables that actually store current_data.
|
|
293
|
+
const sizeLookups = batch.batch
|
|
294
|
+
.filter((r) => r.record.sourceTable.storeCurrentData)
|
|
295
|
+
.map((r) => ({
|
|
296
|
+
sourceTableId: mongoTableId(r.record.sourceTable.id),
|
|
297
|
+
replicaId: r.beforeId
|
|
298
|
+
}));
|
|
256
299
|
|
|
257
300
|
sizes = await this.sourceRecordStore.loadSizes(session, sizeLookups);
|
|
258
301
|
}
|
|
@@ -329,12 +372,17 @@ export abstract class MongoBucketBatch
|
|
|
329
372
|
}
|
|
330
373
|
}
|
|
331
374
|
|
|
332
|
-
|
|
375
|
+
const clearedError = didFlush && !this.clearedError;
|
|
376
|
+
if (clearedError) {
|
|
377
|
+
// No need to clear an error more than once per batch, since an error would always result in restarting the batch.
|
|
333
378
|
using _ = this.tracer.span('storage', 'clear_error');
|
|
334
|
-
await this.clearError();
|
|
379
|
+
await this.clearError(this.session);
|
|
335
380
|
}
|
|
336
381
|
|
|
337
|
-
return
|
|
382
|
+
return {
|
|
383
|
+
resumeBatch: resumeBatch?.hasData() ? resumeBatch : null,
|
|
384
|
+
clearedError
|
|
385
|
+
};
|
|
338
386
|
}
|
|
339
387
|
|
|
340
388
|
private saveOperation(
|
|
@@ -348,6 +396,9 @@ export abstract class MongoBucketBatch
|
|
|
348
396
|
const afterId = operation.afterId;
|
|
349
397
|
let after = record.after;
|
|
350
398
|
const sourceTable = record.sourceTable;
|
|
399
|
+
// Effective per-record flag: store current_data only if both the batch (source-level,
|
|
400
|
+
// e.g. Postgres) and the table (e.g. non-FULL replica identity) require it.
|
|
401
|
+
const storeCurrentData = this.storeCurrentData && sourceTable.storeCurrentData;
|
|
351
402
|
|
|
352
403
|
let existing_buckets: LoadedSourceRecord['buckets'] = [];
|
|
353
404
|
let new_buckets: LoadedSourceRecord['buckets'] = [];
|
|
@@ -376,7 +427,7 @@ export abstract class MongoBucketBatch
|
|
|
376
427
|
// Not an error if we re-apply a transaction
|
|
377
428
|
existing_buckets = [];
|
|
378
429
|
existing_lookups = [];
|
|
379
|
-
if (!isCompleteRow(
|
|
430
|
+
if (!isCompleteRow(storeCurrentData, after!)) {
|
|
380
431
|
if (this.markRecordUnavailable != null) {
|
|
381
432
|
// This will trigger a "resnapshot" of the record.
|
|
382
433
|
// This is not relevant if storeCurrentData is false, since we'll get the full row
|
|
@@ -392,7 +443,7 @@ export abstract class MongoBucketBatch
|
|
|
392
443
|
} else {
|
|
393
444
|
existing_buckets = result.buckets;
|
|
394
445
|
existing_lookups = result.lookups;
|
|
395
|
-
if (
|
|
446
|
+
if (storeCurrentData && result.data != null) {
|
|
396
447
|
const data = deserializeBson(result.data.buffer) as SqliteRow;
|
|
397
448
|
after = storage.mergeToast<SqliteValue>(after!, data);
|
|
398
449
|
}
|
|
@@ -403,7 +454,9 @@ export abstract class MongoBucketBatch
|
|
|
403
454
|
// Not an error if we re-apply a transaction
|
|
404
455
|
existing_buckets = [];
|
|
405
456
|
existing_lookups = [];
|
|
406
|
-
// Log to help with debugging if there was a consistency issue
|
|
457
|
+
// Log to help with debugging if there was a consistency issue.
|
|
458
|
+
// Gate on the batch-level flag: FULL tables (per-record flag false) still get a
|
|
459
|
+
// current_data entry, so a missing record on DELETE is meaningful for them too.
|
|
407
460
|
if (this.storeCurrentData && this.markRecordUnavailable == null) {
|
|
408
461
|
this.logger.warn(
|
|
409
462
|
`Cannot find previous record for delete on ${record.sourceTable.qualifiedName}: ${beforeId} / ${record.before?.id}`
|
|
@@ -416,7 +469,7 @@ export abstract class MongoBucketBatch
|
|
|
416
469
|
}
|
|
417
470
|
|
|
418
471
|
let afterData: bson.Binary | null = null;
|
|
419
|
-
if (afterId != null && !
|
|
472
|
+
if (afterId != null && !storeCurrentData) {
|
|
420
473
|
afterData = null;
|
|
421
474
|
} else if (afterId != null) {
|
|
422
475
|
try {
|
|
@@ -440,7 +493,7 @@ export abstract class MongoBucketBatch
|
|
|
440
493
|
{
|
|
441
494
|
level: errors.ErrorSeverity.WARNING,
|
|
442
495
|
metadata: {
|
|
443
|
-
replication_slot: this.
|
|
496
|
+
replication_slot: this.replicationStreamName,
|
|
444
497
|
table: record.sourceTable.qualifiedName
|
|
445
498
|
}
|
|
446
499
|
}
|
|
@@ -483,7 +536,7 @@ export abstract class MongoBucketBatch
|
|
|
483
536
|
// However, it will be valid by the end of the transaction.
|
|
484
537
|
//
|
|
485
538
|
// In this case, we don't save the op, but we do save the current data.
|
|
486
|
-
if (afterId && after && utils.isCompleteRow(
|
|
539
|
+
if (afterId && after && utils.isCompleteRow(storeCurrentData, after)) {
|
|
487
540
|
// Insert or update
|
|
488
541
|
if (sourceTable.syncData) {
|
|
489
542
|
const { results, errors: syncErrors } = this.sync_rules.evaluateRowWithErrors({
|
|
@@ -499,7 +552,7 @@ export abstract class MongoBucketBatch
|
|
|
499
552
|
{
|
|
500
553
|
level: errors.ErrorSeverity.WARNING,
|
|
501
554
|
metadata: {
|
|
502
|
-
replication_slot: this.
|
|
555
|
+
replication_slot: this.replicationStreamName,
|
|
503
556
|
table: record.sourceTable.qualifiedName
|
|
504
557
|
}
|
|
505
558
|
}
|
|
@@ -534,7 +587,7 @@ export abstract class MongoBucketBatch
|
|
|
534
587
|
{
|
|
535
588
|
level: errors.ErrorSeverity.WARNING,
|
|
536
589
|
metadata: {
|
|
537
|
-
replication_slot: this.
|
|
590
|
+
replication_slot: this.replicationStreamName,
|
|
538
591
|
table: record.sourceTable.qualifiedName
|
|
539
592
|
}
|
|
540
593
|
}
|
|
@@ -669,7 +722,7 @@ export abstract class MongoBucketBatch
|
|
|
669
722
|
|
|
670
723
|
await this.db.sync_rules.updateOne(
|
|
671
724
|
{
|
|
672
|
-
_id: this.
|
|
725
|
+
_id: this.replicationStreamId
|
|
673
726
|
},
|
|
674
727
|
{
|
|
675
728
|
$set: {
|
|
@@ -678,12 +731,41 @@ export abstract class MongoBucketBatch
|
|
|
678
731
|
},
|
|
679
732
|
{ session }
|
|
680
733
|
);
|
|
734
|
+
|
|
735
|
+
// Allow subclasses to persist additional flush-time state in the same transaction
|
|
736
|
+
// (e.g. v3 advances the stream-level last_persisted_op).
|
|
737
|
+
await this.onReplicationTransactionFlush(session, opSeq.last());
|
|
681
738
|
// We don't notify checkpoint here - we don't make any checkpoint updates directly
|
|
682
739
|
});
|
|
683
740
|
}
|
|
684
741
|
|
|
742
|
+
/**
|
|
743
|
+
* Hook called inside the replication flush transaction, after ops have been persisted.
|
|
744
|
+
*
|
|
745
|
+
* The base implementation does nothing; v3 storage overrides this to `$max` the stream-level
|
|
746
|
+
* `last_persisted_op` durably within the same transaction.
|
|
747
|
+
*/
|
|
748
|
+
protected async onReplicationTransactionFlush(_session: mongo.ClientSession, _lastOp: InternalOpId): Promise<void> {
|
|
749
|
+
// No-op by default (v1 behaviour unchanged).
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Called after a replication transaction has successfully committed, with the last persisted op id.
|
|
754
|
+
*
|
|
755
|
+
* v1 storage tracks this in memory to fold into the next checkpoint. v3 storage does not need it:
|
|
756
|
+
* the stream-level `last_persisted_op` is already advanced durably by
|
|
757
|
+
* {@link onReplicationTransactionFlush} within the same transaction, and checkpoints read it
|
|
758
|
+
* from the document.
|
|
759
|
+
*
|
|
760
|
+
* Keep calls to this adjacent to {@link withReplicationTransaction} usage - both must observe
|
|
761
|
+
* every path that persists ops.
|
|
762
|
+
*/
|
|
763
|
+
protected recordPersistedOp(_lastOp: InternalOpId): void {
|
|
764
|
+
// No-op by default.
|
|
765
|
+
}
|
|
766
|
+
|
|
685
767
|
async [Symbol.asyncDispose]() {
|
|
686
|
-
if (this.batch
|
|
768
|
+
if (this.batch?.hasData() || this.write_checkpoint_batch.length > 0) {
|
|
687
769
|
// We don't error here, since:
|
|
688
770
|
// 1. In error states, this is expected (we can't distinguish between disposing after success or error).
|
|
689
771
|
// 2. SuppressedError is messy to deal with.
|
|
@@ -699,19 +781,27 @@ export abstract class MongoBucketBatch
|
|
|
699
781
|
|
|
700
782
|
async save(record: storage.SaveOptions): Promise<storage.FlushedResult | null> {
|
|
701
783
|
const { after, before, sourceTable, tag } = record;
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
784
|
+
const storeCurrentData = this.storeCurrentData && sourceTable.storeCurrentData;
|
|
785
|
+
// V3 source tables own disjoint event-definition ids for each physical table. Multiple
|
|
786
|
+
// SourceTables may evaluate different events, but each definition is evaluated through
|
|
787
|
+
// at most one record for this row change.
|
|
788
|
+
// Legacy storage leaves eventDefinitionIds undefined and selects by table ref.
|
|
789
|
+
if (sourceTable.syncEvent) {
|
|
790
|
+
for (const { event, eventId } of this.getTableEvents(sourceTable)) {
|
|
791
|
+
this.iterateListeners((cb) =>
|
|
792
|
+
cb.replicationEvent?.({
|
|
793
|
+
batch: this,
|
|
794
|
+
table: sourceTable,
|
|
795
|
+
data: {
|
|
796
|
+
op: tag,
|
|
797
|
+
after: after && utils.isCompleteRow(storeCurrentData, after) ? after : undefined,
|
|
798
|
+
before: before && utils.isCompleteRow(storeCurrentData, before) ? before : undefined
|
|
799
|
+
},
|
|
800
|
+
event,
|
|
801
|
+
event_id: eventId
|
|
802
|
+
})
|
|
803
|
+
);
|
|
804
|
+
}
|
|
715
805
|
}
|
|
716
806
|
|
|
717
807
|
/**
|
|
@@ -744,7 +834,7 @@ export abstract class MongoBucketBatch
|
|
|
744
834
|
|
|
745
835
|
await this.withTransaction(async () => {
|
|
746
836
|
for (let table of sourceTables) {
|
|
747
|
-
await this.db.commonSourceTables(this.
|
|
837
|
+
await this.db.commonSourceTables(this.replicationStreamId).deleteOne({ _id: mongoTableId(table.id) });
|
|
748
838
|
}
|
|
749
839
|
});
|
|
750
840
|
|
|
@@ -761,7 +851,7 @@ export abstract class MongoBucketBatch
|
|
|
761
851
|
}
|
|
762
852
|
|
|
763
853
|
if (last_op) {
|
|
764
|
-
this.
|
|
854
|
+
this.recordPersistedOp(last_op);
|
|
765
855
|
return {
|
|
766
856
|
flushed_op: last_op
|
|
767
857
|
};
|
|
@@ -830,7 +920,7 @@ export abstract class MongoBucketBatch
|
|
|
830
920
|
copy.snapshotStatus = snapshotStatus;
|
|
831
921
|
|
|
832
922
|
await this.withTransaction(async () => {
|
|
833
|
-
await this.db.commonSourceTables(this.
|
|
923
|
+
await this.db.commonSourceTables(this.replicationStreamId).updateOne(
|
|
834
924
|
{ _id: mongoTableId(table.id) },
|
|
835
925
|
{
|
|
836
926
|
$set: {
|
|
@@ -848,32 +938,47 @@ export abstract class MongoBucketBatch
|
|
|
848
938
|
return copy;
|
|
849
939
|
}
|
|
850
940
|
|
|
851
|
-
protected async clearError(): Promise<void> {
|
|
852
|
-
// No need to clear an error more than once per batch, since an error would always result in restarting the batch.
|
|
853
|
-
if (this.clearedError) {
|
|
854
|
-
return;
|
|
855
|
-
}
|
|
856
|
-
|
|
941
|
+
protected async clearError(session: mongo.ClientSession): Promise<void> {
|
|
857
942
|
await this.db.sync_rules.updateOne(
|
|
858
943
|
{
|
|
859
|
-
_id: this.
|
|
944
|
+
_id: this.replicationStreamId
|
|
860
945
|
},
|
|
861
946
|
{
|
|
862
947
|
$set: {
|
|
863
948
|
last_fatal_error: null,
|
|
864
949
|
last_fatal_error_ts: null
|
|
865
950
|
}
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
session
|
|
866
954
|
}
|
|
867
955
|
);
|
|
868
|
-
this.clearedError = true;
|
|
869
956
|
}
|
|
870
957
|
|
|
871
958
|
/**
|
|
872
|
-
* Gets relevant {@link
|
|
959
|
+
* Gets relevant {@link HydratedEventDescriptor}s for the given {@link SourceTable}
|
|
873
960
|
*/
|
|
874
|
-
protected getTableEvents(
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
961
|
+
protected getTableEvents(
|
|
962
|
+
table: storage.SourceTable
|
|
963
|
+
): { event: HydratedEventDescriptor; eventId?: EventDefinitionId }[] {
|
|
964
|
+
// V3 storage assigns event-definition ids to each source table, so membership is authoritative.
|
|
965
|
+
// Iterate the table's distinct ids and resolve each through the stream's deduped event map, so a
|
|
966
|
+
// definition reused across configs has one evaluator for that id. The evaluator may still return
|
|
967
|
+
// multiple payloads from matching queries. Legacy storage leaves this undefined and selects by table ref.
|
|
968
|
+
if (table.eventDefinitionIds != null) {
|
|
969
|
+
const eventById = this.options.parsedSyncConfig.eventById;
|
|
970
|
+
const events: { event: HydratedEventDescriptor; eventId: EventDefinitionId }[] = [];
|
|
971
|
+
for (const id of table.eventDefinitionIds) {
|
|
972
|
+
const event = eventById.get(id);
|
|
973
|
+
if (event != null && event.tableTriggersEvent(table.ref)) {
|
|
974
|
+
events.push({ event, eventId: id });
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return events;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
return this.sync_rules.eventDescriptors
|
|
981
|
+
.filter((event) => event.tableTriggersEvent(table.ref))
|
|
982
|
+
.map((event) => ({ event }));
|
|
878
983
|
}
|
|
879
984
|
}
|