@fluidframework/container-runtime 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191258

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 (526) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/README.md +4 -3
  3. package/dist/batchTracker.d.ts +3 -2
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js +6 -5
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +10 -16
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +184 -172
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +25 -16
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +161 -35
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +697 -449
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.d.ts.map +1 -1
  19. package/dist/dataStore.js +15 -7
  20. package/dist/dataStore.js.map +1 -1
  21. package/dist/dataStoreContext.d.ts +3 -2
  22. package/dist/dataStoreContext.d.ts.map +1 -1
  23. package/dist/dataStoreContext.js +83 -87
  24. package/dist/dataStoreContext.js.map +1 -1
  25. package/dist/dataStoreContexts.d.ts +1 -2
  26. package/dist/dataStoreContexts.d.ts.map +1 -1
  27. package/dist/dataStoreContexts.js +8 -9
  28. package/dist/dataStoreContexts.js.map +1 -1
  29. package/dist/dataStoreRegistry.js +2 -2
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.d.ts +22 -6
  32. package/dist/dataStores.d.ts.map +1 -1
  33. package/dist/dataStores.js +123 -81
  34. package/dist/dataStores.js.map +1 -1
  35. package/dist/deltaManagerProxyBase.d.ts +35 -0
  36. package/dist/deltaManagerProxyBase.d.ts.map +1 -0
  37. package/dist/deltaManagerProxyBase.js +77 -0
  38. package/dist/deltaManagerProxyBase.js.map +1 -0
  39. package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
  40. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  41. package/dist/deltaManagerSummarizerProxy.js +4 -2
  42. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  43. package/dist/deltaScheduler.d.ts.map +1 -1
  44. package/dist/deltaScheduler.js +10 -10
  45. package/dist/deltaScheduler.js.map +1 -1
  46. package/dist/error.d.ts +14 -0
  47. package/dist/error.d.ts.map +1 -0
  48. package/dist/error.js +21 -0
  49. package/dist/error.js.map +1 -0
  50. package/dist/gc/garbageCollection.d.ts +10 -9
  51. package/dist/gc/garbageCollection.d.ts.map +1 -1
  52. package/dist/gc/garbageCollection.js +61 -53
  53. package/dist/gc/garbageCollection.js.map +1 -1
  54. package/dist/gc/gcConfigs.d.ts.map +1 -1
  55. package/dist/gc/gcConfigs.js +18 -14
  56. package/dist/gc/gcConfigs.js.map +1 -1
  57. package/dist/gc/gcDefinitions.d.ts +17 -4
  58. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  59. package/dist/gc/gcDefinitions.js +14 -15
  60. package/dist/gc/gcDefinitions.js.map +1 -1
  61. package/dist/gc/gcHelpers.d.ts +0 -8
  62. package/dist/gc/gcHelpers.d.ts.map +1 -1
  63. package/dist/gc/gcHelpers.js +11 -24
  64. package/dist/gc/gcHelpers.js.map +1 -1
  65. package/dist/gc/gcSummaryStateTracker.d.ts +4 -7
  66. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  67. package/dist/gc/gcSummaryStateTracker.js +19 -58
  68. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  69. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  70. package/dist/gc/gcTelemetry.js +45 -35
  71. package/dist/gc/gcTelemetry.js.map +1 -1
  72. package/dist/gc/gcUnreferencedStateTracker.js +4 -4
  73. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  74. package/dist/gc/index.d.ts +2 -2
  75. package/dist/gc/index.d.ts.map +1 -1
  76. package/dist/gc/index.js +3 -5
  77. package/dist/gc/index.js.map +1 -1
  78. package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
  79. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  80. package/dist/id-compressor/appendOnlySortedMap.js +26 -68
  81. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  82. package/dist/id-compressor/finalSpace.d.ts +29 -0
  83. package/dist/id-compressor/finalSpace.d.ts.map +1 -0
  84. package/dist/id-compressor/finalSpace.js +62 -0
  85. package/dist/id-compressor/finalSpace.js.map +1 -0
  86. package/dist/id-compressor/idCompressor.d.ts +25 -250
  87. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  88. package/dist/id-compressor/idCompressor.js +390 -1153
  89. package/dist/id-compressor/idCompressor.js.map +1 -1
  90. package/dist/id-compressor/identifiers.d.ts +32 -0
  91. package/dist/id-compressor/identifiers.d.ts.map +1 -0
  92. package/dist/id-compressor/identifiers.js +15 -0
  93. package/dist/id-compressor/identifiers.js.map +1 -0
  94. package/dist/id-compressor/index.d.ts +5 -6
  95. package/dist/id-compressor/index.d.ts.map +1 -1
  96. package/dist/id-compressor/index.js +20 -26
  97. package/dist/id-compressor/index.js.map +1 -1
  98. package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
  99. package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
  100. package/dist/id-compressor/persistanceUtilities.js +43 -0
  101. package/dist/id-compressor/persistanceUtilities.js.map +1 -0
  102. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  103. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  104. package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
  105. package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  106. package/dist/id-compressor/sessions.d.ts +115 -0
  107. package/dist/id-compressor/sessions.d.ts.map +1 -0
  108. package/dist/id-compressor/sessions.js +305 -0
  109. package/dist/id-compressor/sessions.js.map +1 -0
  110. package/dist/id-compressor/utilities.d.ts +49 -0
  111. package/dist/id-compressor/utilities.d.ts.map +1 -0
  112. package/dist/id-compressor/utilities.js +166 -0
  113. package/dist/id-compressor/utilities.js.map +1 -0
  114. package/dist/index.d.ts +3 -3
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +6 -4
  117. package/dist/index.js.map +1 -1
  118. package/dist/opLifecycle/batchManager.js +10 -6
  119. package/dist/opLifecycle/batchManager.js.map +1 -1
  120. package/dist/opLifecycle/opCompressor.d.ts +2 -2
  121. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  122. package/dist/opLifecycle/opCompressor.js +12 -7
  123. package/dist/opLifecycle/opCompressor.js.map +1 -1
  124. package/dist/opLifecycle/opDecompressor.d.ts +2 -2
  125. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  126. package/dist/opLifecycle/opDecompressor.js +23 -20
  127. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  128. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  129. package/dist/opLifecycle/opGroupingManager.js +19 -9
  130. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  131. package/dist/opLifecycle/opSplitter.d.ts +2 -2
  132. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  133. package/dist/opLifecycle/opSplitter.js +22 -19
  134. package/dist/opLifecycle/opSplitter.js.map +1 -1
  135. package/dist/opLifecycle/outbox.d.ts +7 -5
  136. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  137. package/dist/opLifecycle/outbox.js +22 -31
  138. package/dist/opLifecycle/outbox.js.map +1 -1
  139. package/dist/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  140. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  141. package/dist/opLifecycle/remoteMessageProcessor.js +19 -7
  142. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  143. package/dist/opProperties.js +1 -2
  144. package/dist/opProperties.js.map +1 -1
  145. package/dist/packageVersion.d.ts +1 -1
  146. package/dist/packageVersion.js +1 -1
  147. package/dist/packageVersion.js.map +1 -1
  148. package/dist/pendingStateManager.d.ts +18 -8
  149. package/dist/pendingStateManager.d.ts.map +1 -1
  150. package/dist/pendingStateManager.js +73 -51
  151. package/dist/pendingStateManager.js.map +1 -1
  152. package/dist/scheduleManager.d.ts.map +1 -1
  153. package/dist/scheduleManager.js +36 -32
  154. package/dist/scheduleManager.js.map +1 -1
  155. package/dist/summary/index.d.ts +3 -3
  156. package/dist/summary/index.d.ts.map +1 -1
  157. package/dist/summary/index.js +2 -1
  158. package/dist/summary/index.js.map +1 -1
  159. package/dist/summary/orderedClientElection.d.ts +3 -3
  160. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  161. package/dist/summary/orderedClientElection.js +26 -27
  162. package/dist/summary/orderedClientElection.js.map +1 -1
  163. package/dist/summary/runWhileConnectedCoordinator.js +3 -3
  164. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  165. package/dist/summary/runningSummarizer.d.ts +31 -10
  166. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  167. package/dist/summary/runningSummarizer.js +271 -139
  168. package/dist/summary/runningSummarizer.js.map +1 -1
  169. package/dist/summary/summarizer.d.ts +8 -7
  170. package/dist/summary/summarizer.d.ts.map +1 -1
  171. package/dist/summary/summarizer.js +79 -78
  172. package/dist/summary/summarizer.js.map +1 -1
  173. package/dist/summary/summarizerClientElection.d.ts +2 -2
  174. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  175. package/dist/summary/summarizerClientElection.js +7 -11
  176. package/dist/summary/summarizerClientElection.js.map +1 -1
  177. package/dist/summary/summarizerHeuristics.js +10 -14
  178. package/dist/summary/summarizerHeuristics.js.map +1 -1
  179. package/dist/summary/summarizerNode/index.d.ts +1 -1
  180. package/dist/summary/summarizerNode/index.d.ts.map +1 -1
  181. package/dist/summary/summarizerNode/index.js.map +1 -1
  182. package/dist/summary/summarizerNode/summarizerNode.d.ts +10 -19
  183. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  184. package/dist/summary/summarizerNode/summarizerNode.js +57 -130
  185. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  186. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  187. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  188. package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  189. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  190. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -14
  191. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  192. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +15 -101
  193. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  194. package/dist/summary/summarizerTypes.d.ts +38 -25
  195. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  196. package/dist/summary/summarizerTypes.js.map +1 -1
  197. package/dist/summary/summaryCollection.d.ts +2 -3
  198. package/dist/summary/summaryCollection.d.ts.map +1 -1
  199. package/dist/summary/summaryCollection.js +12 -13
  200. package/dist/summary/summaryCollection.js.map +1 -1
  201. package/dist/summary/summaryFormat.d.ts +3 -0
  202. package/dist/summary/summaryFormat.d.ts.map +1 -1
  203. package/dist/summary/summaryFormat.js +6 -4
  204. package/dist/summary/summaryFormat.js.map +1 -1
  205. package/dist/summary/summaryGenerator.d.ts +10 -4
  206. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  207. package/dist/summary/summaryGenerator.js +106 -57
  208. package/dist/summary/summaryGenerator.js.map +1 -1
  209. package/dist/summary/summaryManager.d.ts +8 -8
  210. package/dist/summary/summaryManager.d.ts.map +1 -1
  211. package/dist/summary/summaryManager.js +38 -28
  212. package/dist/summary/summaryManager.js.map +1 -1
  213. package/lib/batchTracker.d.ts +3 -2
  214. package/lib/batchTracker.d.ts.map +1 -1
  215. package/lib/batchTracker.js +5 -4
  216. package/lib/batchTracker.js.map +1 -1
  217. package/lib/blobManager.d.ts +10 -16
  218. package/lib/blobManager.d.ts.map +1 -1
  219. package/lib/blobManager.js +159 -147
  220. package/lib/blobManager.js.map +1 -1
  221. package/lib/connectionTelemetry.d.ts.map +1 -1
  222. package/lib/connectionTelemetry.js +15 -6
  223. package/lib/connectionTelemetry.js.map +1 -1
  224. package/lib/containerRuntime.d.ts +161 -35
  225. package/lib/containerRuntime.d.ts.map +1 -1
  226. package/lib/containerRuntime.js +651 -402
  227. package/lib/containerRuntime.js.map +1 -1
  228. package/lib/dataStore.d.ts.map +1 -1
  229. package/lib/dataStore.js +13 -5
  230. package/lib/dataStore.js.map +1 -1
  231. package/lib/dataStoreContext.d.ts +3 -2
  232. package/lib/dataStoreContext.d.ts.map +1 -1
  233. package/lib/dataStoreContext.js +47 -51
  234. package/lib/dataStoreContext.js.map +1 -1
  235. package/lib/dataStoreContexts.d.ts +1 -2
  236. package/lib/dataStoreContexts.d.ts.map +1 -1
  237. package/lib/dataStoreContexts.js +3 -4
  238. package/lib/dataStoreContexts.js.map +1 -1
  239. package/lib/dataStoreRegistry.js +1 -1
  240. package/lib/dataStoreRegistry.js.map +1 -1
  241. package/lib/dataStores.d.ts +22 -6
  242. package/lib/dataStores.d.ts.map +1 -1
  243. package/lib/dataStores.js +107 -65
  244. package/lib/dataStores.js.map +1 -1
  245. package/lib/deltaManagerProxyBase.d.ts +35 -0
  246. package/lib/deltaManagerProxyBase.d.ts.map +1 -0
  247. package/lib/deltaManagerProxyBase.js +73 -0
  248. package/lib/deltaManagerProxyBase.js.map +1 -0
  249. package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
  250. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  251. package/lib/deltaManagerSummarizerProxy.js +3 -1
  252. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  253. package/lib/deltaScheduler.d.ts.map +1 -1
  254. package/lib/deltaScheduler.js +7 -7
  255. package/lib/deltaScheduler.js.map +1 -1
  256. package/lib/error.d.ts +14 -0
  257. package/lib/error.d.ts.map +1 -0
  258. package/lib/error.js +17 -0
  259. package/lib/error.js.map +1 -0
  260. package/lib/gc/garbageCollection.d.ts +10 -9
  261. package/lib/gc/garbageCollection.d.ts.map +1 -1
  262. package/lib/gc/garbageCollection.js +61 -53
  263. package/lib/gc/garbageCollection.js.map +1 -1
  264. package/lib/gc/gcConfigs.d.ts.map +1 -1
  265. package/lib/gc/gcConfigs.js +16 -12
  266. package/lib/gc/gcConfigs.js.map +1 -1
  267. package/lib/gc/gcDefinitions.d.ts +17 -4
  268. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  269. package/lib/gc/gcDefinitions.js +13 -14
  270. package/lib/gc/gcDefinitions.js.map +1 -1
  271. package/lib/gc/gcHelpers.d.ts +0 -8
  272. package/lib/gc/gcHelpers.d.ts.map +1 -1
  273. package/lib/gc/gcHelpers.js +5 -17
  274. package/lib/gc/gcHelpers.js.map +1 -1
  275. package/lib/gc/gcSummaryStateTracker.d.ts +4 -7
  276. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  277. package/lib/gc/gcSummaryStateTracker.js +20 -59
  278. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  279. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  280. package/lib/gc/gcTelemetry.js +46 -36
  281. package/lib/gc/gcTelemetry.js.map +1 -1
  282. package/lib/gc/gcUnreferencedStateTracker.js +1 -1
  283. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  284. package/lib/gc/index.d.ts +2 -2
  285. package/lib/gc/index.d.ts.map +1 -1
  286. package/lib/gc/index.js +2 -2
  287. package/lib/gc/index.js.map +1 -1
  288. package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
  289. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  290. package/lib/id-compressor/appendOnlySortedMap.js +25 -66
  291. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  292. package/lib/id-compressor/finalSpace.d.ts +29 -0
  293. package/lib/id-compressor/finalSpace.d.ts.map +1 -0
  294. package/lib/id-compressor/finalSpace.js +58 -0
  295. package/lib/id-compressor/finalSpace.js.map +1 -0
  296. package/lib/id-compressor/idCompressor.d.ts +25 -250
  297. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  298. package/lib/id-compressor/idCompressor.js +385 -1142
  299. package/lib/id-compressor/idCompressor.js.map +1 -1
  300. package/lib/id-compressor/identifiers.d.ts +32 -0
  301. package/lib/id-compressor/identifiers.d.ts.map +1 -0
  302. package/lib/id-compressor/identifiers.js +11 -0
  303. package/lib/id-compressor/identifiers.js.map +1 -0
  304. package/lib/id-compressor/index.d.ts +5 -6
  305. package/lib/id-compressor/index.d.ts.map +1 -1
  306. package/lib/id-compressor/index.js +5 -6
  307. package/lib/id-compressor/index.js.map +1 -1
  308. package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
  309. package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
  310. package/lib/id-compressor/persistanceUtilities.js +34 -0
  311. package/lib/id-compressor/persistanceUtilities.js.map +1 -0
  312. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  313. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  314. package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
  315. package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  316. package/lib/id-compressor/sessions.d.ts +115 -0
  317. package/lib/id-compressor/sessions.d.ts.map +1 -0
  318. package/lib/id-compressor/sessions.js +290 -0
  319. package/lib/id-compressor/sessions.js.map +1 -0
  320. package/lib/id-compressor/utilities.d.ts +49 -0
  321. package/lib/id-compressor/utilities.d.ts.map +1 -0
  322. package/lib/id-compressor/utilities.js +148 -0
  323. package/lib/id-compressor/utilities.js.map +1 -0
  324. package/lib/index.d.ts +3 -3
  325. package/lib/index.d.ts.map +1 -1
  326. package/lib/index.js +2 -2
  327. package/lib/index.js.map +1 -1
  328. package/lib/opLifecycle/batchManager.js +10 -6
  329. package/lib/opLifecycle/batchManager.js.map +1 -1
  330. package/lib/opLifecycle/opCompressor.d.ts +2 -2
  331. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  332. package/lib/opLifecycle/opCompressor.js +10 -5
  333. package/lib/opLifecycle/opCompressor.js.map +1 -1
  334. package/lib/opLifecycle/opDecompressor.d.ts +2 -2
  335. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  336. package/lib/opLifecycle/opDecompressor.js +15 -12
  337. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  338. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  339. package/lib/opLifecycle/opGroupingManager.js +17 -7
  340. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  341. package/lib/opLifecycle/opSplitter.d.ts +2 -2
  342. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  343. package/lib/opLifecycle/opSplitter.js +13 -10
  344. package/lib/opLifecycle/opSplitter.js.map +1 -1
  345. package/lib/opLifecycle/outbox.d.ts +7 -5
  346. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  347. package/lib/opLifecycle/outbox.js +13 -22
  348. package/lib/opLifecycle/outbox.js.map +1 -1
  349. package/lib/opLifecycle/remoteMessageProcessor.d.ts +6 -1
  350. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  351. package/lib/opLifecycle/remoteMessageProcessor.js +20 -8
  352. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  353. package/lib/opProperties.js +1 -2
  354. package/lib/opProperties.js.map +1 -1
  355. package/lib/packageVersion.d.ts +1 -1
  356. package/lib/packageVersion.js +1 -1
  357. package/lib/packageVersion.js.map +1 -1
  358. package/lib/pendingStateManager.d.ts +18 -8
  359. package/lib/pendingStateManager.d.ts.map +1 -1
  360. package/lib/pendingStateManager.js +62 -40
  361. package/lib/pendingStateManager.js.map +1 -1
  362. package/lib/scheduleManager.d.ts.map +1 -1
  363. package/lib/scheduleManager.js +18 -14
  364. package/lib/scheduleManager.js.map +1 -1
  365. package/lib/summary/index.d.ts +3 -3
  366. package/lib/summary/index.d.ts.map +1 -1
  367. package/lib/summary/index.js +1 -1
  368. package/lib/summary/index.js.map +1 -1
  369. package/lib/summary/orderedClientElection.d.ts +3 -3
  370. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  371. package/lib/summary/orderedClientElection.js +21 -22
  372. package/lib/summary/orderedClientElection.js.map +1 -1
  373. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  374. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  375. package/lib/summary/runningSummarizer.d.ts +31 -10
  376. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  377. package/lib/summary/runningSummarizer.js +265 -133
  378. package/lib/summary/runningSummarizer.js.map +1 -1
  379. package/lib/summary/summarizer.d.ts +8 -7
  380. package/lib/summary/summarizer.d.ts.map +1 -1
  381. package/lib/summary/summarizer.js +75 -74
  382. package/lib/summary/summarizer.js.map +1 -1
  383. package/lib/summary/summarizerClientElection.d.ts +2 -2
  384. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  385. package/lib/summary/summarizerClientElection.js +6 -10
  386. package/lib/summary/summarizerClientElection.js.map +1 -1
  387. package/lib/summary/summarizerHeuristics.js +9 -13
  388. package/lib/summary/summarizerHeuristics.js.map +1 -1
  389. package/lib/summary/summarizerNode/index.d.ts +1 -1
  390. package/lib/summary/summarizerNode/index.d.ts.map +1 -1
  391. package/lib/summary/summarizerNode/index.js.map +1 -1
  392. package/lib/summary/summarizerNode/summarizerNode.d.ts +10 -19
  393. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  394. package/lib/summary/summarizerNode/summarizerNode.js +42 -115
  395. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  396. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  397. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  398. package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
  399. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  400. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -14
  401. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  402. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +14 -100
  403. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  404. package/lib/summary/summarizerTypes.d.ts +38 -25
  405. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  406. package/lib/summary/summarizerTypes.js.map +1 -1
  407. package/lib/summary/summaryCollection.d.ts +2 -3
  408. package/lib/summary/summaryCollection.d.ts.map +1 -1
  409. package/lib/summary/summaryCollection.js +5 -6
  410. package/lib/summary/summaryCollection.js.map +1 -1
  411. package/lib/summary/summaryFormat.d.ts +3 -0
  412. package/lib/summary/summaryFormat.d.ts.map +1 -1
  413. package/lib/summary/summaryFormat.js +5 -3
  414. package/lib/summary/summaryFormat.js.map +1 -1
  415. package/lib/summary/summaryGenerator.d.ts +10 -4
  416. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  417. package/lib/summary/summaryGenerator.js +100 -51
  418. package/lib/summary/summaryGenerator.js.map +1 -1
  419. package/lib/summary/summaryManager.d.ts +8 -8
  420. package/lib/summary/summaryManager.d.ts.map +1 -1
  421. package/lib/summary/summaryManager.js +35 -25
  422. package/lib/summary/summaryManager.js.map +1 -1
  423. package/package.json +28 -31
  424. package/src/batchTracker.ts +7 -5
  425. package/src/blobManager.ts +188 -166
  426. package/src/connectionTelemetry.ts +9 -4
  427. package/src/containerRuntime.ts +806 -441
  428. package/src/dataStore.ts +12 -4
  429. package/src/dataStoreContext.ts +39 -43
  430. package/src/dataStoreContexts.ts +4 -6
  431. package/src/dataStoreRegistry.ts +1 -1
  432. package/src/dataStores.ts +114 -80
  433. package/src/deltaManagerProxyBase.ts +111 -0
  434. package/src/deltaManagerSummarizerProxy.ts +4 -1
  435. package/src/deltaScheduler.ts +7 -11
  436. package/src/error.ts +18 -0
  437. package/src/gc/garbageCollection.md +53 -5
  438. package/src/gc/garbageCollection.ts +58 -52
  439. package/src/gc/gcConfigs.ts +4 -2
  440. package/src/gc/gcDefinitions.ts +17 -20
  441. package/src/gc/gcEarlyAdoption.md +145 -0
  442. package/src/gc/gcHelpers.ts +1 -12
  443. package/src/gc/gcSummaryStateTracker.ts +19 -65
  444. package/src/gc/gcTelemetry.ts +14 -12
  445. package/src/gc/gcUnreferencedStateTracker.ts +1 -1
  446. package/src/gc/index.ts +2 -4
  447. package/src/id-compressor/appendOnlySortedMap.ts +26 -87
  448. package/src/id-compressor/finalSpace.ts +67 -0
  449. package/src/id-compressor/idCompressor.ts +458 -1682
  450. package/src/id-compressor/identifiers.ts +42 -0
  451. package/src/id-compressor/index.ts +11 -20
  452. package/src/id-compressor/persistanceUtilities.ts +58 -0
  453. package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
  454. package/src/id-compressor/sessions.ts +405 -0
  455. package/src/id-compressor/utilities.ts +187 -0
  456. package/src/index.ts +7 -2
  457. package/src/opLifecycle/opCompressor.ts +6 -5
  458. package/src/opLifecycle/opDecompressor.ts +6 -4
  459. package/src/opLifecycle/opGroupingManager.ts +9 -6
  460. package/src/opLifecycle/opSplitter.ts +7 -6
  461. package/src/opLifecycle/outbox.ts +23 -32
  462. package/src/opLifecycle/remoteMessageProcessor.ts +27 -8
  463. package/src/packageVersion.ts +1 -1
  464. package/src/pendingStateManager.ts +72 -42
  465. package/src/scheduleManager.ts +7 -5
  466. package/src/summary/index.ts +4 -3
  467. package/src/summary/orderedClientElection.ts +10 -6
  468. package/src/summary/runWhileConnectedCoordinator.ts +1 -1
  469. package/src/summary/runningSummarizer.ts +291 -163
  470. package/src/summary/summarizer.ts +27 -16
  471. package/src/summary/summarizerClientElection.ts +2 -2
  472. package/src/summary/summarizerHeuristics.ts +1 -1
  473. package/src/summary/summarizerNode/index.ts +1 -2
  474. package/src/summary/summarizerNode/summarizerNode.ts +36 -160
  475. package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -38
  476. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +11 -130
  477. package/src/summary/summarizerTypes.ts +40 -25
  478. package/src/summary/summaryCollection.ts +3 -3
  479. package/src/summary/summaryFormat.ts +4 -1
  480. package/src/summary/summaryGenerator.ts +52 -52
  481. package/src/summary/summaryManager.ts +44 -17
  482. package/dist/id-compressor/idRange.d.ts +0 -11
  483. package/dist/id-compressor/idRange.d.ts.map +0 -1
  484. package/dist/id-compressor/idRange.js +0 -29
  485. package/dist/id-compressor/idRange.js.map +0 -1
  486. package/dist/id-compressor/numericUuid.d.ts +0 -59
  487. package/dist/id-compressor/numericUuid.d.ts.map +0 -1
  488. package/dist/id-compressor/numericUuid.js +0 -325
  489. package/dist/id-compressor/numericUuid.js.map +0 -1
  490. package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
  491. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  492. package/dist/id-compressor/sessionIdNormalizer.js +0 -488
  493. package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
  494. package/dist/id-compressor/utils.d.ts +0 -57
  495. package/dist/id-compressor/utils.d.ts.map +0 -1
  496. package/dist/id-compressor/utils.js +0 -90
  497. package/dist/id-compressor/utils.js.map +0 -1
  498. package/dist/id-compressor/uuidUtilities.d.ts +0 -28
  499. package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
  500. package/dist/id-compressor/uuidUtilities.js +0 -104
  501. package/dist/id-compressor/uuidUtilities.js.map +0 -1
  502. package/lib/id-compressor/idRange.d.ts +0 -11
  503. package/lib/id-compressor/idRange.d.ts.map +0 -1
  504. package/lib/id-compressor/idRange.js +0 -25
  505. package/lib/id-compressor/idRange.js.map +0 -1
  506. package/lib/id-compressor/numericUuid.d.ts +0 -59
  507. package/lib/id-compressor/numericUuid.d.ts.map +0 -1
  508. package/lib/id-compressor/numericUuid.js +0 -315
  509. package/lib/id-compressor/numericUuid.js.map +0 -1
  510. package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
  511. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  512. package/lib/id-compressor/sessionIdNormalizer.js +0 -484
  513. package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
  514. package/lib/id-compressor/utils.d.ts +0 -57
  515. package/lib/id-compressor/utils.d.ts.map +0 -1
  516. package/lib/id-compressor/utils.js +0 -79
  517. package/lib/id-compressor/utils.js.map +0 -1
  518. package/lib/id-compressor/uuidUtilities.d.ts +0 -28
  519. package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
  520. package/lib/id-compressor/uuidUtilities.js +0 -96
  521. package/lib/id-compressor/uuidUtilities.js.map +0 -1
  522. package/src/id-compressor/idRange.ts +0 -35
  523. package/src/id-compressor/numericUuid.ts +0 -383
  524. package/src/id-compressor/sessionIdNormalizer.ts +0 -609
  525. package/src/id-compressor/utils.ts +0 -114
  526. package/src/id-compressor/uuidUtilities.ts +0 -120
