@powersync/service-module-mongodb-storage 0.17.0 → 0.18.1
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 +27 -0
- package/dist/storage/MongoBucketStorage.d.ts +34 -16
- package/dist/storage/MongoBucketStorage.js +219 -70
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +42 -23
- package/dist/storage/implementation/MongoBucketBatch.js +61 -44
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoChecksums.d.ts +10 -9
- package/dist/storage/implementation/MongoChecksums.js +3 -111
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +2 -0
- package/dist/storage/implementation/MongoCompactor.js +18 -9
- 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 +6 -5
- package/dist/storage/implementation/MongoParameterCompactor.js +24 -1
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +13 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +64 -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 +123 -0
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -0
- package/dist/storage/implementation/MongoStorageProvider.js +5 -2
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +41 -23
- package/dist/storage/implementation/MongoSyncBucketStorage.js +51 -43
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.js +3 -3
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +6 -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 +1 -2
- package/dist/storage/implementation/common/PersistedBatch.js +5 -0
- 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.js +9 -14
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +4 -13
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +9 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +42 -26
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoChecksumsV1.js +114 -3
- package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +15 -17
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +47 -45
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.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/v3/MongoBucketBatchV3.d.ts +8 -4
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +286 -259
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +27 -7
- package/dist/storage/implementation/v3/MongoChecksumsV3.js +202 -18
- package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +19 -2
- package/dist/storage/implementation/v3/MongoCompactorV3.js +511 -22
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +62 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +350 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +40 -28
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +232 -116
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +1 -1
- package/dist/storage/implementation/v3/PersistedBatchV3.js +43 -20
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js +52 -16
- package/dist/storage/implementation/v3/SingleBucketStoreV3.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 +13 -12
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +29 -27
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
- package/dist/storage/implementation/v3/bucket-format.d.ts +4 -0
- package/dist/storage/implementation/v3/bucket-format.js +58 -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 +28 -0
- package/dist/storage/implementation/v3/chunking.js.map +1 -0
- package/dist/storage/implementation/v3/models.d.ts +64 -21
- package/dist/storage/implementation/v3/models.js +11 -28
- package/dist/storage/implementation/v3/models.js.map +1 -1
- package/dist/storage/implementation/v3/source-table-utils.d.ts +55 -0
- package/dist/storage/implementation/v3/source-table-utils.js +214 -0
- package/dist/storage/implementation/v3/source-table-utils.js.map +1 -0
- package/dist/storage/storage-index.d.ts +4 -4
- package/dist/storage/storage-index.js +4 -4
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/types/types.d.ts +2 -2
- package/dist/utils/test-utils.d.ts +1 -2
- package/dist/utils/test-utils.js +5 -1
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.d.ts +1 -1
- package/dist/utils/util.js +3 -2
- package/dist/utils/util.js.map +1 -1
- package/package.json +9 -19
- package/src/storage/MongoBucketStorage.ts +334 -87
- package/src/storage/implementation/MongoBucketBatch.ts +86 -58
- package/src/storage/implementation/MongoChecksums.ts +6 -138
- package/src/storage/implementation/MongoCompactor.ts +19 -9
- package/src/storage/implementation/MongoHydrationState.ts +61 -0
- package/src/storage/implementation/MongoParameterCompactor.ts +24 -5
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +88 -0
- package/src/storage/implementation/MongoPersistedReplicationStream.ts +118 -0
- package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +154 -0
- package/src/storage/implementation/MongoStorageProvider.ts +5 -2
- package/src/storage/implementation/MongoSyncBucketStorage.ts +70 -56
- package/src/storage/implementation/MongoSyncRulesLock.ts +7 -4
- package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +7 -0
- package/src/storage/implementation/common/PersistedBatch.ts +7 -3
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +1 -1
- package/src/storage/implementation/createMongoSyncBucketStorage.ts +21 -7
- package/src/storage/implementation/db.ts +11 -19
- package/src/storage/implementation/models.ts +4 -14
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +55 -34
- package/src/storage/implementation/v1/MongoChecksumsV1.ts +137 -4
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +70 -64
- package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +11 -1
- package/src/storage/implementation/v1/models.ts +11 -1
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +358 -314
- package/src/storage/implementation/v3/MongoChecksumsV3.ts +262 -26
- package/src/storage/implementation/v3/MongoCompactorV3.ts +646 -29
- package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +480 -0
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +315 -157
- package/src/storage/implementation/v3/PersistedBatchV3.ts +62 -36
- package/src/storage/implementation/v3/SingleBucketStoreV3.ts +59 -19
- package/src/storage/implementation/v3/SourceRecordStoreV3.ts +12 -12
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +41 -36
- package/src/storage/implementation/v3/bucket-format.ts +70 -0
- package/src/storage/implementation/v3/chunking.ts +38 -0
- package/src/storage/implementation/v3/models.ts +93 -55
- package/src/storage/implementation/v3/source-table-utils.ts +392 -0
- package/src/storage/storage-index.ts +12 -4
- package/src/utils/test-utils.ts +6 -3
- package/src/utils/util.ts +3 -2
- package/test/src/__snapshots__/storage.test.ts.snap +0 -75
- package/test/src/__snapshots__/storage_sync.test.ts.snap +48 -48
- package/test/src/cleanup-stopped-sync-configs.test.ts +648 -0
- package/test/src/storage.test.ts +11 -11
- package/test/src/storage_compacting.test.ts +1956 -6
- package/test/src/storage_sync.test.ts +1077 -68
- package/test/src/storeCurrentData.test.ts +17 -7
- package/test/src/util.ts +2 -1
- 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/v3/MongoParameterCompactorV3.d.ts +0 -9
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +0 -18
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.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/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/v3/MongoParameterCompactorV3.ts +0 -24
- package/src/storage/implementation/v3/MongoParameterLookupV3.ts +0 -11
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
PopulateChecksumCacheOptions,
|
|
18
18
|
PopulateChecksumCacheResults,
|
|
19
19
|
ReplicationCheckpoint,
|
|
20
|
+
ReplicationStreamStorageIds,
|
|
20
21
|
storage,
|
|
21
22
|
utils,
|
|
22
23
|
WatchWriteCheckpointOptions
|
|
@@ -27,18 +28,18 @@ import { LRUCache } from 'lru-cache';
|
|
|
27
28
|
import * as timers from 'timers/promises';
|
|
28
29
|
import { retryOnMongoMaxTimeMSExpired } from '../../utils/util.js';
|
|
29
30
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
30
|
-
import { MongoSyncBucketStorageContext } from './common/MongoSyncBucketStorageContext.js';
|
|
31
31
|
import type { VersionedPowerSyncMongo } from './db.js';
|
|
32
32
|
import { StorageConfig } from './models.js';
|
|
33
33
|
import { MongoBucketBatchOptions } from './MongoBucketBatch.js';
|
|
34
34
|
import { MongoChecksumOptions, MongoChecksums } from './MongoChecksums.js';
|
|
35
35
|
import { MongoCompactOptions, MongoCompactor } from './MongoCompactor.js';
|
|
36
36
|
import { MongoParameterCompactor } from './MongoParameterCompactor.js';
|
|
37
|
-
import {
|
|
37
|
+
import { MongoParsedSyncConfigSet } from './MongoParsedSyncConfigSet.js';
|
|
38
|
+
import { MongoPersistedReplicationStream } from './MongoPersistedReplicationStream.js';
|
|
38
39
|
import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js';
|
|
39
40
|
|
|
40
41
|
export interface MongoSyncBucketStorageOptions {
|
|
41
|
-
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'
|
|
42
|
+
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'>;
|
|
42
43
|
storageConfig: StorageConfig;
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -47,13 +48,6 @@ interface InternalCheckpointChanges extends CheckpointChanges {
|
|
|
47
48
|
invalidateWriteCheckpoints: boolean;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
interface WriterSyncState {
|
|
51
|
-
lastCheckpointLsn: string | null;
|
|
52
|
-
resumeFromLsn: string | null;
|
|
53
|
-
keepaliveOp: InternalOpId | null;
|
|
54
|
-
syncConfigId?: bson.ObjectId | null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
/**
|
|
58
52
|
* Only keep checkpoints around for a minute, before fetching a fresh one.
|
|
59
53
|
*
|
|
@@ -70,11 +64,19 @@ export abstract class MongoSyncBucketStorage
|
|
|
70
64
|
implements storage.SyncRulesBucketStorage
|
|
71
65
|
{
|
|
72
66
|
readonly db: VersionedPowerSyncMongo;
|
|
67
|
+
|
|
73
68
|
[DO_NOT_LOG] = true;
|
|
74
69
|
|
|
75
70
|
readonly checksums: MongoChecksums;
|
|
76
71
|
|
|
77
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Canonical parsed sync config sets, keyed by defaultSchema.
|
|
74
|
+
*
|
|
75
|
+
* Entries are never evicted: each parse options value maps to exactly one parsed set for
|
|
76
|
+
* the lifetime of this storage instance, so parsed source objects and mappings always
|
|
77
|
+
* stay associated.
|
|
78
|
+
*/
|
|
79
|
+
private readonly parsedSyncConfigSets = new Map<string, MongoParsedSyncConfigSet>();
|
|
78
80
|
private writeCheckpointAPI: MongoWriteCheckpointAPI;
|
|
79
81
|
public readonly logger: Logger;
|
|
80
82
|
public readonly storageConfig: StorageConfig;
|
|
@@ -82,9 +84,9 @@ export abstract class MongoSyncBucketStorage
|
|
|
82
84
|
|
|
83
85
|
constructor(
|
|
84
86
|
public readonly factory: MongoBucketStorage,
|
|
85
|
-
public readonly
|
|
86
|
-
|
|
87
|
-
public readonly
|
|
87
|
+
public readonly replicationStreamId: number,
|
|
88
|
+
public readonly replicationStream: MongoPersistedReplicationStream,
|
|
89
|
+
public readonly replicationStreamName: string,
|
|
88
90
|
writeCheckpointMode: storage.WriteCheckpointMode | undefined,
|
|
89
91
|
options: MongoSyncBucketStorageOptions
|
|
90
92
|
) {
|
|
@@ -95,9 +97,9 @@ export abstract class MongoSyncBucketStorage
|
|
|
95
97
|
this.writeCheckpointAPI = new MongoWriteCheckpointAPI({
|
|
96
98
|
db: this.db,
|
|
97
99
|
mode: writeCheckpointMode ?? storage.WriteCheckpointMode.MANAGED,
|
|
98
|
-
sync_rules_id:
|
|
100
|
+
sync_rules_id: replicationStreamId
|
|
99
101
|
});
|
|
100
|
-
this.logger =
|
|
102
|
+
this.logger = replicationStream.logger;
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
/**
|
|
@@ -117,16 +119,11 @@ export abstract class MongoSyncBucketStorage
|
|
|
117
119
|
return this.writeCheckpointAPI.writeCheckpointMode;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
db: this.db,
|
|
127
|
-
group_id: this.group_id,
|
|
128
|
-
mapping: this.mapping
|
|
129
|
-
};
|
|
122
|
+
/**
|
|
123
|
+
* Persisted storage ids of all sync configs in this replication stream. Parse-free.
|
|
124
|
+
*/
|
|
125
|
+
get storageIds(): ReplicationStreamStorageIds {
|
|
126
|
+
return this.replicationStream.storageIds;
|
|
130
127
|
}
|
|
131
128
|
|
|
132
129
|
setWriteCheckpointMode(mode: storage.WriteCheckpointMode): void {
|
|
@@ -140,17 +137,21 @@ export abstract class MongoSyncBucketStorage
|
|
|
140
137
|
lastWriteCheckpoint(filters: storage.SyncStorageLastWriteCheckpointFilters): Promise<bigint | null> {
|
|
141
138
|
return this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
142
139
|
...filters,
|
|
143
|
-
sync_rules_id: this.
|
|
140
|
+
sync_rules_id: this.replicationStreamId
|
|
144
141
|
});
|
|
145
142
|
}
|
|
146
143
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
|
|
144
|
+
getParsedSyncConfigSet(options: storage.ParseSyncConfigOptions): MongoParsedSyncConfigSet {
|
|
145
|
+
let parsed = this.parsedSyncConfigSets.get(options.defaultSchema);
|
|
146
|
+
if (parsed == null) {
|
|
147
|
+
parsed = this.replicationStream.parsed(options);
|
|
148
|
+
this.parsedSyncConfigSets.set(options.defaultSchema, parsed);
|
|
151
149
|
}
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
getParsedSyncRules(options: storage.ParseSyncConfigOptions): HydratedSyncConfig {
|
|
154
|
+
return this.getParsedSyncConfigSet(options).hydratedSyncConfig;
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
async getCheckpoint(): Promise<storage.ReplicationCheckpoint> {
|
|
@@ -183,37 +184,40 @@ export abstract class MongoSyncBucketStorage
|
|
|
183
184
|
return;
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
await this.db.initializeStreamStorage(this.
|
|
187
|
+
await this.db.initializeStreamStorage(this.replicationStreamId);
|
|
187
188
|
await this.initializeVersionStorage();
|
|
188
189
|
this.#storageInitialized = true;
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const state = await this.getWriterSyncState();
|
|
192
|
+
/**
|
|
193
|
+
* Create the version-specific writer. Implementations fetch their own resume state
|
|
194
|
+
* (e.g. resume LSN, v1 keepalive op) and construct the batch from
|
|
195
|
+
* {@link writerBatchOptions} plus the version-specific fields.
|
|
196
|
+
*/
|
|
197
|
+
protected abstract createWriterImpl(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch>;
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
/**
|
|
200
|
+
* The version-independent part of the batch options.
|
|
201
|
+
*/
|
|
202
|
+
protected writerBatchOptions(options: storage.CreateWriterOptions): Omit<MongoBucketBatchOptions, 'resumeFromLsn'> {
|
|
203
|
+
return {
|
|
200
204
|
logger: options.logger ?? this.logger,
|
|
201
205
|
db: this.db,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
slotName: this.slot_name,
|
|
206
|
-
lastCheckpointLsn: state.lastCheckpointLsn,
|
|
207
|
-
resumeFromLsn: state.resumeFromLsn,
|
|
208
|
-
keepaliveOp: state.keepaliveOp,
|
|
206
|
+
parsedSyncConfig: this.getParsedSyncConfigSet(options),
|
|
207
|
+
replicationStreamId: this.replicationStreamId,
|
|
208
|
+
replicationStreamName: this.replicationStreamName,
|
|
209
209
|
storeCurrentData: options.storeCurrentData,
|
|
210
210
|
skipExistingRows: options.skipExistingRows ?? false,
|
|
211
211
|
markRecordUnavailable: options.markRecordUnavailable,
|
|
212
212
|
hooks: options.hooks,
|
|
213
|
-
syncConfigId: state.syncConfigId,
|
|
214
213
|
tracer: options.tracer
|
|
215
214
|
};
|
|
216
|
-
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async createWriter(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
|
|
218
|
+
await this.initializeStorage();
|
|
219
|
+
|
|
220
|
+
const writer = await this.createWriterImpl(options);
|
|
217
221
|
this.iterateListeners((cb) => cb.batchStarted?.(writer));
|
|
218
222
|
return writer;
|
|
219
223
|
}
|
|
@@ -277,9 +281,9 @@ export abstract class MongoSyncBucketStorage
|
|
|
277
281
|
await this.db.notifyCheckpoint();
|
|
278
282
|
}
|
|
279
283
|
|
|
280
|
-
protected abstract getStatusImpl(): Promise<storage.
|
|
284
|
+
protected abstract getStatusImpl(): Promise<storage.ReplicationStreamStatus>;
|
|
281
285
|
|
|
282
|
-
async getStatus(): Promise<storage.
|
|
286
|
+
async getStatus(): Promise<storage.ReplicationStreamStatus> {
|
|
283
287
|
return this.getStatusImpl();
|
|
284
288
|
}
|
|
285
289
|
|
|
@@ -333,7 +337,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
333
337
|
const message = String(e.message ?? 'Replication failure');
|
|
334
338
|
await this.db.sync_rules.updateOne(
|
|
335
339
|
{
|
|
336
|
-
_id: this.
|
|
340
|
+
_id: this.replicationStreamId
|
|
337
341
|
},
|
|
338
342
|
{
|
|
339
343
|
$set: {
|
|
@@ -357,11 +361,21 @@ export abstract class MongoSyncBucketStorage
|
|
|
357
361
|
}
|
|
358
362
|
}
|
|
359
363
|
|
|
364
|
+
/**
|
|
365
|
+
* The highest op id persisted for this stream, whether or not covered by a checkpoint.
|
|
366
|
+
*
|
|
367
|
+
* Used as the default `maxOpId` for {@link populatePersistentChecksumCache}, which runs after
|
|
368
|
+
* initial replication but before the first checkpoint exists.
|
|
369
|
+
*/
|
|
370
|
+
protected abstract fetchPersistedOpHead(): Promise<InternalOpId | null>;
|
|
371
|
+
|
|
360
372
|
async populatePersistentChecksumCache(options: PopulateChecksumCacheOptions): Promise<PopulateChecksumCacheResults> {
|
|
361
373
|
this.logger.info(`Populating persistent checksum cache...`);
|
|
362
374
|
const start = Date.now();
|
|
375
|
+
const maxOpId = options.maxOpId ?? (await this.fetchPersistedOpHead()) ?? undefined;
|
|
363
376
|
const compactor = this.createMongoCompactor({
|
|
364
377
|
...options,
|
|
378
|
+
maxOpId,
|
|
365
379
|
memoryLimitMB: 0,
|
|
366
380
|
logger: this.logger
|
|
367
381
|
});
|
|
@@ -413,7 +427,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
413
427
|
for await (const nextCheckpoint of iter) {
|
|
414
428
|
if (nextCheckpoint.lsn != null && !queriedInitialWriteCheckpoint) {
|
|
415
429
|
writeCheckpoint = await this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
416
|
-
sync_rules_id: this.
|
|
430
|
+
sync_rules_id: this.replicationStreamId,
|
|
417
431
|
user_id: options.user_id,
|
|
418
432
|
heads: {
|
|
419
433
|
'1': nextCheckpoint.lsn
|
|
@@ -446,7 +460,7 @@ export abstract class MongoSyncBucketStorage
|
|
|
446
460
|
let updatedWriteCheckpoint = updates.updatedWriteCheckpoints.get(options.user_id) ?? null;
|
|
447
461
|
if (updates.invalidateWriteCheckpoints) {
|
|
448
462
|
updatedWriteCheckpoint = await this.writeCheckpointAPI.lastWriteCheckpoint({
|
|
449
|
-
sync_rules_id: this.
|
|
463
|
+
sync_rules_id: this.replicationStreamId,
|
|
450
464
|
user_id: options.user_id,
|
|
451
465
|
heads: {
|
|
452
466
|
'1': nextCheckpoint.lsn!
|
|
@@ -617,7 +631,7 @@ class EmptyReplicationCheckpoint implements ReplicationCheckpoint {
|
|
|
617
631
|
readonly checkpoint: InternalOpId = 0n;
|
|
618
632
|
readonly lsn: string | null = null;
|
|
619
633
|
|
|
620
|
-
async getParameterSets(_lookups: ScopedParameterLookup[]): Promise<ParameterLookupRows[]> {
|
|
634
|
+
async getParameterSets(_lookups: ScopedParameterLookup[], _limit: number): Promise<ParameterLookupRows[]> {
|
|
621
635
|
return [];
|
|
622
636
|
}
|
|
623
637
|
}
|
|
@@ -17,12 +17,12 @@ export class MongoSyncRulesLock implements storage.ReplicationLock {
|
|
|
17
17
|
*/
|
|
18
18
|
static async createLock(
|
|
19
19
|
db: VersionedPowerSyncMongo,
|
|
20
|
-
sync_rules: storage.
|
|
20
|
+
sync_rules: storage.PersistedReplicationStream,
|
|
21
21
|
session?: mongo.ClientSession
|
|
22
22
|
): Promise<MongoSyncRulesLock> {
|
|
23
23
|
const lockId = crypto.randomBytes(8).toString('hex');
|
|
24
24
|
const doc = await db.sync_rules.findOneAndUpdate(
|
|
25
|
-
{ _id: sync_rules.
|
|
25
|
+
{ _id: sync_rules.replicationStreamId, $or: [{ lock: null }, { 'lock.expires_at': { $lt: new Date() } }] },
|
|
26
26
|
{
|
|
27
27
|
$set: {
|
|
28
28
|
lock: {
|
|
@@ -40,7 +40,10 @@ export class MongoSyncRulesLock implements storage.ReplicationLock {
|
|
|
40
40
|
|
|
41
41
|
if (doc == null) {
|
|
42
42
|
// Query the existing lock to get the expiration time (best effort - it may have been released in the meantime).
|
|
43
|
-
const heldLock = await db.sync_rules.findOne(
|
|
43
|
+
const heldLock = await db.sync_rules.findOne(
|
|
44
|
+
{ _id: sync_rules.replicationStreamId },
|
|
45
|
+
{ projection: { lock: 1 }, session }
|
|
46
|
+
);
|
|
44
47
|
if (heldLock?.lock?.expires_at) {
|
|
45
48
|
throw new ServiceError(
|
|
46
49
|
ErrorCode.PSYNC_S1003,
|
|
@@ -51,7 +54,7 @@ export class MongoSyncRulesLock implements storage.ReplicationLock {
|
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
sync_rules.logger.info(`Locked replication stream for processing`);
|
|
54
|
-
return new MongoSyncRulesLock(db, sync_rules.
|
|
57
|
+
return new MongoSyncRulesLock(db, sync_rules.replicationStreamId, lockId, sync_rules.logger);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
constructor(
|
|
@@ -3,10 +3,9 @@ import { BucketDataSource, BucketDefinitionId, EvaluatedParameters, EvaluatedRow
|
|
|
3
3
|
import * as bson from 'bson';
|
|
4
4
|
|
|
5
5
|
import { logger as defaultLogger, Logger } from '@powersync/lib-services-framework';
|
|
6
|
-
import { InternalOpId, storage, utils } from '@powersync/service-core';
|
|
6
|
+
import { BucketDefinitionMapping, InternalOpId, storage, utils } from '@powersync/service-core';
|
|
7
7
|
import { JSONBig } from '@powersync/service-jsonbig';
|
|
8
8
|
import { mongoTableId, replicaIdToSubkey } from '../../../utils/util.js';
|
|
9
|
-
import { BucketDefinitionMapping } from '../BucketDefinitionMapping.js';
|
|
10
9
|
import { currentBucketKey, MAX_ROW_SIZE } from '../MongoBucketBatchShared.js';
|
|
11
10
|
import { MongoIdSequence } from '../MongoIdSequence.js';
|
|
12
11
|
import type { VersionedPowerSyncMongo } from '../db.js';
|
|
@@ -97,7 +96,7 @@ export abstract class PersistedBatch {
|
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
saveBucketData(options: SaveBucketDataOptions) {
|
|
100
|
-
const remaining_buckets = new Map<string,
|
|
99
|
+
const remaining_buckets = new Map<string, SourceRecordBucketState>();
|
|
101
100
|
for (let bucket of options.before_buckets) {
|
|
102
101
|
const mapped: SourceRecordBucketState = {
|
|
103
102
|
bucket: bucket.bucket,
|
|
@@ -105,6 +104,11 @@ export abstract class PersistedBatch {
|
|
|
105
104
|
id: bucket.id,
|
|
106
105
|
table: bucket.table
|
|
107
106
|
};
|
|
107
|
+
if (options.table.bucketDataSourceIds != null && !options.table.bucketDataSourceIds.has(mapped.definitionId!)) {
|
|
108
|
+
// The bucket definition is not active anymore.
|
|
109
|
+
// We don't cleanup these references upfront, but do need to ignore them after the definition is removed.
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
108
112
|
remaining_buckets.set(currentBucketKey(mapped), mapped);
|
|
109
113
|
}
|
|
110
114
|
|
|
@@ -67,7 +67,7 @@ export abstract class BaseVersionedPowerSyncMongo {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
protected async listCollectionsByPrefix<T extends mongo.Document>(prefix: string): Promise<mongo.Collection<T>[]> {
|
|
70
|
-
const collections = await this.db.listCollections({ name:
|
|
70
|
+
const collections = await this.db.listCollections({ name: { $regex: `^${prefix}` } }, { nameOnly: true }).toArray();
|
|
71
71
|
|
|
72
72
|
return collections
|
|
73
73
|
.filter((collection) => collection.name.startsWith(prefix))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { storage } from '@powersync/service-core';
|
|
2
2
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
3
|
-
import {
|
|
3
|
+
import { MongoPersistedReplicationStream } from './MongoPersistedReplicationStream.js';
|
|
4
4
|
import { MongoSyncBucketStorage, MongoSyncBucketStorageOptions } from './MongoSyncBucketStorage.js';
|
|
5
5
|
import { MongoSyncBucketStorageV1 } from './v1/MongoSyncBucketStorageV1.js';
|
|
6
6
|
import { MongoSyncBucketStorageV3 } from './v3/MongoSyncBucketStorageV3.js';
|
|
@@ -11,15 +11,29 @@ export type { MongoSyncBucketStorage };
|
|
|
11
11
|
|
|
12
12
|
export function createMongoSyncBucketStorage(
|
|
13
13
|
factory: MongoBucketStorage,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
replicationStreamId: number,
|
|
15
|
+
replicationStream: MongoPersistedReplicationStream,
|
|
16
|
+
replicationStreamName: string,
|
|
17
17
|
writeCheckpointMode: storage.WriteCheckpointMode | undefined,
|
|
18
18
|
options: MongoSyncBucketStorageOptions
|
|
19
19
|
): MongoSyncBucketStorage {
|
|
20
|
-
if (
|
|
21
|
-
return new MongoSyncBucketStorageV3(
|
|
20
|
+
if (replicationStream.getStorageConfig().incrementalReprocessing) {
|
|
21
|
+
return new MongoSyncBucketStorageV3(
|
|
22
|
+
factory,
|
|
23
|
+
replicationStreamId,
|
|
24
|
+
replicationStream,
|
|
25
|
+
replicationStreamName,
|
|
26
|
+
writeCheckpointMode,
|
|
27
|
+
options
|
|
28
|
+
);
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
return new MongoSyncBucketStorageV1(
|
|
31
|
+
return new MongoSyncBucketStorageV1(
|
|
32
|
+
factory,
|
|
33
|
+
replicationStreamId,
|
|
34
|
+
replicationStream,
|
|
35
|
+
replicationStreamName,
|
|
36
|
+
writeCheckpointMode,
|
|
37
|
+
options
|
|
38
|
+
);
|
|
25
39
|
}
|
|
@@ -81,7 +81,7 @@ export class PowerSyncMongo {
|
|
|
81
81
|
versioned(storageConfig: StorageConfig & { incrementalReprocessing: false }): VersionedPowerSyncMongoV1;
|
|
82
82
|
versioned(storageConfig: StorageConfig): VersionedPowerSyncMongo;
|
|
83
83
|
versioned(storageConfig: StorageConfig): VersionedPowerSyncMongo {
|
|
84
|
-
if (storageConfig.
|
|
84
|
+
if (storageConfig.version >= storage.STORAGE_VERSION_3) {
|
|
85
85
|
return new VersionedPowerSyncMongoV3(this, storageConfig);
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -93,22 +93,18 @@ export class PowerSyncMongo {
|
|
|
93
93
|
*/
|
|
94
94
|
async listBucketDataCollectionsV3(groupId?: number): Promise<mongo.Collection<BucketDataDocumentV3>[]> {
|
|
95
95
|
const prefix = groupId == null ? 'bucket_data_' : `bucket_data_${groupId}_`;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return collections
|
|
99
|
-
.filter((collection) => collection.name.startsWith(prefix))
|
|
100
|
-
.map((collection) => this.db.collection<BucketDataDocumentV3>(collection.name));
|
|
96
|
+
return this.collectionsByPrefix<BucketDataDocumentV3>(prefix);
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
/**
|
|
104
100
|
* Not safe for user-provided prefix - only for hardcoded values.
|
|
105
101
|
*/
|
|
106
|
-
private async collectionsByPrefix(prefix: string): Promise<mongo.Collection<
|
|
107
|
-
const collections = await this.db.listCollections({ name:
|
|
102
|
+
private async collectionsByPrefix<T extends mongo.Document = never>(prefix: string): Promise<mongo.Collection<T>[]> {
|
|
103
|
+
const collections = await this.db.listCollections({ name: { $regex: `^${prefix}` } }, { nameOnly: true }).toArray();
|
|
108
104
|
|
|
109
105
|
return collections
|
|
110
106
|
.filter((collection) => collection.name.startsWith(prefix))
|
|
111
|
-
.map((collection) => this.db.collection<
|
|
107
|
+
.map((collection) => this.db.collection<T>(collection.name));
|
|
112
108
|
}
|
|
113
109
|
|
|
114
110
|
/**
|
|
@@ -144,16 +140,12 @@ export class PowerSyncMongo {
|
|
|
144
140
|
async listSourceTableCollections(
|
|
145
141
|
replicationStreamId?: number
|
|
146
142
|
): Promise<mongo.Collection<CommonSourceTableDocument>[]> {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return collections
|
|
155
|
-
.filter((collection) => collection.name.startsWith(prefix))
|
|
156
|
-
.map((collection) => this.db.collection<CommonSourceTableDocument>(collection.name));
|
|
143
|
+
if (replicationStreamId == null) {
|
|
144
|
+
return this.collectionsByPrefix('source_table_');
|
|
145
|
+
}
|
|
146
|
+
const name = this.sourceTableCollectionName(replicationStreamId);
|
|
147
|
+
const collections = await this.db.listCollections({ name }, { nameOnly: true }).toArray();
|
|
148
|
+
return collections.map((c) => this.db.collection<CommonSourceTableDocument>(c.name));
|
|
157
149
|
}
|
|
158
150
|
|
|
159
151
|
/**
|
|
@@ -4,7 +4,7 @@ import { ParameterIndexId, SqliteJsonValue } from '@powersync/service-sync-rules
|
|
|
4
4
|
import { event_types } from '@powersync/service-types';
|
|
5
5
|
import * as bson from 'bson';
|
|
6
6
|
import type { CurrentDataDocument, SourceTableDocumentV1 } from './v1/models.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { CurrentDataDocumentV3, RecordedLookupV3 } from './v3/models.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Replica id uniquely identifying a row on the source database.
|
|
@@ -208,7 +208,7 @@ export interface SyncRuleDocumentBase {
|
|
|
208
208
|
storage_version?: number;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
export interface SyncRuleCheckpointFields
|
|
211
|
+
export interface SyncRuleCheckpointFields {
|
|
212
212
|
/**
|
|
213
213
|
* The last consistent checkpoint.
|
|
214
214
|
*
|
|
@@ -225,16 +225,6 @@ export interface SyncRuleCheckpointFields<TKeepaliveOp extends string | bigint |
|
|
|
225
225
|
* If set, no new checkpoints may be created < this value.
|
|
226
226
|
*/
|
|
227
227
|
no_checkpoint_before: string | null;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Goes together with no_checkpoint_before.
|
|
231
|
-
*
|
|
232
|
-
* If a keepalive is triggered that creates the checkpoint > no_checkpoint_before,
|
|
233
|
-
* then the checkpoint must be equal to this keepalive_op.
|
|
234
|
-
*
|
|
235
|
-
* This is a string in V1, bigint in V3.
|
|
236
|
-
*/
|
|
237
|
-
keepalive_op: TKeepaliveOp;
|
|
238
228
|
}
|
|
239
229
|
|
|
240
230
|
export interface StorageConfig extends storage.StorageVersionConfig {
|
|
@@ -306,6 +296,6 @@ export interface InstanceDocument {
|
|
|
306
296
|
export interface ClientConnectionDocument extends event_types.ClientConnection {}
|
|
307
297
|
|
|
308
298
|
export type CurrentDataDocumentId = CurrentDataDocument['_id'] | CurrentDataDocumentV3['_id'];
|
|
309
|
-
export type CommonCurrentBucket = CurrentBucket
|
|
299
|
+
export type CommonCurrentBucket = CurrentBucket;
|
|
310
300
|
export type CommonCurrentLookup = bson.Binary | RecordedLookupV3;
|
|
311
|
-
export type CommonSourceTableDocument = SourceTableDocumentV1 |
|
|
301
|
+
export type CommonSourceTableDocument = Pick<SourceTableDocumentV1, '_id' | 'snapshot_status'>;
|