@powersync/service-module-mongodb-storage 0.0.0-dev-20260602073133 → 0.0.0-dev-20260909133214

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 (275) hide show
  1. package/CHANGELOG.md +177 -5
  2. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js +41 -0
  4. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js.map +1 -0
  5. package/dist/storage/MongoBucketStorage.d.ts +71 -18
  6. package/dist/storage/MongoBucketStorage.js +516 -202
  7. package/dist/storage/MongoBucketStorage.js.map +1 -1
  8. package/dist/storage/implementation/MongoBucketBatch.d.ts +71 -29
  9. package/dist/storage/implementation/MongoBucketBatch.js +140 -66
  10. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  11. package/dist/storage/implementation/MongoChecksums.d.ts +41 -13
  12. package/dist/storage/implementation/MongoChecksums.js +36 -121
  13. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  14. package/dist/storage/implementation/MongoCompactor.d.ts +28 -90
  15. package/dist/storage/implementation/MongoCompactor.js +87 -481
  16. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  17. package/dist/storage/implementation/MongoHydrationState.d.ts +11 -0
  18. package/dist/storage/implementation/MongoHydrationState.js +49 -0
  19. package/dist/storage/implementation/MongoHydrationState.js.map +1 -0
  20. package/dist/storage/implementation/MongoParameterCompactor.d.ts +82 -8
  21. package/dist/storage/implementation/MongoParameterCompactor.js +312 -76
  22. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  23. package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +21 -0
  24. package/dist/storage/implementation/MongoParsedSyncConfigSet.js +93 -0
  25. package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -0
  26. package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +36 -0
  27. package/dist/storage/implementation/MongoPersistedReplicationStream.js +90 -0
  28. package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -0
  29. package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +25 -0
  30. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +125 -0
  31. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -0
  32. package/dist/storage/implementation/MongoStorageProvider.js +41 -4
  33. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  34. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +81 -37
  35. package/dist/storage/implementation/MongoSyncBucketStorage.js +159 -86
  36. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  37. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +1 -1
  38. package/dist/storage/implementation/MongoSyncRulesLock.js +23 -11
  39. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  40. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +11 -8
  41. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +159 -33
  42. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  43. package/dist/storage/implementation/SyncRuleStateUpdate.d.ts +11 -5
  44. package/dist/storage/implementation/SyncRuleStateUpdate.js +14 -6
  45. package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -1
  46. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +28 -0
  47. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js +2 -0
  48. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js.map +1 -0
  49. package/dist/storage/implementation/common/PersistedBatch.d.ts +34 -2
  50. package/dist/storage/implementation/common/PersistedBatch.js +63 -10
  51. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
  52. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +1 -1
  53. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
  54. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +2 -2
  55. package/dist/storage/implementation/createMongoSyncBucketStorage.js +4 -4
  56. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -1
  57. package/dist/storage/implementation/db.d.ts +4 -1
  58. package/dist/storage/implementation/db.js +31 -16
  59. package/dist/storage/implementation/db.js.map +1 -1
  60. package/dist/storage/implementation/models.d.ts +55 -13
  61. package/dist/storage/implementation/models.js.map +1 -1
  62. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +15 -1
  63. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +135 -107
  64. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
  65. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +4 -4
  66. package/dist/storage/implementation/v1/MongoChecksumsV1.js +119 -7
  67. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -1
  68. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +47 -7
  69. package/dist/storage/implementation/v1/MongoCompactorV1.js +478 -8
  70. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
  71. package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +16 -2
  72. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -9
  73. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -1
  74. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +33 -27
  75. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +146 -73
  76. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
  77. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +9 -10
  78. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +2 -8
  79. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -1
  80. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +2 -1
  81. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +3 -0
  82. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -1
  83. package/dist/storage/implementation/v1/models.d.ts +10 -1
  84. package/dist/storage/implementation/v1/models.js +1 -0
  85. package/dist/storage/implementation/v1/models.js.map +1 -1
  86. package/dist/storage/implementation/v3/BucketDataContextV3.d.ts +13 -0
  87. package/dist/storage/implementation/v3/BucketDataContextV3.js +23 -0
  88. package/dist/storage/implementation/v3/BucketDataContextV3.js.map +1 -0
  89. package/dist/storage/implementation/v3/CompactionLease.d.ts +50 -0
  90. package/dist/storage/implementation/v3/CompactionLease.js +131 -0
  91. package/dist/storage/implementation/v3/CompactionLease.js.map +1 -0
  92. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +16 -5
  93. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +393 -262
  94. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
  95. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +30 -9
  96. package/dist/storage/implementation/v3/MongoChecksumsV3.js +161 -20
  97. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
  98. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +108 -18
  99. package/dist/storage/implementation/v3/MongoCompactorV3.js +1115 -47
  100. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
  101. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +12 -3
  102. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +13 -8
  103. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -1
  104. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +54 -0
  105. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +319 -0
  106. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -0
  107. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +61 -36
  108. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +353 -161
  109. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
  110. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.d.ts +26 -0
  111. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js +82 -0
  112. package/dist/storage/implementation/v3/MongoWriteCheckpointAPIV3.js.map +1 -0
  113. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +8 -3
  114. package/dist/storage/implementation/v3/PersistedBatchV3.js +131 -29
  115. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
  116. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +3 -3
  117. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +13 -11
  118. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
  119. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +26 -14
  120. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +73 -29
  121. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
  122. package/dist/storage/implementation/v3/bucket-format.d.ts +13 -0
  123. package/dist/storage/implementation/v3/bucket-format.js +79 -0
  124. package/dist/storage/implementation/v3/bucket-format.js.map +1 -0
  125. package/dist/storage/implementation/v3/chunking.d.ts +10 -0
  126. package/dist/storage/implementation/v3/chunking.js +30 -0
  127. package/dist/storage/implementation/v3/chunking.js.map +1 -0
  128. package/dist/storage/implementation/v3/compact-utils.d.ts +107 -0
  129. package/dist/storage/implementation/v3/compact-utils.js +216 -0
  130. package/dist/storage/implementation/v3/compact-utils.js.map +1 -0
  131. package/dist/storage/implementation/v3/compaction-constants.d.ts +5 -0
  132. package/dist/storage/implementation/v3/compaction-constants.js +6 -0
  133. package/dist/storage/implementation/v3/compaction-constants.js.map +1 -0
  134. package/dist/storage/implementation/v3/models.d.ts +187 -23
  135. package/dist/storage/implementation/v3/models.js +11 -28
  136. package/dist/storage/implementation/v3/models.js.map +1 -1
  137. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +20 -0
  138. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +48 -0
  139. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
  140. package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +33 -0
  141. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js +12 -0
  142. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js.map +1 -0
  143. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +68 -0
  144. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +154 -0
  145. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
  146. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.d.ts +37 -0
  147. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js +167 -0
  148. package/dist/storage/implementation/v3/object-storage/ObjectStorageUsage.js.map +1 -0
  149. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +67 -0
  150. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +439 -0
  151. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
  152. package/dist/storage/implementation/v3/source-table-utils.d.ts +63 -0
  153. package/dist/storage/implementation/v3/source-table-utils.js +206 -0
  154. package/dist/storage/implementation/v3/source-table-utils.js.map +1 -0
  155. package/dist/storage/storage-index.d.ts +5 -4
  156. package/dist/storage/storage-index.js +5 -4
  157. package/dist/storage/storage-index.js.map +1 -1
  158. package/dist/types/types.d.ts +71 -3
  159. package/dist/types/types.js +58 -2
  160. package/dist/types/types.js.map +1 -1
  161. package/dist/utils/test-utils.d.ts +1 -2
  162. package/dist/utils/test-utils.js +7 -1
  163. package/dist/utils/test-utils.js.map +1 -1
  164. package/dist/utils/util.d.ts +9 -2
  165. package/dist/utils/util.js +131 -5
  166. package/dist/utils/util.js.map +1 -1
  167. package/package.json +13 -19
  168. package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
  169. package/src/storage/MongoBucketStorage.ts +728 -242
  170. package/src/storage/implementation/MongoBucketBatch.ts +196 -91
  171. package/src/storage/implementation/MongoChecksums.ts +93 -153
  172. package/src/storage/implementation/MongoCompactor.ts +106 -631
  173. package/src/storage/implementation/MongoHydrationState.ts +61 -0
  174. package/src/storage/implementation/MongoParameterCompactor.ts +392 -87
  175. package/src/storage/implementation/MongoParsedSyncConfigSet.ts +122 -0
  176. package/src/storage/implementation/MongoPersistedReplicationStream.ts +118 -0
  177. package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +156 -0
  178. package/src/storage/implementation/MongoStorageProvider.ts +48 -4
  179. package/src/storage/implementation/MongoSyncBucketStorage.ts +226 -118
  180. package/src/storage/implementation/MongoSyncRulesLock.ts +28 -12
  181. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +194 -52
  182. package/src/storage/implementation/SyncRuleStateUpdate.ts +13 -6
  183. package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +31 -0
  184. package/src/storage/implementation/common/PersistedBatch.ts +83 -15
  185. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +1 -1
  186. package/src/storage/implementation/createMongoSyncBucketStorage.ts +21 -7
  187. package/src/storage/implementation/db.ts +40 -22
  188. package/src/storage/implementation/models.ts +58 -14
  189. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +174 -125
  190. package/src/storage/implementation/v1/MongoChecksumsV1.ts +154 -12
  191. package/src/storage/implementation/v1/MongoCompactorV1.ts +594 -25
  192. package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +25 -9
  193. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +226 -129
  194. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
  195. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +11 -1
  196. package/src/storage/implementation/v1/models.ts +12 -1
  197. package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
  198. package/src/storage/implementation/v3/CompactionLease.ts +152 -0
  199. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +502 -324
  200. package/src/storage/implementation/v3/MongoChecksumsV3.ts +250 -32
  201. package/src/storage/implementation/v3/MongoCompactorV3.ts +1439 -70
  202. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +19 -9
  203. package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +473 -0
  204. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +453 -211
  205. package/src/storage/implementation/v3/MongoWriteCheckpointAPIV3.ts +111 -0
  206. package/src/storage/implementation/v3/PersistedBatchV3.ts +169 -45
  207. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +12 -12
  208. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +99 -38
  209. package/src/storage/implementation/v3/bucket-format.ts +99 -0
  210. package/src/storage/implementation/v3/chunking.ts +40 -0
  211. package/src/storage/implementation/v3/compact-utils.ts +320 -0
  212. package/src/storage/implementation/v3/compaction-constants.ts +5 -0
  213. package/src/storage/implementation/v3/models.ts +228 -58
  214. package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +62 -0
  215. package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +44 -0
  216. package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +182 -0
  217. package/src/storage/implementation/v3/object-storage/ObjectStorageUsage.ts +230 -0
  218. package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +573 -0
  219. package/src/storage/implementation/v3/source-table-utils.ts +398 -0
  220. package/src/storage/storage-index.ts +14 -4
  221. package/src/types/types.ts +76 -2
  222. package/src/utils/test-utils.ts +8 -3
  223. package/src/utils/util.ts +188 -7
  224. package/test/src/__snapshots__/storage.test.ts.snap +4 -54
  225. package/test/src/__snapshots__/storage_sync.test.ts.snap +652 -645
  226. package/test/src/cleanup-stopped-sync-configs.test.ts +698 -0
  227. package/test/src/compact-utils.test.ts +226 -0
  228. package/test/src/helpers/MemoryObjectStorage.ts +61 -0
  229. package/test/src/helpers/s3TestFactory.ts +69 -0
  230. package/test/src/object_storage_lifecycle.test.ts +59 -0
  231. package/test/src/object_storage_usage.test.ts +255 -0
  232. package/test/src/parameter_compacting_v1.test.ts +120 -0
  233. package/test/src/parameter_compacting_v3.test.ts +192 -0
  234. package/test/src/parameter_compaction_fence.test.ts +276 -0
  235. package/test/src/setup.ts +6 -1
  236. package/test/src/storage.test.ts +478 -13
  237. package/test/src/storage_compacting.test.ts +2516 -107
  238. package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
  239. package/test/src/storage_s3_checksums.test.ts +190 -0
  240. package/test/src/storage_s3_compaction_lifecycle.test.ts +543 -0
  241. package/test/src/storage_s3_reading.test.ts +768 -0
  242. package/test/src/storage_s3_writing.test.ts +136 -0
  243. package/test/src/storage_sync.test.ts +1507 -76
  244. package/test/src/storeCurrentData.test.ts +227 -0
  245. package/test/src/util.ts +3 -2
  246. package/tsconfig.json +1 -4
  247. package/tsconfig.tsbuildinfo +1 -1
  248. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +0 -15
  249. package/dist/storage/implementation/BucketDefinitionMapping.js +0 -58
  250. package/dist/storage/implementation/BucketDefinitionMapping.js.map +0 -1
  251. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -14
  252. package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -67
  253. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
  254. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +0 -29
  255. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +0 -76
  256. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +0 -1
  257. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +0 -13
  258. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +0 -2
  259. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +0 -1
  260. package/dist/storage/implementation/common/SingleBucketStore.d.ts +0 -54
  261. package/dist/storage/implementation/common/SingleBucketStore.js +0 -3
  262. package/dist/storage/implementation/common/SingleBucketStore.js.map +0 -1
  263. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +0 -4
  264. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +0 -9
  265. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +0 -1
  266. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
  267. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -48
  268. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
  269. package/src/storage/implementation/BucketDefinitionMapping.ts +0 -75
  270. package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -82
  271. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +0 -101
  272. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +0 -15
  273. package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
  274. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +0 -11
  275. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -68
