@powersync/service-module-mongodb-storage 0.0.0-dev-20260225160713 → 0.0.0-dev-20260511080634

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 (213) hide show
  1. package/CHANGELOG.md +119 -6
  2. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +1 -1
  3. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -1
  4. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +3 -3
  5. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  6. package/dist/migrations/db/migrations/1770213298299-storage-version.js.map +1 -1
  7. package/dist/storage/MongoBucketStorage.d.ts +5 -3
  8. package/dist/storage/MongoBucketStorage.js +53 -26
  9. package/dist/storage/MongoBucketStorage.js.map +1 -1
  10. package/dist/storage/MongoReportStorage.js.map +1 -1
  11. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +17 -0
  12. package/dist/storage/implementation/BucketDefinitionMapping.js +58 -0
  13. package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
  14. package/dist/storage/implementation/MongoBucketBatch.d.ts +25 -21
  15. package/dist/storage/implementation/MongoBucketBatch.js +256 -210
  16. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  17. package/dist/storage/implementation/MongoBucketBatchShared.d.ts +5 -0
  18. package/dist/storage/implementation/MongoBucketBatchShared.js +8 -0
  19. package/dist/storage/implementation/MongoBucketBatchShared.js.map +1 -0
  20. package/dist/storage/implementation/MongoChecksums.d.ts +30 -19
  21. package/dist/storage/implementation/MongoChecksums.js +13 -71
  22. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  23. package/dist/storage/implementation/MongoCompactor.d.ts +99 -53
  24. package/dist/storage/implementation/MongoCompactor.js +265 -303
  25. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  26. package/dist/storage/implementation/MongoParameterCompactor.d.ts +12 -7
  27. package/dist/storage/implementation/MongoParameterCompactor.js +24 -9
  28. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  29. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +14 -0
  30. package/dist/storage/implementation/MongoPersistedSyncRules.js +64 -0
  31. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
  32. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +3 -0
  33. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +11 -7
  34. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
  35. package/dist/storage/implementation/MongoStorageProvider.js +1 -1
  36. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  37. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +54 -30
  38. package/dist/storage/implementation/MongoSyncBucketStorage.js +118 -472
  39. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  40. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +7 -5
  41. package/dist/storage/implementation/MongoSyncRulesLock.js +12 -10
  42. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  43. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +4 -4
  44. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +1 -1
  45. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  46. package/dist/storage/implementation/OperationBatch.js +3 -2
  47. package/dist/storage/implementation/OperationBatch.js.map +1 -1
  48. package/dist/storage/implementation/common/BucketDataDoc.d.ts +35 -0
  49. package/dist/storage/implementation/common/BucketDataDoc.js +2 -0
  50. package/dist/storage/implementation/common/BucketDataDoc.js.map +1 -0
  51. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +13 -0
  52. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +2 -0
  53. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +1 -0
  54. package/dist/storage/implementation/common/PersistedBatch.d.ts +108 -0
  55. package/dist/storage/implementation/common/PersistedBatch.js +237 -0
  56. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -0
  57. package/dist/storage/implementation/common/SingleBucketStore.d.ts +54 -0
  58. package/dist/storage/implementation/common/SingleBucketStore.js +3 -0
  59. package/dist/storage/implementation/common/SingleBucketStore.js.map +1 -0
  60. package/dist/storage/implementation/common/SourceRecordStore.d.ts +36 -0
  61. package/dist/storage/implementation/common/SourceRecordStore.js +2 -0
  62. package/dist/storage/implementation/common/SourceRecordStore.js.map +1 -0
  63. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +27 -0
  64. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +57 -0
  65. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -0
  66. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +7 -0
  67. package/dist/storage/implementation/createMongoSyncBucketStorage.js +9 -0
  68. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -0
  69. package/dist/storage/implementation/db.d.ts +38 -4
  70. package/dist/storage/implementation/db.js +80 -1
  71. package/dist/storage/implementation/db.js.map +1 -1
  72. package/dist/storage/implementation/models.d.ts +66 -25
  73. package/dist/storage/implementation/models.js +22 -2
  74. package/dist/storage/implementation/models.js.map +1 -1
  75. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +13 -0
  76. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +22 -0
  77. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -0
  78. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +12 -0
  79. package/dist/storage/implementation/v1/MongoChecksumsV1.js +56 -0
  80. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -0
  81. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +23 -0
  82. package/dist/storage/implementation/v1/MongoCompactorV1.js +52 -0
  83. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -0
  84. package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +9 -0
  85. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -0
  86. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -0
  87. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +41 -0
  88. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +269 -0
  89. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -0
  90. package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +26 -0
  91. package/dist/storage/implementation/v1/PersistedBatchV1.js +183 -0
  92. package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -0
  93. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +18 -0
  94. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +57 -0
  95. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -0
  96. package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +19 -0
  97. package/dist/storage/implementation/v1/SourceRecordStoreV1.js +105 -0
  98. package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -0
  99. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +12 -0
  100. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +20 -0
  101. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -0
  102. package/dist/storage/implementation/v1/models.d.ts +34 -0
  103. package/dist/storage/implementation/v1/models.js +37 -0
  104. package/dist/storage/implementation/v1/models.js.map +1 -0
  105. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +13 -0
  106. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +34 -0
  107. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -0
  108. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +15 -0
  109. package/dist/storage/implementation/v3/MongoChecksumsV3.js +84 -0
  110. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -0
  111. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -0
  112. package/dist/storage/implementation/v3/MongoCompactorV3.js +68 -0
  113. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -0
  114. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +9 -0
  115. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +18 -0
  116. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
  117. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +5 -0
  118. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +9 -0
  119. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +1 -0
  120. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +41 -0
  121. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +404 -0
  122. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -0
  123. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +29 -0
  124. package/dist/storage/implementation/v3/PersistedBatchV3.js +259 -0
  125. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -0
  126. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +18 -0
  127. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +48 -0
  128. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +1 -0
  129. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +22 -0
  130. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +164 -0
  131. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -0
  132. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +21 -0
  133. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +71 -0
  134. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -0
  135. package/dist/storage/implementation/v3/models.d.ts +43 -0
  136. package/dist/storage/implementation/v3/models.js +34 -0
  137. package/dist/storage/implementation/v3/models.js.map +1 -0
  138. package/dist/storage/storage-index.d.ts +8 -5
  139. package/dist/storage/storage-index.js +8 -5
  140. package/dist/storage/storage-index.js.map +1 -1
  141. package/dist/utils/test-utils.d.ts +4 -1
  142. package/dist/utils/test-utils.js +15 -12
  143. package/dist/utils/test-utils.js.map +1 -1
  144. package/dist/utils/util.d.ts +13 -5
  145. package/dist/utils/util.js +40 -5
  146. package/dist/utils/util.js.map +1 -1
  147. package/package.json +9 -9
  148. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +1 -1
  149. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -7
  150. package/src/migrations/db/migrations/1770213298299-storage-version.ts +1 -1
  151. package/src/storage/MongoBucketStorage.ts +111 -55
  152. package/src/storage/MongoReportStorage.ts +2 -2
  153. package/src/storage/implementation/BucketDefinitionMapping.ts +72 -0
  154. package/src/storage/implementation/MongoBucketBatch.ts +322 -270
  155. package/src/storage/implementation/MongoBucketBatchShared.ts +11 -0
  156. package/src/storage/implementation/MongoChecksums.ts +54 -75
  157. package/src/storage/implementation/MongoCompactor.ts +411 -412
  158. package/src/storage/implementation/MongoParameterCompactor.ts +52 -26
  159. package/src/storage/implementation/MongoPersistedSyncRules.ts +76 -0
  160. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +19 -10
  161. package/src/storage/implementation/MongoStorageProvider.ts +1 -1
  162. package/src/storage/implementation/MongoSyncBucketStorage.ts +206 -466
  163. package/src/storage/implementation/MongoSyncRulesLock.ts +14 -16
  164. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +7 -5
  165. package/src/storage/implementation/OperationBatch.ts +3 -2
  166. package/src/storage/implementation/common/BucketDataDoc.ts +37 -0
  167. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +15 -0
  168. package/src/storage/implementation/common/PersistedBatch.ts +364 -0
  169. package/src/storage/implementation/common/SingleBucketStore.ts +63 -0
  170. package/src/storage/implementation/common/SourceRecordStore.ts +49 -0
  171. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +80 -0
  172. package/src/storage/implementation/createMongoSyncBucketStorage.ts +25 -0
  173. package/src/storage/implementation/db.ts +115 -8
  174. package/src/storage/implementation/models.ts +88 -28
  175. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +32 -0
  176. package/src/storage/implementation/v1/MongoChecksumsV1.ts +75 -0
  177. package/src/storage/implementation/v1/MongoCompactorV1.ts +93 -0
  178. package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +26 -0
  179. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +432 -0
  180. package/src/storage/implementation/v1/PersistedBatchV1.ts +230 -0
  181. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +74 -0
  182. package/src/storage/implementation/v1/SourceRecordStoreV1.ts +156 -0
  183. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +28 -0
  184. package/src/storage/implementation/v1/models.ts +84 -0
  185. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +44 -0
  186. package/src/storage/implementation/v3/MongoChecksumsV3.ts +120 -0
  187. package/src/storage/implementation/v3/MongoCompactorV3.ts +107 -0
  188. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +24 -0
  189. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +12 -0
  190. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +545 -0
  191. package/src/storage/implementation/v3/PersistedBatchV3.ts +318 -0
  192. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +68 -0
  193. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +226 -0
  194. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +112 -0
  195. package/src/storage/implementation/v3/models.ts +96 -0
  196. package/src/storage/storage-index.ts +8 -5
  197. package/src/utils/test-utils.ts +15 -12
  198. package/src/utils/util.ts +53 -9
  199. package/test/src/__snapshots__/storage.test.ts.snap +201 -0
  200. package/test/src/__snapshots__/storage_compacting.test.ts.snap +17 -0
  201. package/test/src/__snapshots__/storage_sync.test.ts.snap +1393 -16
  202. package/test/src/connection-report-storage.test.ts +3 -3
  203. package/test/src/setup.ts +1 -1
  204. package/test/src/storage.test.ts +10 -8
  205. package/test/src/storage_compacting.test.ts +146 -46
  206. package/test/src/storage_sync.test.ts +404 -56
  207. package/test/src/util.ts +3 -3
  208. package/test/tsconfig.json +0 -1
  209. package/tsconfig.tsbuildinfo +1 -1
  210. package/dist/storage/implementation/PersistedBatch.d.ts +0 -64
  211. package/dist/storage/implementation/PersistedBatch.js +0 -323
  212. package/dist/storage/implementation/PersistedBatch.js.map +0 -1
  213. package/src/storage/implementation/PersistedBatch.ts +0 -401
