@powersync/service-core 0.13.0 → 0.15.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.
Files changed (181) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/entry/commands/compact-action.js +14 -14
  3. package/dist/entry/commands/compact-action.js.map +1 -1
  4. package/dist/entry/commands/migrate-action.js +15 -4
  5. package/dist/entry/commands/migrate-action.js.map +1 -1
  6. package/dist/index.d.ts +1 -3
  7. package/dist/index.js +1 -3
  8. package/dist/index.js.map +1 -1
  9. package/dist/migrations/PowerSyncMigrationManager.d.ts +17 -0
  10. package/dist/migrations/PowerSyncMigrationManager.js +21 -0
  11. package/dist/migrations/PowerSyncMigrationManager.js.map +1 -0
  12. package/dist/migrations/ensure-automatic-migrations.d.ts +4 -0
  13. package/dist/migrations/ensure-automatic-migrations.js +14 -0
  14. package/dist/migrations/ensure-automatic-migrations.js.map +1 -0
  15. package/dist/migrations/migrations-index.d.ts +2 -3
  16. package/dist/migrations/migrations-index.js +2 -3
  17. package/dist/migrations/migrations-index.js.map +1 -1
  18. package/dist/routes/configure-fastify.d.ts +12 -12
  19. package/dist/routes/endpoints/admin.d.ts +24 -24
  20. package/dist/storage/BucketStorage.d.ts +51 -3
  21. package/dist/storage/BucketStorage.js +26 -0
  22. package/dist/storage/BucketStorage.js.map +1 -1
  23. package/dist/storage/bson.d.ts +24 -0
  24. package/dist/storage/bson.js +73 -0
  25. package/dist/storage/bson.js.map +1 -0
  26. package/dist/storage/storage-index.d.ts +3 -14
  27. package/dist/storage/storage-index.js +3 -14
  28. package/dist/storage/storage-index.js.map +1 -1
  29. package/dist/sync/sync.js +3 -1
  30. package/dist/sync/sync.js.map +1 -1
  31. package/dist/system/ServiceContext.d.ts +3 -0
  32. package/dist/system/ServiceContext.js +11 -3
  33. package/dist/system/ServiceContext.js.map +1 -1
  34. package/dist/util/config/types.d.ts +2 -2
  35. package/dist/util/utils.d.ts +17 -1
  36. package/dist/util/utils.js +49 -1
  37. package/dist/util/utils.js.map +1 -1
  38. package/package.json +7 -8
  39. package/src/entry/commands/compact-action.ts +19 -14
  40. package/src/entry/commands/migrate-action.ts +17 -4
  41. package/src/index.ts +1 -4
  42. package/src/migrations/PowerSyncMigrationManager.ts +42 -0
  43. package/src/migrations/ensure-automatic-migrations.ts +15 -0
  44. package/src/migrations/migrations-index.ts +2 -3
  45. package/src/storage/BucketStorage.ts +59 -3
  46. package/src/storage/bson.ts +78 -0
  47. package/src/storage/storage-index.ts +3 -15
  48. package/src/sync/sync.ts +3 -1
  49. package/src/system/ServiceContext.ts +17 -4
  50. package/src/util/config/types.ts +2 -2
  51. package/src/util/utils.ts +47 -1
  52. package/test/src/env.ts +0 -1
  53. package/tsconfig.tsbuildinfo +1 -1
  54. package/dist/db/db-index.d.ts +0 -1
  55. package/dist/db/db-index.js +0 -2
  56. package/dist/db/db-index.js.map +0 -1
  57. package/dist/db/mongo.d.ts +0 -35
  58. package/dist/db/mongo.js +0 -73
  59. package/dist/db/mongo.js.map +0 -1
  60. package/dist/locks/LockManager.d.ts +0 -10
  61. package/dist/locks/LockManager.js +0 -7
  62. package/dist/locks/LockManager.js.map +0 -1
  63. package/dist/locks/MongoLocks.d.ts +0 -36
  64. package/dist/locks/MongoLocks.js +0 -81
  65. package/dist/locks/MongoLocks.js.map +0 -1
  66. package/dist/locks/locks-index.d.ts +0 -2
  67. package/dist/locks/locks-index.js +0 -3
  68. package/dist/locks/locks-index.js.map +0 -1
  69. package/dist/migrations/db/migrations/1684951997326-init.d.ts +0 -3
  70. package/dist/migrations/db/migrations/1684951997326-init.js +0 -33
  71. package/dist/migrations/db/migrations/1684951997326-init.js.map +0 -1
  72. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.d.ts +0 -2
  73. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +0 -5
  74. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +0 -1
  75. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +0 -3
  76. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +0 -56
  77. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +0 -1
  78. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +0 -3
  79. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +0 -29
  80. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +0 -1
  81. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +0 -3
  82. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +0 -31
  83. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +0 -1
  84. package/dist/migrations/definitions.d.ts +0 -18
  85. package/dist/migrations/definitions.js +0 -6
  86. package/dist/migrations/definitions.js.map +0 -1
  87. package/dist/migrations/executor.d.ts +0 -16
  88. package/dist/migrations/executor.js +0 -64
  89. package/dist/migrations/executor.js.map +0 -1
  90. package/dist/migrations/migrations.d.ts +0 -18
  91. package/dist/migrations/migrations.js +0 -110
  92. package/dist/migrations/migrations.js.map +0 -1
  93. package/dist/migrations/store/migration-store.d.ts +0 -11
  94. package/dist/migrations/store/migration-store.js +0 -46
  95. package/dist/migrations/store/migration-store.js.map +0 -1
  96. package/dist/storage/MongoBucketStorage.d.ts +0 -48
  97. package/dist/storage/MongoBucketStorage.js +0 -427
  98. package/dist/storage/MongoBucketStorage.js.map +0 -1
  99. package/dist/storage/mongo/MongoBucketBatch.d.ts +0 -74
  100. package/dist/storage/mongo/MongoBucketBatch.js +0 -683
  101. package/dist/storage/mongo/MongoBucketBatch.js.map +0 -1
  102. package/dist/storage/mongo/MongoCompactor.d.ts +0 -40
  103. package/dist/storage/mongo/MongoCompactor.js +0 -310
  104. package/dist/storage/mongo/MongoCompactor.js.map +0 -1
  105. package/dist/storage/mongo/MongoIdSequence.d.ts +0 -12
  106. package/dist/storage/mongo/MongoIdSequence.js +0 -21
  107. package/dist/storage/mongo/MongoIdSequence.js.map +0 -1
  108. package/dist/storage/mongo/MongoPersistedSyncRules.d.ts +0 -9
  109. package/dist/storage/mongo/MongoPersistedSyncRules.js +0 -9
  110. package/dist/storage/mongo/MongoPersistedSyncRules.js.map +0 -1
  111. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +0 -20
  112. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +0 -26
  113. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +0 -1
  114. package/dist/storage/mongo/MongoStorageProvider.d.ts +0 -5
  115. package/dist/storage/mongo/MongoStorageProvider.js +0 -26
  116. package/dist/storage/mongo/MongoStorageProvider.js.map +0 -1
  117. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +0 -38
  118. package/dist/storage/mongo/MongoSyncBucketStorage.js +0 -534
  119. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +0 -1
  120. package/dist/storage/mongo/MongoSyncRulesLock.d.ts +0 -16
  121. package/dist/storage/mongo/MongoSyncRulesLock.js +0 -65
  122. package/dist/storage/mongo/MongoSyncRulesLock.js.map +0 -1
  123. package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +0 -20
  124. package/dist/storage/mongo/MongoWriteCheckpointAPI.js +0 -104
  125. package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +0 -1
  126. package/dist/storage/mongo/OperationBatch.d.ts +0 -35
  127. package/dist/storage/mongo/OperationBatch.js +0 -119
  128. package/dist/storage/mongo/OperationBatch.js.map +0 -1
  129. package/dist/storage/mongo/PersistedBatch.d.ts +0 -46
  130. package/dist/storage/mongo/PersistedBatch.js +0 -223
  131. package/dist/storage/mongo/PersistedBatch.js.map +0 -1
  132. package/dist/storage/mongo/config.d.ts +0 -19
  133. package/dist/storage/mongo/config.js +0 -26
  134. package/dist/storage/mongo/config.js.map +0 -1
  135. package/dist/storage/mongo/db.d.ts +0 -36
  136. package/dist/storage/mongo/db.js +0 -47
  137. package/dist/storage/mongo/db.js.map +0 -1
  138. package/dist/storage/mongo/models.d.ts +0 -163
  139. package/dist/storage/mongo/models.js +0 -27
  140. package/dist/storage/mongo/models.js.map +0 -1
  141. package/dist/storage/mongo/util.d.ts +0 -54
  142. package/dist/storage/mongo/util.js +0 -190
  143. package/dist/storage/mongo/util.js.map +0 -1
  144. package/src/db/db-index.ts +0 -1
  145. package/src/db/mongo.ts +0 -81
  146. package/src/locks/LockManager.ts +0 -16
  147. package/src/locks/MongoLocks.ts +0 -142
  148. package/src/locks/locks-index.ts +0 -2
  149. package/src/migrations/db/migrations/1684951997326-init.ts +0 -38
  150. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +0 -5
  151. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +0 -102
  152. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +0 -34
  153. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +0 -37
  154. package/src/migrations/definitions.ts +0 -21
  155. package/src/migrations/executor.ts +0 -87
  156. package/src/migrations/migrations.ts +0 -142
  157. package/src/migrations/store/migration-store.ts +0 -63
  158. package/src/storage/MongoBucketStorage.ts +0 -541
  159. package/src/storage/mongo/MongoBucketBatch.ts +0 -900
  160. package/src/storage/mongo/MongoCompactor.ts +0 -393
  161. package/src/storage/mongo/MongoIdSequence.ts +0 -24
  162. package/src/storage/mongo/MongoPersistedSyncRules.ts +0 -16
  163. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +0 -50
  164. package/src/storage/mongo/MongoStorageProvider.ts +0 -31
  165. package/src/storage/mongo/MongoSyncBucketStorage.ts +0 -640
  166. package/src/storage/mongo/MongoSyncRulesLock.ts +0 -85
  167. package/src/storage/mongo/MongoWriteCheckpointAPI.ts +0 -154
  168. package/src/storage/mongo/OperationBatch.ts +0 -131
  169. package/src/storage/mongo/PersistedBatch.ts +0 -285
  170. package/src/storage/mongo/config.ts +0 -40
  171. package/src/storage/mongo/db.ts +0 -88
  172. package/src/storage/mongo/models.ts +0 -187
  173. package/src/storage/mongo/util.ts +0 -203
  174. package/test/src/__snapshots__/sync.test.ts.snap +0 -332
  175. package/test/src/bucket_validation.test.ts +0 -143
  176. package/test/src/bucket_validation.ts +0 -60
  177. package/test/src/compacting.test.ts +0 -295
  178. package/test/src/data_storage.test.ts +0 -1569
  179. package/test/src/stream_utils.ts +0 -42
  180. package/test/src/sync.test.ts +0 -511
  181. package/test/src/util.ts +0 -150
