@powersync/service-module-mongodb-storage 0.20.0 → 0.22.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 +62 -0
- package/dist/storage/MongoBucketStorage.d.ts +36 -3
- package/dist/storage/MongoBucketStorage.js +372 -207
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +17 -5
- package/dist/storage/implementation/MongoBucketBatch.js +44 -17
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +19 -79
- package/dist/storage/implementation/MongoCompactor.js +27 -238
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParameterCompactor.d.ts +83 -10
- package/dist/storage/implementation/MongoParameterCompactor.js +309 -96
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +9 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +29 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +4 -2
- package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -1
- package/dist/storage/implementation/MongoStorageProvider.js +7 -3
- package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +27 -11
- package/dist/storage/implementation/MongoSyncBucketStorage.js +78 -31
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.js +21 -9
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/MongoWriteBatch.d.ts +49 -0
- package/dist/storage/implementation/MongoWriteBatch.js +149 -0
- package/dist/storage/implementation/MongoWriteBatch.js.map +1 -0
- package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +9 -7
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js +9 -30
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/SyncRuleStateUpdate.d.ts +11 -5
- package/dist/storage/implementation/SyncRuleStateUpdate.js +14 -6
- package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -1
- package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +22 -2
- package/dist/storage/implementation/common/PersistedBatch.d.ts +32 -4
- package/dist/storage/implementation/common/PersistedBatch.js +49 -6
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +3 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +3 -0
- package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +9 -1
- package/dist/storage/implementation/db.js +27 -1
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +31 -0
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +2 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +33 -4
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +38 -6
- package/dist/storage/implementation/v1/MongoCompactorV1.js +247 -20
- package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +16 -2
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -9
- package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +18 -11
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +65 -16
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +7 -5
- package/dist/storage/implementation/v1/PersistedBatchV1.js +22 -28
- package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/models.js +1 -0
- package/dist/storage/implementation/v1/models.js.map +1 -1
- package/dist/storage/implementation/v3/CompactionLease.d.ts +50 -0
- package/dist/storage/implementation/v3/CompactionLease.js +131 -0
- package/dist/storage/implementation/v3/CompactionLease.js.map +1 -0
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +10 -2
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +100 -26
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +82 -25
- package/dist/storage/implementation/v3/MongoCompactorV3.js +698 -159
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +18 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +23 -0
- package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +2 -15
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +60 -92
- package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -1
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +19 -9
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +91 -31
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.d.ts +26 -0
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js +82 -0
- package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js.map +1 -0
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +14 -8
- package/dist/storage/implementation/v3/PersistedBatchV3.js +76 -42
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +12 -2
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +42 -3
- package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
- package/dist/storage/implementation/v3/bucket-format.js +2 -0
- package/dist/storage/implementation/v3/bucket-format.js.map +1 -1
- package/dist/storage/implementation/v3/compact-utils.d.ts +107 -0
- package/dist/storage/implementation/v3/compact-utils.js +216 -0
- package/dist/storage/implementation/v3/compact-utils.js.map +1 -0
- package/dist/storage/implementation/v3/compaction-constants.d.ts +5 -0
- package/dist/storage/implementation/v3/compaction-constants.js +6 -0
- package/dist/storage/implementation/v3/compaction-constants.js.map +1 -0
- package/dist/storage/implementation/v3/models.d.ts +84 -4
- package/dist/storage/implementation/v3/models.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +7 -8
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +16 -5
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +14 -11
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +6 -8
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +17 -11
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +38 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +164 -0
- package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -0
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +37 -12
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +197 -25
- package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/source-table-utils.d.ts +6 -6
- package/dist/storage/implementation/v3/source-table-utils.js +30 -37
- package/dist/storage/implementation/v3/source-table-utils.js.map +1 -1
- package/dist/storage/storage-index.d.ts +2 -1
- package/dist/storage/storage-index.js +1 -0
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/types/types.d.ts +28 -1
- package/dist/types/types.js +28 -7
- package/dist/types/types.js.map +1 -1
- package/dist/utils/test-utils.js +1 -0
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.js +3 -1
- package/dist/utils/util.js.map +1 -1
- package/package.json +10 -9
- package/src/storage/MongoBucketStorage.ts +507 -269
- package/src/storage/implementation/MongoBucketBatch.ts +67 -24
- package/src/storage/implementation/MongoCompactor.ts +35 -346
- package/src/storage/implementation/MongoParameterCompactor.ts +388 -102
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +34 -0
- package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +4 -2
- package/src/storage/implementation/MongoStorageProvider.ts +15 -3
- package/src/storage/implementation/MongoSyncBucketStorage.ts +114 -40
- package/src/storage/implementation/MongoSyncRulesLock.ts +22 -9
- package/src/storage/implementation/MongoWriteBatch.ts +172 -0
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +16 -46
- package/src/storage/implementation/SyncRuleStateUpdate.ts +13 -6
- package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +24 -2
- package/src/storage/implementation/common/PersistedBatch.ts +66 -10
- package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +4 -0
- package/src/storage/implementation/db.ts +35 -2
- package/src/storage/implementation/models.ts +34 -0
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +46 -6
- package/src/storage/implementation/v1/MongoCompactorV1.ts +327 -40
- package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +25 -9
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +87 -27
- package/src/storage/implementation/v1/PersistedBatchV1.ts +25 -30
- package/src/storage/implementation/v1/models.ts +1 -0
- package/src/storage/implementation/v3/CompactionLease.ts +152 -0
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +138 -34
- package/src/storage/implementation/v3/MongoCompactorV3.ts +958 -225
- package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +34 -0
- package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +100 -109
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +111 -41
- package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
- package/src/storage/implementation/v3/PersistedBatchV3.ts +93 -48
- package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +55 -4
- package/src/storage/implementation/v3/bucket-format.ts +2 -0
- package/src/storage/implementation/v3/compact-utils.ts +320 -0
- package/src/storage/implementation/v3/compaction-constants.ts +5 -0
- package/src/storage/implementation/v3/models.ts +91 -3
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +24 -9
- package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +20 -5
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +26 -14
- package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +229 -0
- package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +279 -29
- package/src/storage/implementation/v3/source-table-utils.ts +39 -41
- package/src/storage/storage-index.ts +2 -0
- package/src/types/types.ts +42 -7
- package/src/utils/test-utils.ts +1 -0
- package/src/utils/util.ts +3 -1
- package/test/src/__snapshots__/storage.test.ts.snap +25 -0
- package/test/src/__snapshots__/storage_sync.test.ts.snap +605 -16
- package/test/src/chunk_compaction_config.test.ts +38 -0
- package/test/src/cleanup-stopped-sync-configs.test.ts +40 -13
- package/test/src/compact-utils.test.ts +226 -0
- package/test/src/helpers/MemoryObjectStorage.ts +14 -6
- package/test/src/object_storage_usage.test.ts +267 -0
- package/test/src/parameter_compacting_v1.test.ts +120 -0
- package/test/src/parameter_compacting_v3.test.ts +192 -0
- package/test/src/parameter_compaction_fence.test.ts +276 -0
- package/test/src/storage.test.ts +273 -22
- package/test/src/storage_compacting.test.ts +968 -246
- package/test/src/storage_s3_checksums.test.ts +3 -4
- package/test/src/storage_s3_compaction_lifecycle.test.ts +138 -12
- package/test/src/storage_s3_reading.test.ts +290 -2
- package/test/src/storage_s3_writing.test.ts +1 -0
- package/test/src/storage_sync.test.ts +336 -41
- package/test/src/util.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,6 +3,8 @@ import { BucketDefinitionMapping, ColumnDescriptor, JsonValue, storage } from '@
|
|
|
3
3
|
import {
|
|
4
4
|
BucketDataSource,
|
|
5
5
|
BucketDefinitionId,
|
|
6
|
+
EventDefinitionId,
|
|
7
|
+
HydratedEventDescriptor,
|
|
6
8
|
HydratedSyncConfig,
|
|
7
9
|
MatchingSources,
|
|
8
10
|
ParameterIndexId,
|
|
@@ -22,12 +24,13 @@ export interface SourceTableIdentity {
|
|
|
22
24
|
export interface SourceTableMembershipIds {
|
|
23
25
|
bucketDataSourceIds: BucketDefinitionId[];
|
|
24
26
|
parameterLookupSourceIds: ParameterIndexId[];
|
|
27
|
+
eventDefinitionIds: EventDefinitionId[];
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export interface SourceTableDesiredResolution {
|
|
28
31
|
bucketSourceById: Map<BucketDefinitionId, BucketDataSource>;
|
|
29
32
|
parameterLookupSourceById: Map<ParameterIndexId, ParameterIndexLookupCreator>;
|
|
30
|
-
|
|
33
|
+
eventDefinitionById: Map<EventDefinitionId, HydratedEventDescriptor>;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export interface SourceTableReconciliationContext {
|
|
@@ -55,7 +58,7 @@ export interface SourceTableReconciliationPlan {
|
|
|
55
58
|
narrowingUpdates: SourceTableMembershipUpdate[];
|
|
56
59
|
/**
|
|
57
60
|
* Memberships for a new source-table doc covering desired ids no existing doc covers,
|
|
58
|
-
* or null if no new doc is needed.
|
|
61
|
+
* or null if no new doc is needed.
|
|
59
62
|
*/
|
|
60
63
|
newTableMemberships: SourceTableMembershipIds | null;
|
|
61
64
|
/** Identity-overlapping docs that conflict with the current identity and must be dropped. */
|
|
@@ -75,7 +78,8 @@ export interface NewSourceTable {
|
|
|
75
78
|
export function sourceTableDesiredResolution(
|
|
76
79
|
syncConfig: HydratedSyncConfig,
|
|
77
80
|
ref: SourceTableRef,
|
|
78
|
-
mapping: BucketDefinitionMapping
|
|
81
|
+
mapping: BucketDefinitionMapping,
|
|
82
|
+
eventById: ReadonlyMap<EventDefinitionId, HydratedEventDescriptor>
|
|
79
83
|
): SourceTableDesiredResolution {
|
|
80
84
|
const matchingSources = syncConfig.getMatchingSources(ref);
|
|
81
85
|
return {
|
|
@@ -85,7 +89,7 @@ export function sourceTableDesiredResolution(
|
|
|
85
89
|
parameterLookupSourceById: new Map(
|
|
86
90
|
matchingSources.parameterLookupSources.map((source) => [mapping.parameterLookupId(source), source] as const)
|
|
87
91
|
),
|
|
88
|
-
|
|
92
|
+
eventDefinitionById: new Map([...eventById].filter(([, event]) => event.tableTriggersEvent(ref)))
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
95
|
|
|
@@ -116,28 +120,33 @@ function intersectMembershipIds(
|
|
|
116
120
|
): SourceTableMembershipIds {
|
|
117
121
|
return {
|
|
118
122
|
bucketDataSourceIds: doc.bucket_data_source_ids.filter((id) => desired.bucketSourceById.has(id)),
|
|
119
|
-
parameterLookupSourceIds: doc.parameter_lookup_source_ids.filter((id) => desired.parameterLookupSourceById.has(id))
|
|
123
|
+
parameterLookupSourceIds: doc.parameter_lookup_source_ids.filter((id) => desired.parameterLookupSourceById.has(id)),
|
|
124
|
+
eventDefinitionIds: doc.event_definition_ids.filter((id) => desired.eventDefinitionById.has(id))
|
|
120
125
|
};
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
function hasMembershipIds(memberships: SourceTableMembershipIds) {
|
|
124
|
-
return
|
|
129
|
+
return (
|
|
130
|
+
memberships.bucketDataSourceIds.length > 0 ||
|
|
131
|
+
memberships.parameterLookupSourceIds.length > 0 ||
|
|
132
|
+
memberships.eventDefinitionIds.length > 0
|
|
133
|
+
);
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
function sameMembershipIds(doc: SourceTableDocumentV3, memberships: SourceTableMembershipIds) {
|
|
128
137
|
return (
|
|
129
138
|
sameStringArray(doc.bucket_data_source_ids, memberships.bucketDataSourceIds) &&
|
|
130
|
-
sameStringArray(doc.parameter_lookup_source_ids, memberships.parameterLookupSourceIds)
|
|
139
|
+
sameStringArray(doc.parameter_lookup_source_ids, memberships.parameterLookupSourceIds) &&
|
|
140
|
+
sameStringArray(doc.event_definition_ids, memberships.eventDefinitionIds)
|
|
131
141
|
);
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
class SourceTableReconciliationPlanner {
|
|
135
145
|
private readonly coveredBucketDataSourceIds = new Set<string>();
|
|
136
146
|
private readonly coveredParameterLookupSourceIds = new Set<string>();
|
|
137
|
-
private readonly
|
|
147
|
+
private readonly coveredEventDefinitionIds = new Set<string>();
|
|
138
148
|
private readonly tables: storage.SourceTable[] = [];
|
|
139
149
|
private readonly narrowingUpdates: SourceTableMembershipUpdate[] = [];
|
|
140
|
-
private retainedEventOnlyTable = false;
|
|
141
150
|
|
|
142
151
|
constructor(private readonly context: SourceTableReconciliationContext) {}
|
|
143
152
|
|
|
@@ -168,24 +177,15 @@ class SourceTableReconciliationPlanner {
|
|
|
168
177
|
private retainDoc(doc: SourceTableDocumentV3) {
|
|
169
178
|
const memberships = intersectMembershipIds(doc, this.context.desired);
|
|
170
179
|
const coversDesiredMembership = hasMembershipIds(memberships);
|
|
171
|
-
const coversEventOnlyTable =
|
|
172
|
-
!this.desiredHasMembership() && this.context.desired.triggersEvent && !this.retainedEventOnlyTable;
|
|
173
180
|
|
|
174
181
|
this.recordCoverage(doc, memberships);
|
|
175
|
-
this.planNarrowingUpdate(doc, memberships, coversDesiredMembership
|
|
182
|
+
this.planNarrowingUpdate(doc, memberships, coversDesiredMembership);
|
|
176
183
|
|
|
177
|
-
if (coversDesiredMembership
|
|
178
|
-
this.retainedEventOnlyTable ||= coversEventOnlyTable;
|
|
179
|
-
this.retainedDocIds.add(doc._id.toHexString());
|
|
184
|
+
if (coversDesiredMembership) {
|
|
180
185
|
this.tables.push(this.sourceTableFor(doc, memberships));
|
|
181
186
|
}
|
|
182
187
|
}
|
|
183
188
|
|
|
184
|
-
private desiredHasMembership() {
|
|
185
|
-
const { desired } = this.context;
|
|
186
|
-
return desired.bucketSourceById.size > 0 || desired.parameterLookupSourceById.size > 0;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
189
|
private recordCoverage(doc: SourceTableDocumentV3, memberships: SourceTableMembershipIds) {
|
|
190
190
|
this.addCoverage(doc, 'bucket data source', this.coveredBucketDataSourceIds, memberships.bucketDataSourceIds);
|
|
191
191
|
this.addCoverage(
|
|
@@ -194,12 +194,14 @@ class SourceTableReconciliationPlanner {
|
|
|
194
194
|
this.coveredParameterLookupSourceIds,
|
|
195
195
|
memberships.parameterLookupSourceIds
|
|
196
196
|
);
|
|
197
|
+
this.addCoverage(doc, 'event definition', this.coveredEventDefinitionIds, memberships.eventDefinitionIds);
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
// Membership sets must be pairwise disjoint across the docs of one physical table:
|
|
200
|
-
// each desired id is covered by exactly one doc, so each definition
|
|
201
|
-
//
|
|
202
|
-
//
|
|
201
|
+
// each desired id is covered by exactly one doc, so each definition is evaluated through
|
|
202
|
+
// only one SourceTable for a physical row. Different docs may own different event ids.
|
|
203
|
+
// The algorithm maintains this (new docs only get uncovered ids, narrowing only removes ids) -
|
|
204
|
+
// overlap means the persisted state is corrupt.
|
|
203
205
|
private addCoverage(doc: SourceTableDocumentV3, kind: string, covered: Set<string>, ids: string[]) {
|
|
204
206
|
const { schema, name } = this.context.identity;
|
|
205
207
|
for (const id of ids) {
|
|
@@ -215,11 +217,9 @@ class SourceTableReconciliationPlanner {
|
|
|
215
217
|
private planNarrowingUpdate(
|
|
216
218
|
doc: SourceTableDocumentV3,
|
|
217
219
|
memberships: SourceTableMembershipIds,
|
|
218
|
-
coversDesiredMembership: boolean
|
|
219
|
-
coversEventOnlyTable: boolean
|
|
220
|
+
coversDesiredMembership: boolean
|
|
220
221
|
) {
|
|
221
|
-
const shouldNarrow =
|
|
222
|
-
(coversDesiredMembership || coversEventOnlyTable) && !doc.snapshot_done && !sameMembershipIds(doc, memberships);
|
|
222
|
+
const shouldNarrow = coversDesiredMembership && !doc.snapshot_done && !sameMembershipIds(doc, memberships);
|
|
223
223
|
|
|
224
224
|
if (!shouldNarrow) {
|
|
225
225
|
return;
|
|
@@ -239,9 +239,12 @@ class SourceTableReconciliationPlanner {
|
|
|
239
239
|
),
|
|
240
240
|
parameterLookupSourceIds: [...desired.parameterLookupSourceById.keys()].filter(
|
|
241
241
|
(id) => !this.coveredParameterLookupSourceIds.has(id)
|
|
242
|
+
),
|
|
243
|
+
eventDefinitionIds: [...desired.eventDefinitionById.keys()].filter(
|
|
244
|
+
(id) => !this.coveredEventDefinitionIds.has(id)
|
|
242
245
|
)
|
|
243
246
|
};
|
|
244
|
-
if (hasMembershipIds(uncovered)
|
|
247
|
+
if (hasMembershipIds(uncovered)) {
|
|
245
248
|
return uncovered;
|
|
246
249
|
}
|
|
247
250
|
return null;
|
|
@@ -254,6 +257,7 @@ class SourceTableReconciliationPlanner {
|
|
|
254
257
|
connectionTag,
|
|
255
258
|
syncConfig,
|
|
256
259
|
mapping,
|
|
260
|
+
desired.eventDefinitionById,
|
|
257
261
|
matchingSourcesFor(desired, memberships),
|
|
258
262
|
memberships
|
|
259
263
|
);
|
|
@@ -306,6 +310,7 @@ export function createNewSourceTable(
|
|
|
306
310
|
snapshot_status: undefined,
|
|
307
311
|
bucket_data_source_ids: memberships.bucketDataSourceIds,
|
|
308
312
|
parameter_lookup_source_ids: memberships.parameterLookupSourceIds,
|
|
313
|
+
event_definition_ids: memberships.eventDefinitionIds,
|
|
309
314
|
// Records created together share the same source metadata.
|
|
310
315
|
source_metadata: newTableSourceMetadata
|
|
311
316
|
};
|
|
@@ -314,6 +319,7 @@ export function createNewSourceTable(
|
|
|
314
319
|
connectionTag,
|
|
315
320
|
syncConfig,
|
|
316
321
|
mapping,
|
|
322
|
+
desired.eventDefinitionById,
|
|
317
323
|
matchingSourcesFor(desired, memberships),
|
|
318
324
|
memberships
|
|
319
325
|
);
|
|
@@ -322,17 +328,6 @@ export function createNewSourceTable(
|
|
|
322
328
|
return { doc, table };
|
|
323
329
|
}
|
|
324
330
|
|
|
325
|
-
export function designateEventCarrier(tables: storage.SourceTable[], triggersEvent: boolean) {
|
|
326
|
-
if (!triggersEvent) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const eventCarrier = tables.find((table) => table.snapshotComplete) ?? tables[0];
|
|
331
|
-
for (const table of tables) {
|
|
332
|
-
table.syncEvent = table === eventCarrier;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
331
|
function sourceTableMembershipsFromDocument(
|
|
337
332
|
doc: SourceTableDocumentV3,
|
|
338
333
|
syncConfig: HydratedSyncConfig,
|
|
@@ -356,6 +351,7 @@ export function sourceTableFromDocument(
|
|
|
356
351
|
connectionTag: string,
|
|
357
352
|
syncConfig: HydratedSyncConfig,
|
|
358
353
|
mapping: BucketDefinitionMapping,
|
|
354
|
+
eventById: ReadonlyMap<EventDefinitionId, HydratedEventDescriptor>,
|
|
359
355
|
memberships?: MatchingSources,
|
|
360
356
|
membershipIds?: SourceTableMembershipIds
|
|
361
357
|
): storage.SourceTable {
|
|
@@ -364,7 +360,8 @@ export function sourceTableFromDocument(
|
|
|
364
360
|
bucketDataSourceIds: resolvedMemberships.bucketDataSources.map((source) => mapping.bucketSourceId(source)),
|
|
365
361
|
parameterLookupSourceIds: resolvedMemberships.parameterLookupSources.map((source) =>
|
|
366
362
|
mapping.parameterLookupId(source)
|
|
367
|
-
)
|
|
363
|
+
),
|
|
364
|
+
eventDefinitionIds: doc.event_definition_ids.filter((id) => eventById.has(id))
|
|
368
365
|
};
|
|
369
366
|
const table = new storage.SourceTable({
|
|
370
367
|
id: doc._id,
|
|
@@ -383,11 +380,12 @@ export function sourceTableFromDocument(
|
|
|
383
380
|
parameterLookupSources: resolvedMemberships.parameterLookupSources,
|
|
384
381
|
bucketDataSourceIds: new Set(resolvedMembershipIds.bucketDataSourceIds),
|
|
385
382
|
parameterLookupSourceIds: new Set(resolvedMembershipIds.parameterLookupSourceIds),
|
|
383
|
+
eventDefinitionIds: new Set(resolvedMembershipIds.eventDefinitionIds),
|
|
386
384
|
sourceMetadata: doc.source_metadata ?? null
|
|
387
385
|
});
|
|
388
386
|
table.syncData = table.bucketDataSources.length > 0;
|
|
389
387
|
table.syncParameters = table.parameterLookupSources.length > 0;
|
|
390
|
-
table.syncEvent =
|
|
388
|
+
table.syncEvent = table.eventDefinitionIds!.size > 0;
|
|
391
389
|
table.snapshotStatus =
|
|
392
390
|
doc.snapshot_status == null
|
|
393
391
|
? undefined
|
|
@@ -15,11 +15,13 @@ export { loadBucketDataDocument, serializeBucketData } from './implementation/v3
|
|
|
15
15
|
export {
|
|
16
16
|
BucketDataDocumentV3,
|
|
17
17
|
BucketOperation,
|
|
18
|
+
ObjectStorageUsageDocument,
|
|
18
19
|
RecordedLookupV3,
|
|
19
20
|
ReplicationStreamDocumentV3,
|
|
20
21
|
SyncConfigDefinition,
|
|
21
22
|
SyncRuleConfigStateV3,
|
|
22
23
|
taggedBucketParameterDocumentToTagged
|
|
23
24
|
} from './implementation/v3/models.js';
|
|
25
|
+
export * from './implementation/v3/object-storage/ObjectStorageUsage.js';
|
|
24
26
|
export * from './MongoBucketStorage.js';
|
|
25
27
|
export * from './MongoReportStorage.js';
|
package/src/types/types.ts
CHANGED
|
@@ -3,6 +3,20 @@ import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
|
3
3
|
import * as service_types from '@powersync/service-types';
|
|
4
4
|
import * as t from 'ts-codec';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* AWS defaults mode, as used by the AWS SDK.
|
|
8
|
+
*
|
|
9
|
+
* This is the baseline for the object storage request timeouts, so that they do not each need to be
|
|
10
|
+
* configured individually.
|
|
11
|
+
*
|
|
12
|
+
* The SDK's `legacy` and `auto` modes are not selectable here: `legacy` defines no timeouts at all,
|
|
13
|
+
* and `auto` makes the timeouts depend on where the process happens to be running. Both are still
|
|
14
|
+
* handled when they come from the AWS environment, and are then treated as `standard`.
|
|
15
|
+
*/
|
|
16
|
+
export const S3DefaultsMode = service_types.enumLiteral('standard', 'in-region', 'cross-region', 'mobile');
|
|
17
|
+
|
|
18
|
+
export type S3DefaultsMode = t.Encoded<typeof S3DefaultsMode>;
|
|
19
|
+
|
|
6
20
|
const S3ObjectStorageConfig = t.object({
|
|
7
21
|
type: t.literal('s3'),
|
|
8
22
|
bucket: t.string,
|
|
@@ -13,21 +27,24 @@ const S3ObjectStorageConfig = t.object({
|
|
|
13
27
|
access_key_id: t.string.optional(),
|
|
14
28
|
secret_access_key: t.string.optional(),
|
|
15
29
|
concurrency_limit: t.number.optional(),
|
|
30
|
+
// Defaults to the AWS_DEFAULTS_MODE environment variable.
|
|
31
|
+
defaults_mode: S3DefaultsMode.optional(),
|
|
16
32
|
// Chunks whose BSON-serialized size falls below this byte threshold
|
|
17
33
|
// stay inline in MongoDB instead of being offloaded to S3. Default 1024.
|
|
18
34
|
inline_threshold_bytes: t.number.optional()
|
|
19
35
|
});
|
|
20
36
|
|
|
21
|
-
export const MongoStorageReadPreference =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
export const MongoStorageReadPreference = service_types.enumLiteral(
|
|
38
|
+
'primary',
|
|
39
|
+
'primaryPreferred',
|
|
40
|
+
'secondary',
|
|
41
|
+
'secondaryPreferred',
|
|
42
|
+
'nearest'
|
|
43
|
+
);
|
|
27
44
|
|
|
28
45
|
export type MongoStorageReadPreference = t.Encoded<typeof MongoStorageReadPreference>;
|
|
29
46
|
|
|
30
|
-
export const MongoStorageConfig = lib_mongo.BaseMongoConfig.and(
|
|
47
|
+
export const MongoStorageConfig = service_types.configFile.BaseStorageConfig.and(lib_mongo.BaseMongoConfig).and(
|
|
31
48
|
t.object({
|
|
32
49
|
/**
|
|
33
50
|
* Read preference for bulk checksum and bucket data reads.
|
|
@@ -48,6 +65,9 @@ export const MongoStorageConfig = lib_mongo.BaseMongoConfig.and(
|
|
|
48
65
|
*/
|
|
49
66
|
clear_batch_throttle_rate: t.number.optional(),
|
|
50
67
|
|
|
68
|
+
/** Maximum concurrent buckets across V3 chunk-compaction jobs. Range: 1–64. Default: 4 with object storage, otherwise 2. */
|
|
69
|
+
chunk_compaction_concurrency: t.number.optional(),
|
|
70
|
+
|
|
51
71
|
object_storage: S3ObjectStorageConfig.optional()
|
|
52
72
|
})
|
|
53
73
|
);
|
|
@@ -56,6 +76,21 @@ export type MongoStorageConfig = t.Encoded<typeof MongoStorageConfig>;
|
|
|
56
76
|
export type MongoStorageConfigDecoded = t.Decoded<typeof MongoStorageConfig>;
|
|
57
77
|
|
|
58
78
|
export const DEFAULT_CLEAR_BATCH_THROTTLE_RATE = 0.2;
|
|
79
|
+
export const DEFAULT_CHUNK_COMPACTION_CONCURRENCY = 2;
|
|
80
|
+
export const DEFAULT_OBJECT_STORAGE_CHUNK_COMPACTION_CONCURRENCY = 4;
|
|
81
|
+
|
|
82
|
+
export function normalizeChunkCompactionConcurrency(value: number | undefined, hasObjectStorage = false): number {
|
|
83
|
+
const concurrency =
|
|
84
|
+
value ??
|
|
85
|
+
(hasObjectStorage ? DEFAULT_OBJECT_STORAGE_CHUNK_COMPACTION_CONCURRENCY : DEFAULT_CHUNK_COMPACTION_CONCURRENCY);
|
|
86
|
+
if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 64) {
|
|
87
|
+
throw new ServiceError(
|
|
88
|
+
ErrorCode.PSYNC_S3201,
|
|
89
|
+
'storage.chunk_compaction_concurrency must be an integer between 1 and 64'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return concurrency;
|
|
93
|
+
}
|
|
59
94
|
|
|
60
95
|
export function normalizeClearBatchThrottleRate(value: number | undefined): number {
|
|
61
96
|
const rate = value ?? DEFAULT_CLEAR_BATCH_THROTTLE_RATE;
|
package/src/utils/test-utils.ts
CHANGED
|
@@ -31,6 +31,7 @@ export function mongoTestStorageFactoryGenerator(factoryOptions: MongoTestStorag
|
|
|
31
31
|
checksumOptions: factoryOptions.checksumOptions,
|
|
32
32
|
supportsMultipleSyncConfigs: factoryOptions.supportsMultipleSyncConfigs,
|
|
33
33
|
objectStorage: factoryOptions.objectStorage,
|
|
34
|
+
chunkCompactionConcurrency: factoryOptions.chunkCompactionConcurrency,
|
|
34
35
|
inlineThresholdBytes: factoryOptions.inlineThresholdBytes
|
|
35
36
|
});
|
|
36
37
|
},
|
package/src/utils/util.ts
CHANGED
|
@@ -121,7 +121,9 @@ export function mapOpEntry(row: BucketDataDoc): utils.OplogEntry {
|
|
|
121
121
|
object_type: row.table,
|
|
122
122
|
object_id: row.row_id,
|
|
123
123
|
checksum: Number(row.checksum),
|
|
124
|
-
|
|
124
|
+
// Storage V3 always persists this during replication. The fallback serves V1 data
|
|
125
|
+
// written before subkey persistence was introduced.
|
|
126
|
+
subkey: row.subkey ?? replicaIdToSubkey(row.source_table!, row.source_key!),
|
|
125
127
|
data: row.data
|
|
126
128
|
};
|
|
127
129
|
} else {
|
|
@@ -75,6 +75,31 @@ exports[`Mongo Sync Bucket Storage - Data - v3 > (insert, delete, insert), (dele
|
|
|
75
75
|
]
|
|
76
76
|
`;
|
|
77
77
|
|
|
78
|
+
exports[`Mongo Sync Bucket Storage - Data - v4 > (insert, delete, insert), (delete) 1`] = `
|
|
79
|
+
[
|
|
80
|
+
{
|
|
81
|
+
"checksum": 2871785649,
|
|
82
|
+
"object_id": "test1",
|
|
83
|
+
"op": "PUT",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"checksum": 2872534815,
|
|
87
|
+
"object_id": "test1",
|
|
88
|
+
"op": "REMOVE",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"checksum": 2871785649,
|
|
92
|
+
"object_id": "test1",
|
|
93
|
+
"op": "PUT",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"checksum": 2872534815,
|
|
97
|
+
"object_id": "test1",
|
|
98
|
+
"op": "REMOVE",
|
|
99
|
+
},
|
|
100
|
+
]
|
|
101
|
+
`;
|
|
102
|
+
|
|
78
103
|
exports[`Mongo Sync Bucket Storage - split buckets > (insert, delete, insert), (delete) 1`] = `
|
|
79
104
|
[
|
|
80
105
|
{
|