@@ -1,401 +0,0 @@
1
- import { mongo } from '@powersync/lib-service-mongodb';
2
- import { JSONBig } from '@powersync/service-jsonbig';
3
- import { EvaluatedParameters, EvaluatedRow } from '@powersync/service-sync-rules';
4
- import * as bson from 'bson';
5
-
6
- import { Logger, logger as defaultLogger } from '@powersync/lib-services-framework';
7
- import { InternalOpId, storage, utils } from '@powersync/service-core';
8
- import { currentBucketKey, MAX_ROW_SIZE } from './MongoBucketBatch.js';
9
- import { MongoIdSequence } from './MongoIdSequence.js';
10
- import { PowerSyncMongo } from './db.js';
11
- import {
12
- BucketDataDocument,
13
- BucketParameterDocument,
14
- BucketStateDocument,
15
- CurrentBucket,
16
- CurrentDataDocument,
17
- SourceKey
18
- } from './models.js';
19
- import { replicaIdToSubkey } from '../../utils/util.js';
20
-
21
- /**
22
- * Maximum size of operations we write in a single transaction.
23
- *
24
- * It's tricky to find the exact limit, but from experience, over 100MB
25
- * can cause an error:
26
- * > transaction is too large and will not fit in the storage engine cache
27
- *
28
- * Additionally, unbounded size here can balloon our memory usage in some edge
29
- * cases.
30
- *
31
- * When we reach this threshold, we commit the transaction and start a new one.
32
- */
33
- const MAX_TRANSACTION_BATCH_SIZE = 30_000_000;
34
-
35
- /**
36
- * Limit number of documents to write in a single transaction.
37
- *
38
- * This has an effect on error message size in some cases.
39
- */
40
- const MAX_TRANSACTION_DOC_COUNT = 2_000;
41
-
42
- /**
43
- * Keeps track of bulkwrite operations within a transaction.
44
- *
45
- * There may be multiple of these batches per transaction, but it may not span
46
- * multiple transactions.
47
- */
48
- export class PersistedBatch {
49
- logger: Logger;
50
- bucketData: mongo.AnyBulkWriteOperation<BucketDataDocument>[] = [];
51
- bucketParameters: mongo.AnyBulkWriteOperation<BucketParameterDocument>[] = [];
52
- currentData: mongo.AnyBulkWriteOperation<CurrentDataDocument>[] = [];
53
- bucketStates: Map<string, BucketStateUpdate> = new Map();
54
-
55
- /**
56
- * For debug logging only.
57
- */
58
- debugLastOpId: InternalOpId | null = null;
59
-
60
- /**
61
- * Very rough estimate of transaction size.
62
- */
63
- currentSize = 0;
64
-
65
- constructor(
66
- private group_id: number,
67
- writtenSize: number,
68
- options?: { logger?: Logger }
69
- ) {
70
- this.currentSize = writtenSize;
71
- this.logger = options?.logger ?? defaultLogger;
72
- }
73
-
74
- private incrementBucket(bucket: string, op_id: InternalOpId, bytes: number) {
75
- let existingState = this.bucketStates.get(bucket);
76
- if (existingState) {
77
- existingState.lastOp = op_id;
78
- existingState.incrementCount += 1;
79
- existingState.incrementBytes += bytes;
80
- } else {
81
- this.bucketStates.set(bucket, {
82
- lastOp: op_id,
83
- incrementCount: 1,
84
- incrementBytes: bytes
85
- });
86
- }
87
- }
88
-
89
- saveBucketData(options: {
90
- op_seq: MongoIdSequence;
91
- sourceKey: storage.ReplicaId;
92
- table: storage.SourceTable;
93
- evaluated: EvaluatedRow[];
94
- before_buckets: CurrentBucket[];
95
- }) {
96
- const remaining_buckets = new Map<string, CurrentBucket>();
97
- for (let b of options.before_buckets) {
98
- const key = currentBucketKey(b);
99
- remaining_buckets.set(key, b);
100
- }
101
-
102
- const dchecksum = BigInt(utils.hashDelete(replicaIdToSubkey(options.table.id, options.sourceKey)));
103
-
104
- for (const k of options.evaluated) {
105
- const key = currentBucketKey(k);
106
-
107
- // INSERT
108
- const recordData = JSONBig.stringify(k.data);
109
- const checksum = utils.hashData(k.table, k.id, recordData);
110
- if (recordData.length > MAX_ROW_SIZE) {
111
- // In many cases, the raw data size would have been too large already. But there are cases where
112
- // the BSON size is small enough, but the JSON size is too large.
113
- // In these cases, we can't store the data, so we skip it, or generate a REMOVE operation if the row
114
- // was synced previously.
115
- this.logger.error(`Row ${key} too large: ${recordData.length} bytes. Removing.`);
116
- continue;
117
- }
118
-
119
- remaining_buckets.delete(key);
120
- const byteEstimate = recordData.length + 200;
121
- this.currentSize += byteEstimate;
122
-
123
- const op_id = options.op_seq.next();
124
- this.debugLastOpId = op_id;
125
-
126
- this.bucketData.push({
127
- insertOne: {
128
- document: {
129
- _id: {
130
- g: this.group_id,
131
- b: k.bucket,
132
- o: op_id
133
- },
134
- op: 'PUT',
135
- source_table: options.table.id,
136
- source_key: options.sourceKey,
137
- table: k.table,
138
- row_id: k.id,
139
- checksum: BigInt(checksum),
140
- data: recordData
141
- }
142
- }
143
- });
144
- this.incrementBucket(k.bucket, op_id, byteEstimate);
145
- }
146
-
147
- for (let bd of remaining_buckets.values()) {
148
- // REMOVE
149
-
150
- const op_id = options.op_seq.next();
151
- this.debugLastOpId = op_id;
152
-
153
- this.bucketData.push({
154
- insertOne: {
155
- document: {
156
- _id: {
157
- g: this.group_id,
158
- b: bd.bucket,
159
- o: op_id
160
- },
161
- op: 'REMOVE',
162
- source_table: options.table.id,
163
- source_key: options.sourceKey,
164
- table: bd.table,
165
- row_id: bd.id,
166
- checksum: dchecksum,
167
- data: null
168
- }
169
- }
170
- });
171
- this.currentSize += 200;
172
- this.incrementBucket(bd.bucket, op_id, 200);
173
- }
174
- }
175
-
176
- saveParameterData(data: {
177
- op_seq: MongoIdSequence;
178
- sourceKey: storage.ReplicaId;
179
- sourceTable: storage.SourceTable;
180
- evaluated: EvaluatedParameters[];
181
- existing_lookups: bson.Binary[];
182
- }) {
183
- // This is similar to saving bucket data.
184
- // A key difference is that we don't need to keep the history intact.
185
- // We do need to keep track of recent history though - enough that we can get consistent data for any specific checkpoint.
186
- // Instead of storing per bucket id, we store per "lookup".
187
- // A key difference is that we don't need to store or keep track of anything per-bucket - the entire record is
188
- // either persisted or removed.
189
- // We also don't need to keep history intact.
190
- const { sourceTable, sourceKey, evaluated } = data;
191
-
192
- const remaining_lookups = new Map<string, bson.Binary>();
193
- for (let l of data.existing_lookups) {
194
- remaining_lookups.set(l.toString('base64'), l);
195
- }
196
-
197
- // 1. Insert new entries
198
- for (let result of evaluated) {
199
- const binLookup = storage.serializeLookup(result.lookup);
200
- const hex = binLookup.toString('base64');
201
- remaining_lookups.delete(hex);
202
-
203
- const op_id = data.op_seq.next();
204
- this.debugLastOpId = op_id;
205
- this.bucketParameters.push({
206
- insertOne: {
207
- document: {
208
- _id: op_id,
209
- key: {
210
- g: this.group_id,
211
- t: sourceTable.id,
212
- k: sourceKey
213
- },
214
- lookup: binLookup,
215
- bucket_parameters: result.bucketParameters
216
- }
217
- }
218
- });
219
-
220
- this.currentSize += 200;
221
- }
222
-
223
- // 2. "REMOVE" entries for any lookup not touched.
224
- for (let lookup of remaining_lookups.values()) {
225
- const op_id = data.op_seq.next();
226
- this.debugLastOpId = op_id;
227
- this.bucketParameters.push({
228
- insertOne: {
229
- document: {
230
- _id: op_id,
231
- key: {
232
- g: this.group_id,
233
- t: sourceTable.id,
234
- k: sourceKey
235
- },
236
- lookup: lookup,
237
- bucket_parameters: []
238
- }
239
- }
240
- });
241
-
242
- this.currentSize += 200;
243
- }
244
- }
245
-
246
- deleteCurrentData(id: SourceKey) {
247
- const op: mongo.AnyBulkWriteOperation<CurrentDataDocument> = {
248
- deleteOne: {
249
- filter: { _id: id }
250
- }
251
- };
252
- this.currentData.push(op);
253
- this.currentSize += 50;
254
- }
255
-
256
- upsertCurrentData(id: SourceKey, values: Partial<CurrentDataDocument>) {
257
- const op: mongo.AnyBulkWriteOperation<CurrentDataDocument> = {
258
- updateOne: {
259
- filter: { _id: id },
260
- update: {
261
- $set: values
262
- },
263
- upsert: true
264
- }
265
- };
266
- this.currentData.push(op);
267
- this.currentSize += (values.data?.length() ?? 0) + 100;
268
- }
269
-
270
- shouldFlushTransaction() {
271
- return (
272
- this.currentSize >= MAX_TRANSACTION_BATCH_SIZE ||
273
- this.bucketData.length >= MAX_TRANSACTION_DOC_COUNT ||
274
- this.currentData.length >= MAX_TRANSACTION_DOC_COUNT ||
275
- this.bucketParameters.length >= MAX_TRANSACTION_DOC_COUNT
276
- );
277
- }
278
-
279
- async flush(db: PowerSyncMongo, session: mongo.ClientSession, options?: storage.BucketBatchCommitOptions) {
280
- const startAt = performance.now();
281
- let flushedSomething = false;
282
- if (this.bucketData.length > 0) {
283
- flushedSomething = true;
284
- await db.bucket_data.bulkWrite(this.bucketData, {
285
- session,
286
- // inserts only - order doesn't matter
287
- ordered: false
288
- });
289
- }
290
- if (this.bucketParameters.length > 0) {
291
- flushedSomething = true;
292
- await db.bucket_parameters.bulkWrite(this.bucketParameters, {
293
- session,
294
- // inserts only - order doesn't matter
295
- ordered: false
296
- });
297
- }
298
- if (this.currentData.length > 0) {
299
- flushedSomething = true;
300
- await db.current_data.bulkWrite(this.currentData, {
301
- session,
302
- // may update and delete data within the same batch - order matters
303
- ordered: true
304
- });
305
- }
306
-
307
- if (this.bucketStates.size > 0) {
308
- flushedSomething = true;
309
- await db.bucket_state.bulkWrite(this.getBucketStateUpdates(), {
310
- session,
311
- // Per-bucket operation - order doesn't matter
312
- ordered: false
313
- });
314
- }
315
-
316
- if (flushedSomething) {
317
- const duration = Math.round(performance.now() - startAt);
318
- if (options?.oldestUncommittedChange != null) {
319
- const replicationLag = Math.round((Date.now() - options.oldestUncommittedChange.getTime()) / 1000);
320
-
321
- this.logger.info(
322
- `Flushed ${this.bucketData.length} + ${this.bucketParameters.length} + ${
323
- this.currentData.length
324
- } updates, ${Math.round(this.currentSize / 1024)}kb in ${duration}ms. Last op_id: ${this.debugLastOpId}. Replication lag: ${replicationLag}s`,
325
- {
326
- flushed: {
327
- duration: duration,
328
- size: this.currentSize,
329
- bucket_data_count: this.bucketData.length,
330
- parameter_data_count: this.bucketParameters.length,
331
- current_data_count: this.currentData.length,
332
- replication_lag_seconds: replicationLag
333
- }
334
- }
335
- );
336
- } else {
337
- this.logger.info(
338
- `Flushed ${this.bucketData.length} + ${this.bucketParameters.length} + ${
339
- this.currentData.length
340
- } updates, ${Math.round(this.currentSize / 1024)}kb in ${duration}ms. Last op_id: ${this.debugLastOpId}`,
341
- {
342
- flushed: {
343
- duration: duration,
344
- size: this.currentSize,
345
- bucket_data_count: this.bucketData.length,
346
- parameter_data_count: this.bucketParameters.length,
347
- current_data_count: this.currentData.length
348
- }
349
- }
350
- );
351
- }
352
- }
353
-
354
- const stats = {
355
- bucketDataCount: this.bucketData.length,
356
- parameterDataCount: this.bucketParameters.length,
357
- currentDataCount: this.currentData.length,
358
- flushedAny: flushedSomething
359
- };
360
-
361
- this.bucketData = [];
362
- this.bucketParameters = [];
363
- this.currentData = [];
364
- this.bucketStates.clear();
365
- this.currentSize = 0;
366
- this.debugLastOpId = null;
367
-
368
- return stats;
369
- }
370
-
371
- private getBucketStateUpdates(): mongo.AnyBulkWriteOperation<BucketStateDocument>[] {
372
- return Array.from(this.bucketStates.entries()).map(([bucket, state]) => {
373
- return {
374
- updateOne: {
375
- filter: {
376
- _id: {
377
- g: this.group_id,
378
- b: bucket
379
- }
380
- },
381
- update: {
382
- $set: {
383
- last_op: state.lastOp
384
- },
385
- $inc: {
386
- 'estimate_since_compact.count': state.incrementCount,
387
- 'estimate_since_compact.bytes': state.incrementBytes
388
- }
389
- },
390
- upsert: true
391
- }
392
- } satisfies mongo.AnyBulkWriteOperation<BucketStateDocument>;
393
- });
394
- }
395
- }
396
-
397
- interface BucketStateUpdate {
398
- lastOp: InternalOpId;
399
- incrementCount: number;
400
- incrementBytes: number;
401
- }