@powersync/service-module-mongodb-storage 0.0.0-dev-20250310190630 → 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.
Files changed (29) hide show
  1. package/CHANGELOG.md +6 -8
  2. package/dist/migrations/db/migrations/1741697235857-bucket-state-index.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1741697235857-bucket-state-index.js +28 -0
  4. package/dist/migrations/db/migrations/1741697235857-bucket-state-index.js.map +1 -0
  5. package/dist/storage/implementation/MongoBucketBatch.d.ts +4 -0
  6. package/dist/storage/implementation/MongoBucketBatch.js +1 -1
  7. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  8. package/dist/storage/implementation/MongoCompactor.js +14 -1
  9. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  10. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +6 -0
  11. package/dist/storage/implementation/MongoSyncBucketStorage.js +100 -8
  12. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  13. package/dist/storage/implementation/PersistedBatch.d.ts +8 -0
  14. package/dist/storage/implementation/PersistedBatch.js +57 -2
  15. package/dist/storage/implementation/PersistedBatch.js.map +1 -1
  16. package/dist/storage/implementation/db.d.ts +2 -1
  17. package/dist/storage/implementation/db.js +3 -0
  18. package/dist/storage/implementation/db.js.map +1 -1
  19. package/dist/storage/implementation/models.d.ts +8 -0
  20. package/package.json +5 -5
  21. package/src/migrations/db/migrations/1741697235857-bucket-state-index.ts +40 -0
  22. package/src/storage/implementation/MongoBucketBatch.ts +1 -1
  23. package/src/storage/implementation/MongoCompactor.ts +19 -1
  24. package/src/storage/implementation/MongoSyncBucketStorage.ts +128 -10
  25. package/src/storage/implementation/PersistedBatch.ts +66 -2
  26. package/src/storage/implementation/db.ts +4 -0
  27. package/src/storage/implementation/models.ts +9 -0
  28. package/test/src/setup.ts +3 -2
  29. package/tsconfig.tsbuildinfo +1 -1
@@ -1,7 +1,7 @@
1
1
  import { JSONBig } from '@powersync/service-jsonbig';
2
2
  import { logger } from '@powersync/lib-services-framework';
3
3
  import { storage, utils } from '@powersync/service-core';
4
- import { currentBucketKey } from './MongoBucketBatch.js';
4
+ import { currentBucketKey, MAX_ROW_SIZE } from './MongoBucketBatch.js';
5
5
  import { replicaIdToSubkey } from './util.js';
6
6
  /**
7
7
  * Maximum size of operations we write in a single transaction.
@@ -33,6 +33,7 @@ export class PersistedBatch {
33
33
  bucketData = [];
34
34
  bucketParameters = [];
35
35
  currentData = [];
36
+ bucketStates = new Map();
36
37
  /**
37
38
  * For debug logging only.
38
39
  */
@@ -45,6 +46,19 @@ export class PersistedBatch {
45
46
  this.group_id = group_id;
46
47
  this.currentSize = writtenSize;
47
48
  }
49
+ incrementBucket(bucket, op_id) {
50
+ let existingState = this.bucketStates.get(bucket);
51
+ if (existingState) {
52
+ existingState.lastOp = op_id;
53
+ existingState.incrementCount += 1;
54
+ }
55
+ else {
56
+ this.bucketStates.set(bucket, {
57
+ lastOp: op_id,
58
+ incrementCount: 1
59
+ });
60
+ }
61
+ }
48
62
  saveBucketData(options) {
49
63
  const remaining_buckets = new Map();
50
64
  for (let b of options.before_buckets) {
@@ -54,10 +68,18 @@ export class PersistedBatch {
54
68
  const dchecksum = utils.hashDelete(replicaIdToSubkey(options.table.id, options.sourceKey));
55
69
  for (const k of options.evaluated) {
56
70
  const key = currentBucketKey(k);
57
- remaining_buckets.delete(key);
58
71
  // INSERT
59
72
  const recordData = JSONBig.stringify(k.data);
60
73
  const checksum = utils.hashData(k.table, k.id, recordData);
74
+ if (recordData.length > MAX_ROW_SIZE) {
75
+ // In many cases, the raw data size would have been too large already. But there are cases where
76
+ // the BSON size is small enough, but the JSON size is too large.
77
+ // In these cases, we can't store the data, so we skip it, or generate a REMOVE operation if the row
78
+ // was synced previously.
79
+ logger.error(`powersync_${this.group_id} Row ${key} too large: ${recordData.length} bytes. Removing.`);
80
+ continue;
81
+ }
82
+ remaining_buckets.delete(key);
61
83
  this.currentSize += recordData.length + 200;
62
84
  const op_id = options.op_seq.next();
63
85
  this.debugLastOpId = op_id;
@@ -79,6 +101,7 @@ export class PersistedBatch {
79
101
  }
80
102
  }
81
103
  });
104
+ this.incrementBucket(k.bucket, op_id);
82
105
  }