@@ -3,110 +3,81 @@
3
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
4
  * Licensed under the MIT License.
5
5
  */
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
6
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.hasOngoingSession = exports.IdCompressor = exports.isLocalId = exports.isFinalId = exports.defaultClusterCapacity = void 0;
11
- const common_utils_1 = require("@fluidframework/common-utils");
12
- const sorted_btree_1 = __importDefault(require("sorted-btree"));
13
- const utils_1 = require("./utils");
14
- const uuidUtilities_1 = require("./uuidUtilities");
15
- const appendOnlySortedMap_1 = require("./appendOnlySortedMap");
16
- const idRange_1 = require("./idRange");
17
- const numericUuid_1 = require("./numericUuid");
18
- const sessionIdNormalizer_1 = require("./sessionIdNormalizer");
7
+ exports.IdCompressor = void 0;
8
+ const core_utils_1 = require("@fluidframework/core-utils");
9
+ const client_utils_1 = require("@fluid-internal/client-utils");
10
+ const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
11
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
12
+ const identifiers_1 = require("./identifiers");
13
+ const utilities_1 = require("./utilities");
14
+ const persistanceUtilities_1 = require("./persistanceUtilities");
15
+ const sessions_1 = require("./sessions");
16
+ const sessionSpaceNormalizer_1 = require("./sessionSpaceNormalizer");
17
+ const finalSpace_1 = require("./finalSpace");
19
18
  /**
20
- * Roughly equates to a minimum of 1M sessions before we start allocating 64 bit IDs.
21
- * This value must *NOT* change without careful consideration to compatibility.
19
+ * The version of IdCompressor that is currently persisted.
20
+ * This should not be changed without careful consideration to compatibility.
22
21
  */
