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