83
106
  for (let bd of remaining_buckets.values()) {
84
107
  // REMOVE
@@ -103,6 +126,7 @@ export class PersistedBatch {
103
126
  }
104
127
  });
105
128
  this.currentSize += 200;
129
+ this.incrementBucket(bd.bucket, op_id);
106
130
  }
107
131
  }
108
132
  saveParameterData(data) {
@@ -213,13 +237,44 @@ export class PersistedBatch {
213
237
  ordered: true
214
238
  });
215
239
  }
240
+ if (this.bucketStates.size > 0) {
241
+ await db.bucket_state.bulkWrite(this.getBucketStateUpdates(), {
242
+ session,
243
+ // Per-bucket operation - order doesn't matter
244
+ ordered: false
245
+ });
246
+ }
216
247
  const duration = performance.now() - startAt;
217
248
  logger.info(`powersync_${this.group_id} Flushed ${this.bucketData.length} + ${this.bucketParameters.length} + ${this.currentData.length} updates, ${Math.round(this.currentSize / 1024)}kb in ${duration.toFixed(0)}ms. Last op_id: ${this.debugLastOpId}`);
218
249
  this.bucketData = [];
219
250
  this.bucketParameters = [];
220
251
  this.currentData = [];
252
+ this.bucketStates.clear();
221
253
  this.currentSize = 0;
222
254
  this.debugLastOpId = null;
223
255
  }
256
+ getBucketStateUpdates() {
257
+ return Array.from(this.bucketStates.entries()).map(([bucket, state]) => {
258
+ return {
259
+ updateOne: {
260
+ filter: {
261
+ _id: {
262
+ g: this.group_id,
263
+ b: bucket
264
+ }
265
+ },
266
+ update: {
267
+ $set: {
268
+ last_op: state.lastOp
269
+ },
270
+ $inc: {
271
+ op_count: state.incrementCount
272
+ }
273
+ },
274
+ upsert: true
275
+ }
276
+ };
277
+ });
278
+ }
224
279
  }
225
280
  //# sourceMappingURL=PersistedBatch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PersistedBatch.js","sourceRoot":"","sources":["../../../src/storage/implementation/PersistedBatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PersistedBatch.js","sourceRoot":"","sources":["../../../src/storage/implementation/PersistedBatch.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import * as lib_mongo from '@powersync/lib-service-mongodb';
2
2
  import { mongo } from '@powersync/lib-service-mongodb';
3
3
  import { MongoStorageConfig } from '../../types/types.js';
4
- import { BucketDataDocument, BucketParameterDocument, CurrentDataDocument, CustomWriteCheckpointDocument, IdSequenceDocument, InstanceDocument, SourceTableDocument, SyncRuleDocument, WriteCheckpointDocument } from './models.js';
4
+ import { BucketDataDocument, BucketParameterDocument, BucketStateDocument, CurrentDataDocument, CustomWriteCheckpointDocument, IdSequenceDocument, InstanceDocument, SourceTableDocument, SyncRuleDocument, WriteCheckpointDocument } from './models.js';
5
5
  export interface PowerSyncMongoOptions {
6
6
  /**
7
7
  * Optional - uses the database from the MongoClient connection URI if not specified.
@@ -19,6 +19,7 @@ export declare class PowerSyncMongo {
19
19
  readonly write_checkpoints: mongo.Collection<WriteCheckpointDocument>;
20
20
  readonly instance: mongo.Collection<InstanceDocument>;
21
21
  readonly locks: mongo.Collection<lib_mongo.locks.Lock>;
22
+ readonly bucket_state: mongo.Collection<BucketStateDocument>;
22
23
  readonly client: mongo.MongoClient;
23
24
  readonly db: mongo.Db;
24
25
  constructor(client: mongo.MongoClient, options?: PowerSyncMongoOptions);
@@ -11,6 +11,7 @@ export class PowerSyncMongo {
11
11
  write_checkpoints;
12
12
  instance;
13
13
  locks;
14
+ bucket_state;
14
15
  client;
15
16
  db;
16
17
  constructor(client, options) {
@@ -29,6 +30,7 @@ export class PowerSyncMongo {
29
30
  this.write_checkpoints = db.collection('write_checkpoints');
30
31
  this.instance = db.collection('instance');
31
32
  this.locks = this.db.collection('locks');
33
+ this.bucket_state = this.db.collection('bucket_state');
32
34
  }
33
35
  /**
34
36
  * Clear all collections.
@@ -43,6 +45,7 @@ export class PowerSyncMongo {
43
45
  await this.write_checkpoints.deleteMany({});
44
46
  await this.instance.deleteOne({});
45
47
  await this.locks.deleteMany({});
48
+ await this.bucket_state.deleteMany({});
46
49
  }
47
50
  /**
48
51
  * Drop the entire database.
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/storage/implementation/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAsBlD,MAAM,OAAO,cAAc;IAChB,YAAY,CAAwC;IACpD,WAAW,CAAuC;IAClD,iBAAiB,CAA4C;IAC7D,cAAc,CAAuC;IACrD,UAAU,CAAqC;IAC/C,aAAa,CAAwC;IACrD,wBAAwB,CAAkD;IAC1E,iBAAiB,CAA4C;IAC7D,QAAQ,CAAqC;IAC7C,KAAK,CAAyC;IAE9C,MAAM,CAAoB;IAC1B,EAAE,CAAW;IAEtB,YAAY,MAAyB,EAAE,OAA+B;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE;YACtC,GAAG,OAAO,CAAC,iCAAiC;SAC7C,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAEb,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,UAAU,CAAsB,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;QACpD,IAAI,CAAC,wBAAwB,GAAG,EAAE,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;QAC1E,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,MAA0B,EAAE,OAA0C;IACzG,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AACzG,CAAC"}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/storage/implementation/db.ts"],"names":[],"mappings":"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"}
@@ -69,6 +69,14 @@ export interface SourceTableDocument {
69
69
  }[] | undefined;
70
70
  snapshot_done: boolean | undefined;
71
71
  }
72
+ export interface BucketStateDocument {
73
+ _id: {
74
+ g: number;
75
+ b: string;
76
+ };
77
+ last_op: bigint;
78
+ op_count: number;
79
+ }
72
80
  export interface IdSequenceDocument {
73
81
  _id: string;
74
82
  op_id: bigint;
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-20250310190630",
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-20250310190630",
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.0.0-dev-20250310190630",
35
- "@powersync/lib-service-mongodb": "0.5.0"
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-20250310190630"
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
+ };
@@ -24,7 +24,7 @@ import { idPrefixFilter } from './util.js';
24
24
  /**
25
25
  * 15MB
26
26
  */
27
- const MAX_ROW_SIZE = 15 * 1024 * 1024;
27
+ export const MAX_ROW_SIZE = 15 * 1024 * 1024;
28
28
 
29
29
  // Currently, we can only have a single flush() at a time, since it locks the op_id sequence.
30
30
  // While the MongoDB transaction retry mechanism handles this okay, using an in-process Mutex
@@ -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
- return CHECKPOINT_INVALIDATE_ALL;
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
  }
