@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
-
import { ColumnDescriptor, SourceTable, storage } from '@powersync/service-core';
|
|
2
|
+
import { ColumnDescriptor, InternalOpId, SourceTable, storage } from '@powersync/service-core';
|
|
3
3
|
import * as bson from 'bson';
|
|
4
4
|
import { mongoTableId } from '../../../utils/util.js';
|
|
5
5
|
import { calculateCheckpointState } from '../CheckpointState.js';
|
|
@@ -9,22 +9,35 @@ import { SourceRecordStore } from '../common/SourceRecordStore.js';
|
|
|
9
9
|
import { PersistedBatchV1 } from './PersistedBatchV1.js';
|
|
10
10
|
import { SourceRecordStoreV1 } from './SourceRecordStoreV1.js';
|
|
11
11
|
import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
|
|
12
|
-
import {
|
|
12
|
+
import { SyncRuleDocumentV1 } from './models.js';
|
|
13
13
|
|
|
14
14
|
export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
15
|
-
declare
|
|
15
|
+
declare readonly db: VersionedPowerSyncMongoV1;
|
|
16
16
|
|
|
17
17
|
private readonly store: SourceRecordStore;
|
|
18
18
|
private needsActivation = true;
|
|
19
19
|
private lastWaitingLogThrottled = 0;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The last persisted op that is not yet covered by a checkpoint, if any.
|
|
23
|
+
*
|
|
24
|
+
* Seeded from the persisted keepalive_op, so that ops persisted before a restart can still be
|
|
25
|
+
* included in the next checkpoint.
|
|
26
|
+
*/
|
|
27
|
+
private persisted_op: InternalOpId | null = null;
|
|
28
|
+
|
|
21
29
|
constructor(options: MongoBucketBatchOptions) {
|
|
22
30
|
super(options);
|
|
23
|
-
this.
|
|
31
|
+
this.persisted_op = options.keepaliveOp ?? null;
|
|
32
|
+
this.store = new SourceRecordStoreV1(this.db, this.replicationStreamId);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected override recordPersistedOp(lastOp: InternalOpId): void {
|
|
36
|
+
this.persisted_op = lastOp;
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
protected createPersistedBatch(writtenSize: number): PersistedBatch {
|
|
27
|
-
return new PersistedBatchV1(this.db, this.
|
|
40
|
+
return new PersistedBatchV1(this.db, this.replicationStreamId, this.mapping, writtenSize, {
|
|
28
41
|
logger: this.logger
|
|
29
42
|
});
|
|
30
43
|
}
|
|
@@ -32,13 +45,12 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
32
45
|
protected get sourceRecordStore(): SourceRecordStore {
|
|
33
46
|
return this.store;
|
|
34
47
|
}
|
|
35
|
-
|
|
36
48
|
protected async cleanupDroppedSourceTables(_tables: SourceTable[]) {
|
|
37
49
|
// No-op for V1: source records live in a shared collection.
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
async resolveTables(options: storage.ResolveTablesOptions): Promise<storage.ResolveTablesResult> {
|
|
41
|
-
const syncRules = options.
|
|
53
|
+
const syncRules = options.parsedSyncConfig?.hydratedSyncConfig ?? this.sync_rules;
|
|
42
54
|
const { connection_id, source } = options;
|
|
43
55
|
const { schema, name, objectId, replicaIdColumns, connectionTag, sendsCompleteRows } = source;
|
|
44
56
|
|
|
@@ -50,9 +62,9 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
50
62
|
|
|
51
63
|
let result: storage.ResolveTablesResult | null = null;
|
|
52
64
|
await this.db.client.withSession(async (session) => {
|
|
53
|
-
const col = this.db.
|
|
65
|
+
const col = this.db.sourceTablesV1(this.replicationStreamId);
|
|
54
66
|
const filter: any = {
|
|
55
|
-
group_id: this.
|
|
67
|
+
group_id: this.replicationStreamId,
|
|
56
68
|
connection_id,
|
|
57
69
|
schema_name: schema,
|
|
58
70
|
table_name: name,
|
|
@@ -66,7 +78,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
66
78
|
if (doc == null) {
|
|
67
79
|
doc = {
|
|
68
80
|
_id: options.idGenerator ? (options.idGenerator() as bson.ObjectId) : new bson.ObjectId(),
|
|
69
|
-
group_id: this.
|
|
81
|
+
group_id: this.replicationStreamId,
|
|
70
82
|
connection_id,
|
|
71
83
|
relation_id: objectId,
|
|
72
84
|
schema_name: schema,
|
|
@@ -107,7 +119,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
107
119
|
const truncate = await col
|
|
108
120
|
.find(
|
|
109
121
|
{
|
|
110
|
-
group_id: this.
|
|
122
|
+
group_id: this.replicationStreamId,
|
|
111
123
|
connection_id,
|
|
112
124
|
_id: { $ne: doc._id },
|
|
113
125
|
$or: truncateFilter
|
|
@@ -145,13 +157,13 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
145
157
|
}
|
|
146
158
|
|
|
147
159
|
async getSourceTableStatus(table: storage.SourceTable): Promise<storage.SourceTable | null> {
|
|
148
|
-
const doc =
|
|
160
|
+
const doc = await this.db.sourceTablesV1(this.replicationStreamId).findOne(
|
|
149
161
|
{
|
|
150
|
-
group_id: this.
|
|
162
|
+
group_id: this.replicationStreamId,
|
|
151
163
|
_id: mongoTableId(table.id)
|
|
152
164
|
},
|
|
153
165
|
{ session: this.session }
|
|
154
|
-
)
|
|
166
|
+
);
|
|
155
167
|
if (doc == null) {
|
|
156
168
|
return null;
|
|
157
169
|
}
|
|
@@ -243,7 +255,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
243
255
|
};
|
|
244
256
|
|
|
245
257
|
const preUpdateDocument = (await this.db.sync_rules.findOneAndUpdate(
|
|
246
|
-
{ _id: this.
|
|
258
|
+
{ _id: this.replicationStreamId },
|
|
247
259
|
[
|
|
248
260
|
{
|
|
249
261
|
$set: {
|
|
@@ -296,7 +308,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
296
308
|
|
|
297
309
|
if (preUpdateDocument == null) {
|
|
298
310
|
throw new ReplicationAssertionError(
|
|
299
|
-
'Failed to update checkpoint - no matching sync_rules document for _id: ' + this.
|
|
311
|
+
'Failed to update checkpoint - no matching sync_rules document for _id: ' + this.replicationStreamId
|
|
300
312
|
);
|
|
301
313
|
}
|
|
302
314
|
|
|
@@ -330,7 +342,6 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
330
342
|
await this.autoActivate(lsn);
|
|
331
343
|
await this.db.notifyCheckpoint();
|
|
332
344
|
this.persisted_op = null;
|
|
333
|
-
this.last_checkpoint_lsn = lsn;
|
|
334
345
|
if (checkpointState.newLastCheckpoint != null) {
|
|
335
346
|
await this.sourceRecordStore.postCommitCleanup(checkpointState.newLastCheckpoint, this.logger);
|
|
336
347
|
}
|
|
@@ -349,7 +360,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
349
360
|
async setResumeLsn(lsn: string): Promise<void> {
|
|
350
361
|
await this.db.sync_rules.updateOne(
|
|
351
362
|
{
|
|
352
|
-
_id: this.
|
|
363
|
+
_id: this.replicationStreamId
|
|
353
364
|
},
|
|
354
365
|
{
|
|
355
366
|
$set: {
|
|
@@ -363,7 +374,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
363
374
|
async markAllSnapshotDone(no_checkpoint_before_lsn: string): Promise<void> {
|
|
364
375
|
await this.db.sync_rules.updateOne(
|
|
365
376
|
{
|
|
366
|
-
_id: this.
|
|
377
|
+
_id: this.replicationStreamId
|
|
367
378
|
},
|
|
368
379
|
{
|
|
369
380
|
$set: {
|
|
@@ -381,17 +392,24 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
381
392
|
async markSnapshotDone(no_checkpoint_before_lsn: string, options?: { throwOnConflict?: boolean }): Promise<void> {
|
|
382
393
|
await this.withTransaction(async () => {
|
|
383
394
|
// Protect against race conditions
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
395
|
+
const blockingTables = await this.db
|
|
396
|
+
.sourceTablesV1(this.replicationStreamId)
|
|
397
|
+
.find(
|
|
398
|
+
{
|
|
399
|
+
group_id: this.replicationStreamId,
|
|
400
|
+
snapshot_done: false
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
session: this.session,
|
|
404
|
+
projection: { schema_name: 1, table_name: 1 }
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
.toArray();
|
|
408
|
+
|
|
409
|
+
if (blockingTables.length > 0) {
|
|
392
410
|
if (options?.throwOnConflict ?? true) {
|
|
393
411
|
throw new ReplicationAssertionError(
|
|
394
|
-
`Cannot mark snapshot done while
|
|
412
|
+
`Cannot mark snapshot done while source tables still require snapshotting. Tables: ${blockingTables.map((t) => `${t.schema_name}.${t.table_name}`).join(', ')}`
|
|
395
413
|
);
|
|
396
414
|
} else {
|
|
397
415
|
return;
|
|
@@ -405,7 +423,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
405
423
|
async markTableSnapshotRequired(_table: storage.SourceTable): Promise<void> {
|
|
406
424
|
await this.db.sync_rules.updateOne(
|
|
407
425
|
{
|
|
408
|
-
_id: this.
|
|
426
|
+
_id: this.replicationStreamId
|
|
409
427
|
},
|
|
410
428
|
{
|
|
411
429
|
$set: {
|
|
@@ -424,7 +442,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
424
442
|
const ids = tables.map((table) => mongoTableId(table.id));
|
|
425
443
|
|
|
426
444
|
await this.withTransaction(async () => {
|
|
427
|
-
await this.db.
|
|
445
|
+
await this.db.sourceTablesV1(this.replicationStreamId).updateMany(
|
|
428
446
|
{ _id: { $in: ids } },
|
|
429
447
|
{
|
|
430
448
|
$set: {
|
|
@@ -440,7 +458,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
440
458
|
if (no_checkpoint_before_lsn != null) {
|
|
441
459
|
await this.db.sync_rules.updateOne(
|
|
442
460
|
{
|
|
443
|
-
_id: this.
|
|
461
|
+
_id: this.replicationStreamId
|
|
444
462
|
},
|
|
445
463
|
{
|
|
446
464
|
$set: {
|
|
@@ -469,11 +487,14 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
469
487
|
const session = this.session;
|
|
470
488
|
let activated = false;
|
|
471
489
|
await session.withTransaction(async () => {
|
|
472
|
-
const doc = (await this.db.sync_rules.findOne(
|
|
490
|
+
const doc = (await this.db.sync_rules.findOne(
|
|
491
|
+
{ _id: this.replicationStreamId },
|
|
492
|
+
{ session }
|
|
493
|
+
)) as SyncRuleDocumentV1;
|
|
473
494
|
if (doc && doc.state == storage.SyncRuleState.PROCESSING && doc.snapshot_done && doc.last_checkpoint != null) {
|
|
474
495
|
await this.db.sync_rules.updateOne(
|
|
475
496
|
{
|
|
476
|
-
_id: this.
|
|
497
|
+
_id: this.replicationStreamId
|
|
477
498
|
},
|
|
478
499
|
{
|
|
479
500
|
$set: {
|
|
@@ -485,7 +506,7 @@ export class MongoBucketBatchV1 extends MongoBucketBatch {
|
|
|
485
506
|
|
|
486
507
|
await this.db.sync_rules.updateMany(
|
|
487
508
|
{
|
|
488
|
-
_id: { $ne: this.
|
|
509
|
+
_id: { $ne: this.replicationStreamId },
|
|
489
510
|
state: { $in: [storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED] }
|
|
490
511
|
},
|
|
491
512
|
{
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
1
2
|
import {
|
|
3
|
+
addPartialChecksums,
|
|
2
4
|
bson,
|
|
3
5
|
BucketChecksum,
|
|
4
6
|
FetchPartialBucketChecksum,
|
|
5
7
|
InternalOpId,
|
|
6
|
-
|
|
8
|
+
isPartialChecksum,
|
|
9
|
+
PartialChecksumMap,
|
|
10
|
+
PartialOrFullChecksum
|
|
7
11
|
} from '@powersync/service-core';
|
|
8
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
checksumFromAggregate,
|
|
14
|
+
DEFAULT_OPERATION_BATCH_LIMIT,
|
|
15
|
+
FetchPartialBucketChecksumByBucket,
|
|
16
|
+
MongoChecksums
|
|
17
|
+
} from '../MongoChecksums.js';
|
|
9
18
|
import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
|
|
10
19
|
|
|
11
20
|
export class MongoChecksumsV1 extends MongoChecksums {
|
|
@@ -14,7 +23,8 @@ export class MongoChecksumsV1 extends MongoChecksums {
|
|
|
14
23
|
async computePartialChecksumsDirectByBucket(
|
|
15
24
|
batch: FetchPartialBucketChecksumByBucket[]
|
|
16
25
|
): Promise<PartialChecksumMap> {
|
|
17
|
-
|
|
26
|
+
const collection = this.db.bucketDataV1;
|
|
27
|
+
const createFilter = (request: FetchPartialBucketChecksumByBucket) => ({
|
|
18
28
|
_id: {
|
|
19
29
|
$gt: {
|
|
20
30
|
g: this.group_id,
|
|
@@ -27,7 +37,130 @@ export class MongoChecksumsV1 extends MongoChecksums {
|
|
|
27
37
|
o: request.end
|
|
28
38
|
}
|
|
29
39
|
}
|
|
30
|
-
})
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const batchLimit = this.options?.operationBatchLimit ?? DEFAULT_OPERATION_BATCH_LIMIT;
|
|
43
|
+
|
|
44
|
+
// Map requests by bucket. We adjust this as we get partial results.
|
|
45
|
+
let requests = new Map<string, FetchPartialBucketChecksumByBucket>();
|
|
46
|
+
for (let request of batch) {
|
|
47
|
+
requests.set(request.bucket, request);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const partialChecksums = new Map<string, PartialOrFullChecksum>();
|
|
51
|
+
|
|
52
|
+
while (requests.size > 0) {
|
|
53
|
+
const filters = Array.from(requests.values(), createFilter);
|
|
54
|
+
|
|
55
|
+
// Historically, checksum may be stored as 'int' or 'double'.
|
|
56
|
+
// More recently, this should be a 'long'.
|
|
57
|
+
// $toLong ensures that we always sum it as a long, avoiding inaccuracies in the calculations.
|
|
58
|
+
const checksumLong = this.storageConfig.longChecksums ? '$checksum' : { $toLong: '$checksum' };
|
|
59
|
+
|
|
60
|
+
// Aggregate over a max of `batchLimit` operations at a time.
|
|
61
|
+
// Let's say we have 3 buckets (A, B, C), each with 10 operations, and our batch limit is 12.
|
|
62
|
+
// Then we'll do three batches:
|
|
63
|
+
// 1. Query: A[1-end], B[1-end], C[1-end]
|
|
64
|
+
// Returns: A[1-10], B[1-2]
|
|
65
|
+
// 2. Query: B[3-end], C[1-end]
|
|
66
|
+
// Returns: B[3-10], C[1-4]
|
|
67
|
+
// 3. Query: C[5-end]
|
|
68
|
+
// Returns: C[5-10]
|
|
69
|
+
const aggregate = await collection
|
|
70
|
+
.aggregate(
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
$match: {
|
|
74
|
+
$or: filters
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
// sort and limit _before_ grouping
|
|
78
|
+
{ $sort: { _id: 1 } },
|
|
79
|
+
{ $limit: batchLimit },
|
|
80
|
+
{
|
|
81
|
+
$group: {
|
|
82
|
+
_id: '$_id.b',
|
|
83
|
+
checksum_total: { $sum: checksumLong },
|
|
84
|
+
count: { $sum: 1 },
|
|
85
|
+
has_clear_op: {
|
|
86
|
+
$max: {
|
|
87
|
+
$cond: [{ $eq: ['$op', 'CLEAR'] }, 1, 0]
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
last_op: { $max: '$_id.o' }
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
// Sort the aggregated results (100 max, so should be fast).
|
|
94
|
+
// This is important to identify which buckets we have partial data for.
|
|
95
|
+
{ $sort: { _id: 1 } }
|
|
96
|
+
],
|
|
97
|
+
{
|
|
98
|
+
session: undefined,
|
|
99
|
+
readConcern: 'snapshot',
|
|
100
|
+
maxTimeMS: lib_mongo.MONGO_CHECKSUM_TIMEOUT_MS
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
.toArray()
|
|
104
|
+
.catch((e) => {
|
|
105
|
+
throw lib_mongo.mapQueryError(e, 'while reading checksums');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
let batchCount = 0;
|
|
109
|
+
let limitReached = false;
|
|
110
|
+
for (let doc of aggregate) {
|
|
111
|
+
const bucket = doc._id;
|
|
112
|
+
const checksum = checksumFromAggregate(doc);
|
|
113
|
+
|
|
114
|
+
const existing = partialChecksums.get(bucket);
|
|
115
|
+
if (existing != null) {
|
|
116
|
+
partialChecksums.set(bucket, addPartialChecksums(bucket, existing, checksum));
|
|
117
|
+
} else {
|
|
118
|
+
partialChecksums.set(bucket, checksum);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
batchCount += doc.count;
|
|
122
|
+
if (batchCount == batchLimit) {
|
|
123
|
+
// Limit reached. Request more in the next batch.
|
|
124
|
+
// Note that this only affects the _last_ bucket in a batch.
|
|
125
|
+
limitReached = true;
|
|
126
|
+
const req = requests.get(bucket);
|
|
127
|
+
requests.set(bucket, {
|
|
128
|
+
...req!,
|
|
129
|
+
start: doc.last_op
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
// All done for this bucket
|
|
133
|
+
requests.delete(bucket);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!limitReached) {
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return new Map<string, PartialOrFullChecksum>(
|
|
142
|
+
batch.map((request) => {
|
|
143
|
+
const bucket = request.bucket;
|
|
144
|
+
let partialChecksum = partialChecksums.get(bucket);
|
|
145
|
+
// Could be null if we got no data
|
|
146
|
+
if (partialChecksum == null) {
|
|
147
|
+
partialChecksum = {
|
|
148
|
+
bucket,
|
|
149
|
+
partialCount: 0,
|
|
150
|
+
partialChecksum: 0
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (request.start == null && isPartialChecksum(partialChecksum)) {
|
|
154
|
+
partialChecksum = {
|
|
155
|
+
bucket,
|
|
156
|
+
count: partialChecksum.partialCount,
|
|
157
|
+
checksum: partialChecksum.partialChecksum
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return [bucket, partialChecksum];
|
|
162
|
+
})
|
|
163
|
+
);
|
|
31
164
|
}
|
|
32
165
|
|
|
33
166
|
protected async fetchPreStates(
|