@powersync/service-module-mongodb-storage 0.15.4 → 0.17.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 +69 -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 +2 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +8 -6
- package/dist/storage/MongoBucketStorage.js +153 -66
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/BucketDefinitionMapping.d.ts +15 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js +58 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
- package/dist/storage/implementation/CheckpointState.d.ts +20 -0
- package/dist/storage/implementation/CheckpointState.js +31 -0
- package/dist/storage/implementation/CheckpointState.js.map +1 -0
- package/dist/storage/implementation/MongoBucketBatch.d.ts +48 -35
- package/dist/storage/implementation/MongoBucketBatch.js +118 -379
- 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 +29 -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 +67 -0
- package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +22 -5
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +56 -13
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +61 -32
- package/dist/storage/implementation/MongoSyncBucketStorage.js +85 -523
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +10 -4
- package/dist/storage/implementation/MongoSyncRulesLock.js +19 -13
- 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/SyncRuleStateUpdate.d.ts +14 -0
- package/dist/storage/implementation/SyncRuleStateUpdate.js +36 -0
- package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -0
- 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 +35 -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 +41 -36
- package/dist/storage/implementation/db.js +77 -99
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +79 -66
- package/dist/storage/implementation/models.js +20 -1
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +27 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +407 -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 +50 -0
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +354 -0
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -0
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +25 -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 +45 -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 +30 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +463 -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 +4 -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 +63 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +508 -0
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +28 -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 +22 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +74 -0
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -0
- package/dist/storage/implementation/v3/models.d.ts +101 -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 +6 -3
- package/dist/storage/storage-index.js +6 -3
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/utils/util.d.ts +10 -3
- package/dist/utils/util.js +24 -3
- 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/storage/MongoBucketStorage.ts +254 -99
- package/src/storage/implementation/BucketDefinitionMapping.ts +75 -0
- package/src/storage/implementation/CheckpointState.ts +59 -0
- package/src/storage/implementation/MongoBucketBatch.ts +182 -490
- package/src/storage/implementation/MongoBucketBatchShared.ts +11 -0
- package/src/storage/implementation/MongoChecksums.ts +53 -75
- package/src/storage/implementation/MongoCompactor.ts +374 -404
- package/src/storage/implementation/MongoParameterCompactor.ts +37 -24
- package/src/storage/implementation/MongoPersistedSyncRules.ts +82 -0
- package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +78 -16
- package/src/storage/implementation/MongoSyncBucketStorage.ts +179 -628
- package/src/storage/implementation/MongoSyncRulesLock.ts +20 -16
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +3 -1
- package/src/storage/implementation/OperationBatch.ts +1 -1
- package/src/storage/implementation/SyncRuleStateUpdate.ts +38 -0
- 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 +48 -0
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +80 -0
- package/src/storage/implementation/createMongoSyncBucketStorage.ts +25 -0
- package/src/storage/implementation/db.ts +110 -131
- package/src/storage/implementation/models.ts +102 -79
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +509 -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 +543 -0
- package/src/storage/implementation/v1/PersistedBatchV1.ts +229 -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 +99 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +607 -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 +11 -0
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +678 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +317 -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 +117 -0
- package/src/storage/implementation/v3/models.ts +164 -0
- package/src/storage/storage-index.ts +6 -3
- package/src/utils/util.ts +34 -5
- package/test/src/storage_compacting.test.ts +57 -29
- package/test/src/storage_sync.test.ts +767 -5
- package/test/src/storeCurrentData.test.ts +211 -0
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetIntanceOptions, storage } from '@powersync/service-core';
|
|
1
|
+
import { GetIntanceOptions, LEGACY_STORAGE_VERSION, storage } from '@powersync/service-core';
|
|
2
2
|
|
|
3
3
|
import { DO_NOT_LOG, ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
4
4
|
import { v4 as uuid } from 'uuid';
|
|
@@ -6,15 +6,25 @@ import { v4 as uuid } from 'uuid';
|
|
|
6
6
|
import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
7
7
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
8
8
|
|
|
9
|
+
import { ObjectId } from 'bson';
|
|
9
10
|
import { generateSlotName } from '../utils/util.js';
|
|
11
|
+
import { BucketDefinitionMapping } from './implementation/BucketDefinitionMapping.js';
|
|
12
|
+
import type { MongoSyncBucketStorage } from './implementation/createMongoSyncBucketStorage.js';
|
|
13
|
+
import { createMongoSyncBucketStorage } from './implementation/createMongoSyncBucketStorage.js';
|
|
10
14
|
import { PowerSyncMongo } from './implementation/db.js';
|
|
11
|
-
import { getMongoStorageConfig,
|
|
15
|
+
import { getMongoStorageConfig, StorageConfig, SyncRuleDocumentBase } from './implementation/models.js';
|
|
12
16
|
import { MongoChecksumOptions } from './implementation/MongoChecksums.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
17
|
+
import {
|
|
18
|
+
MongoPersistedSyncRulesContentV1,
|
|
19
|
+
MongoPersistedSyncRulesContentV3
|
|
20
|
+
} from './implementation/MongoPersistedSyncRulesContent.js';
|
|
21
|
+
import { syncRuleStateUpdatePipeline } from './implementation/SyncRuleStateUpdate.js';
|
|
22
|
+
import { SyncRuleDocumentV1 } from './implementation/v1/models.js';
|
|
23
|
+
import { VersionedPowerSyncMongoV3 } from './implementation/v3/VersionedPowerSyncMongoV3.js';
|
|
24
|
+
import { ReplicationStreamDocumentV3, SyncConfigDefinition } from './storage-index.js';
|
|
15
25
|
|
|
16
26
|
export interface MongoBucketStorageOptions {
|
|
17
|
-
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'>;
|
|
27
|
+
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig' | 'mapping'>;
|
|
18
28
|
}
|
|
19
29
|
|
|
20
30
|
export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
@@ -52,11 +62,11 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
52
62
|
if ((typeof id as any) == 'bigint') {
|
|
53
63
|
id = Number(id);
|
|
54
64
|
}
|
|
55
|
-
const storageConfig = (syncRules as
|
|
56
|
-
const storage =
|
|
65
|
+
const storageConfig = (syncRules as MongoPersistedSyncRulesContentV1).getStorageConfig();
|
|
66
|
+
const storage = createMongoSyncBucketStorage(
|
|
57
67
|
this,
|
|
58
68
|
id,
|
|
59
|
-
syncRules as
|
|
69
|
+
syncRules as MongoPersistedSyncRulesContentV1,
|
|
60
70
|
slot_name,
|
|
61
71
|
undefined,
|
|
62
72
|
{
|
|
@@ -100,7 +110,7 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
100
110
|
const active = await this.getActiveSyncRulesContent();
|
|
101
111
|
|
|
102
112
|
if (next != null && next.id == sync_rules_group_id) {
|
|
103
|
-
// We need to redo the "next"
|
|
113
|
+
// We need to redo the "next" replication stream
|
|
104
114
|
await this.updateSyncRules(next.asUpdateOptions());
|
|
105
115
|
// Pro-actively stop replicating
|
|
106
116
|
await this.db.sync_rules.updateOne(
|
|
@@ -108,15 +118,11 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
108
118
|
_id: next.id,
|
|
109
119
|
state: storage.SyncRuleState.PROCESSING
|
|
110
120
|
},
|
|
111
|
-
|
|
112
|
-
$set: {
|
|
113
|
-
state: storage.SyncRuleState.STOP
|
|
114
|
-
}
|
|
115
|
-
}
|
|
121
|
+
syncRuleStateUpdatePipeline(storage.SyncRuleState.STOP)
|
|
116
122
|
);
|
|
117
123
|
await this.db.notifyCheckpoint();
|
|
118
124
|
} else if (next == null && active?.id == sync_rules_group_id) {
|
|
119
|
-
// Slot removed for "active"
|
|
125
|
+
// Slot removed for "active" replication stream, while there is no "next" one.
|
|
120
126
|
await this.updateSyncRules(active.asUpdateOptions());
|
|
121
127
|
|
|
122
128
|
// In this case we keep the old one as active for clients, so that that existing clients
|
|
@@ -128,45 +134,133 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
128
134
|
_id: active.id,
|
|
129
135
|
state: storage.SyncRuleState.ACTIVE
|
|
130
136
|
},
|
|
131
|
-
|
|
132
|
-
$set: {
|
|
133
|
-
state: storage.SyncRuleState.ERRORED
|
|
134
|
-
}
|
|
135
|
-
}
|
|
137
|
+
syncRuleStateUpdatePipeline(storage.SyncRuleState.ERRORED)
|
|
136
138
|
);
|
|
137
139
|
await this.db.notifyCheckpoint();
|
|
138
140
|
} else if (next != null && active?.id == sync_rules_group_id) {
|
|
139
|
-
// Already have next
|
|
141
|
+
// Already have next replication stream, but need to stop replicating the active one.
|
|
140
142
|
|
|
141
143
|
await this.db.sync_rules.updateOne(
|
|
142
144
|
{
|
|
143
145
|
_id: active.id,
|
|
144
146
|
state: storage.SyncRuleState.ACTIVE
|
|
145
147
|
},
|
|
148
|
+
syncRuleStateUpdatePipeline(storage.SyncRuleState.ERRORED)
|
|
149
|
+
);
|
|
150
|
+
await this.db.notifyCheckpoint();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private async updateSyncRulesV3(
|
|
155
|
+
options: storage.UpdateSyncRulesOptions,
|
|
156
|
+
storageVersion: number,
|
|
157
|
+
storageConfig: StorageConfig
|
|
158
|
+
): Promise<MongoPersistedSyncRulesContentV3> {
|
|
159
|
+
let rules: MongoPersistedSyncRulesContentV3 | undefined = undefined;
|
|
160
|
+
const versioned = this.db.versioned(storageConfig) as VersionedPowerSyncMongoV3;
|
|
161
|
+
|
|
162
|
+
const session = this.session;
|
|
163
|
+
|
|
164
|
+
await session.withTransaction(async () => {
|
|
165
|
+
// Only have a single replication stream with PROCESSING.
|
|
166
|
+
await this.db.sync_rules.updateMany(
|
|
167
|
+
{
|
|
168
|
+
state: storage.SyncRuleState.PROCESSING
|
|
169
|
+
},
|
|
170
|
+
syncRuleStateUpdatePipeline(storage.SyncRuleState.STOP),
|
|
171
|
+
{ session }
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const id_doc = await this.db.op_id_sequence.findOneAndUpdate(
|
|
175
|
+
{
|
|
176
|
+
_id: 'sync_rules'
|
|
177
|
+
},
|
|
146
178
|
{
|
|
147
|
-
$
|
|
148
|
-
|
|
179
|
+
$inc: {
|
|
180
|
+
op_id: 1n
|
|
149
181
|
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
upsert: true,
|
|
185
|
+
returnDocument: 'after',
|
|
186
|
+
session
|
|
150
187
|
}
|
|
151
188
|
);
|
|
189
|
+
|
|
190
|
+
const id = Number(id_doc!.op_id);
|
|
191
|
+
const slot_name = generateSlotName(this.slot_name_prefix, id);
|
|
192
|
+
|
|
193
|
+
const mapping = BucketDefinitionMapping.fromParsedSyncRules(options.config.parsed);
|
|
194
|
+
|
|
195
|
+
const syncConfigDoc: SyncConfigDefinition = {
|
|
196
|
+
_id: new ObjectId(),
|
|
197
|
+
replication_stream_id: id,
|
|
198
|
+
created_at: new Date(),
|
|
199
|
+
storage_version: storageVersion,
|
|
200
|
+
content: options.config.yaml,
|
|
201
|
+
serialized_plan: options.config.plan,
|
|
202
|
+
rule_mapping: mapping.serialize()
|
|
203
|
+
};
|
|
204
|
+
await versioned.syncConfigDefinitions.insertOne(syncConfigDoc, { session });
|
|
205
|
+
|
|
206
|
+
const doc: ReplicationStreamDocumentV3 = {
|
|
207
|
+
_id: id,
|
|
208
|
+
storage_version: storageVersion,
|
|
209
|
+
sync_configs: [
|
|
210
|
+
{
|
|
211
|
+
_id: syncConfigDoc._id,
|
|
212
|
+
state: storage.SyncRuleState.PROCESSING,
|
|
213
|
+
keepalive_op: null,
|
|
214
|
+
last_checkpoint: null,
|
|
215
|
+
last_checkpoint_lsn: null,
|
|
216
|
+
no_checkpoint_before: null,
|
|
217
|
+
snapshot_done: false
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
snapshot_lsn: undefined,
|
|
221
|
+
state: storage.SyncRuleState.PROCESSING,
|
|
222
|
+
slot_name: slot_name,
|
|
223
|
+
last_checkpoint_ts: null,
|
|
224
|
+
last_fatal_error: null,
|
|
225
|
+
last_fatal_error_ts: null,
|
|
226
|
+
last_keepalive_ts: null
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
await this.db.sync_rules.insertOne(doc, { session });
|
|
152
230
|
await this.db.notifyCheckpoint();
|
|
153
|
-
|
|
231
|
+
rules = new MongoPersistedSyncRulesContentV3(this.db, doc, syncConfigDoc);
|
|
232
|
+
if (options.lock) {
|
|
233
|
+
// The lock is persisted on rules.current_lock
|
|
234
|
+
await rules.lock(session);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return rules!;
|
|
154
239
|
}
|
|
155
240
|
|
|
156
|
-
async updateSyncRules(
|
|
157
|
-
|
|
241
|
+
async updateSyncRules(
|
|
242
|
+
options: storage.UpdateSyncRulesOptions
|
|
243
|
+
): Promise<MongoPersistedSyncRulesContentV1 | MongoPersistedSyncRulesContentV3> {
|
|
244
|
+
const storageVersion =
|
|
245
|
+
options.storageVersion ?? options.config.parsed.config.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
|
|
246
|
+
|
|
158
247
|
const storageConfig = getMongoStorageConfig(storageVersion);
|
|
159
|
-
|
|
248
|
+
if (storageConfig.incrementalReprocessing) {
|
|
249
|
+
return this.updateSyncRulesV3(options, storageVersion, storageConfig);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let rules: MongoPersistedSyncRulesContentV1 | undefined = undefined;
|
|
160
253
|
|
|
161
|
-
|
|
254
|
+
const session = this.session;
|
|
162
255
|
|
|
163
|
-
await
|
|
164
|
-
// Only have a single
|
|
256
|
+
await session.withTransaction(async () => {
|
|
257
|
+
// Only have a single replication stream with PROCESSING.
|
|
165
258
|
await this.db.sync_rules.updateMany(
|
|
166
259
|
{
|
|
167
260
|
state: storage.SyncRuleState.PROCESSING
|
|
168
261
|
},
|
|
169
|
-
|
|
262
|
+
syncRuleStateUpdatePipeline(storage.SyncRuleState.STOP),
|
|
263
|
+
{ session }
|
|
170
264
|
);
|
|
171
265
|
|
|
172
266
|
const id_doc = await this.db.op_id_sequence.findOneAndUpdate(
|
|
@@ -180,14 +274,15 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
180
274
|
},
|
|
181
275
|
{
|
|
182
276
|
upsert: true,
|
|
183
|
-
returnDocument: 'after'
|
|
277
|
+
returnDocument: 'after',
|
|
278
|
+
session
|
|
184
279
|
}
|
|
185
280
|
);
|
|
186
281
|
|
|
187
282
|
const id = Number(id_doc!.op_id);
|
|
188
283
|
const slot_name = generateSlotName(this.slot_name_prefix, id);
|
|
189
284
|
|
|
190
|
-
const doc:
|
|
285
|
+
const doc: SyncRuleDocumentV1 = {
|
|
191
286
|
_id: id,
|
|
192
287
|
storage_version: storageVersion,
|
|
193
288
|
content: options.config.yaml,
|
|
@@ -205,43 +300,68 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
205
300
|
last_fatal_error_ts: null,
|
|
206
301
|
last_keepalive_ts: null
|
|
207
302
|
};
|
|
208
|
-
|
|
303
|
+
|
|
304
|
+
await this.db.sync_rules.insertOne(doc, { session });
|
|
209
305
|
await this.db.notifyCheckpoint();
|
|
210
|
-
rules = new
|
|
306
|
+
rules = new MongoPersistedSyncRulesContentV1(this.db, doc);
|
|
211
307
|
if (options.lock) {
|
|
212
|
-
|
|
308
|
+
// The lock is persisted on rules.current_lock
|
|
309
|
+
await rules.lock(session);
|
|
213
310
|
}
|
|
214
311
|
});
|
|
215
312
|
|
|
216
313
|
return rules!;
|
|
217
314
|
}
|
|
218
315
|
|
|
219
|
-
async getActiveSyncRulesContent(): Promise<
|
|
316
|
+
async getActiveSyncRulesContent(): Promise<
|
|
317
|
+
MongoPersistedSyncRulesContentV1 | MongoPersistedSyncRulesContentV3 | null
|
|
318
|
+
> {
|
|
220
319
|
const doc = await this.db.sync_rules.findOne(
|
|
221
320
|
{
|
|
222
321
|
state: { $in: [storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED] }
|
|
223
322
|
},
|
|
224
323
|
{ sort: { _id: -1 }, limit: 1 }
|
|
225
324
|
);
|
|
325
|
+
|
|
326
|
+
return this.getSyncRulesContent(doc, [storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED]);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private async getSyncRulesContent(doc: SyncRuleDocumentBase | null, stateFilter: storage.SyncRuleState[]) {
|
|
226
330
|
if (doc == null) {
|
|
227
331
|
return null;
|
|
228
332
|
}
|
|
333
|
+
const storageConfig = getMongoStorageConfig(doc.storage_version ?? LEGACY_STORAGE_VERSION);
|
|
334
|
+
|
|
335
|
+
if (storageConfig.incrementalReprocessing) {
|
|
336
|
+
const v3 = doc as ReplicationStreamDocumentV3;
|
|
337
|
+
const active = v3.sync_configs.find((c) => stateFilter.includes(c.state));
|
|
338
|
+
if (active == null) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
229
341
|
|
|
230
|
-
|
|
342
|
+
// TODO: cache the config. It could specifically help for the main replication loop
|
|
343
|
+
// that checks for active replication streams.
|
|
344
|
+
// It is not a major bottleneck though, since it only runs once every couple of seconds at most.
|
|
345
|
+
const db = this.db.versioned(storageConfig) as VersionedPowerSyncMongoV3;
|
|
346
|
+
const syncConfigDoc = await db.syncConfigDefinitions.findOne({ _id: active._id });
|
|
347
|
+
if (syncConfigDoc == null) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
return new MongoPersistedSyncRulesContentV3(this.db, v3, syncConfigDoc);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return new MongoPersistedSyncRulesContentV1(this.db, doc as SyncRuleDocumentV1);
|
|
231
354
|
}
|
|
232
355
|
|
|
233
|
-
async getNextSyncRulesContent(): Promise<
|
|
356
|
+
async getNextSyncRulesContent(): Promise<MongoPersistedSyncRulesContentV1 | MongoPersistedSyncRulesContentV3 | null> {
|
|
234
357
|
const doc = await this.db.sync_rules.findOne(
|
|
235
358
|
{
|
|
236
359
|
state: storage.SyncRuleState.PROCESSING
|
|
237
360
|
},
|
|
238
361
|
{ sort: { _id: -1 }, limit: 1 }
|
|
239
362
|
);
|
|
240
|
-
if (doc == null) {
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
363
|
|
|
244
|
-
return
|
|
364
|
+
return this.getSyncRulesContent(doc, [storage.SyncRuleState.PROCESSING]);
|
|
245
365
|
}
|
|
246
366
|
|
|
247
367
|
async getReplicatingSyncRules(): Promise<storage.PersistedSyncRulesContent[]> {
|
|
@@ -251,9 +371,13 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
251
371
|
})
|
|
252
372
|
.toArray();
|
|
253
373
|
|
|
254
|
-
return
|
|
255
|
-
|
|
256
|
-
|
|
374
|
+
return (
|
|
375
|
+
await Promise.all(
|
|
376
|
+
docs.map((doc) => {
|
|
377
|
+
return this.getSyncRulesContent(doc, [storage.SyncRuleState.PROCESSING, storage.SyncRuleState.ACTIVE]);
|
|
378
|
+
})
|
|
379
|
+
)
|
|
380
|
+
).filter((r) => r != null);
|
|
257
381
|
}
|
|
258
382
|
|
|
259
383
|
async getStoppedSyncRules(): Promise<storage.PersistedSyncRulesContent[]> {
|
|
@@ -263,9 +387,13 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
263
387
|
})
|
|
264
388
|
.toArray();
|
|
265
389
|
|
|
266
|
-
return
|
|
267
|
-
|
|
268
|
-
|
|
390
|
+
return (
|
|
391
|
+
await Promise.all(
|
|
392
|
+
docs.map((doc) => {
|
|
393
|
+
return this.getSyncRulesContent(doc, [storage.SyncRuleState.STOP]);
|
|
394
|
+
})
|
|
395
|
+
)
|
|
396
|
+
).filter((d) => d != null);
|
|
269
397
|
}
|
|
270
398
|
|
|
271
399
|
async getActiveStorage(): Promise<MongoSyncBucketStorage | null> {
|
|
@@ -296,63 +424,90 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
296
424
|
}
|
|
297
425
|
};
|
|
298
426
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return {
|
|
302
|
-
operations_size_bytes: 0,
|
|
303
|
-
parameters_size_bytes: 0,
|
|
304
|
-
replication_size_bytes: 0
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
const operations_aggregate = await this.db.bucket_data
|
|
427
|
+
// For now, we get storage metrics over all v1 and v3 collections.
|
|
428
|
+
// In the future, we may split these metrics to report separately for active replication streams versus processing streams.
|
|
308
429
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
430
|
+
const aggregateStaticCollection = async <T extends mongo.Document>(collection: mongo.Collection<T>) => {
|
|
431
|
+
// We check whether the collection exists before getting the statistics. This avoids repeated
|
|
432
|
+
// errors in the MongoDB logs if the collection hasn't been created yet.
|
|
433
|
+
const exists =
|
|
434
|
+
(await this.db.db.listCollections({ name: collection.collectionName }, { nameOnly: true }).toArray()).length >
|
|
435
|
+
0;
|
|
436
|
+
if (!exists) {
|
|
437
|
+
return [{ storageStats: { size: 0 } }];
|
|
438
|
+
}
|
|
318
439
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
440
|
+
return collection
|
|
441
|
+
.aggregate([
|
|
442
|
+
{
|
|
443
|
+
$collStats: {
|
|
444
|
+
storageStats: {}
|
|
445
|
+
}
|
|
324
446
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
447
|
+
])
|
|
448
|
+
.toArray()
|
|
449
|
+
.catch(ignoreNotExisting);
|
|
450
|
+
};
|
|
329
451
|
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
452
|
+
const operations_aggregate = await aggregateStaticCollection(this.db.bucket_data);
|
|
453
|
+
const v3_operation_aggregates = await Promise.all(
|
|
454
|
+
(await this.db.listBucketDataCollectionsV3()).map((collection) =>
|
|
455
|
+
collection
|
|
456
|
+
.aggregate([
|
|
457
|
+
{
|
|
458
|
+
$collStats: {
|
|
459
|
+
storageStats: {}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
])
|
|
463
|
+
.toArray()
|
|
464
|
+
.catch(ignoreNotExisting)
|
|
465
|
+
)
|
|
466
|
+
);
|
|
340
467
|
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
468
|
+
const parameters_aggregate = await aggregateStaticCollection(this.db.bucket_parameters);
|
|
469
|
+
|
|
470
|
+
const v3_parameter_aggregates = await Promise.all(
|
|
471
|
+
(await this.db.listAllParameterIndexCollectionsV3()).map((collection) =>
|
|
472
|
+
collection
|
|
473
|
+
.aggregate([
|
|
474
|
+
{
|
|
475
|
+
$collStats: {
|
|
476
|
+
storageStats: {}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
])
|
|
480
|
+
.toArray()
|
|
481
|
+
.catch(ignoreNotExisting)
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
const v1_source_record_aggregate = await aggregateStaticCollection(this.db.current_data);
|
|
486
|
+
|
|
487
|
+
const source_record_aggregates = await Promise.all(
|
|
488
|
+
(await this.db.listAllSourceRecordCollectionsV3()).map((collection) =>
|
|
489
|
+
collection
|
|
490
|
+
.aggregate([
|
|
491
|
+
{
|
|
492
|
+
$collStats: {
|
|
493
|
+
storageStats: {}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
])
|
|
497
|
+
.toArray()
|
|
498
|
+
.catch(ignoreNotExisting)
|
|
499
|
+
)
|
|
500
|
+
);
|
|
351
501
|
return {
|
|
352
|
-
operations_size_bytes:
|
|
353
|
-
|
|
502
|
+
operations_size_bytes:
|
|
503
|
+
Number(operations_aggregate[0].storageStats.size) +
|
|
504
|
+
v3_operation_aggregates.reduce((total, aggregate) => total + Number(aggregate[0].storageStats.size), 0),
|
|
505
|
+
parameters_size_bytes:
|
|
506
|
+
Number(parameters_aggregate[0].storageStats.size) +
|
|
507
|
+
v3_parameter_aggregates.reduce((total, aggregate) => total + Number(aggregate[0].storageStats.size), 0),
|
|
354
508
|
replication_size_bytes:
|
|
355
|
-
Number(
|
|
509
|
+
Number(v1_source_record_aggregate[0]?.storageStats?.size ?? 0) +
|
|
510
|
+
source_record_aggregates.reduce((total, aggregate) => total + Number(aggregate[0]?.storageStats?.size ?? 0), 0)
|
|
356
511
|
};
|
|
357
512
|
}
|
|
358
513
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import {
|
|
3
|
+
BucketDataSource,
|
|
4
|
+
BucketDefinitionId,
|
|
5
|
+
ParameterIndexId,
|
|
6
|
+
ParameterIndexLookupCreator,
|
|
7
|
+
SyncConfigWithErrors
|
|
8
|
+
} from '@powersync/service-sync-rules';
|
|
9
|
+
import { SyncConfigDefinition } from '../storage-index.js';
|
|
10
|
+
|
|
11
|
+
export class BucketDefinitionMapping {
|
|
12
|
+
static fromSyncConfig(doc: Pick<SyncConfigDefinition, 'rule_mapping'>): BucketDefinitionMapping {
|
|
13
|
+
return new BucketDefinitionMapping(doc.rule_mapping?.definitions ?? {}, doc.rule_mapping?.parameter_indexes ?? {});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static fromParsedSyncRules(syncRules: SyncConfigWithErrors): BucketDefinitionMapping {
|
|
17
|
+
const definitionNames = syncRules.config.bucketDataSources.map((source) => source.uniqueName).sort();
|
|
18
|
+
const parameterKeys = syncRules.config.bucketParameterLookupSources
|
|
19
|
+
.map((source) => `${source.sourceId.lookupName}#${source.sourceId.queryId}`)
|
|
20
|
+
.sort();
|
|
21
|
+
|
|
22
|
+
const definitions: Record<string, BucketDefinitionId> = {};
|
|
23
|
+
const parameterLookups: Record<string, ParameterIndexId> = {};
|
|
24
|
+
|
|
25
|
+
for (const [index, uniqueName] of definitionNames.entries()) {
|
|
26
|
+
definitions[uniqueName] = (index + 1).toString(16);
|
|
27
|
+
}
|
|
28
|
+
for (const [index, key] of parameterKeys.entries()) {
|
|
29
|
+
parameterLookups[key] = (index + 1).toString(16);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return new BucketDefinitionMapping(definitions, parameterLookups);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
private definitions: Record<string, BucketDefinitionId> = {},
|
|
37
|
+
private parameterLookupMapping: Record<string, ParameterIndexId> = {}
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
bucketSourceId(source: BucketDataSource): BucketDefinitionId {
|
|
41
|
+
const defId = this.definitions[source.uniqueName];
|
|
42
|
+
if (defId == null) {
|
|
43
|
+
throw new ServiceAssertionError(`No mapping found for bucket source ${source.uniqueName}`);
|
|
44
|
+
}
|
|
45
|
+
return defId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
allBucketDefinitionIds(): BucketDefinitionId[] {
|
|
49
|
+
return Object.values(this.definitions);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
allParameterIndexIds(): ParameterIndexId[] {
|
|
53
|
+
return Object.values(this.parameterLookupMapping);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
parameterLookupId(source: ParameterIndexLookupCreator): ParameterIndexId {
|
|
57
|
+
const key = this.parameterLookupKey(source.sourceId.lookupName, source.sourceId.queryId);
|
|
58
|
+
const defId = this.parameterLookupMapping[key];
|
|
59
|
+
if (defId == null) {
|
|
60
|
+
throw new ServiceAssertionError(`No mapping found for parameter lookup source ${key}`);
|
|
61
|
+
}
|
|
62
|
+
return defId;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private parameterLookupKey(lookupName: string, queryId: string) {
|
|
66
|
+
return `${lookupName}#${queryId}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
serialize(): SyncConfigDefinition['rule_mapping'] {
|
|
70
|
+
return {
|
|
71
|
+
definitions: { ...this.definitions },
|
|
72
|
+
parameter_indexes: { ...this.parameterLookupMapping }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface CheckpointStateInput {
|
|
2
|
+
lsn: string;
|
|
3
|
+
snapshotDone: boolean;
|
|
4
|
+
lastCheckpointLsn: string | null;
|
|
5
|
+
noCheckpointBefore: string | null;
|
|
6
|
+
keepaliveOp: bigint | null;
|
|
7
|
+
lastCheckpoint: bigint | null;
|
|
8
|
+
persistedOp: bigint | null;
|
|
9
|
+
createEmptyCheckpoints: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CheckpointStateResult {
|
|
13
|
+
canCheckpoint: boolean;
|
|
14
|
+
checkpointBlocked: boolean;
|
|
15
|
+
checkpointCreated: boolean;
|
|
16
|
+
notEmpty: boolean;
|
|
17
|
+
newKeepaliveOp: bigint | null;
|
|
18
|
+
newLastCheckpoint: bigint | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function maxOpId(...values: (bigint | null | undefined)[]): bigint {
|
|
22
|
+
let max = 0n;
|
|
23
|
+
for (const value of values) {
|
|
24
|
+
if (value != null && value > max) {
|
|
25
|
+
max = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return max;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function canCheckpointState(
|
|
32
|
+
lsn: string,
|
|
33
|
+
state: Pick<CheckpointStateInput, 'snapshotDone' | 'lastCheckpointLsn' | 'noCheckpointBefore'>
|
|
34
|
+
): boolean {
|
|
35
|
+
return (
|
|
36
|
+
state.snapshotDone === true &&
|
|
37
|
+
(state.lastCheckpointLsn == null || state.lastCheckpointLsn <= lsn) &&
|
|
38
|
+
(state.noCheckpointBefore == null || state.noCheckpointBefore <= lsn)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function calculateCheckpointState(input: CheckpointStateInput): CheckpointStateResult {
|
|
43
|
+
const canCheckpoint = canCheckpointState(input.lsn, input);
|
|
44
|
+
const newKeepaliveOp = canCheckpoint ? null : maxOpId(input.keepaliveOp, input.persistedOp);
|
|
45
|
+
const newLastCheckpoint = canCheckpoint
|
|
46
|
+
? maxOpId(input.lastCheckpoint, input.persistedOp, input.keepaliveOp)
|
|
47
|
+
: input.lastCheckpoint;
|
|
48
|
+
const notEmpty =
|
|
49
|
+
input.createEmptyCheckpoints || input.keepaliveOp !== newKeepaliveOp || input.lastCheckpoint !== newLastCheckpoint;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
canCheckpoint,
|
|
53
|
+
checkpointBlocked: !canCheckpoint,
|
|
54
|
+
checkpointCreated: canCheckpoint && notEmpty,
|
|
55
|
+
notEmpty,
|
|
56
|
+
newKeepaliveOp,
|
|
57
|
+
newLastCheckpoint
|
|
58
|
+
};
|
|
59
|
+
}
|