@powersync/service-module-mongodb-storage 0.15.3 → 0.16.0
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 +54 -0
- package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +1 -1
- package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -1
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +3 -3
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/migrations/db/migrations/1770213298299-storage-version.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +5 -3
- package/dist/storage/MongoBucketStorage.js +50 -36
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/MongoReportStorage.js.map +1 -1
- package/dist/storage/implementation/BucketDefinitionMapping.d.ts +17 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js +58 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
- package/dist/storage/implementation/MongoBucketBatch.d.ts +16 -14
- package/dist/storage/implementation/MongoBucketBatch.js +80 -115
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatchShared.d.ts +5 -0
- package/dist/storage/implementation/MongoBucketBatchShared.js +8 -0
- package/dist/storage/implementation/MongoBucketBatchShared.js.map +1 -0
- package/dist/storage/implementation/MongoChecksums.d.ts +28 -17
- package/dist/storage/implementation/MongoChecksums.js +13 -72
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +98 -58
- package/dist/storage/implementation/MongoCompactor.js +229 -296
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParameterCompactor.d.ts +11 -6
- package/dist/storage/implementation/MongoParameterCompactor.js +11 -8
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +14 -0
- package/dist/storage/implementation/MongoPersistedSyncRules.js +64 -0
- package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +3 -0
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +9 -0
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +49 -30
- package/dist/storage/implementation/MongoSyncBucketStorage.js +96 -388
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +5 -3
- package/dist/storage/implementation/MongoSyncRulesLock.js +12 -10
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js +1 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/OperationBatch.js +1 -1
- package/dist/storage/implementation/common/BucketDataDoc.d.ts +35 -0
- package/dist/storage/implementation/common/BucketDataDoc.js +2 -0
- package/dist/storage/implementation/common/BucketDataDoc.js.map +1 -0
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +13 -0
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +2 -0
- package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +1 -0
- package/dist/storage/implementation/common/PersistedBatch.d.ts +108 -0
- package/dist/storage/implementation/common/PersistedBatch.js +237 -0
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -0
- package/dist/storage/implementation/common/SingleBucketStore.d.ts +54 -0
- package/dist/storage/implementation/common/SingleBucketStore.js +3 -0
- package/dist/storage/implementation/common/SingleBucketStore.js.map +1 -0
- package/dist/storage/implementation/common/SourceRecordStore.d.ts +36 -0
- package/dist/storage/implementation/common/SourceRecordStore.js +2 -0
- package/dist/storage/implementation/common/SourceRecordStore.js.map +1 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +27 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +57 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -0
- package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +7 -0
- package/dist/storage/implementation/createMongoSyncBucketStorage.js +9 -0
- package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -0
- package/dist/storage/implementation/db.d.ts +34 -34
- package/dist/storage/implementation/db.js +78 -98
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +63 -34
- package/dist/storage/implementation/models.js +21 -2
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +13 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +22 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -0
- package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +12 -0
- package/dist/storage/implementation/v1/MongoChecksumsV1.js +56 -0
- package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -0
- package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +23 -0
- package/dist/storage/implementation/v1/MongoCompactorV1.js +52 -0
- package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -0
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +9 -0
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -0
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -0
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +41 -0
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +283 -0
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -0
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +26 -0
- package/dist/storage/implementation/v1/PersistedBatchV1.js +183 -0
- package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -0
- package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +18 -0
- package/dist/storage/implementation/v1/SingleBucketStoreV1.js +57 -0
- package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -0
- package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +19 -0
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js +105 -0
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -0
- package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +12 -0
- package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +20 -0
- package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -0
- package/dist/storage/implementation/v1/models.d.ts +34 -0
- package/dist/storage/implementation/v1/models.js +37 -0
- package/dist/storage/implementation/v1/models.js.map +1 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +13 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +34 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +15 -0
- package/dist/storage/implementation/v3/MongoChecksumsV3.js +84 -0
- package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -0
- package/dist/storage/implementation/v3/MongoCompactorV3.js +68 -0
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +9 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +18 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +5 -0
- package/dist/storage/implementation/v3/MongoParameterLookupV3.js +9 -0
- package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +41 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +407 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +29 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.js +259 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -0
- package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +18 -0
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js +48 -0
- package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +1 -0
- package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +22 -0
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js +164 -0
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +21 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +71 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -0
- package/dist/storage/implementation/v3/models.d.ts +43 -0
- package/dist/storage/implementation/v3/models.js +34 -0
- package/dist/storage/implementation/v3/models.js.map +1 -0
- package/dist/storage/storage-index.d.ts +8 -5
- package/dist/storage/storage-index.js +8 -5
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/utils/util.d.ts +11 -4
- package/dist/utils/util.js +25 -4
- package/dist/utils/util.js.map +1 -1
- package/package.json +9 -9
- package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +1 -1
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -7
- package/src/migrations/db/migrations/1770213298299-storage-version.ts +1 -1
- package/src/storage/MongoBucketStorage.ts +97 -62
- package/src/storage/MongoReportStorage.ts +2 -2
- package/src/storage/implementation/BucketDefinitionMapping.ts +72 -0
- package/src/storage/implementation/MongoBucketBatch.ts +110 -144
- package/src/storage/implementation/MongoBucketBatchShared.ts +11 -0
- package/src/storage/implementation/MongoChecksums.ts +53 -76
- package/src/storage/implementation/MongoCompactor.ts +374 -404
- package/src/storage/implementation/MongoParameterCompactor.ts +37 -24
- package/src/storage/implementation/MongoPersistedSyncRules.ts +76 -0
- package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +18 -1
- package/src/storage/implementation/MongoStorageProvider.ts +1 -1
- package/src/storage/implementation/MongoSyncBucketStorage.ts +190 -457
- package/src/storage/implementation/MongoSyncRulesLock.ts +12 -14
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +4 -2
- package/src/storage/implementation/OperationBatch.ts +1 -1
- package/src/storage/implementation/common/BucketDataDoc.ts +37 -0
- package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +15 -0
- package/src/storage/implementation/common/PersistedBatch.ts +364 -0
- package/src/storage/implementation/common/SingleBucketStore.ts +63 -0
- package/src/storage/implementation/common/SourceRecordStore.ts +49 -0
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +80 -0
- package/src/storage/implementation/createMongoSyncBucketStorage.ts +25 -0
- package/src/storage/implementation/db.ts +107 -128
- package/src/storage/implementation/models.ts +84 -38
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +32 -0
- package/src/storage/implementation/v1/MongoChecksumsV1.ts +75 -0
- package/src/storage/implementation/v1/MongoCompactorV1.ts +93 -0
- package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +26 -0
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +448 -0
- package/src/storage/implementation/v1/PersistedBatchV1.ts +230 -0
- package/src/storage/implementation/v1/SingleBucketStoreV1.ts +74 -0
- package/src/storage/implementation/v1/SourceRecordStoreV1.ts +156 -0
- package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +28 -0
- package/src/storage/implementation/v1/models.ts +84 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +44 -0
- package/src/storage/implementation/v3/MongoChecksumsV3.ts +120 -0
- package/src/storage/implementation/v3/MongoCompactorV3.ts +107 -0
- package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +24 -0
- package/src/storage/implementation/v3/MongoParameterLookupV3.ts +12 -0
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +550 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +318 -0
- package/src/storage/implementation/v3/SingleBucketStoreV3.ts +68 -0
- package/src/storage/implementation/v3/SourceRecordStoreV3.ts +226 -0
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +112 -0
- package/src/storage/implementation/v3/models.ts +96 -0
- package/src/storage/storage-index.ts +8 -5
- package/src/utils/util.ts +36 -7
- package/test/src/__snapshots__/storage_sync.test.ts.snap +282 -0
- package/test/src/connection-report-storage.test.ts +3 -3
- package/test/src/setup.ts +1 -1
- package/test/src/storage.test.ts +2 -2
- package/test/src/storage_compacting.test.ts +57 -29
- package/test/src/storage_sync.test.ts +351 -5
- package/test/tsconfig.json +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/storage/implementation/PersistedBatch.d.ts +0 -71
- package/dist/storage/implementation/PersistedBatch.js +0 -354
- package/dist/storage/implementation/PersistedBatch.js.map +0 -1
- package/src/storage/implementation/PersistedBatch.ts +0 -432
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { BucketDataSource, ParameterIndexLookupCreator, SyncConfigWithErrors } from '@powersync/service-sync-rules';
|
|
3
|
+
import { SyncRuleDocument } from './models.js';
|
|
4
|
+
|
|
5
|
+
export type BucketDefinitionId = string;
|
|
6
|
+
export type ParameterIndexId = string;
|
|
7
|
+
|
|
8
|
+
export class BucketDefinitionMapping {
|
|
9
|
+
static fromSyncRules(doc: Pick<SyncRuleDocument, 'rule_mapping'>): BucketDefinitionMapping {
|
|
10
|
+
return new BucketDefinitionMapping(doc.rule_mapping?.definitions ?? {}, doc.rule_mapping?.parameter_indexes ?? {});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static fromParsedSyncRules(syncRules: SyncConfigWithErrors): BucketDefinitionMapping {
|
|
14
|
+
const definitionNames = syncRules.config.bucketDataSources.map((source) => source.uniqueName).sort();
|
|
15
|
+
const parameterKeys = syncRules.config.bucketParameterLookupSources
|
|
16
|
+
.map((source) => `${source.defaultLookupScope.lookupName}#${source.defaultLookupScope.queryId}`)
|
|
17
|
+
.sort();
|
|
18
|
+
|
|
19
|
+
const definitions: Record<string, BucketDefinitionId> = {};
|
|
20
|
+
const parameterLookups: Record<string, ParameterIndexId> = {};
|
|
21
|
+
|
|
22
|
+
for (const [index, uniqueName] of definitionNames.entries()) {
|
|
23
|
+
definitions[uniqueName] = (index + 1).toString(16);
|
|
24
|
+
}
|
|
25
|
+
for (const [index, key] of parameterKeys.entries()) {
|
|
26
|
+
parameterLookups[key] = (index + 1).toString(16);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return new BucketDefinitionMapping(definitions, parameterLookups);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
private definitions: Record<string, BucketDefinitionId> = {},
|
|
34
|
+
private parameterLookupMapping: Record<string, ParameterIndexId> = {}
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
bucketSourceId(source: BucketDataSource): BucketDefinitionId {
|
|
38
|
+
const defId = this.definitions[source.uniqueName];
|
|
39
|
+
if (defId == null) {
|
|
40
|
+
throw new ServiceAssertionError(`No mapping found for bucket source ${source.uniqueName}`);
|
|
41
|
+
}
|
|
42
|
+
return defId;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
allBucketDefinitionIds(): BucketDefinitionId[] {
|
|
46
|
+
return Object.values(this.definitions);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
allParameterIndexIds(): ParameterIndexId[] {
|
|
50
|
+
return Object.values(this.parameterLookupMapping);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId {
|
|
54
|
+
const key = this.parameterLookupKey(source.defaultLookupScope.lookupName, source.defaultLookupScope.queryId);
|
|
55
|
+
const defId = this.parameterLookupMapping[key];
|
|
56
|
+
if (defId == null) {
|
|
57
|
+
throw new ServiceAssertionError(`No mapping found for parameter lookup source ${key}`);
|
|
58
|
+
}
|
|
59
|
+
return defId;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private parameterLookupKey(lookupName: string, queryId: string) {
|
|
63
|
+
return `${lookupName}#${queryId}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
serialize(): NonNullable<SyncRuleDocument['rule_mapping']> {
|
|
67
|
+
return {
|
|
68
|
+
definitions: { ...this.definitions },
|
|
69
|
+
parameter_indexes: { ...this.parameterLookupMapping }
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -5,7 +5,6 @@ import * as bson from 'bson';
|
|
|
5
5
|
import {
|
|
6
6
|
BaseObserver,
|
|
7
7
|
container,
|
|
8
|
-
logger as defaultLogger,
|
|
9
8
|
ErrorCode,
|
|
10
9
|
errors,
|
|
11
10
|
Logger,
|
|
@@ -18,24 +17,23 @@ import {
|
|
|
18
17
|
deserializeBson,
|
|
19
18
|
InternalOpId,
|
|
20
19
|
isCompleteRow,
|
|
20
|
+
PerformanceTracer,
|
|
21
21
|
SaveOperationTag,
|
|
22
22
|
storage,
|
|
23
23
|
SyncRuleState,
|
|
24
24
|
utils
|
|
25
25
|
} from '@powersync/service-core';
|
|
26
26
|
import * as timers from 'node:timers/promises';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
27
|
+
import { mongoTableId } from '../../utils/util.js';
|
|
28
|
+
import { BucketDefinitionMapping } from './BucketDefinitionMapping.js';
|
|
29
|
+
import { PersistedBatch } from './common/PersistedBatch.js';
|
|
30
|
+
import { LoadedSourceRecord, SourceRecordStore } from './common/SourceRecordStore.js';
|
|
31
|
+
import type { VersionedPowerSyncMongo } from './db.js';
|
|
32
|
+
import { SyncRuleDocument } from './models.js';
|
|
33
|
+
import { MAX_ROW_SIZE } from './MongoBucketBatchShared.js';
|
|
30
34
|
import { MongoIdSequence } from './MongoIdSequence.js';
|
|
31
35
|
import { batchCreateCustomWriteCheckpoints } from './MongoWriteCheckpointAPI.js';
|
|
32
|
-
import {
|
|
33
|
-
import { PersistedBatch } from './PersistedBatch.js';
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 15MB
|
|
37
|
-
*/
|
|
38
|
-
export const MAX_ROW_SIZE = 15 * 1024 * 1024;
|
|
36
|
+
import { OperationBatch, RecordOperation } from './OperationBatch.js';
|
|
39
37
|
|
|
40
38
|
// Currently, we can only have a single flush() at a time, since it locks the op_id sequence.
|
|
41
39
|
// While the MongoDB transaction retry mechanism handles this okay, using an in-process Mutex
|
|
@@ -44,8 +42,6 @@ export const MAX_ROW_SIZE = 15 * 1024 * 1024;
|
|
|
44
42
|
// In the future, we can investigate allowing multiple replication streams operating independently.
|
|
45
43
|
const replicationMutex = new utils.Mutex();
|
|
46
44
|
|
|
47
|
-
export const EMPTY_DATA = new bson.Binary(bson.serialize({}));
|
|
48
|
-
|
|
49
45
|
export interface MongoBucketBatchOptions {
|
|
50
46
|
db: VersionedPowerSyncMongo;
|
|
51
47
|
syncRules: HydratedSyncRules;
|
|
@@ -55,6 +51,7 @@ export interface MongoBucketBatchOptions {
|
|
|
55
51
|
keepaliveOp: InternalOpId | null;
|
|
56
52
|
resumeFromLsn: string | null;
|
|
57
53
|
storeCurrentData: boolean;
|
|
54
|
+
mapping: BucketDefinitionMapping;
|
|
58
55
|
/**
|
|
59
56
|
* Set to true for initial replication.
|
|
60
57
|
*/
|
|
@@ -62,31 +59,35 @@ export interface MongoBucketBatchOptions {
|
|
|
62
59
|
|
|
63
60
|
markRecordUnavailable: BucketStorageMarkRecordUnavailable | undefined;
|
|
64
61
|
|
|
65
|
-
logger
|
|
62
|
+
logger: Logger;
|
|
63
|
+
tracer?: PerformanceTracer<'storage' | 'evaluate'>;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
export class MongoBucketBatch
|
|
66
|
+
export abstract class MongoBucketBatch
|
|
69
67
|
extends BaseObserver<storage.BucketBatchStorageListener>
|
|
70
68
|
implements storage.BucketStorageBatch
|
|
71
69
|
{
|
|
72
|
-
|
|
70
|
+
protected logger: Logger;
|
|
73
71
|
|
|
74
72
|
private readonly client: mongo.MongoClient;
|
|
75
73
|
public readonly db: VersionedPowerSyncMongo;
|
|
76
74
|
public readonly session: mongo.ClientSession;
|
|
77
75
|
private readonly sync_rules: HydratedSyncRules;
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
protected readonly group_id: number;
|
|
80
78
|
|
|
81
79
|
private readonly slot_name: string;
|
|
82
80
|
private readonly storeCurrentData: boolean;
|
|
83
81
|
private readonly skipExistingRows: boolean;
|
|
82
|
+
protected readonly mapping: BucketDefinitionMapping;
|
|
84
83
|
|
|
85
84
|
private batch: OperationBatch | null = null;
|
|
86
85
|
private write_checkpoint_batch: storage.CustomWriteCheckpointOptions[] = [];
|
|
87
86
|
private markRecordUnavailable: BucketStorageMarkRecordUnavailable | undefined;
|
|
88
87
|
private clearedError = false;
|
|
89
88
|
|
|
89
|
+
private tracer: PerformanceTracer<'storage' | 'evaluate'>;
|
|
90
|
+
|
|
90
91
|
/**
|
|
91
92
|
* Last LSN received associated with a checkpoint.
|
|
92
93
|
*
|
|
@@ -119,7 +120,7 @@ export class MongoBucketBatch
|
|
|
119
120
|
|
|
120
121
|
constructor(options: MongoBucketBatchOptions) {
|
|
121
122
|
super();
|
|
122
|
-
this.logger = options.logger
|
|
123
|
+
this.logger = options.logger;
|
|
123
124
|
this.client = options.db.client;
|
|
124
125
|
this.db = options.db;
|
|
125
126
|
this.group_id = options.groupId;
|
|
@@ -129,11 +130,13 @@ export class MongoBucketBatch
|
|
|
129
130
|
this.slot_name = options.slotName;
|
|
130
131
|
this.sync_rules = options.syncRules;
|
|
131
132
|
this.storeCurrentData = options.storeCurrentData;
|
|
133
|
+
this.mapping = options.mapping;
|
|
132
134
|
this.skipExistingRows = options.skipExistingRows;
|
|
133
135
|
this.markRecordUnavailable = options.markRecordUnavailable;
|
|
134
136
|
this.batch = new OperationBatch();
|
|
135
137
|
|
|
136
138
|
this.persisted_op = options.keepaliveOp ?? null;
|
|
139
|
+
this.tracer = options.tracer ?? new PerformanceTracer('MongoDB storage');
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
addCustomWriteCheckpoint(checkpoint: storage.BatchedCustomWriteCheckpointOptions): void {
|
|
@@ -147,6 +150,12 @@ export class MongoBucketBatch
|
|
|
147
150
|
return this.last_checkpoint_lsn;
|
|
148
151
|
}
|
|
149
152
|
|
|
153
|
+
protected abstract createPersistedBatch(writtenSize: number): PersistedBatch;
|
|
154
|
+
|
|
155
|
+
protected abstract get sourceRecordStore(): SourceRecordStore;
|
|
156
|
+
|
|
157
|
+
protected abstract cleanupDroppedSourceTables(sourceTables: storage.SourceTable[]): Promise<void>;
|
|
158
|
+
|
|
150
159
|
async flush(options?: storage.BatchBucketFlushOptions): Promise<storage.FlushedResult | null> {
|
|
151
160
|
let result: storage.FlushedResult | null = null;
|
|
152
161
|
// One flush may be split over multiple transactions.
|
|
@@ -165,6 +174,8 @@ export class MongoBucketBatch
|
|
|
165
174
|
let last_op: InternalOpId | null = null;
|
|
166
175
|
let resumeBatch: OperationBatch | null = null;
|
|
167
176
|
|
|
177
|
+
using _ = this.tracer.span('storage', 'flush');
|
|
178
|
+
|
|
168
179
|
await this.withReplicationTransaction(`Flushing ${batch?.length ?? 0} ops`, async (session, opSeq) => {
|
|
169
180
|
if (batch != null) {
|
|
170
181
|
resumeBatch = await this.replicateBatch(session, batch, opSeq, options);
|
|
@@ -198,6 +209,7 @@ export class MongoBucketBatch
|
|
|
198
209
|
options?: storage.BucketBatchCommitOptions
|
|
199
210
|
): Promise<OperationBatch | null> {
|
|
200
211
|
let sizes: Map<string, number> | undefined = undefined;
|
|
212
|
+
using _ = this.tracer.span('storage', 'replicate_batch');
|
|
201
213
|
if (this.storeCurrentData && !this.skipExistingRows) {
|
|
202
214
|
// We skip this step if we don't store current_data, since the sizes will
|
|
203
215
|
// always be small in that case.
|
|
@@ -212,33 +224,12 @@ export class MongoBucketBatch
|
|
|
212
224
|
// (automatically limited to 48MB(?) per batch by MongoDB). The issue is that it changes
|
|
213
225
|
// the order of processing, which then becomes really tricky to manage.
|
|
214
226
|
// This now takes 2+ queries, but doesn't have any issues with order of operations.
|
|
215
|
-
const sizeLookups
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
sizes = new Map<string, number>();
|
|
227
|
+
const sizeLookups = batch.batch.map((r) => ({
|
|
228
|
+
sourceTableId: mongoTableId(r.record.sourceTable.id),
|
|
229
|
+
replicaId: r.beforeId
|
|
230
|
+
}));
|
|
220
231
|
|
|
221
|
-
|
|
222
|
-
this.db.common_current_data.aggregate(
|
|
223
|
-
[
|
|
224
|
-
{
|
|
225
|
-
$match: {
|
|
226
|
-
_id: { $in: sizeLookups }
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
$project: {
|
|
231
|
-
_id: 1,
|
|
232
|
-
size: { $bsonSize: '$$ROOT' }
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
],
|
|
236
|
-
{ session }
|
|
237
|
-
);
|
|
238
|
-
for await (let doc of sizeCursor.stream()) {
|
|
239
|
-
const key = cacheKey(doc._id.t, doc._id.k);
|
|
240
|
-
sizes.set(key, doc.size);
|
|
241
|
-
}
|
|
232
|
+
sizes = await this.sourceRecordStore.loadSizes(session, sizeLookups);
|
|
242
233
|
}
|
|
243
234
|
|
|
244
235
|
// If set, we need to start a new transaction with this batch.
|
|
@@ -256,64 +247,65 @@ export class MongoBucketBatch
|
|
|
256
247
|
}
|
|
257
248
|
continue;
|
|
258
249
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
current_data_lookup.set(cacheKey(doc._id.t, doc._id.k), doc);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
let persistedBatch: PersistedBatch | null = new PersistedBatch(this.db, this.group_id, transactionSize, {
|
|
276
|
-
logger: this.logger
|
|
277
|
-
});
|
|
278
|
-
|
|
250
|
+
using lookupSpan = this.tracer.span('storage', 'lookup');
|
|
251
|
+
const lookups = b.map((r) => ({
|
|
252
|
+
sourceTableId: mongoTableId(r.record.sourceTable.id),
|
|
253
|
+
replicaId: r.beforeId
|
|
254
|
+
}));
|
|
255
|
+
let sourceRecordLookup = await this.sourceRecordStore.loadDocuments(session, lookups, this.skipExistingRows);
|
|
256
|
+
lookupSpan.end();
|
|
257
|
+
|
|
258
|
+
let persistedBatch: PersistedBatch | null = this.createPersistedBatch(transactionSize);
|
|
259
|
+
|
|
260
|
+
// The current code structure makes it tricky to cleanly split this span from the one
|
|
261
|
+
// where fluhsing. So we manually end and re-create this span whenever we flush.
|
|
262
|
+
let evalSpan = this.tracer.span('evaluate');
|
|
279
263
|
for (let op of b) {
|
|
280
264
|
if (resumeBatch) {
|
|
281
265
|
resumeBatch.push(op);
|
|
282
266
|
continue;
|
|
283
267
|
}
|
|
284
|
-
const
|
|
285
|
-
if (
|
|
268
|
+
const sourceRecord = sourceRecordLookup.get(op.internalBeforeKey) ?? null;
|
|
269
|
+
if (sourceRecord != null) {
|
|
286
270
|
// If it will be used again later, it will be set again using nextData below
|
|
287
|
-
|
|
271
|
+
sourceRecordLookup.delete(op.internalBeforeKey);
|
|
288
272
|
}
|
|
289
|
-
const nextData = this.saveOperation(persistedBatch!, op,
|
|
273
|
+
const nextData = this.saveOperation(persistedBatch!, op, sourceRecord, op_seq);
|
|
290
274
|
if (nextData != null) {
|
|
291
275
|
// Update our current_data and size cache
|
|
292
|
-
|
|
293
|
-
sizes?.set(op.internalAfterKey!, nextData.data
|
|
276
|
+
sourceRecordLookup.set(op.internalAfterKey!, nextData);
|
|
277
|
+
sizes?.set(op.internalAfterKey!, nextData.data?.length() ?? 0);
|
|
294
278
|
}
|
|
295
279
|
|
|
296
280
|
if (persistedBatch!.shouldFlushTransaction()) {
|
|
281
|
+
evalSpan.end();
|
|
297
282
|
// Transaction is getting big.
|
|
298
283
|
// Flush, and resume in a new transaction.
|
|
284
|
+
using persistSpan = this.tracer.span('storage', 'persist_flush');
|
|
299
285
|
const { flushedAny } = await persistedBatch!.flush(this.session, options);
|
|
286
|
+
|
|
300
287
|
didFlush ||= flushedAny;
|
|
301
288
|
persistedBatch = null;
|
|
302
289
|
// Computing our current progress is a little tricky here, since
|
|
303
290
|
// we're stopping in the middle of a batch.
|
|
304
291
|
// We create a new batch, and push any remaining operations to it.
|
|
305
292
|
resumeBatch = new OperationBatch();
|
|
293
|
+
persistSpan.end();
|
|
294
|
+
evalSpan = this.tracer.span('evaluate');
|
|
306
295
|
}
|
|
307
296
|
}
|
|
297
|
+
evalSpan.end();
|
|
308
298
|
|
|
309
299
|
if (persistedBatch) {
|
|
310
300
|
transactionSize = persistedBatch.currentSize;
|
|
301
|
+
using _ = this.tracer.span('storage', 'persist_flush');
|
|
311
302
|
const { flushedAny } = await persistedBatch.flush(this.session, options);
|
|
312
303
|
didFlush ||= flushedAny;
|
|
313
304
|
}
|
|
314
305
|
}
|
|
315
306
|
|
|
316
307
|
if (didFlush) {
|
|
308
|
+
using _ = this.tracer.span('storage', 'clear_error');
|
|
317
309
|
await this.clearError();
|
|
318
310
|
}
|
|
319
311
|
|
|
@@ -323,7 +315,7 @@ export class MongoBucketBatch
|
|
|
323
315
|
private saveOperation(
|
|
324
316
|
batch: PersistedBatch,
|
|
325
317
|
operation: RecordOperation,
|
|
326
|
-
|
|
318
|
+
sourceRecord: LoadedSourceRecord | null,
|
|
327
319
|
opSeq: MongoIdSequence
|
|
328
320
|
) {
|
|
329
321
|
const record = operation.record;
|
|
@@ -332,16 +324,16 @@ export class MongoBucketBatch
|
|
|
332
324
|
let after = record.after;
|
|
333
325
|
const sourceTable = record.sourceTable;
|
|
334
326
|
|
|
335
|
-
let existing_buckets:
|
|
336
|
-
let new_buckets:
|
|
337
|
-
let existing_lookups:
|
|
338
|
-
let new_lookups:
|
|
327
|
+
let existing_buckets: LoadedSourceRecord['buckets'] = [];
|
|
328
|
+
let new_buckets: LoadedSourceRecord['buckets'] = [];
|
|
329
|
+
let existing_lookups: LoadedSourceRecord['lookups'] = [];
|
|
330
|
+
let new_lookups: LoadedSourceRecord['lookups'] = [];
|
|
339
331
|
|
|
340
|
-
const
|
|
332
|
+
const sourceTableId = mongoTableId(record.sourceTable.id);
|
|
341
333
|
|
|
342
334
|
if (this.skipExistingRows) {
|
|
343
335
|
if (record.tag == SaveOperationTag.INSERT) {
|
|
344
|
-
if (
|
|
336
|
+
if (sourceRecord != null) {
|
|
345
337
|
// Initial replication, and we already have the record.
|
|
346
338
|
// This may be a different version of the record, but streaming replication
|
|
347
339
|
// will take care of that.
|
|
@@ -354,7 +346,7 @@ export class MongoBucketBatch
|
|
|
354
346
|
}
|
|
355
347
|
|
|
356
348
|
if (record.tag == SaveOperationTag.UPDATE) {
|
|
357
|
-
const result =
|
|
349
|
+
const result = sourceRecord;
|
|
358
350
|
if (result == null) {
|
|
359
351
|
// Not an error if we re-apply a transaction
|
|
360
352
|
existing_buckets = [];
|
|
@@ -375,13 +367,13 @@ export class MongoBucketBatch
|
|
|
375
367
|
} else {
|
|
376
368
|
existing_buckets = result.buckets;
|
|
377
369
|
existing_lookups = result.lookups;
|
|
378
|
-
if (this.storeCurrentData) {
|
|
379
|
-
const data = deserializeBson(
|
|
370
|
+
if (this.storeCurrentData && result.data != null) {
|
|
371
|
+
const data = deserializeBson(result.data.buffer) as SqliteRow;
|
|
380
372
|
after = storage.mergeToast<SqliteValue>(after!, data);
|
|
381
373
|
}
|
|
382
374
|
}
|
|
383
375
|
} else if (record.tag == SaveOperationTag.DELETE) {
|
|
384
|
-
const result =
|
|
376
|
+
const result = sourceRecord;
|
|
385
377
|
if (result == null) {
|
|
386
378
|
// Not an error if we re-apply a transaction
|
|
387
379
|
existing_buckets = [];
|
|
@@ -398,9 +390,9 @@ export class MongoBucketBatch
|
|
|
398
390
|
}
|
|
399
391
|
}
|
|
400
392
|
|
|
401
|
-
let afterData: bson.Binary |
|
|
393
|
+
let afterData: bson.Binary | null = null;
|
|
402
394
|
if (afterId != null && !this.storeCurrentData) {
|
|
403
|
-
afterData =
|
|
395
|
+
afterData = null;
|
|
404
396
|
} else if (afterId != null) {
|
|
405
397
|
try {
|
|
406
398
|
// This will fail immediately if the record is > 16MB.
|
|
@@ -498,13 +490,7 @@ export class MongoBucketBatch
|
|
|
498
490
|
table: sourceTable,
|
|
499
491
|
before_buckets: existing_buckets
|
|
500
492
|
});
|
|
501
|
-
new_buckets =
|
|
502
|
-
return {
|
|
503
|
-
bucket: e.bucket,
|
|
504
|
-
table: e.table,
|
|
505
|
-
id: e.id
|
|
506
|
-
};
|
|
507
|
-
});
|
|
493
|
+
new_buckets = this.sourceRecordStore.mapEvaluatedBuckets(evaluated);
|
|
508
494
|
}
|
|
509
495
|
|
|
510
496
|
if (sourceTable.syncParameters) {
|
|
@@ -537,28 +523,29 @@ export class MongoBucketBatch
|
|
|
537
523
|
evaluated: paramEvaluated,
|
|
538
524
|
existing_lookups
|
|
539
525
|
});
|
|
540
|
-
new_lookups =
|
|
541
|
-
return storage.serializeLookup(p.lookup);
|
|
542
|
-
});
|
|
526
|
+
new_lookups = this.sourceRecordStore.mapParameterLookups(paramEvaluated);
|
|
543
527
|
}
|
|
544
528
|
}
|
|
545
529
|
|
|
546
|
-
let result:
|
|
530
|
+
let result: LoadedSourceRecord | null = null;
|
|
547
531
|
|
|
548
532
|
// 5. TOAST: Update current data and bucket list.
|
|
549
533
|
if (afterId) {
|
|
550
534
|
// Insert or update
|
|
551
|
-
|
|
552
|
-
|
|
535
|
+
batch.upsertCurrentData({
|
|
536
|
+
sourceTableId,
|
|
537
|
+
replicaId: afterId,
|
|
553
538
|
data: afterData,
|
|
554
539
|
buckets: new_buckets,
|
|
555
540
|
lookups: new_lookups
|
|
556
541
|
});
|
|
557
542
|
result = {
|
|
558
|
-
|
|
559
|
-
|
|
543
|
+
sourceTableId,
|
|
544
|
+
replicaId: afterId,
|
|
545
|
+
data: afterData,
|
|
560
546
|
buckets: new_buckets,
|
|
561
|
-
lookups: new_lookups
|
|
547
|
+
lookups: new_lookups,
|
|
548
|
+
cacheKey: operation.internalAfterKey!
|
|
562
549
|
};
|
|
563
550
|
}
|
|
564
551
|
|
|
@@ -567,13 +554,15 @@ export class MongoBucketBatch
|
|
|
567
554
|
// Note that this is a soft delete.
|
|
568
555
|
// We don't specifically need a new or unique op_id here, but it must be greater than the
|
|
569
556
|
// last checkpoint, so we use next().
|
|
570
|
-
batch.softDeleteCurrentData(
|
|
557
|
+
batch.softDeleteCurrentData(sourceTableId, beforeId, opSeq.next());
|
|
571
558
|
}
|
|
572
559
|
return result;
|
|
573
560
|
}
|
|
574
561
|
|
|
575
562
|
private async withTransaction(cb: () => Promise<void>) {
|
|
563
|
+
using lockSpan = this.tracer.span('storage', 'internal_lock');
|
|
576
564
|
await replicationMutex.exclusiveLock(async () => {
|
|
565
|
+
lockSpan.end();
|
|
577
566
|
await this.session.withTransaction(
|
|
578
567
|
async () => {
|
|
579
568
|
try {
|
|
@@ -584,7 +573,9 @@ export class MongoBucketBatch
|
|
|
584
573
|
} else {
|
|
585
574
|
this.logger.warn('Transaction error', e as Error);
|
|
586
575
|
}
|
|
587
|
-
|
|
576
|
+
const delay = Math.random() * 50;
|
|
577
|
+
using _ = this.tracer.span('storage', 'retry_delay');
|
|
578
|
+
await timers.setTimeout(delay);
|
|
588
579
|
throw e;
|
|
589
580
|
}
|
|
590
581
|
},
|
|
@@ -848,25 +839,13 @@ export class MongoBucketBatch
|
|
|
848
839
|
await this.db.notifyCheckpoint();
|
|
849
840
|
this.persisted_op = null;
|
|
850
841
|
this.last_checkpoint_lsn = lsn;
|
|
851
|
-
if (
|
|
852
|
-
await this.
|
|
842
|
+
if (newLastCheckpoint != null) {
|
|
843
|
+
await this.sourceRecordStore.postCommitCleanup(newLastCheckpoint, this.logger);
|
|
853
844
|
}
|
|
854
845
|
}
|
|
855
846
|
return { checkpointBlocked, checkpointCreated };
|
|
856
847
|
}
|
|
857
848
|
|
|
858
|
-
private async cleanupCurrentData(lastCheckpoint: bigint) {
|
|
859
|
-
const result = await this.db.v3_current_data.deleteMany({
|
|
860
|
-
'_id.g': this.group_id,
|
|
861
|
-
pending_delete: { $exists: true, $lte: lastCheckpoint }
|
|
862
|
-
});
|
|
863
|
-
if (result.deletedCount > 0) {
|
|
864
|
-
this.logger.info(
|
|
865
|
-
`Cleaned up ${result.deletedCount} pending delete current_data records for checkpoint ${lastCheckpoint}`
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
|
|
870
849
|
/**
|
|
871
850
|
* Switch from processing -> active if relevant.
|
|
872
851
|
*
|
|
@@ -915,7 +894,7 @@ export class MongoBucketBatch
|
|
|
915
894
|
}
|
|
916
895
|
});
|
|
917
896
|
if (activated) {
|
|
918
|
-
this.logger.info(`Activated new
|
|
897
|
+
this.logger.info(`Activated new replication stream at ${lsn}`);
|
|
919
898
|
await this.db.notifyCheckpoint();
|
|
920
899
|
this.needsActivation = false;
|
|
921
900
|
}
|
|
@@ -988,9 +967,11 @@ export class MongoBucketBatch
|
|
|
988
967
|
|
|
989
968
|
await this.withTransaction(async () => {
|
|
990
969
|
for (let table of sourceTables) {
|
|
991
|
-
await this.db.
|
|
970
|
+
await this.db.commonSourceTables(this.group_id).deleteOne({ _id: mongoTableId(table.id) });
|
|
992
971
|
}
|
|
993
972
|
});
|
|
973
|
+
|
|
974
|
+
await this.cleanupDroppedSourceTables(sourceTables);
|
|
994
975
|
return result;
|
|
995
976
|
}
|
|
996
977
|
|
|
@@ -1022,24 +1003,10 @@ export class MongoBucketBatch
|
|
|
1022
1003
|
let lastBatchCount = BATCH_LIMIT;
|
|
1023
1004
|
while (lastBatchCount == BATCH_LIMIT) {
|
|
1024
1005
|
await this.withReplicationTransaction(`Truncate ${sourceTable.qualifiedName}`, async (session, opSeq) => {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
pending_delete: { $exists: false }
|
|
1030
|
-
};
|
|
1031
|
-
|
|
1032
|
-
const cursor = this.db.common_current_data.find(current_data_filter, {
|
|
1033
|
-
projection: {
|
|
1034
|
-
_id: 1,
|
|
1035
|
-
buckets: 1,
|
|
1036
|
-
lookups: 1
|
|
1037
|
-
},
|
|
1038
|
-
limit: BATCH_LIMIT,
|
|
1039
|
-
session: session
|
|
1040
|
-
});
|
|
1041
|
-
const batch = await cursor.toArray();
|
|
1042
|
-
const persistedBatch = new PersistedBatch(this.db, this.group_id, 0, { logger: this.logger });
|
|
1006
|
+
using evalSpan = this.tracer.span('evaluate');
|
|
1007
|
+
const sourceTableId = mongoTableId(sourceTable.id);
|
|
1008
|
+
const batch = await this.sourceRecordStore.loadTruncateBatch(session, sourceTableId, BATCH_LIMIT);
|
|
1009
|
+
const persistedBatch = this.createPersistedBatch(0);
|
|
1043
1010
|
|
|
1044
1011
|
for (let value of batch) {
|
|
1045
1012
|
persistedBatch.saveBucketData({
|
|
@@ -1047,19 +1014,22 @@ export class MongoBucketBatch
|
|
|
1047
1014
|
before_buckets: value.buckets,
|
|
1048
1015
|
evaluated: [],
|
|
1049
1016
|
table: sourceTable,
|
|
1050
|
-
sourceKey: value.
|
|
1017
|
+
sourceKey: value.replicaId
|
|
1051
1018
|
});
|
|
1052
1019
|
persistedBatch.saveParameterData({
|
|
1053
1020
|
op_seq: opSeq,
|
|
1054
1021
|
existing_lookups: value.lookups,
|
|
1055
1022
|
evaluated: [],
|
|
1056
1023
|
sourceTable: sourceTable,
|
|
1057
|
-
sourceKey: value.
|
|
1024
|
+
sourceKey: value.replicaId
|
|
1058
1025
|
});
|
|
1059
1026
|
|
|
1060
1027
|
// Since this is not from streaming replication, we can do a hard delete
|
|
1061
|
-
persistedBatch.hardDeleteCurrentData(value.
|
|
1028
|
+
persistedBatch.hardDeleteCurrentData(sourceTableId, value.replicaId);
|
|
1062
1029
|
}
|
|
1030
|
+
evalSpan.end();
|
|
1031
|
+
|
|
1032
|
+
using _ = this.tracer.span('storage', 'persist_flush');
|
|
1063
1033
|
await persistedBatch.flush(session);
|
|
1064
1034
|
lastBatchCount = batch.length;
|
|
1065
1035
|
|
|
@@ -1083,7 +1053,7 @@ export class MongoBucketBatch
|
|
|
1083
1053
|
copy.snapshotStatus = snapshotStatus;
|
|
1084
1054
|
|
|
1085
1055
|
await this.withTransaction(async () => {
|
|
1086
|
-
await this.db.
|
|
1056
|
+
await this.db.commonSourceTables(this.group_id).updateOne(
|
|
1087
1057
|
{ _id: mongoTableId(table.id) },
|
|
1088
1058
|
{
|
|
1089
1059
|
$set: {
|
|
@@ -1138,7 +1108,7 @@ export class MongoBucketBatch
|
|
|
1138
1108
|
const ids = tables.map((table) => mongoTableId(table.id));
|
|
1139
1109
|
|
|
1140
1110
|
await this.withTransaction(async () => {
|
|
1141
|
-
await this.db.
|
|
1111
|
+
await this.db.commonSourceTables(this.group_id).updateMany(
|
|
1142
1112
|
{ _id: { $in: ids } },
|
|
1143
1113
|
{
|
|
1144
1114
|
$set: {
|
|
@@ -1204,7 +1174,3 @@ export class MongoBucketBatch
|
|
|
1204
1174
|
);
|
|
1205
1175
|
}
|
|
1206
1176
|
}
|
|
1207
|
-
|
|
1208
|
-
export function currentBucketKey(b: CurrentBucket) {
|
|
1209
|
-
return `${b.bucket}/${b.table}/${b.id}`;
|
|
1210
|
-
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as bson from 'bson';
|
|
2
|
+
import { SourceRecordBucketState } from './common/SourceRecordStore.js';
|
|
3
|
+
|
|
4
|
+
export const MAX_ROW_SIZE = 15 * 1024 * 1024;
|
|
5
|
+
|
|
6
|
+
export const EMPTY_DATA = new bson.Binary(bson.serialize({}));
|
|
7
|
+
|
|
8
|
+
export function currentBucketKey(bucket: SourceRecordBucketState) {
|
|
9
|
+
const prefix = bucket.definitionId == null ? '' : `${bucket.definitionId}:`;
|
|
10
|
+
return `${prefix}${bucket.bucket}/${bucket.table}/${bucket.id}`;
|
|
11
|
+
}
|