@@ -1,4 +1,5 @@
1
1
  import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { bson, InternalOpId } from '@powersync/service-core';
2
3
  import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
3
4
  import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
4
5
 
@@ -9,18 +10,33 @@ export class MongoParameterCompactorV1 extends MongoParameterCompactor {
9
10
  return [this.db.parameterIndexV1 as unknown as mongo.Collection<mongo.Document>];
10
11
  }
11
12
 
12
- protected collectionFilter(): mongo.Document {
13
- return {
14
- 'key.g': this.group_id
15
- };
13
+ // The shared V1 collection is scanned using only its default `_id` index. Filter the stream in
14
+ // code so compaction does not require an index on `key.g`.
15
+ protected override shouldCompactDocument(doc: { key: mongo.Document }): boolean {
16
+ return doc.key.g === this.replicationStreamId;
16
17
  }
17
18
 
18
- protected deleteFilter(doc: mongo.Document): mongo.Document {
19
+ /**
20
+ * Uses the legacy `{ 'key.g': 1, lookup: 1, _id: 1 }` index to narrow the stream, lookup and
21
+ * operation-id range. `key` is not part of that index at all, so it is a residual predicate applied
22
+ * to every document the range scan returns.
23
+ *
24
+ * That scan may therefore have to filter through many keys for the same lookup, but the cost is
25
+ * amortized: a single scan covers up to 1000 keys, and identities seen again in a later batch skip
26
+ * the scan entirely - they are deleted by `_id`.
27
+ *
28
+ * The V3 storage format uses an index more suitable for this.
29
+ */
30
+ protected leadingHistoryDeleteFilter(
31
+ lookup: bson.Binary,
32
+ keys: mongo.Document[],
33
+ before: InternalOpId
34
+ ): mongo.Document {
19
35
  return {
20
- 'key.g': doc.key.g as number,
21
- lookup: doc.lookup,
22
- _id: { $lte: doc._id },
23
- key: doc.key
36
+ 'key.g': this.replicationStreamId,
37
+ lookup,
38
+ key: { $in: keys },
39
+ _id: { $lt: before }
24
40
  };
25
41
  }
26
42
  }
@@ -3,6 +3,8 @@ import { mongo } from '@powersync/lib-service-mongodb';
3
3
  import { ServiceAssertionError } from '@powersync/lib-services-framework';
4
4
  import {
5
5
  CheckpointChanges,
6
+ CompactInitialReplicationOptions,
7
+ CompactInitialReplicationResults,
6
8
  deserializeParameterLookup,
7
9
  GetCheckpointChangesOptions,
8
10
  InternalOpId,
@@ -16,19 +18,30 @@ import {
16
18
  import { JSONBig } from '@powersync/service-jsonbig';
17
19
  import { ParameterLookupRows, ScopedParameterLookup, SqliteJsonRow } from '@powersync/service-sync-rules';
18
20
  import * as bson from 'bson';
19
- import { idPrefixFilter, mapOpEntry, readSingleBatch, setSessionSnapshotTime } from '../../../utils/util.js';
21
+ import {
22
+ clearCollectionInIdBatches,
23
+ clearCollectionInIdRanges,
24
+ idPrefixFilter,
25
+ mapOpEntry,
26
+ readSingleBatch,
27
+ retryOnMongoMaxTimeMSExpired,
28
+ setSessionSnapshotTime
29
+ } from '../../../utils/util.js';
20
30
  import { MongoBucketStorage } from '../../MongoBucketStorage.js';
21
31
  import {
22
- MongoSyncBucketStorageCheckpoint,
23
- MongoSyncBucketStorageContext
24
- } from '../common/MongoSyncBucketStorageContext.js';
32
+ MongoGetCheckpointChangesOptions,
33
+ MongoSyncBucketStorageCheckpoint
34
+ } from '../common/MongoSyncBucketStorageCheckpoint.js';
25
35
  import { SourceKey } from '../models.js';
26
- import { MongoBucketBatchOptions } from '../MongoBucketBatch.js';
27
36
  import { MongoChecksums } from '../MongoChecksums.js';
28
- import { MongoCompactOptions, MongoCompactor } from '../MongoCompactor.js';
37
+ import { MongoCompactOptions } from '../MongoCompactor.js';
29
38
  import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
30
- import { MongoPersistedSyncRulesContentV1 } from '../MongoPersistedSyncRulesContent.js';
31
- import { MongoSyncBucketStorage, MongoSyncBucketStorageOptions } from '../MongoSyncBucketStorage.js';
39
+ import { MongoPersistedReplicationStream } from '../MongoPersistedReplicationStream.js';
40
+ import {
41
+ MongoCheckpointState,
42
+ MongoSyncBucketStorage,
43
+ MongoSyncBucketStorageOptions
44
+ } from '../MongoSyncBucketStorage.js';
32
45
  import {
33
46
  BucketDataDocumentV1,
34
47
  BucketDataKeyV1,
@@ -42,67 +55,91 @@ import { MongoCompactorV1 } from './MongoCompactorV1.js';
42
55
  import { MongoParameterCompactorV1 } from './MongoParameterCompactorV1.js';
43
56
  import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
44
57
 
58
+ export interface MongoSyncBucketStorageContextV1 {
59
+ db: VersionedPowerSyncMongoV1;
60
+ replicationStreamId: number;
61
+ readPreference?: mongo.ReadPreference;
62
+ }
63
+
45
64
  export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
46
- // Declare types to be more specific
47
65
  declare readonly db: VersionedPowerSyncMongoV1;
48
66
  declare readonly checksums: MongoChecksumsV1;
49
67
 
50
68
  constructor(
51
69
  factory: MongoBucketStorage,
52
- group_id: number,
53
- sync_rules: MongoPersistedSyncRulesContentV1,
54
- slot_name: string,
70
+ replicationStreamId: number,
71
+ replicationStream: MongoPersistedReplicationStream,
72
+ replicationStreamName: string,
55
73
  writeCheckpointMode: storage.WriteCheckpointMode | undefined,
56
74
  options: MongoSyncBucketStorageOptions
57
75
  ) {
58
- super(factory, group_id, sync_rules, slot_name, writeCheckpointMode, options);
76
+ super(factory, replicationStreamId, replicationStream, replicationStreamName, writeCheckpointMode, options);
59
77
  }
60
78
 
61
79
  protected async initializeVersionStorage(): Promise<void> {}
62
80
 
63
- protected createWriterImpl(batchOptions: MongoBucketBatchOptions): storage.BucketStorageBatch {
64
- return new MongoBucketBatchV1(batchOptions);
65
- }
66
-
67
- protected async fetchCheckpointState(
68
- session: mongo.ClientSession
69
- ): Promise<{ checkpoint: bigint; lsn: string | null } | null> {
81
+ protected async fetchPersistedOpHead(): Promise<InternalOpId | null> {
70
82
  const doc = (await this.db.sync_rules.findOne(
71
- { _id: this.group_id },
72
- {
73
- session,
74
- projection: { _id: 1, state: 1, last_checkpoint: 1, last_checkpoint_lsn: 1, snapshot_done: 1 }
75
- }
83
+ { _id: this.replicationStreamId },
84
+ { projection: { keepalive_op: 1, last_checkpoint: 1 } }
76
85
  )) as SyncRuleDocumentV1;
77
- if (!doc?.snapshot_done || ![storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED].includes(doc.state)) {
86
+ // keepalive_op covers ops not yet in a checkpoint (cleared once checkpointed),
87
+ // so the head is the max of the two.
88
+ const keepaliveOp = doc?.keepalive_op == null ? null : BigInt(doc.keepalive_op);
89
+ const lastCheckpoint = doc?.last_checkpoint ?? null;
90
+ if (keepaliveOp == null && lastCheckpoint == null) {
78
91
  return null;
79
92
  }
80
- return {
81
- checkpoint: doc.last_checkpoint ?? 0n,
82
- lsn: doc.last_checkpoint_lsn ?? null
83
- };
93
+ return (keepaliveOp ?? 0n) > (lastCheckpoint ?? 0n) ? keepaliveOp : lastCheckpoint;
84
94
  }
85
95
 
86
- protected async getWriterSyncState() {
96
+ protected async createWriterImpl(options: storage.CreateWriterOptions): Promise<storage.BucketStorageBatch> {
87
97
  const doc = (await this.db.sync_rules.findOne(
88
98
  {
89
- _id: this.group_id
99
+ _id: this.replicationStreamId
90
100
  },
91
101
  { projection: { last_checkpoint_lsn: 1, keepalive_op: 1, snapshot_lsn: 1 } }
92
102
  )) as SyncRuleDocumentV1;
93
- const checkpointLsn = doc?.last_checkpoint_lsn ?? null;
103
+
104
+ return new MongoBucketBatchV1({
105
+ ...this.writerBatchOptions(options),
106
+ // Resume from the last consistent checkpoint, or the in-progress snapshot position if it is newer.
107
+ resumeFromLsn: maxLsn(doc?.last_checkpoint_lsn, doc?.snapshot_lsn),
108
+ keepaliveOp: doc?.keepalive_op ? BigInt(doc.keepalive_op) : null
109
+ });
110
+ }
111
+
112
+ protected async fetchCheckpointState(session: mongo.ClientSession): Promise<MongoCheckpointState | null> {
113
+ const doc = (await this.db.sync_rules.findOne(
114
+ { _id: this.replicationStreamId },
115
+ {
116
+ session,
117
+ projection: {
118
+ _id: 1,
119
+ state: 1,
120
+ last_checkpoint: 1,
121
+ last_checkpoint_lsn: 1,
122
+ snapshot_done: 1,
123
+ // Must be read in the same snapshot as the checkpoint.
124
+ 'parameter_compaction.checkpoint_changes_invalid_before': 1
125
+ }
126
+ }
127
+ )) as SyncRuleDocumentV1;
128
+ if (!doc?.snapshot_done || ![storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED].includes(doc.state)) {
129
+ return null;
130
+ }
94
131
  return {
95
- lastCheckpointLsn: checkpointLsn,
96
- resumeFromLsn: maxLsn(checkpointLsn, doc?.snapshot_lsn),
97
- keepaliveOp: doc?.keepalive_op ? BigInt(doc.keepalive_op) : null,
98
- syncConfigId: null
132
+ checkpoint: doc.last_checkpoint ?? 0n,
133
+ lsn: doc.last_checkpoint_lsn ?? null,
134
+ // Defaults to 0n for streams that have never been compacted.
135
+ parameterChangesInvalidBefore: doc.parameter_compaction?.checkpoint_changes_invalid_before ?? 0n
99
136
  };
100
137
  }
101
138
 
102
139
  protected async terminateSyncRuleState(): Promise<void> {
103
140
  await this.db.sync_rules.updateOne(
104
141
  {
105
- _id: this.group_id
142
+ _id: this.replicationStreamId
106
143
  },
107
144
  {
108
145
  $set: {
@@ -114,18 +151,16 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
114
151
  );
115
152
  }
116
153
 
117
- protected async getStatusImpl(): Promise<storage.SyncRuleStatus> {
154
+ protected async getStatusImpl(): Promise<storage.ReplicationStreamStatus> {
118
155
  const doc = (await this.db.sync_rules.findOne(
119
156
  {
120
- _id: this.group_id
157
+ _id: this.replicationStreamId
121
158
  },
122
159
  {
123
160
  projection: {
124
161
  snapshot_done: 1,
125
162
  last_checkpoint_lsn: 1,
126
- state: 1,
127
- snapshot_lsn: 1,
128
- keepalive_op: 1
163
+ snapshot_lsn: 1
129
164
  }
130
165
  }
131
166
  )) as SyncRuleDocumentV1;
@@ -134,18 +169,15 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
134
169
  }
135
170
 
136
171
  return {
137
- snapshot_done: doc.snapshot_done,
138
- snapshot_lsn: doc.snapshot_lsn ?? null,
139
- active: doc.state == storage.SyncRuleState.ACTIVE,
140
- checkpoint_lsn: doc.last_checkpoint_lsn,
141
- keepalive_op: doc.keepalive_op == null ? null : BigInt(doc.keepalive_op)
172
+ snapshotDone: doc.snapshot_done && doc.last_checkpoint_lsn != null,
173
+ resumeLsn: maxLsn(doc.snapshot_lsn, doc.last_checkpoint_lsn)
142
174
  };
143
175
  }
144
176
 
145
177
  protected async clearSyncRuleState(): Promise<void> {
146
178
  await this.db.sync_rules.updateOne(
147
179
  {
148
- _id: this.group_id
180
+ _id: this.replicationStreamId
149
181
  },
150
182
  {
151
183
  $set: {
@@ -156,7 +188,8 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
156
188
  no_checkpoint_before: null
157
189
  },
158
190
  $unset: {
159
- snapshot_lsn: 1
191
+ snapshot_lsn: 1,
192
+ parameter_compaction: 1
160
193
  }
161
194
  },
162
195
  { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
@@ -164,29 +197,50 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
164
197
  }
165
198
 
166
199
  protected createMongoChecksums(options: MongoSyncBucketStorageOptions): MongoChecksums {
167
- return new MongoChecksumsV1(this.db, this.group_id, {
200
+ return new MongoChecksumsV1(this.db, this.replicationStreamId, {
168
201
  ...options.checksumOptions,
169
- storageConfig: options?.storageConfig,
170
- mapping: this.sync_rules.mapping
202
+ checksumCacheTtlMs: options.checksumCacheTtlMs,
203
+ storageConfig: options?.storageConfig
171
204
  });
172
205
  }
173
206
 
174
- createMongoCompactor(options: MongoCompactOptions): MongoCompactor {
207
+ createMongoCompactor(options: MongoCompactOptions): MongoCompactorV1 {
175
208
  return new MongoCompactorV1(this, this.db, options);
176
209
  }
177
210
 
211
+ async compactInitialReplication(
212
+ options: CompactInitialReplicationOptions
213
+ ): Promise<CompactInitialReplicationResults> {
214
+ this.logger.info(`Compacting after initial replication...`);
215
+ const start = Date.now();
216
+ const maxOpId = options.maxOpId ?? (await this.fetchPersistedOpHead()) ?? undefined;
217
+ const compactor = this.createMongoCompactor({
218
+ ...options,
219
+ maxOpId,
220
+ memoryLimitMB: 0,
221
+ logger: this.logger
222
+ });
223
+
224
+ const result = await compactor.populateChecksums({
225
+ minBucketChanges: options.minBucketChanges ?? 10
226
+ });
227
+ const duration = Date.now() - start;
228
+ this.logger.info(`Compacted after initial replication in ${(duration / 1000).toFixed(1)}s`);
229
+ return result;
230
+ }
231
+
178
232
  protected createMongoParameterCompactor(
179
233
  checkpoint: InternalOpId,
180
234
  options: storage.CompactOptions
181
235
  ): MongoParameterCompactor {
182
- return new MongoParameterCompactorV1(this.db, this.group_id, checkpoint, options);
236
+ return new MongoParameterCompactorV1(this.db, this.replicationStreamId, checkpoint, options);
183
237
  }
184
238
 
185
- protected override get versionContext(): MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1> {
239
+ protected get versionContext(): MongoSyncBucketStorageContextV1 {
186
240
  return {
187
241
  db: this.db,
188
- group_id: this.group_id,
189
- mapping: this.mapping
242
+ replicationStreamId: this.replicationStreamId,
243
+ readPreference: this.readPreference
190
244
  };
191
245
  }
192
246
 
@@ -199,7 +253,7 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
199
253
  }
200
254
 
201
255
  protected getBucketDataBatchImpl(
202
- checkpoint: utils.InternalOpId,
256
+ checkpoint: MongoSyncBucketStorageCheckpoint,
203
257
  dataBuckets: storage.BucketDataRequest[],
204
258
  options?: storage.BucketDataBatchOptions
205
259
  ): AsyncIterable<storage.SyncBucketDataChunk> {
@@ -207,72 +261,77 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
207
261
  }
208
262
 
209
263
  protected async clearBucketData(signal?: AbortSignal): Promise<void> {
210
- await this.clearDeleteMany(
264
+ await clearCollectionInIdRanges(
265
+ this.logger,
211
266
  'bucket data',
212
- () =>
213
- this.db.bucket_data.deleteMany(
214
- {
215
- _id: idPrefixFilter<BucketDataKeyV1>({ g: this.group_id }, ['b', 'o'])
216
- },
217
- { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
218
- ),
219
- signal
267
+ this.db.bucket_data,
268
+ {
269
+ _id: idPrefixFilter<BucketDataKeyV1>({ g: this.replicationStreamId }, ['b', 'o'])
270
+ },
271
+ signal,
272
+ this.clearBatchThrottleRate
220
273
  );
221
274
  }
222
275
 
223
276
  protected async clearParameterIndexes(signal?: AbortSignal): Promise<void> {
224
- await this.clearDeleteMany(
277
+ await clearCollectionInIdBatches(
278
+ this.logger,
225
279
  'parameter index',
226
- () =>
227
- this.db.parameterIndexV1.deleteMany(
228
- {
229
- 'key.g': this.group_id
230
- },
231
- { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
232
- ),
233
- signal
280
+ this.db.parameterIndexV1,
281
+ {
282
+ 'key.g': this.replicationStreamId
283
+ },
284
+ signal,
285
+ this.clearBatchThrottleRate
234
286
  );
235
287
  }
236
288
 
237
289
  protected async clearSourceRecords(signal?: AbortSignal): Promise<void> {
238
- await this.clearDeleteMany(
290
+ await clearCollectionInIdRanges(
291
+ this.logger,
239
292
  'source records',
240
- () =>
241
- this.db.sourceRecordsV1.deleteMany(
242
- {
243
- _id: idPrefixFilter<SourceKey>({ g: this.group_id }, ['t', 'k'])
244
- },
245
- { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
246
- ),
247
- signal
293
+ this.db.sourceRecordsV1,
294
+ {
295
+ _id: idPrefixFilter<SourceKey>({ g: this.replicationStreamId }, ['t', 'k'])
296
+ },
297
+ signal,
298
+ this.clearBatchThrottleRate
248
299
  );
249
300
  }
250
301
 
251
302
  protected async clearBucketState(signal?: AbortSignal): Promise<void> {
252
- await this.clearDeleteMany(
303
+ await clearCollectionInIdRanges(
304
+ this.logger,
253
305
  'bucket state',
254
- () =>
255
- this.db.bucketStateV1.deleteMany(
256
- {
257
- _id: idPrefixFilter<BucketStateDocument['_id']>({ g: this.group_id }, ['b'])
258
- },
259
- { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
260
- ),
261
- signal
306
+ this.db.bucketStateV1,
307
+ {
308
+ _id: idPrefixFilter<BucketStateDocument['_id']>({ g: this.replicationStreamId }, ['b'])
309
+ },
310
+ signal,
311
+ this.clearBatchThrottleRate
262
312
  );
263
313
  }
264
314
 
265
315
  protected async clearSourceTables(signal?: AbortSignal): Promise<void> {
266
- await this.clearDeleteMany(
267
- 'source tables',
316
+ await retryOnMongoMaxTimeMSExpired(
268
317
  () =>
269
- this.db.commonSourceTables(this.group_id).deleteMany(
318
+ this.db.sourceTablesV1(this.replicationStreamId).deleteMany(
270
319
  {
271
- group_id: this.group_id
320
+ group_id: this.replicationStreamId
272
321
  },
273
322
  { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
274
323
  ),
275
- signal
324
+ {
325
+ signal,
326
+ abortMessage: 'Aborted clearing data',
327
+ // This is a fairly long delay - only expected to hit this when the storage database is under high load.
328
+ retryDelayMs: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS,
329
+ onRetry: () => {
330
+ this.logger.info(
331
+ `Clearing batch of source tables timed out after ${lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS}ms, retrying...`
332
+ );
333
+ }
334
+ }
276
335
  );
277
336
  }
278
337
 
@@ -283,14 +342,14 @@ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
283
342
  }
284
343
 
285
344
  protected getParameterBucketChangesImpl(
286
- options: GetCheckpointChangesOptions
345
+ options: MongoGetCheckpointChangesOptions
287
346
  ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
288
347
  return getParameterBucketChangesV1(this.versionContext, options);
289
348
  }
290
349
  }
291
350
 
292
351
  export async function getParameterSetsV1(
293
- ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
352
+ ctx: MongoSyncBucketStorageContextV1,
294
353
  checkpoint: MongoSyncBucketStorageCheckpoint,
295
354
  lookups: ScopedParameterLookup[],
296
355
  limit: number
@@ -306,7 +365,7 @@ export async function getParameterSetsV1(
306
365
  [
307
366
  {
308
367
  $match: {
309
- 'key.g': ctx.group_id,
368
+ 'key.g': ctx.replicationStreamId,
310
369
  lookup: { $in: lookupFilter },
311
370
  _id: { $lte: checkpoint.checkpoint }
312
371
  }
@@ -364,31 +423,44 @@ export async function getParameterSetsV1(
364
423
  }
365
424
 
366
425
  export async function* getBucketDataBatchV1(
367
- ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
368
- checkpoint: utils.InternalOpId,
426
+ ctx: MongoSyncBucketStorageContextV1,
427
+ checkpoint: MongoSyncBucketStorageCheckpoint,
369
428
  dataBuckets: storage.BucketDataRequest[],
370
429
  options?: storage.BucketDataBatchOptions
371
430
  ): AsyncIterable<storage.SyncBucketDataChunk> {
372
431
  if (dataBuckets.length == 0) {
373
432
  return;
374
433
  }
434
+ const readPreference = options?.requestHint == 'bulk' ? ctx.readPreference : undefined;
435
+ const readConcern = ctx.readPreference == null ? undefined : 'majority';
436
+ const session =
437
+ readPreference == null || checkpoint.snapshotTime == null
438
+ ? undefined
439
+ : ctx.db.client.startSession({ causalConsistency: true });
440
+ await using _ = { [Symbol.asyncDispose]: async () => session?.endSession() };
441
+
442
+ if (session != null) {
443
+ session.advanceOperationTime(checkpoint.snapshotTime);
444
+ session.advanceClusterTime(checkpoint.clusterTime);
445
+ }
446
+
375
447
  let filters: mongo.Filter<BucketDataDocumentV1>[] = [];
376
448
  const bucketMap = new Map(dataBuckets.map((request) => [request.bucket, request.start]));
377
449
 
378
- if (checkpoint == null) {
450
+ if (checkpoint.checkpoint == null) {
379
451
  throw new Error('checkpoint is null');
380
452
  }
381
- const end = checkpoint;
453
+ const end = checkpoint.checkpoint;
382
454
  for (let { bucket: name, start } of dataBuckets) {
383
455
  filters.push({
384
456
  _id: {
385
457
  $gt: {
386
- g: ctx.group_id,
458
+ g: ctx.replicationStreamId,
387
459
  b: name,
388
460
  o: start
389
461
  },
390
462
  $lte: {
391
- g: ctx.group_id,
463
+ g: ctx.replicationStreamId,
392
464
  b: name,
393
465
  o: end as any
394
466
  }
@@ -399,12 +471,16 @@ export async function* getBucketDataBatchV1(
399
471
  const batchLimit = options?.limit ?? storage.DEFAULT_DOCUMENT_BATCH_LIMIT;
400
472
  const chunkSizeLimitBytes = options?.chunkLimitBytes ?? storage.DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES;
401
473
 
474
+ // raw: true returns Buffers, but the driver typing doesn't reflect that
475
+ // without an explicit cast to FindCursor<Buffer>.
402
476
  const cursor = ctx.db.bucket_data.find(
403
477
  {
404
478
  $or: filters
405
479
  },
406
480
  {
407
- session: undefined,
481
+ session,
482
+ readPreference,
483
+ readConcern,
408
484
  sort: { _id: 1 },
409
485
  limit: batchLimit,
410
486
  batchSize: batchLimit + 1,
@@ -481,14 +557,14 @@ export async function* getBucketDataBatchV1(
481
557
  }
482
558
 
483
559
  export async function getDataBucketChangesV1(
484
- ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
560
+ ctx: MongoSyncBucketStorageContextV1,
485
561
  options: GetCheckpointChangesOptions
486
562
  ): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
487
563
  const limit = 1000;
488
564
  const bucketStateUpdates = await ctx.db.bucketStateV1
489
565
  .find(
490
566
  {
491
- '_id.g': ctx.group_id,
567
+ '_id.g': ctx.replicationStreamId,
492
568
  last_op: { $gt: options.lastCheckpoint.checkpoint }
493
569
  },
494
570
  {
@@ -511,27 +587,48 @@ export async function getDataBucketChangesV1(
511
587
  };
512
588
  }
513
589
 
590
+ /**
591
+ * Query the parameter entries changed between the two checkpoints, to determine which parameter
592
+ * lookups need to be re-evaluated.
593
+ *
594
+ * This runs at the next checkpoint's snapshot, so it still sees entries that parameter compaction
595
+ * deleted after that snapshot. Compaction that deleted entries before the snapshot is covered by
596
+ * the invalidation fence, checked before we get here.
597
+ */
514
598
  export async function getParameterBucketChangesV1(
515
- ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
516
- options: GetCheckpointChangesOptions
599
+ ctx: MongoSyncBucketStorageContextV1,
600
+ options: MongoGetCheckpointChangesOptions
517
601
  ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
518
602
  const limit = 1000;
519
- const parameterUpdates = await ctx.db.parameterIndexV1
520
- .find(
521
- {
522
- _id: { $gt: options.lastCheckpoint.checkpoint, $lte: options.nextCheckpoint.checkpoint },
523
- 'key.g': ctx.group_id
524
- },
525
- {
526
- projection: {
527
- lookup: 1
603
+ const parameterUpdates = await ctx.db.client.withSession({ snapshot: true }, async (session) => {
604
+ setSessionSnapshotTime(session, options.nextCheckpoint.snapshotTime);
605
+ return await ctx.db.parameterIndexV1
606
+ .find(
607
+ {
608
+ _id: { $gt: options.lastCheckpoint.checkpoint, $lte: options.nextCheckpoint.checkpoint },
609
+ 'key.g': ctx.replicationStreamId
528
610
  },
529
- limit: limit + 1,
530
- batchSize: limit + 2,
531
- singleBatch: true
532
- }
533
- )
534
- .toArray();
611
+ {
612
+ session,
613
+ readConcern: 'snapshot',
614
+ projection: {
615
+ lookup: 1
616
+ },
617
+ limit: limit + 1,
618
+ batchSize: limit + 2,
619
+ singleBatch: true
620
+ }
621
+ )
622
+ .toArray()
623
+ .catch((e) => {
624
+ // Includes the case where the checkpoint snapshot has expired. Degrading to
625
+ // invalidateParameterBuckets would be safe in itself - it reads nothing - but it gains
626
+ // nothing: the caller responds to that by re-evaluating the parameter queries at this
627
+ // same snapshot, which fails too. The checkpoint has to be refetched instead, which is
628
+ // what the existing sync retry behavior does.
629
+ throw lib_mongo.mapQueryError(e, 'while querying parameter changes');
630
+ });
631
+ });
535
632
  const invalidateParameterUpdates = parameterUpdates.length > limit;
536
633
 
537
634
  return {