@powersync/service-module-mongodb-storage 0.0.0-dev-20250310210938 → 0.0.0-dev-20250312090341
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 +4 -9
- package/dist/migrations/db/migrations/1741697235857-bucket-state-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1741697235857-bucket-state-index.js +28 -0
- package/dist/migrations/db/migrations/1741697235857-bucket-state-index.js.map +1 -0
- package/dist/storage/implementation/MongoCompactor.js +14 -1
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +6 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.js +100 -8
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/PersistedBatch.d.ts +8 -0
- package/dist/storage/implementation/PersistedBatch.js +47 -0
- package/dist/storage/implementation/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +2 -1
- package/dist/storage/implementation/db.js +3 -0
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +8 -0
- package/package.json +5 -5
- package/src/migrations/db/migrations/1741697235857-bucket-state-index.ts +40 -0
- package/src/storage/implementation/MongoCompactor.ts +19 -1
- package/src/storage/implementation/MongoSyncBucketStorage.ts +128 -10
- package/src/storage/implementation/PersistedBatch.ts +55 -0
- package/src/storage/implementation/db.ts +4 -0
- package/src/storage/implementation/models.ts +9 -0
- package/test/src/setup.ts +3 -2
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@powersync/service-module-mongodb-storage",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
4
|
"types": "dist/index.d.ts",
|
|
5
|
-
"version": "0.0.0-dev-
|
|
5
|
+
"version": "0.0.0-dev-20250312090341",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"license": "FSL-1.1-Apache-2.0",
|
|
8
8
|
"type": "module",
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"lru-cache": "^10.2.2",
|
|
29
29
|
"uuid": "^9.0.1",
|
|
30
30
|
"@powersync/lib-services-framework": "0.5.3",
|
|
31
|
-
"@powersync/service-core": "0.0.0-dev-
|
|
31
|
+
"@powersync/service-core": "0.0.0-dev-20250312090341",
|
|
32
32
|
"@powersync/service-jsonbig": "0.17.10",
|
|
33
33
|
"@powersync/service-sync-rules": "0.24.1",
|
|
34
|
-
"@powersync/service-types": "0.
|
|
35
|
-
"@powersync/lib-service-mongodb": "0.0.0-dev-
|
|
34
|
+
"@powersync/service-types": "0.9.0",
|
|
35
|
+
"@powersync/lib-service-mongodb": "0.0.0-dev-20250312090341"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/uuid": "^9.0.4",
|
|
39
|
-
"@powersync/service-core-tests": "0.0.0-dev-
|
|
39
|
+
"@powersync/service-core-tests": "0.0.0-dev-20250312090341"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -b",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { migrations } from '@powersync/service-core';
|
|
2
|
+
import * as storage from '../../../storage/storage-index.js';
|
|
3
|
+
import { MongoStorageConfig } from '../../../types/types.js';
|
|
4
|
+
|
|
5
|
+
const INDEX_NAME = 'bucket_updates';
|
|
6
|
+
|
|
7
|
+
export const up: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
8
|
+
const {
|
|
9
|
+
service_context: { configuration }
|
|
10
|
+
} = context;
|
|
11
|
+
const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
await db.bucket_state.createIndex(
|
|
15
|
+
{
|
|
16
|
+
'_id.g': 1,
|
|
17
|
+
last_op: 1
|
|
18
|
+
},
|
|
19
|
+
{ name: INDEX_NAME, unique: true }
|
|
20
|
+
);
|
|
21
|
+
} finally {
|
|
22
|
+
await db.client.close();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const down: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
27
|
+
const {
|
|
28
|
+
service_context: { configuration }
|
|
29
|
+
} = context;
|
|
30
|
+
|
|
31
|
+
const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (await db.bucket_state.indexExists(INDEX_NAME)) {
|
|
35
|
+
await db.bucket_state.dropIndex(INDEX_NAME);
|
|
36
|
+
}
|
|
37
|
+
} finally {
|
|
38
|
+
await db.client.close();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -314,10 +314,12 @@ export class MongoCompactor {
|
|
|
314
314
|
let lastOpId: BucketDataKey | null = null;
|
|
315
315
|
let targetOp: bigint | null = null;
|
|
316
316
|
let gotAnOp = false;
|
|
317
|
+
let numberOfOpsToClear = 0;
|
|
317
318
|
for await (let op of query.stream()) {
|
|
318
319
|
if (op.op == 'MOVE' || op.op == 'REMOVE' || op.op == 'CLEAR') {
|
|
319
320
|
checksum = utils.addChecksums(checksum, op.checksum);
|
|
320
321
|
lastOpId = op._id;
|
|
322
|
+
numberOfOpsToClear += 1;
|
|
321
323
|
if (op.op != 'CLEAR') {
|
|
322
324
|
gotAnOp = true;
|
|
323
325
|
}
|
|
@@ -337,7 +339,7 @@ export class MongoCompactor {
|
|
|
337
339
|
return;
|
|
338
340
|
}
|
|
339
341
|
|
|
340
|
-
logger.info(`Flushing CLEAR at ${lastOpId?.o}`);
|
|
342
|
+
logger.info(`Flushing CLEAR for ${numberOfOpsToClear} ops at ${lastOpId?.o}`);
|
|
341
343
|
await this.db.bucket_data.deleteMany(
|
|
342
344
|
{
|
|
343
345
|
_id: {
|
|
@@ -362,6 +364,22 @@ export class MongoCompactor {
|
|
|
362
364
|
},
|
|
363
365
|
{ session }
|
|
364
366
|
);
|
|
367
|
+
|
|
368
|
+
// Note: This does not update anything if there is no existing state
|
|
369
|
+
await this.db.bucket_state.updateOne(
|
|
370
|
+
{
|
|
371
|
+
_id: {
|
|
372
|
+
g: this.group_id,
|
|
373
|
+
b: bucket
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
$inc: {
|
|
378
|
+
op_count: 1 - numberOfOpsToClear
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
{ session }
|
|
382
|
+
);
|
|
365
383
|
},
|
|
366
384
|
{
|
|
367
385
|
writeConcern: { w: 'majority' },
|
|
@@ -9,27 +9,30 @@ import {
|
|
|
9
9
|
} from '@powersync/lib-services-framework';
|
|
10
10
|
import {
|
|
11
11
|
BroadcastIterable,
|
|
12
|
-
CHECKPOINT_INVALIDATE_ALL,
|
|
13
12
|
CheckpointChanges,
|
|
14
13
|
GetCheckpointChangesOptions,
|
|
15
14
|
InternalOpId,
|
|
16
15
|
internalToExternalOpId,
|
|
17
16
|
ProtocolOpId,
|
|
17
|
+
getLookupBucketDefinitionName,
|
|
18
18
|
ReplicationCheckpoint,
|
|
19
|
-
SourceTable,
|
|
20
19
|
storage,
|
|
21
20
|
utils,
|
|
22
|
-
WatchWriteCheckpointOptions
|
|
21
|
+
WatchWriteCheckpointOptions,
|
|
22
|
+
CHECKPOINT_INVALIDATE_ALL,
|
|
23
|
+
deserializeParameterLookup
|
|
23
24
|
} from '@powersync/service-core';
|
|
24
25
|
import { SqliteJsonRow, SqliteJsonValue, SqlSyncRules } from '@powersync/service-sync-rules';
|
|
25
26
|
import * as bson from 'bson';
|
|
26
27
|
import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
|
|
28
|
+
import { LRUCache } from 'lru-cache';
|
|
27
29
|
import * as timers from 'timers/promises';
|
|
28
30
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
29
31
|
import { PowerSyncMongo } from './db.js';
|
|
30
32
|
import {
|
|
31
33
|
BucketDataDocument,
|
|
32
34
|
BucketDataKey,
|
|
35
|
+
BucketStateDocument,
|
|
33
36
|
SourceKey,
|
|
34
37
|
SourceTableDocument,
|
|
35
38
|
SyncRuleCheckpointState,
|
|
@@ -39,6 +42,7 @@ import { MongoBucketBatch } from './MongoBucketBatch.js';
|
|
|
39
42
|
import { MongoCompactor } from './MongoCompactor.js';
|
|
40
43
|
import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js';
|
|
41
44
|
import { idPrefixFilter, mapOpEntry, readSingleBatch } from './util.js';
|
|
45
|
+
import { JSONBig } from '@powersync/service-jsonbig';
|
|
42
46
|
|
|
43
47
|
export class MongoSyncBucketStorage
|
|
44
48
|
extends BaseObserver<storage.SyncRulesBucketStorageListener>
|
|
@@ -585,6 +589,13 @@ export class MongoSyncBucketStorage
|
|
|
585
589
|
{ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
586
590
|
);
|
|
587
591
|
|
|
592
|
+
await this.db.bucket_state.deleteMany(
|
|
593
|
+
{
|
|
594
|
+
_id: idPrefixFilter<BucketStateDocument['_id']>({ g: this.group_id }, ['b'])
|
|
595
|
+
},
|
|
596
|
+
{ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
597
|
+
);
|
|
598
|
+
|
|
588
599
|
await this.db.source_tables.deleteMany(
|
|
589
600
|
{
|
|
590
601
|
group_id: this.group_id
|
|
@@ -795,12 +806,7 @@ export class MongoSyncBucketStorage
|
|
|
795
806
|
|
|
796
807
|
const updates: CheckpointChanges =
|
|
797
808
|
lastCheckpoint == null
|
|
798
|
-
?
|
|
799
|
-
invalidateDataBuckets: true,
|
|
800
|
-
invalidateParameterBuckets: true,
|
|
801
|
-
updatedDataBuckets: [],
|
|
802
|
-
updatedParameterBucketDefinitions: []
|
|
803
|
-
}
|
|
809
|
+
? CHECKPOINT_INVALIDATE_ALL
|
|
804
810
|
: await this.getCheckpointChanges({
|
|
805
811
|
lastCheckpoint: lastCheckpoint,
|
|
806
812
|
nextCheckpoint: checkpoint
|
|
@@ -869,7 +875,119 @@ export class MongoSyncBucketStorage
|
|
|
869
875
|
return pipeline;
|
|
870
876
|
}
|
|
871
877
|
|
|
878
|
+
private async getDataBucketChanges(
|
|
879
|
+
options: GetCheckpointChangesOptions
|
|
880
|
+
): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
|
|
881
|
+
const bucketStateUpdates = await this.db.bucket_state
|
|
882
|
+
.find(
|
|
883
|
+
{
|
|
884
|
+
// We have an index on (_id.g, last_op).
|
|
885
|
+
'_id.g': this.group_id,
|
|
886
|
+
last_op: { $gt: BigInt(options.lastCheckpoint) }
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
projection: {
|
|
890
|
+
'_id.b': 1
|
|
891
|
+
},
|
|
892
|
+
limit: 1001,
|
|
893
|
+
batchSize: 1001,
|
|
894
|
+
singleBatch: true
|
|
895
|
+
}
|
|
896
|
+
)
|
|
897
|
+
.toArray();
|
|
898
|
+
|
|
899
|
+
const buckets = bucketStateUpdates.map((doc) => doc._id.b);
|
|
900
|
+
const invalidateDataBuckets = buckets.length > 1000;
|
|
901
|
+
|
|
902
|
+
return {
|
|
903
|
+
invalidateDataBuckets: invalidateDataBuckets,
|
|
904
|
+
updatedDataBuckets: invalidateDataBuckets ? [] : buckets
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private async getParameterBucketChanges(
|
|
909
|
+
options: GetCheckpointChangesOptions
|
|
910
|
+
): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
|
|
911
|
+
// TODO: limit max query running time
|
|
912
|
+
const parameterUpdates = await this.db.bucket_parameters
|
|
913
|
+
.find(
|
|
914
|
+
{
|
|
915
|
+
_id: { $gt: BigInt(options.lastCheckpoint), $lt: BigInt(options.nextCheckpoint) },
|
|
916
|
+
'key.g': this.group_id
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
projection: {
|
|
920
|
+
lookup: 1
|
|
921
|
+
},
|
|
922
|
+
limit: 1001,
|
|
923
|
+
batchSize: 1001,
|
|
924
|
+
singleBatch: true
|
|
925
|
+
}
|
|
926
|
+
)
|
|
927
|
+
.toArray();
|
|
928
|
+
const invalidateParameterUpdates = parameterUpdates.length > 1000;
|
|
929
|
+
|
|
930
|
+
return {
|
|
931
|
+
invalidateParameterBuckets: invalidateParameterUpdates,
|
|
932
|
+
updatedParameterLookups: invalidateParameterUpdates
|
|
933
|
+
? new Set<string>()
|
|
934
|
+
: new Set<string>(parameterUpdates.map((p) => JSONBig.stringify(deserializeParameterLookup(p.lookup))))
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// TODO:
|
|
939
|
+
// We can optimize this by implementing it like ChecksumCache: We can use partial cache results to do
|
|
940
|
+
// more efficient lookups in some cases.
|
|
941
|
+
private checkpointChangesCache = new LRUCache<string, CheckpointChanges, { options: GetCheckpointChangesOptions }>({
|
|
942
|
+
max: 50,
|
|
943
|
+
maxSize: 10 * 1024 * 1024,
|
|
944
|
+
sizeCalculation: (value: CheckpointChanges) => {
|
|
945
|
+
const paramSize = [...value.updatedParameterLookups].reduce<number>((a, b) => a + b.length, 0);
|
|
946
|
+
const bucketSize = [...value.updatedDataBuckets].reduce<number>((a, b) => a + b.length, 0);
|
|
947
|
+
return 100 + paramSize + bucketSize;
|
|
948
|
+
},
|
|
949
|
+
fetchMethod: async (_key, _staleValue, options) => {
|
|
950
|
+
return this.getCheckpointChangesInternal(options.context.options);
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
private _hasDynamicBucketsCached: boolean | undefined = undefined;
|
|
955
|
+
|
|
956
|
+
private hasDynamicBucketQueries(): boolean {
|
|
957
|
+
if (this._hasDynamicBucketsCached != null) {
|
|
958
|
+
return this._hasDynamicBucketsCached;
|
|
959
|
+
}
|
|
960
|
+
const syncRules = this.getParsedSyncRules({
|
|
961
|
+
defaultSchema: 'default' // n/a
|
|
962
|
+
});
|
|
963
|
+
const hasDynamicBuckets = syncRules.hasDynamicBucketQueries();
|
|
964
|
+
this._hasDynamicBucketsCached = hasDynamicBuckets;
|
|
965
|
+
return hasDynamicBuckets;
|
|
966
|
+
}
|
|
967
|
+
|
|
872
968
|
async getCheckpointChanges(options: GetCheckpointChangesOptions): Promise<CheckpointChanges> {
|
|
873
|
-
|
|
969
|
+
if (!this.hasDynamicBucketQueries()) {
|
|
970
|
+
// Special case when we have no dynamic parameter queries.
|
|
971
|
+
// In this case, we can avoid doing any queries.
|
|
972
|
+
return {
|
|
973
|
+
invalidateDataBuckets: true,
|
|
974
|
+
updatedDataBuckets: [],
|
|
975
|
+
invalidateParameterBuckets: false,
|
|
976
|
+
updatedParameterLookups: new Set<string>()
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
const key = `${options.lastCheckpoint}_${options.nextCheckpoint}`;
|
|
980
|
+
const result = await this.checkpointChangesCache.fetch(key, { context: { options } });
|
|
981
|
+
return result!;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
private async getCheckpointChangesInternal(options: GetCheckpointChangesOptions): Promise<CheckpointChanges> {
|
|
985
|
+
const dataUpdates = await this.getDataBucketChanges(options);
|
|
986
|
+
const parameterUpdates = await this.getParameterBucketChanges(options);
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
...dataUpdates,
|
|
990
|
+
...parameterUpdates
|
|
991
|
+
};
|
|
874
992
|
}
|
|
875
993
|
}
|
|
@@ -11,6 +11,7 @@ import { PowerSyncMongo } from './db.js';
|
|
|
11
11
|
import {
|
|
12
12
|
BucketDataDocument,
|
|
13
13
|
BucketParameterDocument,
|
|
14
|
+
BucketStateDocument,
|
|
14
15
|
CurrentBucket,
|
|
15
16
|
CurrentDataDocument,
|
|
16
17
|
SourceKey
|
|
@@ -48,6 +49,7 @@ export class PersistedBatch {
|
|
|
48
49
|
bucketData: mongo.AnyBulkWriteOperation<BucketDataDocument>[] = [];
|
|
49
50
|
bucketParameters: mongo.AnyBulkWriteOperation<BucketParameterDocument>[] = [];
|
|
50
51
|
currentData: mongo.AnyBulkWriteOperation<CurrentDataDocument>[] = [];
|
|
52
|
+
bucketStates: Map<string, BucketStateUpdate> = new Map();
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* For debug logging only.
|
|
@@ -66,6 +68,19 @@ export class PersistedBatch {
|
|
|
66
68
|
this.currentSize = writtenSize;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
private incrementBucket(bucket: string, op_id: InternalOpId) {
|
|
72
|
+
let existingState = this.bucketStates.get(bucket);
|
|
73
|
+
if (existingState) {
|
|
74
|
+
existingState.lastOp = op_id;
|
|
75
|
+
existingState.incrementCount += 1;
|
|
76
|
+
} else {
|
|
77
|
+
this.bucketStates.set(bucket, {
|
|
78
|
+
lastOp: op_id,
|
|
79
|
+
incrementCount: 1
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
saveBucketData(options: {
|
|
70
85
|
op_seq: MongoIdSequence;
|
|
71
86
|
sourceKey: storage.ReplicaId;
|
|
@@ -120,6 +135,7 @@ export class PersistedBatch {
|
|
|
120
135
|
}
|
|
121
136
|
}
|
|
122
137
|
});
|
|
138
|
+
this.incrementBucket(k.bucket, op_id);
|
|
123
139
|
}
|
|
124
140
|
|
|
125
141
|
for (let bd of remaining_buckets.values()) {
|
|
@@ -147,6 +163,7 @@ export class PersistedBatch {
|
|
|
147
163
|
}
|
|
148
164
|
});
|
|
149
165
|
this.currentSize += 200;
|
|
166
|
+
this.incrementBucket(bd.bucket, op_id);
|
|
150
167
|
}
|
|
151
168
|
}
|
|
152
169
|
|
|
@@ -277,6 +294,14 @@ export class PersistedBatch {
|
|
|
277
294
|
});
|
|
278
295
|
}
|
|
279
296
|
|
|
297
|
+
if (this.bucketStates.size > 0) {
|
|
298
|
+
await db.bucket_state.bulkWrite(this.getBucketStateUpdates(), {
|
|
299
|
+
session,
|
|
300
|
+
// Per-bucket operation - order doesn't matter
|
|
301
|
+
ordered: false
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
280
305
|
const duration = performance.now() - startAt;
|
|
281
306
|
logger.info(
|
|
282
307
|
`powersync_${this.group_id} Flushed ${this.bucketData.length} + ${this.bucketParameters.length} + ${
|
|
@@ -287,7 +312,37 @@ export class PersistedBatch {
|
|
|
287
312
|
this.bucketData = [];
|
|
288
313
|
this.bucketParameters = [];
|
|
289
314
|
this.currentData = [];
|
|
315
|
+
this.bucketStates.clear();
|
|
290
316
|
this.currentSize = 0;
|
|
291
317
|
this.debugLastOpId = null;
|
|
292
318
|
}
|
|
319
|
+
|
|
320
|
+
private getBucketStateUpdates(): mongo.AnyBulkWriteOperation<BucketStateDocument>[] {
|
|
321
|
+
return Array.from(this.bucketStates.entries()).map(([bucket, state]) => {
|
|
322
|
+
return {
|
|
323
|
+
updateOne: {
|
|
324
|
+
filter: {
|
|
325
|
+
_id: {
|
|
326
|
+
g: this.group_id,
|
|
327
|
+
b: bucket
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
update: {
|
|
331
|
+
$set: {
|
|
332
|
+
last_op: state.lastOp
|
|
333
|
+
},
|
|
334
|
+
$inc: {
|
|
335
|
+
op_count: state.incrementCount
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
upsert: true
|
|
339
|
+
}
|
|
340
|
+
} satisfies mongo.AnyBulkWriteOperation<BucketStateDocument>;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
interface BucketStateUpdate {
|
|
346
|
+
lastOp: InternalOpId;
|
|
347
|
+
incrementCount: number;
|
|
293
348
|
}
|
|
@@ -6,6 +6,7 @@ import { MongoStorageConfig } from '../../types/types.js';
|
|
|
6
6
|
import {
|
|
7
7
|
BucketDataDocument,
|
|
8
8
|
BucketParameterDocument,
|
|
9
|
+
BucketStateDocument,
|
|
9
10
|
CurrentDataDocument,
|
|
10
11
|
CustomWriteCheckpointDocument,
|
|
11
12
|
IdSequenceDocument,
|
|
@@ -33,6 +34,7 @@ export class PowerSyncMongo {
|
|
|
33
34
|
readonly write_checkpoints: mongo.Collection<WriteCheckpointDocument>;
|
|
34
35
|
readonly instance: mongo.Collection<InstanceDocument>;
|
|
35
36
|
readonly locks: mongo.Collection<lib_mongo.locks.Lock>;
|
|
37
|
+
readonly bucket_state: mongo.Collection<BucketStateDocument>;
|
|
36
38
|
|
|
37
39
|
readonly client: mongo.MongoClient;
|
|
38
40
|
readonly db: mongo.Db;
|
|
@@ -55,6 +57,7 @@ export class PowerSyncMongo {
|
|
|
55
57
|
this.write_checkpoints = db.collection('write_checkpoints');
|
|
56
58
|
this.instance = db.collection('instance');
|
|
57
59
|
this.locks = this.db.collection('locks');
|
|
60
|
+
this.bucket_state = this.db.collection('bucket_state');
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
/**
|
|
@@ -70,6 +73,7 @@ export class PowerSyncMongo {
|
|
|
70
73
|
await this.write_checkpoints.deleteMany({});
|
|
71
74
|
await this.instance.deleteOne({});
|
|
72
75
|
await this.locks.deleteMany({});
|
|
76
|
+
await this.bucket_state.deleteMany({});
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
/**
|
|
@@ -75,6 +75,15 @@ export interface SourceTableDocument {
|
|
|
75
75
|
snapshot_done: boolean | undefined;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export interface BucketStateDocument {
|
|
79
|
+
_id: {
|
|
80
|
+
g: number;
|
|
81
|
+
b: string;
|
|
82
|
+
};
|
|
83
|
+
last_op: bigint;
|
|
84
|
+
op_count: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
export interface IdSequenceDocument {
|
|
79
88
|
_id: string;
|
|
80
89
|
op_id: bigint;
|
package/test/src/setup.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { container } from '@powersync/lib-services-framework';
|
|
2
|
+
import { test_utils } from '@powersync/service-core-tests';
|
|
2
3
|
import { beforeAll, beforeEach } from 'vitest';
|
|
3
|
-
import { METRICS_HELPER } from '@powersync/service-core-tests';
|
|
4
4
|
|
|
5
5
|
beforeAll(async () => {
|
|
6
6
|
// Executes for every test file
|
|
7
7
|
container.registerDefaults();
|
|
8
|
+
await test_utils.initMetrics();
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
beforeEach(async () => {
|
|
11
|
-
|
|
12
|
+
await test_utils.resetMetrics();
|
|
12
13
|
});
|