23
- exports.defaultClusterCapacity = 512;
22
+ const currentWrittenVersion = 1;
24
23
  /**
25
- * The base UUID for the reserved id cluster.
26
- * This should not be changed without consideration to compatibility.
27
- */
28
- const reservedSessionId = (0, numericUuid_1.ensureSessionUuid)((0, uuidUtilities_1.assertIsStableId)("decaf40b-3c1a-47f8-a7a1-e8461ddb69ce"));
29
- /**
30
- * @returns true if the supplied ID is a final ID.
31
- */
32
- function isFinalId(id) {
33
- return id >= 0;
34
- }
35
- exports.isFinalId = isFinalId;
36
- /**
37
- * @returns true if the supplied ID is a local ID.
38
- */
39
- function isLocalId(id) {
40
- return id < 0;
41
- }
42
- exports.isLocalId = isLocalId;
43
- /** Prepended to all keys in {@link IdCompressor.clustersAndOverridesInversion} that are override strings and not valid `StableIds` */
44
- const nonStableOverridePrefix = "\ue15e"; // A character in the Private Use Area of the BMP (https://en.wikipedia.org/wiki/Private_Use_Areas)
45
- /**
46
- * See {@link IIdCompressor}
24
+ * See {@link IIdCompressor} and {@link IIdCompressorCore}
47
25
  */