@@ -5,12 +5,13 @@ import * as bson from 'bson';
5
5
 
6
6
  import { logger } from '@powersync/lib-services-framework';
7
7
  import { InternalOpId, storage, utils } from '@powersync/service-core';
8
- import { currentBucketKey } from './MongoBucketBatch.js';
8
+ import { currentBucketKey, MAX_ROW_SIZE } from './MongoBucketBatch.js';
9
9
  import { MongoIdSequence } from './MongoIdSequence.js';
10
10
  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;
@@ -83,11 +98,20 @@ export class PersistedBatch {
83
98
 
84
99
  for (const k of options.evaluated) {
85
100
  const key = currentBucketKey(k);
86
- remaining_buckets.delete(key);
87
101
 
88
102
  // INSERT
89
103
  const recordData = JSONBig.stringify(k.data);
90
104
  const checksum = utils.hashData(k.table, k.id, recordData);
105
+ if (recordData.length > MAX_ROW_SIZE) {
106
+ // In many cases, the raw data size would have been too large already. But there are cases where
107
+ // the BSON size is small enough, but the JSON size is too large.
108
+ // In these cases, we can't store the data, so we skip it, or generate a REMOVE operation if the row
109
+ // was synced previously.
110
+ logger.error(`powersync_${this.group_id} Row ${key} too large: ${recordData.length} bytes. Removing.`);
111
+ continue;
112
+ }
113
+
114
+ remaining_buckets.delete(key);
91
115
  this.currentSize += recordData.length + 200;
92
116
 
93
117
  const op_id = options.op_seq.next();
@@ -111,6 +135,7 @@ export class PersistedBatch {
111
135
  }
112
136
  }
113
137
  });
138
+ this.incrementBucket(k.bucket, op_id);
114
139
  }
115
140
 
116
141
  for (let bd of remaining_buckets.values()) {
@@ -138,6 +163,7 @@ export class PersistedBatch {
138
163
  }
139
164
  });
140
165
  this.currentSize += 200;
166
+ this.incrementBucket(bd.bucket, op_id);
141
167
  }
142
168
  }
143
169
 
@@ -268,6 +294,14 @@ export class PersistedBatch {
268
294
  });
269
295
  }
270
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
+
271
305
  const duration = performance.now() - startAt;
272
306
  logger.info(
273
307
  `powersync_${this.group_id} Flushed ${this.bucketData.length} + ${this.bucketParameters.length} + ${
@@ -278,7 +312,37 @@ export class PersistedBatch {
278
312
  this.bucketData = [];
279
313
  this.bucketParameters = [];
280
314
  this.currentData = [];
315
+ this.bucketStates.clear();
281
316
  this.currentSize = 0;
282
317
  this.debugLastOpId = null;
283
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;
284
348
  }