@@ -1,393 +0,0 @@
1
- import { logger } from '@powersync/lib-services-framework';
2
- import { AnyBulkWriteOperation, MaxKey, MinKey } from 'mongodb';
3
- import { addChecksums } from '../../util/utils.js';
4
- import { PowerSyncMongo } from './db.js';
5
- import { BucketDataDocument, BucketDataKey } from './models.js';
6
- import { CompactOptions } from '../BucketStorage.js';
7
- import { cacheKey } from './OperationBatch.js';
8
- import { safeBulkWrite } from './util.js';
9
-
10
- interface CurrentBucketState {
11
- /** Bucket name */
12
- bucket: string;
13
- /**
14
- * Rows seen in the bucket, with the last op_id of each.
15
- */
16
- seen: Map<string, bigint>;
17
- /**
18
- * Estimated memory usage of the seen Map.
19
- */
20
- trackingSize: number;
21
-
22
- /**
23
- * Last (lowest) seen op_id that is not a PUT.
24
- */
25
- lastNotPut: bigint | null;
26
-
27
- /**
28
- * Number of REMOVE/MOVE operations seen since lastNotPut.
29
- */
30
- opsSincePut: number;
31
- }
32
-
33
- /**
34
- * Additional options, primarily for testing.
35
- */
36
- export interface MongoCompactOptions extends CompactOptions {
37
- /** Minimum of 2 */
38
- clearBatchLimit?: number;
39
- /** Minimum of 1 */
40
- moveBatchLimit?: number;
41
- /** Minimum of 1 */
42
- moveBatchQueryLimit?: number;
43
- }
44
-
45
- const DEFAULT_CLEAR_BATCH_LIMIT = 5000;
46
- const DEFAULT_MOVE_BATCH_LIMIT = 2000;
47
- const DEFAULT_MOVE_BATCH_QUERY_LIMIT = 10_000;
48
-
49
- /** This default is primarily for tests. */
50
- const DEFAULT_MEMORY_LIMIT_MB = 64;
51
-
52
- export class MongoCompactor {
53
- private updates: AnyBulkWriteOperation<BucketDataDocument>[] = [];
54
-
55
- private idLimitBytes: number;
56
- private moveBatchLimit: number;
57
- private moveBatchQueryLimit: number;
58
- private clearBatchLimit: number;
59
- private maxOpId: bigint | undefined;
60
- private buckets: string[] | undefined;
61
-
62
- constructor(
63
- private db: PowerSyncMongo,
64
- private group_id: number,
65
- options?: MongoCompactOptions
66
- ) {
67
- this.idLimitBytes = (options?.memoryLimitMB ?? DEFAULT_MEMORY_LIMIT_MB) * 1024 * 1024;
68
- this.moveBatchLimit = options?.moveBatchLimit ?? DEFAULT_MOVE_BATCH_LIMIT;
69
- this.moveBatchQueryLimit = options?.moveBatchQueryLimit ?? DEFAULT_MOVE_BATCH_QUERY_LIMIT;
70
- this.clearBatchLimit = options?.clearBatchLimit ?? DEFAULT_CLEAR_BATCH_LIMIT;
71
- this.maxOpId = options?.maxOpId;
72
- this.buckets = options?.compactBuckets;
73
- }
74
-
75
- /**
76
- * Compact buckets by converting operations into MOVE and/or CLEAR operations.
77
- *
78
- * See /docs/compacting-operations.md for details.
79
- */
80
- async compact() {
81
- if (this.buckets) {
82
- for (let bucket of this.buckets) {
83
- // We can make this more efficient later on by iterating
84
- // through the buckets in a single query.
85
- // That makes batching more tricky, so we leave for later.
86
- await this.compactInternal(bucket);
87
- }
88
- } else {
89
- await this.compactInternal(undefined);
90
- }
91
- }
92
-
93
- async compactInternal(bucket: string | undefined) {
94
- const idLimitBytes = this.idLimitBytes;
95
-
96
- let currentState: CurrentBucketState | null = null;
97
-
98
- let bucketLower: string | MinKey;
99
- let bucketUpper: string | MaxKey;
100
-
101
- if (bucket == null) {
102
- bucketLower = new MinKey();
103
- bucketUpper = new MaxKey();
104
- } else if (bucket.includes('[')) {
105
- // Exact bucket name
106
- bucketLower = bucket;
107
- bucketUpper = bucket;
108
- } else {
109
- // Bucket definition name
110
- bucketLower = `${bucket}[`;
111
- bucketUpper = `${bucket}[\uFFFF`;
112
- }
113
-
114
- // Constant lower bound
115
- const lowerBound: BucketDataKey = {
116
- g: this.group_id,
117
- b: bucketLower as string,
118
- o: new MinKey() as any
119
- };
120
-
121
- // Upper bound is adjusted for each batch
122
- let upperBound: BucketDataKey = {
123
- g: this.group_id,
124
- b: bucketUpper as string,
125
- o: new MaxKey() as any
126
- };
127
-
128
- while (true) {
129
- // Query one batch at a time, to avoid cursor timeouts
130
- const batch = await this.db.bucket_data
131
- .find(
132
- {
133
- _id: {
134
- $gte: lowerBound,
135
- $lt: upperBound
136
- }
137
- },
138
- {
139
- projection: {
140
- _id: 1,
141
- op: 1,
142
- table: 1,
143
- row_id: 1,
144
- source_table: 1,
145
- source_key: 1
146
- },
147
- limit: this.moveBatchQueryLimit,
148
- sort: { _id: -1 },
149
- singleBatch: true
150
- }
151
- )
152
- .toArray();
153
-
154
- if (batch.length == 0) {
155
- // We've reached the end
156
- break;
157
- }
158
-
159
- // Set upperBound for the next batch
160
- upperBound = batch[batch.length - 1]._id;
161
-
162
- for (let doc of batch) {
163
- if (currentState == null || doc._id.b != currentState.bucket) {
164
- if (currentState != null && currentState.lastNotPut != null && currentState.opsSincePut >= 1) {
165
- // Important to flush before clearBucket()
166
- await this.flush();
167
- logger.info(
168
- `Inserting CLEAR at ${this.group_id}:${currentState.bucket}:${currentState.lastNotPut} to remove ${currentState.opsSincePut} operations`
169
- );
170
-
171
- const bucket = currentState.bucket;
172
- const clearOp = currentState.lastNotPut;
173
- // Free memory before clearing bucket
174
- currentState = null;
175
- await this.clearBucket(bucket, clearOp);
176
- }
177
- currentState = {
178
- bucket: doc._id.b,
179
- seen: new Map(),
180
- trackingSize: 0,
181
- lastNotPut: null,
182
- opsSincePut: 0
183
- };
184
- }
185
-
186
- if (this.maxOpId != null && doc._id.o > this.maxOpId) {
187
- continue;
188
- }
189
-
190
- let isPersistentPut = doc.op == 'PUT';
191
-
192
- if (doc.op == 'REMOVE' || doc.op == 'PUT') {
193
- const key = `${doc.table}/${doc.row_id}/${cacheKey(doc.source_table!, doc.source_key!)}`;
194
- const targetOp = currentState.seen.get(key);
195
- if (targetOp) {
196
- // Will convert to MOVE, so don't count as PUT
197
- isPersistentPut = false;
198
-
199
- this.updates.push({
200
- updateOne: {
201
- filter: {
202
- _id: doc._id
203
- },
204
- update: {
205
- $set: {
206
- op: 'MOVE',
207
- target_op: targetOp
208
- },
209
- $unset: {
210
- source_table: 1,
211
- source_key: 1,
212
- table: 1,
213
- row_id: 1,
214
- data: 1
215
- }
216
- }
217
- }
218
- });
219
- } else {
220
- if (currentState.trackingSize >= idLimitBytes) {
221
- // Reached memory limit.
222
- // Keep the highest seen values in this case.
223
- } else {
224
- // flatstr reduces the memory usage by flattening the string
225
- currentState.seen.set(flatstr(key), doc._id.o);
226
- // length + 16 for the string
227
- // 24 for the bigint
228
- // 50 for map overhead
229
- // 50 for additional overhead
230
- currentState.trackingSize += key.length + 140;
231
- }
232
- }
233
- }
234
-
235
- if (isPersistentPut) {
236
- currentState.lastNotPut = null;
237
- currentState.opsSincePut = 0;
238
- } else if (doc.op != 'CLEAR') {
239
- if (currentState.lastNotPut == null) {
240
- currentState.lastNotPut = doc._id.o;
241
- }
242
- currentState.opsSincePut += 1;
243
- }
244
-
245
- if (this.updates.length >= this.moveBatchLimit) {
246
- await this.flush();
247
- }
248
- }
249
- }
250
-
251
- await this.flush();
252
- currentState?.seen.clear();
253
- if (currentState?.lastNotPut != null && currentState?.opsSincePut > 1) {
254
- logger.info(
255
- `Inserting CLEAR at ${this.group_id}:${currentState.bucket}:${currentState.lastNotPut} to remove ${currentState.opsSincePut} operations`
256
- );
257
- const bucket = currentState.bucket;
258
- const clearOp = currentState.lastNotPut;
259
- // Free memory before clearing bucket
260
- currentState = null;
261
- await this.clearBucket(bucket, clearOp);
262
- }
263
- }
264
-
265
- private async flush() {
266
- if (this.updates.length > 0) {
267
- logger.info(`Compacting ${this.updates.length} ops`);
268
- await safeBulkWrite(this.db.bucket_data, this.updates, {
269
- // Order is not important.
270
- // Since checksums are not affected, these operations can happen in any order,
271
- // and it's fine if the operations are partially applied.
272
- // Each individual operation is atomic.
273
- ordered: false
274
- });
275
- this.updates = [];
276
- }
277
- }
278
-
279
- /**
280
- * Perform a CLEAR compact for a bucket.
281
- *
282
- * @param bucket bucket name
283
- * @param op op_id of the last non-PUT operation, which will be converted to CLEAR.
284
- */
285
- private async clearBucket(bucket: string, op: bigint) {
286
- const opFilter = {
287
- _id: {
288
- $gte: {
289
- g: this.group_id,
290
- b: bucket,
291
- o: new MinKey() as any
292
- },
293
- $lte: {
294
- g: this.group_id,
295
- b: bucket,
296
- o: op
297
- }
298
- }
299
- };
300
-
301
- const session = this.db.client.startSession();
302
- try {
303
- let done = false;
304
- while (!done) {
305
- // Do the CLEAR operation in batches, with each batch a separate transaction.
306
- // The state after each batch is fully consistent.
307
- // We need a transaction per batch to make sure checksums stay consistent.
308
- await session.withTransaction(
309
- async () => {
310
- const query = this.db.bucket_data.find(opFilter, {
311
- session,
312
- sort: { _id: 1 },
313
- projection: {
314
- _id: 1,
315
- op: 1,
316
- checksum: 1,
317
- target_op: 1
318
- },
319
- limit: this.clearBatchLimit
320
- });
321
- let checksum = 0;
322
- let lastOpId: BucketDataKey | null = null;
323
- let targetOp: bigint | null = null;
324
- let gotAnOp = false;
325
- for await (let op of query.stream()) {
326
- if (op.op == 'MOVE' || op.op == 'REMOVE' || op.op == 'CLEAR') {
327
- checksum = addChecksums(checksum, op.checksum);
328
- lastOpId = op._id;
329
- if (op.op != 'CLEAR') {
330
- gotAnOp = true;
331
- }
332
- if (op.target_op != null) {
333
- if (targetOp == null || op.target_op > targetOp) {
334
- targetOp = op.target_op;
335
- }
336
- }
337
- } else {
338
- throw new Error(`Unexpected ${op.op} operation at ${op._id.g}:${op._id.b}:${op._id.o}`);
339
- }
340
- }
341
- if (!gotAnOp) {
342
- done = true;
343
- return;
344
- }
345
-
346
- logger.info(`Flushing CLEAR at ${lastOpId?.o}`);
347
- await this.db.bucket_data.deleteMany(
348
- {
349
- _id: {
350
- $gte: {
351
- g: this.group_id,
352
- b: bucket,
353
- o: new MinKey() as any
354
- },
355
- $lte: lastOpId!
356
- }
357
- },
358
- { session }
359
- );
360
-
361
- await this.db.bucket_data.insertOne(
362
- {
363
- _id: lastOpId!,
364
- op: 'CLEAR',
365
- checksum: checksum,
366
- data: null,
367
- target_op: targetOp
368
- },
369
- { session }
370
- );
371
- },
372
- {
373
- writeConcern: { w: 'majority' },
374
- readConcern: { level: 'snapshot' }
375
- }
376
- );
377
- }
378
- } finally {
379
- await session.endSession();
380
- }
381
- }
382
- }
383
-
384
- /**
385
- * Flattens string to reduce memory usage (around 320 bytes -> 120 bytes),
386
- * at the cost of some upfront CPU usage.
387
- *
388
- * From: https://github.com/davidmarkclements/flatstr/issues/8
389
- */
390
- function flatstr(s: string) {
391
- s.match(/\n/g);
392
- return s;
393
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Manages op_id or similar sequence in memory.
3
- *
4
- * This is typically used within a transaction, with the last value persisted
5
- * at the end of the transaction.
6
- */
7
- export class MongoIdSequence {
8
- private _last: bigint;
9
-
10
- constructor(last: bigint) {
11
- if (typeof last != 'bigint') {
12
- throw new Error(`BigInt required, got ${last} ${typeof last}`);
13
- }
14
- this._last = last;
15
- }
16
-
17
- next() {
18
- return ++this._last;
19
- }
20
-
21
- last() {
22
- return this._last;
23
- }
24
- }
@@ -1,16 +0,0 @@
1
- import { SqlSyncRules } from '@powersync/service-sync-rules';
2
-
3
- import { PersistedSyncRules } from '../BucketStorage.js';
4
-
5
- export class MongoPersistedSyncRules implements PersistedSyncRules {
6
- public readonly slot_name: string;
7
-
8
- constructor(
9
- public readonly id: number,
10
- public readonly sync_rules: SqlSyncRules,
11
- public readonly checkpoint_lsn: string | null,
12
- slot_name: string | null
13
- ) {
14
- this.slot_name = slot_name ?? `powersync_${id}`;
15
- }
16
- }
@@ -1,50 +0,0 @@
1
- import { SqlSyncRules } from '@powersync/service-sync-rules';
2
- import * as mongo from 'mongodb';
3
-
4
- import { ParseSyncRulesOptions, PersistedSyncRulesContent } from '../BucketStorage.js';
5
- import { MongoPersistedSyncRules } from './MongoPersistedSyncRules.js';
6
- import { MongoSyncRulesLock } from './MongoSyncRulesLock.js';
7
- import { PowerSyncMongo } from './db.js';
8
- import { SyncRuleDocument } from './models.js';
9
-
10
- export class MongoPersistedSyncRulesContent implements PersistedSyncRulesContent {
11
- public readonly slot_name: string;
12
-
13
- public readonly id: number;
14
- public readonly sync_rules_content: string;
15
- public readonly last_checkpoint_lsn: string | null;
16
- public readonly last_fatal_error: string | null;
17
- public readonly last_keepalive_ts: Date | null;
18
- public readonly last_checkpoint_ts: Date | null;
19
-
20
- public current_lock: MongoSyncRulesLock | null = null;
21
-
22
- constructor(
23
- private db: PowerSyncMongo,
24
- doc: mongo.WithId<SyncRuleDocument>
25
- ) {
26
- this.id = doc._id;
27
- this.sync_rules_content = doc.content;
28
- this.last_checkpoint_lsn = doc.last_checkpoint_lsn;
29
- // Handle legacy values
30
- this.slot_name = doc.slot_name ?? `powersync_${this.id}`;
31
- this.last_fatal_error = doc.last_fatal_error;
32
- this.last_checkpoint_ts = doc.last_checkpoint_ts;
33
- this.last_keepalive_ts = doc.last_keepalive_ts;
34
- }
35
-
36
- parsed(options: ParseSyncRulesOptions) {
37
- return new MongoPersistedSyncRules(
38
- this.id,
39
- SqlSyncRules.fromYaml(this.sync_rules_content, options),
40
- this.last_checkpoint_lsn,
41
- this.slot_name
42
- );
43
- }
44
-
45
- async lock() {
46
- const lock = await MongoSyncRulesLock.createLock(this.db, this);
47
- this.current_lock = lock;
48
- return lock;
49
- }
50
- }
@@ -1,31 +0,0 @@
1
- import { logger } from '@powersync/lib-services-framework';
2
- import * as db from '../../db/db-index.js';
3
- import { MongoBucketStorage } from '../MongoBucketStorage.js';
4
- import { ActiveStorage, BucketStorageProvider, GetStorageOptions } from '../StorageProvider.js';
5
- import { PowerSyncMongo } from './db.js';
6
-
7
- export class MongoStorageProvider implements BucketStorageProvider {
8
- get type() {
9
- return 'mongodb';
10
- }
11
-
12
- async getStorage(options: GetStorageOptions): Promise<ActiveStorage> {
13
- const { resolvedConfig } = options;
14
-
15
- const client = db.mongo.createMongoClient(resolvedConfig.storage);
16
-
17
- const database = new PowerSyncMongo(client, { database: resolvedConfig.storage.database });
18
-
19
- return {
20
- storage: new MongoBucketStorage(database, {
21
- // TODO currently need the entire resolved config due to this
22
- slot_name_prefix: resolvedConfig.slot_name_prefix
23
- }),
24
- shutDown: () => client.close(),
25
- tearDown: () => {
26
- logger.info(`Tearing down storage: ${database.db.namespace}...`);
27
- return database.db.dropDatabase();
28
- }
29
- } satisfies ActiveStorage;
30
- }
31
- }