48
26
  class IdCompressor {
49
- /**
50
- * @param localSessionId - the `IdCompressor`'s current local session ID.
51
- * {@link generateStableId}.
52
- */
53
- constructor(localSessionId, logger) {
54
- this.localSessionId = localSessionId;
27
+ // -----------------------
28
+ constructor(localSessionIdOrDeserialized, logger) {
55
29
  this.logger = logger;
56
- /**
57
- * Trivially reach consensus on default cluster size and reserved IDs.
58
- * These initial values must *NOT* change without careful consideration to compatibility.
59
- */
60
- this.newClusterCapacity = exports.defaultClusterCapacity;
61
- /**
62
- * Session ID -\> data about the session's current cluster.
63
- * Sessions are mutable, and thus should only be created via `createSession`.
64
- */
65
- this.sessions = new Map();
66
- /**
67
- * The base final ID of the next cluster to be created.
68
- */
69
- this.nextClusterBaseFinalId = 0;
70
- /**
71
- * Total number of IDs created locally during the current session.
72
- */
73
- this.localIdCount = 0;
74
- /**
75
- * Maps local IDs to override strings. This will contain an entry for every override assigned to a local ID generated during
76
- * the current session, and retains entries for the lifetime of this compressor.
77
- */
78
- this.localOverrides = new appendOnlySortedMap_1.AppendOnlySortedMap(utils_1.compareFiniteNumbersReversed);
79
- /**
80
- * Maps local IDs to the final ID they are associated with (if any), and maps final IDs to the corresponding local ID (if any).
81
- * This is used to efficiently compute normalization. This map can be thought of as mapping ranges of "optimistic uncertainty"
82
- * (local IDs) to the result of consensus (reserved ranges of final IDs, a.k.a. clusters). Any given range of local IDs
83
- * does not necessarily span an entire cluster, as some session-space IDs may be allocated *after* a cluster has been allocated
84
- * but before it is full. In this case, there is no uncertainty, as the range of final IDs was reserved when the cluster was created.
85
- * However, there is always a range of local IDs with size \>= 1 associated with the beginning of every cluster, as clusters are only
86
- * created *after* they are needed and thus there is some period of uncertainty after local IDs have been handed out but before the
87
- * range containing them has been finalized. There may also be ranges of local IDs that do not start at the beginning of a
88
- * cluster; this happens when a cluster is expanded instead of allocating a new one.
89
- * Additionally, session space IDs associated with an override string will also always be local IDs, because there is uncertainty as
90
- * to whether another client simultaneously allocated the same override and could get sequenced first (a.k.a. unification) and its
91
- * final ID would be associated with that override.
92
- * See `SessionIdNormalizer` for more.
93
- */
94
- this.sessionIdNormalizer = new sessionIdNormalizer_1.SessionIdNormalizer();
95
- /**
96
- * Contains entries for cluster base UUIDs and override strings (both local and final).
97
- * As a performance optimization, entries for finalized strings also include the containing cluster object.
98
- * This can be viewed as three separate tables: the inverse table for `localOverrides`, the inverse table for the union of all
99
- * the overrides of the clusters in `finalIdToCluster`, and the inverse lookup of cluster base UUIDs to their clusters.
100
- * This is unified as a performance optimization, as the common case does not have overridden IDs. It is a btree due to the need
101
- * to make range queries.
102
- */
103
- this.clustersAndOverridesInversion = new sorted_btree_1.default(undefined, utils_1.compareStrings);
104
- /**
105
- * Maps the first final ID in a cluster to its owning cluster.
106
- * Can be searched in O(log n) to determine clusters for any final ID.
107
- */
108
- this.finalIdToCluster = new appendOnlySortedMap_1.AppendOnlySortedMap(utils_1.compareFiniteNumbers);
109
- this.localSession = this.createSession(localSessionId);
30
+ this.normalizer = new sessionSpaceNormalizer_1.SessionSpaceNormalizer();
31
+ // The number of IDs generated by the local session
32
+ this.localGenCount = 0;
33
+ // -----------------------
34
+ // ----- Final state -----
35
+ // The gen count to be annotated on the range returned by the next call to `takeNextCreationRange`.
36
+ // This is updated to be equal to `generatedIdCount` + 1 each time it is called.
37
+ this.nextRangeBaseGenCount = 1;
38
+ // The capacity of the next cluster to be created
39
+ this.newClusterCapacity = runtime_definitions_1.initialClusterCapacity;
40
+ this.sessions = new sessions_1.Sessions();
41
+ this.finalSpace = new finalSpace_1.FinalSpace();
42
+ // -----------------------
43
+ // ----- Telemetry state -----
44
+ // The number of local IDs generated since the last telemetry was sent.
45
+ this.telemetryLocalIdCount = 0;
46
+ // The number of eager final IDs generated since the last telemetry was sent.
47
+ this.telemetryEagerFinalIdCount = 0;
48
+ if (typeof localSessionIdOrDeserialized === "string") {
49
+ this.localSessionId = localSessionIdOrDeserialized;
50
+ this.localSession = this.sessions.getOrCreate(localSessionIdOrDeserialized);
51
+ }
52
+ else {
53
+ // Deserialize case
54
+ this.sessions = localSessionIdOrDeserialized;
55
+ // As policy, the first session is always the local session. Preserve this invariant
56
+ // during deserialization.
57
+ const firstSession = localSessionIdOrDeserialized.sessions().next();
58
+ (0, core_utils_1.assert)(!firstSession.done, 0x754 /* First session must be present. */);
59
+ this.localSession = firstSession.value;
60
+ this.localSessionId = (0, utilities_1.stableIdFromNumericUuid)(this.localSession.sessionUuid);
61
+ }
62
+ }
63
+ static create(sessionIdOrLogger, loggerOrUndefined) {
64
+ let localSessionId;
65
+ let logger;
66
+ if (sessionIdOrLogger === undefined) {
67
+ localSessionId = (0, utilities_1.createSessionId)();
68
+ }
69
+ else {
70
+ if (typeof sessionIdOrLogger === "string") {
71
+ localSessionId = sessionIdOrLogger;
72
+ logger = loggerOrUndefined;
73
+ }
74
+ else {
75
+ localSessionId = (0, utilities_1.createSessionId)();
76
+ logger = loggerOrUndefined;
77
+ }
78
+ }
79
+ const compressor = new IdCompressor(localSessionId, logger === undefined ? undefined : (0, telemetry_utils_1.createChildLogger)({ logger }));
80
+ return compressor;
110
81
  }
111
82
  /**
112
83
  * The size of each newly created ID cluster.
@@ -119,1140 +90,406 @@ class IdCompressor {
119
90
  * `IdCompressor.maxClusterSize`.
120
91
  */
121
92
  set clusterCapacity(value) {
122
- (0, common_utils_1.assert)(value > 0, 0x481 /* Clusters must have a positive capacity */);
123
- (0, common_utils_1.assert)(value <= IdCompressor.maxClusterSize, 0x482 /* Clusters must not exceed max cluster size */);
93
+ if (value <= 0) {
94
+ throw new Error("Clusters must have a positive capacity.");
95
+ }
96
+ if (value > IdCompressor.maxClusterSize) {
97
+ throw new Error("Clusters must not exceed max cluster size.");
98
+ }
124
99
  this.newClusterCapacity = value;
125
100
  }
126
- /**
127
- * Creates a session object for the supplied ID.
128
- * Must only be called once per ID.
129
- * @param sessionId - the ID for the session
130
- * @returns the session object for the supplied ID
131
- */
132
- createSession(sessionId) {
133
- (0, common_utils_1.assert)(!this.clustersAndOverridesInversion.has(sessionId), 0x484 /* Attempted to create duplicate session */);
134
- const existingSession = this.sessions.get(sessionId);
135
- if (existingSession !== undefined) {
136
- (0, utils_1.fail)("createSession must only be called once for each session ID.");
137
- }
138
- const sessionUuid = (0, numericUuid_1.numericUuidFromStableId)(sessionId);
139
- const session = {
140
- sessionUuid,
141
- currentClusterDetails: undefined,
142
- lastFinalizedLocalId: undefined,
143
- };
144
- this.sessions.set(sessionId, session);
145
- return session;
101
+ generateCompressedId() {
102
+ this.localGenCount++;
103
+ const lastCluster = this.localSession.getLastCluster();
104
+ if (lastCluster === undefined) {
105
+ this.telemetryLocalIdCount++;
106
+ return this.generateNextLocalId();
107
+ }
108
+ // If there exists a cluster of final IDs already claimed by the local session that still has room in it,
109
+ // it is known prior to range sequencing what a local ID's corresponding final ID will be.
110
+ // In this case, it is safe to return the final ID immediately. This is guaranteed to be safe because
111
+ // any op that the local session sends that contains one of those final IDs are guaranteed to arrive to
112
+ // collaborators *after* the one containing the creation range.
113
+ const clusterOffset = this.localGenCount - (0, utilities_1.genCountFromLocalId)(lastCluster.baseLocalId);
114
+ if (lastCluster.capacity > clusterOffset) {
115
+ this.telemetryEagerFinalIdCount++;
116
+ // Space in the cluster: eager final
117
+ return (lastCluster.baseFinalId +
118
+ clusterOffset);
119
+ }
120
+ // No space in the cluster, return next local
121
+ this.telemetryLocalIdCount++;
122
+ return this.generateNextLocalId();
123
+ }
124
+ generateNextLocalId() {
125
+ // Must tell the normalizer that we generated a local ID
126
+ this.normalizer.addLocalRange(this.localGenCount, 1);
127
+ return (0, utilities_1.localIdFromGenCount)(this.localGenCount);
146
128
  }
147
- /**
148
- * Returns a range of local IDs created by this session in a format for sending to the server for finalizing.
149
- * The range will include all local IDs generated via calls to `generateCompressedId` since the last time this method was called.
150
- * @returns the range of session-local IDs, which may be empty. This range must be sent to the server for ordering before
151
- * it is finalized. Ranges must be sent to the server in the order that they are taken via calls to this method.
152
- */
153
129
  takeNextCreationRange() {
154
- var _a;
155
- const lastLocalInRange = -this.localIdCount;
156
- const lastTakenNormalized = (_a = this.lastTakenLocalId) !== null && _a !== void 0 ? _a : 0;
157
- (0, common_utils_1.assert)(lastLocalInRange <= lastTakenNormalized, 0x485 /* Inconsistent local ID state */);
158
- let ids;
159
- if (lastLocalInRange !== lastTakenNormalized) {
160
- const firstLocalInRange = (lastTakenNormalized - 1);
161
- const overrides = [
162
- ...this.localOverrides.getRange((lastTakenNormalized - 1), lastLocalInRange),
163
- ];
164
- if ((0, utils_1.hasAtLeastLength)(overrides, 1)) {
165
- (0, common_utils_1.assert)(overrides[0][0] <= firstLocalInRange, 0x486 /* Inconsistent override state */);
166
- (0, common_utils_1.assert)(overrides[overrides.length - 1][0] >= lastLocalInRange, 0x487 /* Inconsistent override state */);
167
- ids = {
168
- overrides,
169
- };
170
- const first = firstLocalInRange === overrides[0][0] ? undefined : firstLocalInRange;
171
- const last = lastLocalInRange === overrides[overrides.length - 1][0]
172
- ? undefined
173
- : lastLocalInRange;
174
- (0, utils_1.setPropertyIfDefined)(first, ids, "first");
175
- (0, utils_1.setPropertyIfDefined)(last, ids, "last");
176
- }
177
- else {
178
- ids = {
179
- first: firstLocalInRange,
180
- last: lastLocalInRange,
181
- };
182
- }
183
- this.lastTakenLocalId = lastLocalInRange;
184
- }
185
- const range = { sessionId: this.localSessionId };
186
- if (ids === undefined) {
187
- return range;
130
+ const count = this.localGenCount - (this.nextRangeBaseGenCount - 1);
131
+ if (count === 0) {
132
+ return {
133
+ sessionId: this.localSessionId,
134
+ };
188
135
  }
189
- (0, common_utils_1.assert)(this.lastTakenLocalId === -this.localIdCount &&
190
- this.lastTakenLocalId !== lastTakenNormalized, 0x488 /* Non-empty range must properly consume local IDs */);
191
- range.ids = ids;
136
+ const range = {
137
+ sessionId: this.localSessionId,
138
+ ids: {
139
+ firstGenCount: this.nextRangeBaseGenCount,
140
+ count,
141
+ },
142
+ };
143
+ this.nextRangeBaseGenCount = this.localGenCount + 1;
192
144
  return range;
193
145
  }
194
- /**
195
- * Finalizes the supplied range of IDs (which may be from either a remote or local session).
196
- * @param range - the range of session-local IDs to finalize.
197
- */
198
146
  finalizeCreationRange(range) {
199
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
200
- const { sessionId } = range;
201
- const isLocal = sessionId === this.localSessionId;
202
- const session = (_a = this.sessions.get(sessionId)) !== null && _a !== void 0 ? _a : this.createSession(sessionId);
203
- const ids = (0, idRange_1.getIds)(range);
204
- if (ids === undefined) {
147
+ // Check if the range has IDs
148
+ if (range.ids === undefined) {
205
149
  return;
206
150
  }
207
- const { currentClusterDetails } = session;
208
- const { cluster: currentCluster, clusterBase: currentBaseFinalId } = currentClusterDetails !== null && currentClusterDetails !== void 0 ? currentClusterDetails : {
209
- cluster: undefined,
210
- clusterBase: undefined,
211
- };
212
- const currentClusterExists = currentCluster !== undefined && currentBaseFinalId !== undefined;
213
- const normalizedLastFinalizedLocal = (_b = session.lastFinalizedLocalId) !== null && _b !== void 0 ? _b : 0;
214
- const { first: newFirstFinalizedLocal, last: newLastFinalizedLocal } = ids;
215
- (0, common_utils_1.assert)(newFirstFinalizedLocal === normalizedLastFinalizedLocal - 1, 0x489 /* Ranges finalized out of order. */);
216
- // The total number of session-local IDs to finalize
217
- const finalizeCount = normalizedLastFinalizedLocal - newLastFinalizedLocal;
218
- (0, common_utils_1.assert)(finalizeCount >= 1, 0x48a /* Cannot finalize an empty range. */);
219
- let eagerFinalIdCount = 0;
220
- let initialClusterCount = 0;
221
- let remainingCount = finalizeCount;
222
- let newBaseUuid;
223
- if (currentClusterExists) {
151
+ (0, core_utils_1.assert)(range.ids.count > 0, 0x755 /* Malformed ID Range. */);
152
+ const { sessionId, ids } = range;
153
+ const { count, firstGenCount } = ids;
154
+ const session = this.sessions.getOrCreate(sessionId);
155
+ const isLocal = session === this.localSession;
156
+ const rangeBaseLocal = (0, utilities_1.localIdFromGenCount)(firstGenCount);
157
+ let lastCluster = session.getLastCluster();
158
+ if (lastCluster === undefined) {
159
+ // This is the first cluster in the session space
160
+ if (rangeBaseLocal !== -1) {
161
+ throw new Error("Ranges finalized out of order.");
162
+ }
163
+ lastCluster = this.addEmptyCluster(session, this.clusterCapacity + count);
224
164
  if (isLocal) {
225
- const lastKnownFinal = (_c = this.sessionIdNormalizer.getLastFinalId()) !== null && _c !== void 0 ? _c : (0, utils_1.fail)("Cluster exists but normalizer does not have an entry for it.");
226
- const lastAlignedFinalInCluster = (currentBaseFinalId +
227
- Math.min(currentCluster.count + finalizeCount, currentCluster.capacity) -
228
- 1);
229
- if (lastAlignedFinalInCluster > lastKnownFinal) {
230
- this.sessionIdNormalizer.addFinalIds((lastKnownFinal + 1), lastAlignedFinalInCluster, currentCluster);
231
- }
232
- }
233
- initialClusterCount = currentCluster.count;
234
- const remainingCapacity = currentCluster.capacity - initialClusterCount;
235
- const overflow = remainingCount - remainingCapacity;
236
- const hasRoom = overflow <= 0;
237
- if (hasRoom || currentBaseFinalId === this.finalIdToCluster.maxKey()) {
238
- currentCluster.count += remainingCount;
239
- eagerFinalIdCount = remainingCount;
240
- remainingCount = 0;
241
- // The common case is that there is room in the cluster, and the new final IDs can simply be added to it
242
- if (!hasRoom) {
243
- // The cluster is full but is the last in the list of clusters.
244
- // This allows it to be expanded instead of allocating a new one.
245
- const expansionAmount = this.newClusterCapacity + overflow;
246
- const previousCapacity = currentCluster.capacity;
247
- currentCluster.capacity += expansionAmount;
248
- this.nextClusterBaseFinalId = (this.nextClusterBaseFinalId +
249
- expansionAmount);
250
- (0, common_utils_1.assert)(this.nextClusterBaseFinalId < Number.MAX_SAFE_INTEGER, 0x48b /* The number of allocated final IDs must not exceed the JS maximum safe integer. */);
251
- this.checkClusterForCollision(currentCluster);
252
- if (isLocal) {
253
- // Example with cluster size of 3:
254
- // Ids generated so far: -1 1 2 -4 -5 <-- note positive numbers are eager finals
255
- // Cluster: [ 0 1 2 ]
256
- // ~ finalizing happens, causing expansion of 2 (overflow) + 3 (cluster capacity) ~
257
- // Cluster: [ 0 1 2 3 4 _ _ _ ]
258
- // corresponding locals: -1 -4 -5
259
- // lastFinalizedLocalId^ ^newLastFinalizedLocalId = -5
260
- // overflow = 2: ----
261
- // localIdPivot^
262
- // lastFinalizedFinal^
263
- const newLastFinalizedFinal = (currentBaseFinalId +
264
- currentCluster.count -
265
- 1);
266
- (0, common_utils_1.assert)(session.lastFinalizedLocalId !== undefined, 0x48c /* Cluster already exists for session but there is no finalized local ID */);
267
- const finalPivot = (newLastFinalizedFinal -
268
- overflow +
269
- 1);
270
- // Inform the normalizer of all IDs that we now know will end up being finalized into this cluster, including the ones
271
- // that were given out as locals (non-eager) because they exceeded the bounds of the current cluster before it was expanded.
272
- // It is safe to associate the unfinalized locals with their future final IDs even before the ranges for those locals are
273
- // actually finalized, because total order broadcast guarantees that any usage of those final IDs will be observed after
274
- // the finalization of the ranges.
275
- this.sessionIdNormalizer.registerFinalIdBlock(finalPivot, expansionAmount, currentCluster);
276
- (_d = this.logger) === null || _d === void 0 ? void 0 : _d.sendTelemetryEvent({
277
- eventName: "RuntimeIdCompressor:ClusterExpansion",
278
- sessionId: this.localSessionId,
279
- previousCapacity,
280
- newCapacity: currentCluster.capacity,
281
- overflow,
282
- });
283
- }
284
- }
285
- }
286
- else {
287
- // The range cannot be fully allocated in the existing cluster, so allocate any space left in it and
288
- // form a new one by incrementing the previous baseUuid
289
- newBaseUuid = (0, numericUuid_1.incrementUuid)(currentCluster.baseUuid, currentCluster.capacity);
290
- currentCluster.count += remainingCapacity;
291
- remainingCount -= remainingCapacity;
292
- (_e = this.logger) === null || _e === void 0 ? void 0 : _e.sendTelemetryEvent({
293
- eventName: "RuntimeIdCompressor:OverfilledCluster",
294
- sessionId: this.localSessionId,
295
- });
296
- }
297
- }
298
- else {
299
- // Session has never made a cluster, form a new one with the session UUID as the baseUuid
300
- newBaseUuid = session.sessionUuid;
301
- if (isLocal) {
302
- (_f = this.logger) === null || _f === void 0 ? void 0 : _f.sendTelemetryEvent({
165
+ this.logger?.sendTelemetryEvent({
303
166
  eventName: "RuntimeIdCompressor:FirstCluster",
304
167
  sessionId: this.localSessionId,
305
168
  });
306
169
  }
307
170
  }
308
- // Finalizing a range results in one of three cases:
309
- // 1. All local IDs are finalized into a new cluster (because there was either never a cluster for that session, or the current
310
- // cluster for the session was full).
311
- // 2. All local IDs are finalized into the existing (current) cluster for the session.
312
- // 3. Local IDs are finalized into both the current cluster and a new one, as the current cluster did not have enough room.
313
- let newCluster;
314
- let newBaseFinalId;
315
- // The first local ID that will be finalized into a new cluster, if there is one.
316
- // This lets us quickly compare which cluster an override string will go into.
317
- let localIdPivot;
318
- // Need to make a new cluster
319
- if (newBaseUuid !== undefined) {
320
- if (remainingCount <= 0) {
321
- (0, utils_1.fail)("Should not create an empty cluster.");
322
- }
323
- if (currentCluster !== undefined && currentCluster.capacity !== currentCluster.count) {
324
- (0, utils_1.fail)("Cluster must be filled before another is allocated.");
325
- }
326
- newBaseFinalId = this.nextClusterBaseFinalId;
327
- const newCapacity = Math.max(this.newClusterCapacity, remainingCount);
328
- newCluster = {
329
- baseUuid: newBaseUuid,
330
- capacity: newCapacity,
331
- count: remainingCount,
332
- session,
333
- };
334
- const usedCapacity = finalizeCount - remainingCount;
335
- localIdPivot = (newFirstFinalizedLocal - usedCapacity);
336
- if (isLocal) {
337
- (_g = this.logger) === null || _g === void 0 ? void 0 : _g.sendTelemetryEvent({
338
- eventName: "RuntimeIdCompressor:NewCluster",
339
- sessionId: this.localSessionId,
340
- clusterCapacity: newCapacity,
341
- clusterCount: remainingCount,
342
- });
343
- this.sessionIdNormalizer.registerFinalIdBlock(newBaseFinalId, newCluster.capacity, newCluster);
344
- }
345
- this.checkClusterForCollision(newCluster);
346
- this.clustersAndOverridesInversion.set((0, numericUuid_1.stableIdFromNumericUuid)(newCluster.baseUuid), {
347
- clusterBase: newBaseFinalId,
348
- cluster: newCluster,
349
- });
350
- session.currentClusterDetails = { cluster: newCluster, clusterBase: newBaseFinalId };
351
- this.nextClusterBaseFinalId = (this.nextClusterBaseFinalId +
352
- newCluster.capacity);
353
- (0, common_utils_1.assert)(this.nextClusterBaseFinalId < Number.MAX_SAFE_INTEGER, 0x48e /* The number of allocated final IDs must not exceed the JS maximum safe integer. */);
354
- this.finalIdToCluster.append(newBaseFinalId, newCluster);
171
+ const remainingCapacity = lastCluster.capacity - lastCluster.count;
172
+ if (lastCluster.baseLocalId - lastCluster.count !== rangeBaseLocal) {
173
+ throw new Error("Ranges finalized out of order.");
355
174
  }
356
- // If there are overrides, we must determine which cluster object (current or overflow) each belongs to and add it.
357
- const overrides = ids.overrides;
358
- if (overrides !== undefined) {
359
- for (let i = 0; i < overrides.length; i++) {
360
- const [overriddenLocal, override] = overrides[i];
361
- // Note: recall that local IDs are negative
362
- (0, common_utils_1.assert)(i === 0 || overriddenLocal < overrides[i - 1][0], 0x48f /* Override IDs must be in sorted order. */);
363
- (0, common_utils_1.assert)(overriddenLocal < normalizedLastFinalizedLocal, 0x490 /* Ranges finalized out of order. */);
364
- (0, common_utils_1.assert)(overriddenLocal >= newLastFinalizedLocal, 0x491 /* Malformed range: override ID ahead of range start. */);
365
- let cluster;
366
- let overriddenFinal;
367
- if (localIdPivot !== undefined && overriddenLocal <= localIdPivot) {
368
- // Override is at or past the pivot, so it is in a new cluster.
369
- (0, common_utils_1.assert)(newCluster !== undefined && newBaseFinalId !== undefined, 0x492 /* No cluster was created when overflow occurred. */);
370
- cluster = newCluster;
371
- overriddenFinal = (newBaseFinalId +
372
- (localIdPivot - overriddenLocal));
373
- }
374
- else {
375
- // Override was finalized into an existing cluster
376
- (0, common_utils_1.assert)(currentCluster !== undefined && currentBaseFinalId !== undefined, 0x493 /* No cluster exists but IDs were finalized. */);
377
- cluster = currentCluster;
378
- overriddenFinal = (currentBaseFinalId +
379
- initialClusterCount +
380
- (normalizedLastFinalizedLocal - overriddenLocal) -
381
- 1);
382
- }
383
- (_h = cluster.overrides) !== null && _h !== void 0 ? _h : (cluster.overrides = new Map());
384
- const inversionKey = IdCompressor.createInversionKey(override);
385
- const existingIds = this.getExistingIdsForNewOverride(inversionKey, true);
386
- let overrideForCluster;
387
- let associatedLocal;
388
- if (existingIds !== undefined) {
389
- let mostFinalExistingOverride;
390
- if (typeof existingIds === "number") {
391
- mostFinalExistingOverride = existingIds;
392
- if (isLocalId(mostFinalExistingOverride)) {
393
- associatedLocal = mostFinalExistingOverride;
394
- }
395
- }
396
- else {
397
- [associatedLocal, mostFinalExistingOverride] = existingIds;
398
- }
399
- if (isFinalId(mostFinalExistingOverride)) {
400
- // A previous range already finalized an ID with this override. See `IdCluster` for more.
401
- overrideForCluster = mostFinalExistingOverride;
402
- }
403
- else {
404
- (0, common_utils_1.assert)(!isLocal || mostFinalExistingOverride === overriddenLocal, 0x494 /* Cannot have multiple local IDs with identical overrides. */);
405
- // This session has created an ID with this override before, but has not finalized it yet. The incoming
406
- // range "wins" and will contain the final ID associated with that override, regardless of if that range was
407
- // made by this session or not.
408
- overrideForCluster = override;
409
- }
410
- }
411
- else {
412
- // This is the first time this override has been associated with any ID
413
- overrideForCluster = override;
414
- }
415
- (0, common_utils_1.assert)(!cluster.overrides.has(overriddenFinal), 0x495 /* Cannot add a second override for final id */);
416
- if (typeof overrideForCluster === "string") {
417
- if (isLocal || associatedLocal === undefined) {
418
- cluster.overrides.set(overriddenFinal, override);
419
- }
420
- else {
421
- cluster.overrides.set(overriddenFinal, {
422
- override,
423
- originalOverridingFinal: overriddenFinal,
424
- associatedLocalId: associatedLocal,
425
- });
426
- }
427
- }
428
- else {
429
- const unifiedOverride = {
430
- override,
431
- originalOverridingFinal: overrideForCluster,
432
- };
433
- (0, utils_1.setPropertyIfDefined)(associatedLocal, unifiedOverride, "associatedLocalId");
434
- cluster.overrides.set(overriddenFinal, unifiedOverride);
175
+ if (remainingCapacity >= count) {
176
+ // The current range fits in the existing cluster
177
+ lastCluster.count += count;
178
+ }
179
+ else {
180
+ const overflow = count - remainingCapacity;
181
+ const newClaimedFinalCount = overflow + this.clusterCapacity;
182
+ if (lastCluster === this.finalSpace.getLastCluster()) {
183
+ // The last cluster in the sessions chain is the last cluster globally, so it can be expanded.
184
+ lastCluster.capacity += newClaimedFinalCount;
185
+ lastCluster.count += count;
186
+ (0, core_utils_1.assert)(!this.sessions.clusterCollides(lastCluster), 0x756 /* Cluster collision detected. */);
187
+ if (isLocal) {
188
+ this.logger?.sendTelemetryEvent({
189
+ eventName: "RuntimeIdCompressor:ClusterExpansion",
190
+ sessionId: this.localSessionId,
191
+ previousCapacity: lastCluster.capacity - newClaimedFinalCount,
192
+ newCapacity: lastCluster.capacity,
193
+ overflow,
194
+ });
435
195
  }
436
- const finalizedOverride = {
437
- cluster,
438
- originalOverridingFinal: overriddenFinal,
439
- };
440
- (0, utils_1.setPropertyIfDefined)(associatedLocal, finalizedOverride, "associatedLocalId");
441
- const currentOverride = this.clustersAndOverridesInversion.get(inversionKey);
442
- if (currentOverride === undefined ||
443
- IdCompressor.isUnfinalizedOverride(currentOverride)) {
444
- // Update the map to contain a finalized override, but never update it with future finalized overrides with
445
- // the same string; those should decompress to the first final ID with that override.
446
- this.clustersAndOverridesInversion.set(inversionKey, finalizedOverride);
196
+ }
197
+ else {
198
+ // The last cluster in the sessions chain is *not* the last cluster globally. Fill and overflow to new.
199
+ lastCluster.count = lastCluster.capacity;
200
+ const newCluster = this.addEmptyCluster(session, newClaimedFinalCount);
201
+ newCluster.count += overflow;
202
+ if (isLocal) {
203
+ this.logger?.sendTelemetryEvent({
204
+ eventName: "RuntimeIdCompressor:NewCluster",
205
+ sessionId: this.localSessionId,
206
+ });
447
207
  }
448
208
  }
449
209
  }
450
210
  if (isLocal) {
451
- (_j = this.logger) === null || _j === void 0 ? void 0 : _j.sendTelemetryEvent({
211
+ this.logger?.sendTelemetryEvent({
452
212
  eventName: "RuntimeIdCompressor:IdCompressorStatus",
453
- eagerFinalIdCount: eagerFinalIdCount - ((_k = overrides === null || overrides === void 0 ? void 0 : overrides.length) !== null && _k !== void 0 ? _k : 0),
454
- localIdCount: remainingCount + ((_l = overrides === null || overrides === void 0 ? void 0 : overrides.length) !== null && _l !== void 0 ? _l : 0),
455
- overridesCount: (_m = overrides === null || overrides === void 0 ? void 0 : overrides.length) !== null && _m !== void 0 ? _m : 0,
213
+ eagerFinalIdCount: this.telemetryEagerFinalIdCount,
214
+ localIdCount: this.telemetryLocalIdCount,
456
215
  sessionId: this.localSessionId,
457
216
  });
217
+ this.telemetryEagerFinalIdCount = 0;
218
+ this.telemetryLocalIdCount = 0;
458
219
  }
459
- session.lastFinalizedLocalId = newLastFinalizedLocal;
220
+ (0, core_utils_1.assert)(!session.isEmpty(), 0x757 /* Empty sessions should not be created. */);
460
221
  }
461
- checkClusterForCollision(cluster) {
462
- const maxClusterUuid = (0, numericUuid_1.incrementUuid)(cluster.baseUuid, cluster.capacity - 1);
463
- const maxClusterStableId = (0, numericUuid_1.stableIdFromNumericUuid)(maxClusterUuid);
464
- const closestMatch = this.clustersAndOverridesInversion.getPairOrNextLower(maxClusterStableId);
465
- if (closestMatch !== undefined) {
466
- const [inversionKey, compressionMapping] = closestMatch;
467
- if (!IdCompressor.isClusterInfo(compressionMapping)) {
468
- if ((0, uuidUtilities_1.isStableId)(inversionKey) &&
469
- IdCompressor.uuidsMightCollide(inversionKey, maxClusterStableId, cluster.capacity)) {
470
- const numericOverride = (0, numericUuid_1.numericUuidFromStableId)(inversionKey);
471
- const delta = (0, numericUuid_1.getPositiveDelta)(maxClusterUuid, numericOverride, cluster.capacity - 1);
472
- if (delta !== undefined) {
473
- IdCompressor.failWithCollidingOverride(inversionKey);
474
- }
475
- }
476
- }
477
- }
222
+ addEmptyCluster(session, capacity) {
223
+ const newCluster = session.addNewCluster(this.finalSpace.getAllocatedIdLimit(), capacity, 0);
224
+ (0, core_utils_1.assert)(!this.sessions.clusterCollides(newCluster), 0x758 /* Cluster collision detected. */);
225
+ this.finalSpace.addCluster(newCluster);
226
+ return newCluster;
478
227
  }
479
- static failWithCollidingOverride(override) {
480
- (0, utils_1.fail)(`Override '${override}' collides with another allocated UUID.`);
481
- }
482
- static isClusterInfo(compressionMapping) {
483
- return compressionMapping.clusterBase !== undefined;
484
- }
485
- static isUnfinalizedOverride(compressionMapping) {
486
- return typeof compressionMapping === "number";
487
- }
488
- static createInversionKey(inversionKey) {
489
- return (0, uuidUtilities_1.isStableId)(inversionKey)
490
- ? inversionKey
491
- : `${nonStableOverridePrefix}${inversionKey}`;
492
- }
493
- static isStableInversionKey(inversionKey) {
494
- return inversionKey.charAt(0) !== nonStableOverridePrefix;
495
- }
496
- /**
497
- * Returns an existing ID associated with an override, or undefined if none exists.
498
- */
499
- getExistingIdsForNewOverride(inversionKey, isFinalOverride) {
500
- var _a;
501
- const closestMatch = this.clustersAndOverridesInversion.getPairOrNextLower(inversionKey, reusedArray);
502
- let numericOverride;
503
- let stableOverride;
504
- if (closestMatch !== undefined) {
505
- const [key, compressionMapping] = closestMatch;
506
- if (!IdCompressor.isClusterInfo(compressionMapping)) {
507
- if (key === inversionKey) {
508
- if (IdCompressor.isUnfinalizedOverride(compressionMapping)) {
509
- return compressionMapping;
510
- }
511
- const finalizedOverride = compressionMapping;
512
- return finalizedOverride.associatedLocalId !== undefined
513
- ? [
514
- finalizedOverride.associatedLocalId,
515
- finalizedOverride.originalOverridingFinal,
516
- ]
517
- : finalizedOverride.originalOverridingFinal;
518
- }
519
- }
520
- else if (IdCompressor.isStableInversionKey(inversionKey)) {
521
- stableOverride = inversionKey;
522
- const cluster = compressionMapping.cluster;
523
- if (IdCompressor.uuidsMightCollide(inversionKey, key, cluster.capacity)) {
524
- numericOverride = (0, numericUuid_1.numericUuidFromStableId)(stableOverride);
525
- const delta = (0, numericUuid_1.getPositiveDelta)(numericOverride, cluster.baseUuid, cluster.capacity - 1);
526
- if (delta !== undefined) {
527
- if (!isFinalOverride) {
528
- if (delta >= cluster.count) {
529
- // TODO:#283: Properly implement unification
530
- return undefined;
531
- }
532
- return this.normalizeToSessionSpace((compressionMapping.clusterBase + delta));
533
- }
534
- }
535
- }
536
- }
537
- }
538
- const override = (_a = numericOverride !== null && numericOverride !== void 0 ? numericOverride : stableOverride) !== null && _a !== void 0 ? _a : (IdCompressor.isStableInversionKey(inversionKey) ? inversionKey : undefined);
539
- if (override !== undefined) {
540
- const sessionSpaceId = this.getCompressedIdForStableId(override);
541
- if (sessionSpaceId !== undefined) {
542
- return sessionSpaceId;
543
- }
544
- }
545
- return undefined;
546
- }
547
- /**
548
- * Check if `a` might be within `range` of `b`, where both are treated as hex numbers.
549
- * @param range - an integer
550
- */
551
- static uuidsMightCollide(a, b, range) {
552
- // Check if any of the UUIDs in the cluster collide (i.e. any in [base, base + capacity)).
553
- // Optimization: All UUIDs in a cluster are the same string up until the last few characters which encode the offset from
554
- // the cluster base. So, first compute the length of that shared string, and early out if it is different from the override
555
- // UUID. This way we usually need not do the more expensive check below.
556
- const hexDigitsToCheck = 32 - Math.ceil(Math.log2(range) / 2);
557
- if (a.startsWith(b.slice(0, hexDigitsToCheck))) {
558
- return true;
559
- }
560
- return false;
561
- }
562
- /**
563
- * Helper for retrieving an override.
564
- */
565
- static tryGetOverride(cluster, finalId) {
566
- var _a;
567
- const override = (_a = cluster.overrides) === null || _a === void 0 ? void 0 : _a.get(finalId);
568
- if (override === undefined) {
569
- return undefined;
570
- }
571
- if (typeof override === "string") {
572
- return override;
573
- }
574
- return override.override;
575
- }
576
- /**
577
- * Generates a new compressed ID or returns an existing one.
578
- * This should ONLY be called to generate IDs for local operations.
579
- * @param override - Specifies a specific string to be associated with the returned compressed ID.
580
- * Performance note: assigning override strings incurs a performance overhead.
581
- * @returns an existing ID if one already exists for `override`, and a new local ID otherwise. The returned ID is in session space.
582
- */
583
- generateCompressedId(override) {
584
- let overrideInversionKey;
585
- if (override !== undefined) {
586
- overrideInversionKey = IdCompressor.createInversionKey(override);
587
- const existingIds = this.getExistingIdsForNewOverride(overrideInversionKey, false);
588
- if (existingIds !== undefined) {
589
- return typeof existingIds === "number" ? existingIds : existingIds[0];
590
- }
591
- }
592
- // Bump local counter regardless, then attempt to optimistically return a final ID.
593
- // If the local session has reserved a cluster range via consensus, it is safe to hand out final IDs prior to
594
- // finalizing the range that includes these locals.
595
- const newLocalId = -++this.localIdCount;
596
- const { currentClusterDetails } = this.localSession;
597
- const { sessionIdNormalizer } = this;
598
- let eagerFinalId;
599
- let cluster;
600
- if (currentClusterDetails !== undefined) {
601
- cluster = currentClusterDetails.cluster;
602
- const lastFinalKnown = sessionIdNormalizer.getLastFinalId();
603
- if (lastFinalKnown !== undefined &&
604
- lastFinalKnown - currentClusterDetails.clusterBase + 1 < cluster.capacity) {
605
- eagerFinalId = (lastFinalKnown + 1);
606
- }
607
- }
608
- if (overrideInversionKey !== undefined) {
609
- const registeredLocal = sessionIdNormalizer.addLocalId();
610
- (0, common_utils_1.assert)(registeredLocal === newLocalId, 0x496 /* Session ID Normalizer produced unexpected local ID */);
611
- if (eagerFinalId !== undefined) {
612
- sessionIdNormalizer.addFinalIds(eagerFinalId, eagerFinalId, cluster !== null && cluster !== void 0 ? cluster : (0, utils_1.fail)("No cluster when generating compressed ID"));
613
- }
614
- this.localOverrides.append(newLocalId, override !== null && override !== void 0 ? override : (0, utils_1.fail)("Override must be defined"));
615
- // Since the local ID was just created, it is in both session and op space
616
- const compressionMapping = newLocalId;
617
- this.clustersAndOverridesInversion.set(overrideInversionKey, compressionMapping);
618
- }
619
- else if (eagerFinalId !== undefined) {
620
- sessionIdNormalizer.addFinalIds(eagerFinalId, eagerFinalId, cluster !== null && cluster !== void 0 ? cluster : (0, utils_1.fail)("No cluster when generating compressed ID"));
621
- return eagerFinalId;
228
+ normalizeToOpSpace(id) {
229
+ if ((0, identifiers_1.isFinalId)(id)) {
230
+ return id;
622
231
  }
623
232
  else {
624
- const registeredLocal = sessionIdNormalizer.addLocalId();
625
- (0, common_utils_1.assert)(registeredLocal === newLocalId, 0x497 /* Session ID Normalizer produced unexpected local ID */);
626
- }
627
- return newLocalId;
628
- }
629
- /**
630
- * Decompresses a previously compressed ID into a UUID or override string.
631
- * @param id - the compressed ID to be decompressed.
632
- * @returns the UUID or override string associated with the compressed ID. Fails if the ID was not generated by this compressor.
633
- */
634
- decompress(id) {
635
- var _a;
636
- return (_a = this.tryDecompress(id)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("Compressed ID was not generated by this compressor");
637
- }
638
- /**
639
- * Attempts to decompress a previously compressed ID into a UUID or override string.
640
- * @param id - the compressed ID to be decompressed.
641
- * @returns the UUID or override string associated with the compressed ID, or undefined if the ID was not generated by this compressor.
642
- */
643
- tryDecompress(id) {
644
- var _a;
645
- if (isFinalId(id)) {
646
- const possibleCluster = this.getClusterForFinalId(id);
647
- if (possibleCluster === undefined) {
648
- // It may be an unfinalized eager final ID, so check with normalizer to get the offset from the session UUID
649
- const creationIndex = this.sessionIdNormalizer.getCreationIndex(id);
650
- if (creationIndex !== undefined) {
651
- return (0, numericUuid_1.stableIdFromNumericUuid)(this.localSession.sessionUuid, creationIndex);
233
+ const local = id;
234
+ if (!this.normalizer.contains(local)) {
235
+ throw new Error("Invalid ID to normalize.");
236
+ }
237
+ const finalForm = this.localSession.tryConvertToFinal(local, true);
238
+ return finalForm === undefined
239
+ ? local
240
+ : finalForm;
241
+ }
242
+ }
243
+ normalizeToSessionSpace(id, originSessionId) {
244
+ if ((0, identifiers_1.isFinalId)(id)) {
245
+ const containingCluster = this.localSession.getClusterByAllocatedFinal(id);
246
+ if (containingCluster === undefined) {
247
+ // Does not exist in local cluster chain
248
+ if (id >= this.finalSpace.getFinalizedIdLimit()) {
249
+ throw new Error("Unknown op space ID.");
652
250
  }
653
- return undefined;
251
+ return id;
654
252
  }
655
253
  else {
656
- const [baseFinalId, cluster] = possibleCluster;
657
- const override = IdCompressor.tryGetOverride(cluster, id);
658
- if (override !== undefined) {
659
- return override;
254
+ const alignedLocal = (0, sessions_1.getAlignedLocal)(containingCluster, id);
255
+ if (this.normalizer.contains(alignedLocal)) {
256
+ return alignedLocal;
660
257
  }
661
258
  else {
662
- const offsetInCluster = id - baseFinalId;
663
- return (0, numericUuid_1.stableIdFromNumericUuid)(cluster.baseUuid, offsetInCluster);
259
+ if ((0, utilities_1.genCountFromLocalId)(alignedLocal) > this.localGenCount) {
260
+ throw new Error("Unknown op space ID.");
261
+ }
262
+ return id;
664
263
  }
665
264
  }
666
265
  }
667
266
  else {
668
- const idOffset = -id; // Convert to a positive number
669
- if (idOffset > this.localIdCount) {
670
- // This local ID was never allocated.
671
- return undefined;
672
- }
673
- // If this is a local ID with an override, then it must have been allocated on this machine and will be contained in
674
- // `localOverrides`s. Otherwise, it is a sequential allocation from the session UUID and can simply be negated and
675
- // added to that UUID to obtain the stable ID associated with it.
676
- const localOverride = (_a = this.localOverrides) === null || _a === void 0 ? void 0 : _a.get(id);
677
- return localOverride !== undefined
678
- ? localOverride
679
- : (0, numericUuid_1.stableIdFromNumericUuid)(this.localSession.sessionUuid, idOffset - 1);
680
- }
681
- }
682
- /**
683
- * Recompresses a decompressed ID, which could be a UUID or an override string.
684
- * @param uncompressed - the UUID or override string to recompress.
685
- * @returns the `CompressedId` associated with `uncompressed`. Fails if it has not been previously compressed by this compressor.
686
- */
687
- recompress(uncompressed) {
688
- var _a;
689
- return (_a = this.tryRecompress(uncompressed)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("No such string has ever been compressed");
690
- }
691
- /**
692
- * Attempts to recompresses a decompressed ID, which could be a UUID or an override string.
693
- * @param uncompressed - the UUID or override string to recompress,
694
- * @returns the `CompressedId` associated with `uncompressed` or undefined if it has not been previously compressed by this compressor.
695
- */
696
- tryRecompress(uncompressed) {
697
- return this.recompressInternal(uncompressed);
698
- }
699
- /**
700
- * Helper to compress an uncompressed UUID. It can optionally be supplied with the numeric form of `uncompressedUuid` as a
701
- * performance optimization.
702
- */
703
- recompressInternal(uncompressed, uncompressedUuidNumeric) {
704
- var _a, _b;
705
- let numericUuid = uncompressedUuidNumeric;
706
- const inversionKey = IdCompressor.createInversionKey(uncompressed);
707
- const isStable = IdCompressor.isStableInversionKey(inversionKey);
708
- const closestMatch = this.clustersAndOverridesInversion.getPairOrNextLower(inversionKey, reusedArray);
709
- if (closestMatch !== undefined) {
710
- const [key, compressionMapping] = closestMatch;
711
- if (!IdCompressor.isClusterInfo(compressionMapping)) {
712
- if (key === inversionKey) {
713
- return IdCompressor.isUnfinalizedOverride(compressionMapping)
714
- ? compressionMapping
715
- : (_a = compressionMapping.associatedLocalId) !== null && _a !== void 0 ? _a : compressionMapping.originalOverridingFinal;
267
+ const localToNormalize = id;
268
+ if (originSessionId === this.localSessionId) {
269
+ if (this.normalizer.contains(localToNormalize)) {
270
+ return localToNormalize;
271
+ }
272
+ else {
273
+ // We never generated this local ID, so fail
274
+ throw new Error("Unknown op space ID.");
716
275
  }
717
276
  }
718
277
  else {
719
- if (!isStable) {
720
- return undefined;
278
+ // LocalId from a remote session
279
+ const remoteSession = this.sessions.get(originSessionId);
280
+ if (remoteSession === undefined) {
281
+ throw new Error("No IDs have ever been finalized by the supplied session.");
721
282
  }
722
- const { clusterBase: closestBaseFinalId, cluster: closestCluster } = compressionMapping;
723
- numericUuid !== null && numericUuid !== void 0 ? numericUuid : (numericUuid = (0, numericUuid_1.numericUuidFromStableId)(inversionKey));
724
- const uuidOffset = (0, numericUuid_1.getPositiveDelta)(numericUuid, closestCluster.baseUuid, closestCluster.count - 1);
725
- if (uuidOffset !== undefined) {
726
- let targetFinalId = (closestBaseFinalId + uuidOffset);
727
- const override = (_b = closestCluster.overrides) === null || _b === void 0 ? void 0 : _b.get(targetFinalId);
728
- if (typeof override === "object") {
729
- if (override.associatedLocalId !== undefined) {
730
- return override.associatedLocalId;
731
- }
732
- // This may be a UUID that should actually compress into a different final ID that it aligns with, due to
733
- // another session having an identical override (see `IdCluster` for more).
734
- targetFinalId = override.originalOverridingFinal;
735
- }
736
- return this.normalizeToSessionSpace(targetFinalId);
283
+ const correspondingFinal = remoteSession.tryConvertToFinal(localToNormalize, false);
284
+ if (correspondingFinal === undefined) {
285
+ throw new Error("Unknown op space ID.");
737
286
  }
287
+ return correspondingFinal;
738
288
  }
739
289
  }
740
- if (isStable) {
741
- // May have already computed the numeric UUID, so avoid recomputing if possible
742
- const sessionSpaceId = this.getCompressedIdForStableId(numericUuid !== null && numericUuid !== void 0 ? numericUuid : inversionKey);
743
- if (sessionSpaceId !== undefined) {
744
- return sessionSpaceId;
745
- }
746
- }
747
- return undefined;
748
290
  }
749
- /**
750
- * Normalizes a session space ID into op space.
751
- * @param id - the local ID to normalize.
752
- * @returns the ID in op space.
753
- */
754
- normalizeToOpSpace(id) {
755
- var _a, _b, _c;
756
- if (isFinalId(id)) {
757
- return id;
758
- }
759
- // Check if this local ID has not been allocated yet
760
- if (-id > this.localIdCount) {
761
- (0, utils_1.fail)("Supplied local ID was not created by this compressor.");
762
- }
763
- // Check if this local ID has not been finalized yet.
764
- // Comparing lastFinalizedLocalId is a safe check for eager final IDs because the local IDs corresponding to them
765
- // are never handed out to a consumer, and thus could not be passed into this method.
766
- const { lastFinalizedLocalId } = this.localSession;
767
- if (lastFinalizedLocalId === undefined || id < lastFinalizedLocalId) {
768
- // Eager final IDs do not have overrides in the cluster until finalizing
769
- // This means that using the normalizer to get the final/cluster associated would succeed but would not have the override,
770
- // so checking localOverrides first is necessary.
771
- const override = this.localOverrides.get(id);
772
- if (override !== undefined) {
773
- const inversionKey = IdCompressor.createInversionKey(override);
774
- const compressionMapping = (_a = this.clustersAndOverridesInversion.get(inversionKey)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("Bimap is malformed.");
775
- return !IdCompressor.isClusterInfo(compressionMapping) &&
776
- !IdCompressor.isUnfinalizedOverride(compressionMapping) &&
777
- compressionMapping.associatedLocalId === id
778
- ? compressionMapping.originalOverridingFinal
779
- : id;
780
- }
781
- const possibleFinal = this.sessionIdNormalizer.getFinalId(id);
782
- return (_b = possibleFinal === null || possibleFinal === void 0 ? void 0 : possibleFinal[0]) !== null && _b !== void 0 ? _b : id;
783
- }
784
- const [correspondingFinal, cluster] = (_c = this.sessionIdNormalizer.getFinalId(id)) !== null && _c !== void 0 ? _c : (0, utils_1.fail)("Locally created cluster should be added to the map when allocated");
785
- if (cluster.overrides) {
786
- const override = cluster.overrides.get(correspondingFinal);
787
- if (typeof override === "object" && override.originalOverridingFinal !== undefined) {
788
- // Rare case of two local IDs with same overrides are created concurrently. See `IdCluster` for more.
789
- return override.originalOverridingFinal;
790
- }
791
- }
792
- return correspondingFinal;
793
- }
794
- normalizeToSessionSpace(id, sessionIdIfLocal) {
795
- var _a, _b, _c, _d;
796
- if (isLocalId(id)) {
797
- if (sessionIdIfLocal === undefined || sessionIdIfLocal === this.localSessionId) {
798
- const localIndex = -id;
799
- if (localIndex > this.localIdCount) {
800
- (0, utils_1.fail)("Supplied local ID was not created by this compressor.");
291
+ decompress(id) {
292
+ if ((0, identifiers_1.isFinalId)(id)) {
293
+ const containingCluster = sessions_1.Session.getContainingCluster(id, this.finalSpace.clusters);
294
+ if (containingCluster === undefined) {
295
+ throw new Error("Unknown ID");
296
+ }
297
+ const alignedLocal = (0, sessions_1.getAlignedLocal)(containingCluster, id);
298
+ const alignedGenCount = (0, utilities_1.genCountFromLocalId)(alignedLocal);
299
+ const lastFinalizedGenCount = (0, utilities_1.genCountFromLocalId)((0, sessions_1.lastFinalizedLocal)(containingCluster));
300
+ if (alignedGenCount > lastFinalizedGenCount) {
301
+ // should be an eager final id generated by the local session
302
+ if (containingCluster.session === this.localSession) {
303
+ (0, core_utils_1.assert)(!this.normalizer.contains(alignedLocal), 0x759 /* Normalizer out of sync. */);
304
+ }
305
+ else {
306
+ throw new Error("Unknown ID");
801
307
  }
802
- return id;
803
- }
804
- else {
805
- const session = (_a = this.sessions.get(sessionIdIfLocal)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("No IDs have ever been finalized by the supplied session.");
806
- const localCount = -id;
807
- const numericUuid = (0, numericUuid_1.incrementUuid)(session.sessionUuid, localCount - 1);
808
- return ((_b = this.compressNumericUuid(numericUuid)) !== null && _b !== void 0 ? _b : (0, utils_1.fail)("ID is not known to this compressor."));
809
308
  }
309
+ return (0, utilities_1.stableIdFromNumericUuid)((0, utilities_1.offsetNumericUuid)(containingCluster.session.sessionUuid, alignedGenCount - 1));
810
310
  }
811
- const normalizedId = this.sessionIdNormalizer.getSessionSpaceId(id);
812
- if (normalizedId !== undefined) {
813
- return normalizedId;
814
- }
815
- // Check for a unified override finalized first by another session but to which the local session
816
- // still has an associated local ID.
817
- const [_, cluster] = (_c = this.getClusterForFinalId(id)) !== null && _c !== void 0 ? _c : (0, utils_1.fail)("Supplied final ID was not finalized by this compressor.");
818
- const override = (_d = cluster.overrides) === null || _d === void 0 ? void 0 : _d.get(id);
819
- if (typeof override === "object" && override.associatedLocalId !== undefined) {
820
- return override.associatedLocalId;
821
- }
822
- return id;
823
- }
824
- /**
825
- * Returns the session-space compressed ID corresponding to the numeric UUID, or undefined if it is not known to this compressor.
826
- * Typically, it will return the session-space ID sequentially aligned with it (which will be local if `numericUuid` was made by
827
- * the local session, or final otherwise). However, in the event that the aligned session-space ID was overridden with a UUID
828
- * *and* that override UUID was concurrently used in an older ID (earlier, w.r.t. sequencing), this method can return the first
829
- * ID to correspond to that override.
830
- *
831
- * As an example, consider the following two clients:
832
- * ClientA, session UUID: A0000000-0000-0000-0000-000000000000
833
- * ClientB, session UUID: B0000000-0000-0000-0000-000000000000
834
- *
835
- * If concurrently, two clients performed:
836
- * ClientA: generateCompressedId(override: 'X0000000-0000-0000-0000-000000000000') // aligned with A0000000-0000-0000-0000-000000000000
837
- *
838
- * ClientB: generateCompressedId() // aligned with B0000000-0000-0000-0000-000000000000
839
- * ClientB: generateCompressedId(override: 'X0000000-0000-0000-0000-000000000000') // aligned with B0000000-0000-0000-0000-000000000001
840
- *
841
- * After sequencing, calling this method and passing the numeric UUID for B0000000-0000-0000-0000-000000000001 would return the
842
- * session-space ID corresponding to A0000000-0000-0000-0000-000000000000 (with override X0000000-0000-0000-0000-000000000000).
843
- */
844
- compressNumericUuid(numericUuid) {
845
- const stableId = (0, numericUuid_1.stableIdFromNumericUuid)(numericUuid);
846
- const sessionSpaceId = this.recompressInternal(stableId, numericUuid);
847
- if (sessionSpaceId === undefined) {
848
- return undefined;
849
- }
850
- return sessionSpaceId;
851
- }
852
- /**
853
- * Returns a compressed ID for the supplied stable ID if it was created by the local session, and undefined otherwise.
854
- */
855
- getCompressedIdForStableId(stableId) {
856
- const numericUuid = typeof stableId === "string" ? (0, numericUuid_1.numericUuidFromStableId)(stableId) : stableId;
857
- const creationIndex = (0, numericUuid_1.getPositiveDelta)(numericUuid, this.localSession.sessionUuid, this.localIdCount - 1);
858
- if (creationIndex !== undefined) {
859
- const sessionSpaceId = this.sessionIdNormalizer.getIdByCreationIndex(creationIndex);
860
- if (sessionSpaceId !== undefined) {
861
- return sessionSpaceId;
311
+ else {
312
+ const localToDecompress = id;
313
+ if (!this.normalizer.contains(localToDecompress)) {
314
+ throw new Error("Unknown ID");
862
315
  }
316
+ return (0, utilities_1.stableIdFromNumericUuid)((0, utilities_1.offsetNumericUuid)(this.localSession.sessionUuid, (0, utilities_1.genCountFromLocalId)(localToDecompress) - 1));
863
317
  }
864
- return undefined;
865
318
  }
866
- getClusterForFinalId(finalId) {
867
- const possibleCluster = this.finalIdToCluster.getPairOrNextLower(finalId);
868
- if (possibleCluster === undefined) {
869
- return undefined;
870
- }
871
- const [clusterBase, cluster] = possibleCluster;
872
- if (finalId - clusterBase >= cluster.count) {
873
- return undefined;
319
+ recompress(uncompressed) {
320
+ const recompressed = this.tryRecompress(uncompressed);
321
+ if (recompressed === undefined) {
322
+ throw new Error("Could not recompress.");
874
323
  }
875
- return possibleCluster;
324
+ return recompressed;
876
325
  }
877
- /**
878
- * @returns if `other` is equal to this `IdCompressor`. The equality check includes local session state only if specified.
879
- * \@testOnly
880
- */
881
- equals(other, compareLocalState) {
882
- if (compareLocalState) {
883
- if (this.localIdCount !== other.localIdCount ||
884
- this.localSessionId !== other.localSessionId ||
885
- this.lastTakenLocalId !== other.lastTakenLocalId) {
886
- return false;
887
- }
888
- if (!this.localOverrides.equals(other.localOverrides, (a, b) => a === b)) {
889
- return false;
890
- }
891
- if (!(0, utils_1.compareMaps)(this.sessions, other.sessions, (a, b) => IdCompressor.sessionDataEqual(a, b, true, compareLocalState))) {
892
- return false;
893
- }
894
- if (!this.sessionIdNormalizer.equals(other.sessionIdNormalizer, (a, b) => IdCompressor.idClustersEqual(a, b, false, compareLocalState))) {
895
- return false;
896
- }
897
- }
898
- else {
899
- for (const [keyA, valueA] of this.sessions) {
900
- const valueB = other.sessions.get(keyA);
901
- if (valueB === undefined) {
902
- if (valueA.lastFinalizedLocalId !== undefined) {
903
- return false;
904
- }
905
- }
906
- else if (!IdCompressor.sessionDataEqual(valueA, valueB, true, compareLocalState)) {
907
- return false;
908
- }
909
- }
910
- for (const [keyB, valueB] of other.sessions) {
911
- const valueA = this.sessions.get(keyB);
912
- if (valueA === undefined) {
913
- if (valueB.lastFinalizedLocalId !== undefined) {
914
- return false;
915
- }
326
+ tryRecompress(uncompressed) {
327
+ const match = this.sessions.getContainingCluster(uncompressed);
328
+ if (match === undefined) {
329
+ const numericUncompressed = (0, utilities_1.numericUuidFromStableId)(uncompressed);
330
+ const offset = (0, utilities_1.subtractNumericUuids)(numericUncompressed, this.localSession.sessionUuid);
331
+ if (offset < Number.MAX_SAFE_INTEGER) {
332
+ const genCountEquivalent = Number(offset) + 1;
333
+ const localEquivalent = (0, utilities_1.localIdFromGenCount)(genCountEquivalent);
334
+ if (this.normalizer.contains(localEquivalent)) {
335
+ return localEquivalent;
916
336
  }
917
337
  }
338
+ return undefined;
918
339
  }
919
- if (this.nextClusterBaseFinalId !== other.nextClusterBaseFinalId ||
920
- this.newClusterCapacity !== other.newClusterCapacity) {
921
- return false;
922
- }
923
- if (!this.finalIdToCluster.equals(other.finalIdToCluster, (a, b) => IdCompressor.idClustersEqual(a, b, true, compareLocalState))) {
924
- return false;
925
- }
926
- const missingInOne = (_, value) => {
927
- if (!compareLocalState && IdCompressor.isUnfinalizedOverride(value)) {
928
- return undefined;
929
- }
930
- return { break: true };
931
- };
932
- const compareCompressionMappings = (a, b) => {
933
- const unfinalizedA = IdCompressor.isUnfinalizedOverride(a);
934
- const unfinalizedB = IdCompressor.isUnfinalizedOverride(b);
935
- if (unfinalizedA) {
936
- if (unfinalizedB) {
937
- return a === b;
340
+ else {
341
+ const [containingCluster, alignedLocal] = match;
342
+ if (containingCluster.session === this.localSession) {
343
+ // Local session
344
+ if (this.normalizer.contains(alignedLocal)) {
345
+ return alignedLocal;
938
346
  }
939
- return false;
940
- }
941
- else if (unfinalizedB) {
942
- return false;
943
- }
944
- if (IdCompressor.isClusterInfo(a)) {
945
- if (!IdCompressor.isClusterInfo(b) || a.clusterBase !== b.clusterBase) {
946
- return false;
347
+ else {
348
+ (0, core_utils_1.assert)((0, utilities_1.genCountFromLocalId)(alignedLocal) <= this.localGenCount, 0x75a /* Clusters out of sync. */);
349
+ // Id is an eager final
350
+ return (0, sessions_1.getAlignedFinal)(containingCluster, alignedLocal);
947
351
  }
948
352
  }
949
353
  else {
950
- if (IdCompressor.isClusterInfo(b) ||
951
- (compareLocalState && a.associatedLocalId !== b.associatedLocalId) ||
952
- a.originalOverridingFinal !== b.originalOverridingFinal) {
953
- return false;
954
- }
955
- }
956
- if (!IdCompressor.idClustersEqual(a.cluster, b.cluster, true, compareLocalState)) {
957
- return false;
958
- }
959
- return true;
960
- };
961
- const diff = this.clustersAndOverridesInversion.diffAgainst(other.clustersAndOverridesInversion, missingInOne, missingInOne, (_, valA, valB) => {
962
- if (!compareCompressionMappings(valA, valB)) {
963
- return { break: true };
964
- }
965
- return undefined;
354
+ // Not the local session
355
+ return (0, utilities_1.genCountFromLocalId)(alignedLocal) >= (0, sessions_1.lastFinalizedLocal)(containingCluster)
356
+ ? (0, sessions_1.getAlignedFinal)(containingCluster, alignedLocal)
357
+ : undefined;
358
+ }
359
+ }
360
+ }
361
+ serialize(hasLocalState) {
362
+ const { normalizer, finalSpace, sessions } = this;
363
+ const sessionIndexMap = new Map();
364
+ let sessionIndex = 0;
365
+ for (const session of sessions.sessions()) {
366
+ // Filter empty sessions to prevent them accumulating in the serialized state
367
+ if (!session.isEmpty() || hasLocalState) {
368
+ sessionIndexMap.set(session, sessionIndex);
369
+ sessionIndex++;
370
+ }
371
+ }
372
+ const localStateSize = hasLocalState
373
+ ? 1 + // generated ID count
374
+ 1 + // next range base genCount
375
+ 1 + // count of normalizer pairs
376
+ this.normalizer.idRanges.size * 2 // pairs
377
+ : 0;
378
+ // Layout size, in 8 byte increments
379
+ const totalSize = 1 + // version
380
+ 1 + // hasLocalState
381
+ 1 + // cluster capacity
382
+ 1 + // session count
383
+ 1 + // cluster count
384
+ sessionIndexMap.size * 2 + // session IDs
385
+ finalSpace.clusters.length * 3 + // clusters: (sessionIndex, capacity, count)[]
386
+ localStateSize; // local state, if present
387
+ const serializedFloat = new Float64Array(totalSize);
388
+ const serializedUint = new BigUint64Array(serializedFloat.buffer);
389
+ let index = 0;
390
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, currentWrittenVersion);
391
+ index = (0, persistanceUtilities_1.writeBoolean)(serializedFloat, index, hasLocalState);
392
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, this.clusterCapacity);
393
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, sessionIndexMap.size);
394
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, finalSpace.clusters.length);
395
+ for (const [session] of sessionIndexMap.entries()) {
396
+ index = (0, persistanceUtilities_1.writeNumericUuid)(serializedUint, index, session.sessionUuid);
397
+ }
398
+ finalSpace.clusters.forEach((cluster) => {
399
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, sessionIndexMap.get(cluster.session));
400
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, cluster.capacity);
401
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, cluster.count);
966
402
  });
967
- return diff === undefined;
968
- }
969
- static sessionDataEqual(a, b, checkCluster = true, compareLocalState = true) {
970
- if (!(0, numericUuid_1.numericUuidEquals)(a.sessionUuid, b.sessionUuid) ||
971
- a.lastFinalizedLocalId !== b.lastFinalizedLocalId) {
972
- return false;
973
- }
974
- if (a.currentClusterDetails === undefined || b.currentClusterDetails === undefined) {
975
- if (a.currentClusterDetails !== b.currentClusterDetails) {
976
- return false;
977
- }
978
- return true;
979
- }
980
- if (checkCluster &&
981
- !IdCompressor.idClustersEqual(a.currentClusterDetails.cluster, b.currentClusterDetails.cluster, false, compareLocalState)) {
982
- return false;
983
- }
984
- return true;
985
- }
986
- static idClustersEqual(a, b, checkSessionData = true, compareLocalState = true) {
987
- var _a, _b;
988
- const areEqual = (0, numericUuid_1.numericUuidEquals)(a.baseUuid, b.baseUuid) &&
989
- a.capacity === b.capacity &&
990
- a.count === b.count &&
991
- (!checkSessionData ||
992
- IdCompressor.sessionDataEqual(a.session, b.session, false, compareLocalState)) &&
993
- (a.overrides === undefined) === (b.overrides === undefined) &&
994
- (a.overrides === undefined ||
995
- (0, utils_1.compareMaps)((_a = a.overrides) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("Overrides must be defined"), (_b = b.overrides) !== null && _b !== void 0 ? _b : (0, utils_1.fail)("Overrides must be defined"), (overrideA, overrideB) => {
996
- if (compareLocalState) {
997
- if (typeof overrideA === "string" || typeof overrideB === "string") {
998
- return overrideA === overrideB;
999
- }
1000
- const overridesEqual = overrideA.override === overrideB.override &&
1001
- overrideA.originalOverridingFinal ===
1002
- overrideB.originalOverridingFinal &&
1003
- (!compareLocalState ||
1004
- overrideA.associatedLocalId === overrideB.associatedLocalId);
1005
- return overridesEqual;
1006
- }
1007
- const uuidA = typeof overrideA === "string" ? overrideA : overrideA.override;
1008
- const uuidB = typeof overrideB === "string" ? overrideB : overrideB.override;
1009
- if (typeof overrideA !== "string" &&
1010
- typeof overrideB !== "string" &&
1011
- overrideA.originalOverridingFinal !== overrideB.originalOverridingFinal) {
1012
- return false;
1013
- }
1014
- return uuidA === uuidB;
1015
- }));
1016
- return areEqual;
1017
- }
1018
- serialize(withSession) {
1019
- var _a, _b;
1020
- const serializedSessions = [];
1021
- const sessionIdToSessionIndex = new Map();
1022
- for (const [sessionId, session] of this.sessions) {
1023
- const isLocalSession = sessionId === this.localSessionId;
1024
- const includeSession = sessionId !== reservedSessionId && // Ignore reserved clusters, but
1025
- (session.lastFinalizedLocalId !== undefined || // always serialize sessions that made final IDs,
1026
- (isLocalSession && withSession)); // include the un-acked local session if requested
1027
- if (includeSession) {
1028
- const sessionData = [sessionId];
1029
- sessionIdToSessionIndex.set(sessionId, serializedSessions.length);
1030
- serializedSessions.push(sessionData);
1031
- }
1032
- }
1033
- const serializedClusters = [];
1034
- for (const [baseFinalId, cluster] of this.finalIdToCluster.entries()) {
1035
- const sessionId = (0, numericUuid_1.stableIdFromNumericUuid)(cluster.session.sessionUuid);
1036
- if (sessionId !== reservedSessionId) {
1037
- const sessionIndex = (_a = sessionIdToSessionIndex.get(sessionId)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("Session object contains wrong session numeric UUID");
1038
- const serializedCluster = [
1039
- sessionIndex,
1040
- cluster.capacity,
1041
- ];
1042
- if (cluster.count !== cluster.capacity) {
1043
- serializedCluster.push(cluster.count);
1044
- }
1045
- if (cluster.overrides !== undefined) {
1046
- const serializedOverrides = [];
1047
- for (const [finalId, override] of cluster.overrides) {
1048
- const finalIdIndex = finalId - baseFinalId;
1049
- if (typeof override === "string") {
1050
- serializedOverrides.push([finalIdIndex, override]);
1051
- }
1052
- else if (override.originalOverridingFinal === finalId) {
1053
- serializedOverrides.push([finalIdIndex, override.override]);
1054
- }
1055
- else {
1056
- serializedOverrides.push([
1057
- finalIdIndex,
1058
- override.override,
1059
- override.originalOverridingFinal,
1060
- ]);
1061
- }
1062
- }
1063
- serializedCluster.push(serializedOverrides);
1064
- }
1065
- serializedClusters.push(serializedCluster);
1066
- }
1067
- }
1068
- // Reserved session not serialized, and local session is present but may not make IDs
1069
- (0, common_utils_1.assert)(serializedSessions.length - this.sessions.size <= 2, 0x498 /* session not serialized */);
1070
- const serializedIdCompressor = {
1071
- version: currentWrittenVersion,
1072
- clusterCapacity: this.clusterCapacity,
1073
- sessions: serializedSessions,
1074
- clusters: serializedClusters,
1075
- };
1076
- if (withSession) {
1077
- const serializedWithSession = serializedIdCompressor;
1078
- serializedWithSession.localSessionIndex = serializedWithSession.sessions.findIndex(([sessionId]) => sessionId === this.localSessionId);
1079
- if (this.localIdCount > 0) {
1080
- serializedWithSession.localState = {
1081
- localIdCount: this.localIdCount,
1082
- overrides: [...this.localOverrides.entries()].map((entry) => [...entry]),
1083
- lastTakenLocalId: this.lastTakenLocalId,
1084
- sessionNormalizer: this.sessionIdNormalizer.serialize(),
1085
- };
403
+ if (hasLocalState) {
404
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, this.localGenCount);
405
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, this.nextRangeBaseGenCount);
406
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, normalizer.idRanges.size);
407
+ for (const [leadingGenCount, count] of normalizer.idRanges.entries()) {
408
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, leadingGenCount);
409
+ index = (0, persistanceUtilities_1.writeNumber)(serializedFloat, index, count);
1086
410
  }
1087
- return serializedWithSession;
1088
411
  }
1089
- (_b = this.logger) === null || _b === void 0 ? void 0 : _b.sendTelemetryEvent({
412
+ (0, core_utils_1.assert)(index === totalSize, 0x75b /* Serialized size was incorrectly calculated. */);
413
+ this.logger?.sendTelemetryEvent({
1090
414
  eventName: "RuntimeIdCompressor:SerializedIdCompressorSize",
1091
- size: JSON.stringify(serializedIdCompressor).length,
1092
- clusterCount: serializedIdCompressor.clusters.length,
1093
- sessionCount: serializedIdCompressor.sessions.length,
415
+ size: serializedFloat.byteLength,
416
+ clusterCount: finalSpace.clusters.length,
417
+ sessionCount: sessionIndexMap.size,
1094
418
  });
1095
- return serializedIdCompressor;
1096
- }
1097
- static deserialize(...args) {
1098
- const [serialized, newSessionIdMaybe] = args;
1099
- const { clusterCapacity, sessions: serializedSessions, clusters: serializedClusters, } = serialized;
1100
- let localSessionId;
1101
- let serializedLocalState;
1102
- if (newSessionIdMaybe === undefined) {
1103
- // Alias of serialized, but known to be a SerializedIdCompressorWithOngoingSession
1104
- const [serializedWithSession] = args;
1105
- const serializedSessionData = serializedSessions[serializedWithSession.localSessionIndex];
1106
- localSessionId = serializedSessionData[0];
1107
- serializedLocalState = serializedWithSession.localState;
419
+ return (0, client_utils_1.bufferToString)(serializedFloat.buffer, "base64");
420
+ }
421
+ static deserialize(serialized, sessionId) {
422
+ const buffer = (0, client_utils_1.stringToBuffer)(serialized, "base64");
423
+ const index = {
424
+ index: 0,
425
+ bufferFloat: new Float64Array(buffer),
426
+ bufferUint: new BigUint64Array(buffer),
427
+ };
428
+ const version = (0, persistanceUtilities_1.readNumber)(index);
429
+ (0, core_utils_1.assert)(version === currentWrittenVersion, 0x75c /* Unknown serialized version. */);
430
+ const hasLocalState = (0, persistanceUtilities_1.readBoolean)(index);
431
+ const clusterCapacity = (0, persistanceUtilities_1.readNumber)(index);
432
+ const sessionCount = (0, persistanceUtilities_1.readNumber)(index);
433
+ const clusterCount = (0, persistanceUtilities_1.readNumber)(index);
434
+ // Sessions
435
+ let sessionOffset = 0;
436
+ const sessions = [];
437
+ if (!hasLocalState) {
438
+ // If !hasLocalState, there won't be a serialized local session ID so insert one at the beginning
439
+ (0, core_utils_1.assert)(sessionId !== undefined, 0x75d /* Local session ID is undefined. */);
440
+ const localSessionNumeric = (0, utilities_1.numericUuidFromStableId)(sessionId);
441
+ sessions.push([localSessionNumeric, new sessions_1.Session(localSessionNumeric)]);
442
+ sessionOffset = 1;
1108
443
  }
1109
444
  else {
1110
- localSessionId = newSessionIdMaybe;
1111
- }
1112
- const compressor = new IdCompressor(localSessionId);
1113
- compressor.clusterCapacity = clusterCapacity;
1114
- const localOverridesInverse = new Map();
1115
- if (serializedLocalState !== undefined) {
1116
- // Do this part of local rehydration first since the cluster map population needs to query to local overrides
1117
- compressor.localIdCount = serializedLocalState.localIdCount;
1118
- compressor.lastTakenLocalId = serializedLocalState.lastTakenLocalId;
1119
- if (serializedLocalState.overrides !== undefined) {
1120
- for (const [localId, override] of serializedLocalState.overrides) {
1121
- compressor.localOverrides.append(localId, override);
1122
- localOverridesInverse.set(override, localId);
1123
- compressor.clustersAndOverridesInversion.set(IdCompressor.createInversionKey(override), localId);
1124
- }
1125
- }
1126
- }
1127
- const sessionInfos = [];
1128
- for (const serializedSession of serializedSessions) {
1129
- const [sessionId] = serializedSession;
1130
- if (sessionId === localSessionId) {
1131
- (0, common_utils_1.assert)(hasOngoingSession(serialized), 0x499 /* Cannot resume existing session. */);
1132
- sessionInfos.push({ session: compressor.localSession, sessionId });
1133
- }
1134
- else {
1135
- const session = compressor.createSession(sessionId);
1136
- sessionInfos.push({ session, sessionId });
1137
- }
1138
- }
1139
- for (const serializedCluster of serializedClusters) {
1140
- const { sessionIndex, capacity, count, overrides } = deserializeCluster(serializedCluster);
1141
- const { session, sessionId } = sessionInfos[sessionIndex];
1142
- const { lastFinalizedLocalId, sessionUuid } = session;
1143
- const currentIdCount = lastFinalizedLocalId === undefined ? 0 : -lastFinalizedLocalId;
1144
- const cluster = {
1145
- capacity,
1146
- count,
1147
- baseUuid: (0, numericUuid_1.incrementUuid)(sessionUuid, currentIdCount),
1148
- session,
1149
- };
1150
- const lastFinalizedNormalized = lastFinalizedLocalId !== null && lastFinalizedLocalId !== void 0 ? lastFinalizedLocalId : 0;
1151
- const clusterBase = compressor.nextClusterBaseFinalId;
1152
- session.lastFinalizedLocalId = (lastFinalizedNormalized - count);
1153
- session.currentClusterDetails = { clusterBase, cluster };
1154
- compressor.nextClusterBaseFinalId = (compressor.nextClusterBaseFinalId +
1155
- capacity);
1156
- compressor.finalIdToCluster.append(clusterBase, cluster);
1157
- compressor.clustersAndOverridesInversion.set((0, numericUuid_1.stableIdFromNumericUuid)(cluster.baseUuid), {
1158
- clusterBase,
1159
- cluster,
1160
- });
1161
- if (overrides !== undefined) {
1162
- cluster.overrides = new Map();
1163
- for (const [finalIdIndex, override, originalOverridingFinal] of overrides) {
1164
- const finalId = (clusterBase + finalIdIndex);
1165
- if (originalOverridingFinal !== undefined) {
1166
- const unifiedOverride = {
1167
- override,
1168
- originalOverridingFinal,
1169
- };
1170
- if (serializedLocalState !== undefined) {
1171
- (0, utils_1.setPropertyIfDefined)(localOverridesInverse.get(override), unifiedOverride, "associatedLocalId");
1172
- }
1173
- cluster.overrides.set(finalId, unifiedOverride);
1174
- }
1175
- else {
1176
- const associatedLocal = localOverridesInverse.get(override);
1177
- if (associatedLocal !== undefined && sessionId !== localSessionId) {
1178
- // In this case, there is a local ID associated with this override, but this is the first cluster to contain
1179
- // that override (because only the first cluster will have the string serialized). In this case, the override
1180
- // needs to hold that local value.
1181
- cluster.overrides.set(finalId, {
1182
- override,
1183
- originalOverridingFinal: finalId,
1184
- associatedLocalId: associatedLocal,
1185
- });
1186
- }
1187
- else {
1188
- cluster.overrides.set(finalId, override);
1189
- }
1190
- const finalizedOverride = {
1191
- cluster,
1192
- originalOverridingFinal: finalId,
1193
- };
1194
- if (serializedLocalState !== undefined) {
1195
- (0, utils_1.setPropertyIfDefined)(associatedLocal, finalizedOverride, "associatedLocalId");
1196
- }
1197
- compressor.clustersAndOverridesInversion.set(IdCompressor.createInversionKey(override), finalizedOverride);
1198
- }
1199
- }
1200
- }
445
+ (0, core_utils_1.assert)(sessionId === undefined, 0x75e /* Local state should not exist in serialized form. */);
1201
446
  }
1202
- if (serializedLocalState !== undefined) {
1203
- compressor.sessionIdNormalizer = sessionIdNormalizer_1.SessionIdNormalizer.deserialize(serializedLocalState.sessionNormalizer, (finalId) => {
1204
- var _a;
1205
- const [_, cluster] = (_a = compressor.finalIdToCluster.getPairOrNextLower(finalId)) !== null && _a !== void 0 ? _a : (0, utils_1.fail)("Final in serialized normalizer was never created.");
1206
- return cluster;
1207
- });
447
+ for (let i = 0; i < sessionCount; i++) {
448
+ const numeric = (0, persistanceUtilities_1.readNumericUuid)(index);
449
+ sessions.push([numeric, new sessions_1.Session(numeric)]);
1208
450
  }
1209
- (0, common_utils_1.assert)(compressor.localSession.lastFinalizedLocalId === undefined ||
1210
- compressor.localIdCount >= -compressor.localSession.lastFinalizedLocalId, 0x49a /* Inconsistent last finalized state when deserializing */);
451
+ const compressor = new IdCompressor(new sessions_1.Sessions(sessions));
452
+ compressor.clusterCapacity = clusterCapacity;
453
+ // Clusters
454
+ let baseFinalId = 0;
455
+ for (let i = 0; i < clusterCount; i++) {
456
+ const sessionIndex = (0, persistanceUtilities_1.readNumber)(index);
457
+ const session = sessions[sessionIndex + sessionOffset][1];
458
+ const capacity = (0, persistanceUtilities_1.readNumber)(index);
459
+ const count = (0, persistanceUtilities_1.readNumber)(index);
460
+ const cluster = session.addNewCluster(baseFinalId, capacity, count);
461
+ compressor.finalSpace.addCluster(cluster);
462
+ baseFinalId += capacity;
463
+ }
464
+ // Local state
465
+ if (hasLocalState) {
466
+ compressor.localGenCount = (0, persistanceUtilities_1.readNumber)(index);
467
+ compressor.nextRangeBaseGenCount = (0, persistanceUtilities_1.readNumber)(index);
468
+ const normalizerCount = (0, persistanceUtilities_1.readNumber)(index);
469
+ for (let i = 0; i < normalizerCount; i++) {
470
+ compressor.normalizer.addLocalRange((0, persistanceUtilities_1.readNumber)(index), (0, persistanceUtilities_1.readNumber)(index));
471
+ }
472
+ }
473
+ (0, core_utils_1.assert)(index.index === index.bufferFloat.length, 0x75f /* Failed to read entire serialized compressor. */);
1211
474
  return compressor;
1212
475
  }
1213
- static convertToCurrentVersion(serializedCompressor, hasSession) {
1214
- if (serializedCompressor.version !== currentWrittenVersion) {
1215
- (0, utils_1.fail)("Unknown SerializedIdCompressor version number");
1216
- }
1217
- const serialized = serializedCompressor;
1218
- if (hasSession !== hasOngoingSession(serialized)) {
1219
- return undefined;
476
+ equals(other, includeLocalState) {
477
+ if (includeLocalState &&
478
+ (this.localSessionId !== other.localSessionId ||
479
+ !this.localSession.equals(other.localSession) ||
480
+ !this.normalizer.equals(other.normalizer) ||
481
+ this.nextRangeBaseGenCount !== other.nextRangeBaseGenCount ||
482
+ this.localGenCount !== other.localGenCount)) {
483
+ return false;
1220
484
  }
1221
- return serialized;
485
+ return (this.newClusterCapacity === other.newClusterCapacity &&
486
+ this.sessions.equals(other.sessions, includeLocalState) &&
487
+ this.finalSpace.equals(other.finalSpace));
1222
488
  }
1223
489
  }
1224
490
  exports.IdCompressor = IdCompressor;
1225
491
  /**
1226
- * Max allowed cluster size
492
+ * Max allowed initial cluster size.
1227
493
  */
1228
494
  IdCompressor.maxClusterSize = 2 ** 20;
1229
- /**
1230
- * The version of `IdCompressor` that is currently persisted.
1231
- */
1232
- const currentWrittenVersion = "0.0.1";
1233
- /**
1234
- * @returns whether or not the given serialized ID compressor has an ongoing session.
1235
- */
1236
- function hasOngoingSession(serialized) {
1237
- return (serialized.localSessionIndex !==
1238
- undefined);
1239
- }
1240
- exports.hasOngoingSession = hasOngoingSession;
1241
- function deserializeCluster(serializedCluster) {
1242
- const [sessionIndex, capacity, countOrOverrides, overrides] = serializedCluster;
1243
- const hasCount = typeof countOrOverrides === "number";
1244
- return {
1245
- sessionIndex,
1246
- capacity,
1247
- count: hasCount ? countOrOverrides : capacity,
1248
- overrides: hasCount ? overrides : countOrOverrides,
1249
- };
1250
- }
1251
- /**
1252
- * Optimization used by the sorted-btree library to avoid allocating tuples every time a lookup method is called.
1253
- * Lookup methods on BTree accept a pre-allocated array that it populates with the result of the lookup and retains no ownership
1254
- * of after the call, so this array may be supplied to any of them. References to this array should not be retained elsewhere and
1255
- * lookup results should be extracted from the tuple immediately after invocation.
1256
- */
1257
- const reusedArray = [];
1258
495
  //# sourceMappingURL=idCompressor.js.map