@fluidframework/container-runtime 2.0.0-internal.3.0.2 → 2.0.0-internal.3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/.eslintrc.js +19 -19
  2. package/.mocharc.js +2 -2
  3. package/api-extractor.json +2 -2
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js +2 -1
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +15 -2
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +109 -37
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +11 -9
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerHandleContext.d.ts.map +1 -1
  15. package/dist/containerHandleContext.js +3 -1
  16. package/dist/containerHandleContext.js.map +1 -1
  17. package/dist/containerRuntime.d.ts +23 -11
  18. package/dist/containerRuntime.d.ts.map +1 -1
  19. package/dist/containerRuntime.js +225 -132
  20. package/dist/containerRuntime.js.map +1 -1
  21. package/dist/dataStore.d.ts.map +1 -1
  22. package/dist/dataStore.js +11 -9
  23. package/dist/dataStore.js.map +1 -1
  24. package/dist/dataStoreContext.d.ts +27 -13
  25. package/dist/dataStoreContext.d.ts.map +1 -1
  26. package/dist/dataStoreContext.js +95 -56
  27. package/dist/dataStoreContext.js.map +1 -1
  28. package/dist/dataStoreContexts.d.ts.map +1 -1
  29. package/dist/dataStoreContexts.js +7 -3
  30. package/dist/dataStoreContexts.js.map +1 -1
  31. package/dist/dataStoreRegistry.d.ts.map +1 -1
  32. package/dist/dataStoreRegistry.js +3 -1
  33. package/dist/dataStoreRegistry.js.map +1 -1
  34. package/dist/dataStores.d.ts +28 -4
  35. package/dist/dataStores.d.ts.map +1 -1
  36. package/dist/dataStores.js +122 -44
  37. package/dist/dataStores.js.map +1 -1
  38. package/dist/deltaScheduler.d.ts.map +1 -1
  39. package/dist/deltaScheduler.js +8 -3
  40. package/dist/deltaScheduler.js.map +1 -1
  41. package/dist/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +27 -203
  42. package/dist/gc/garbageCollection.d.ts.map +1 -0
  43. package/dist/{garbageCollection.js → gc/garbageCollection.js} +210 -400
  44. package/dist/gc/garbageCollection.js.map +1 -0
  45. package/dist/gc/gcDefinitions.d.ts +189 -0
  46. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  47. package/dist/{garbageCollectionConstants.js → gc/gcDefinitions.js} +27 -2
  48. package/dist/gc/gcDefinitions.js.map +1 -0
  49. package/dist/gc/gcHelpers.d.ts +30 -0
  50. package/dist/gc/gcHelpers.d.ts.map +1 -0
  51. package/dist/gc/gcHelpers.js +65 -0
  52. package/dist/gc/gcHelpers.js.map +1 -0
  53. package/dist/gc/gcSummaryStateTracker.d.ts +86 -0
  54. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  55. package/dist/gc/gcSummaryStateTracker.js +246 -0
  56. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  57. package/{lib → dist/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  58. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  59. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  60. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  61. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  62. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  63. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  64. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  65. package/dist/gc/index.d.ts +11 -0
  66. package/dist/gc/index.d.ts.map +1 -0
  67. package/dist/gc/index.js +40 -0
  68. package/dist/gc/index.js.map +1 -0
  69. package/dist/index.d.ts +2 -5
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +6 -9
  72. package/dist/index.js.map +1 -1
  73. package/dist/opLifecycle/batchManager.d.ts +2 -13
  74. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  75. package/dist/opLifecycle/batchManager.js +19 -41
  76. package/dist/opLifecycle/batchManager.js.map +1 -1
  77. package/dist/opLifecycle/definitions.d.ts +4 -0
  78. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  79. package/dist/opLifecycle/definitions.js.map +1 -1
  80. package/dist/opLifecycle/index.d.ts.map +1 -1
  81. package/dist/opLifecycle/index.js.map +1 -1
  82. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  83. package/dist/opLifecycle/opCompressor.js +1 -0
  84. package/dist/opLifecycle/opCompressor.js.map +1 -1
  85. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  86. package/dist/opLifecycle/opDecompressor.js +5 -2
  87. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  88. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  89. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  90. package/dist/opLifecycle/opSplitter.js +24 -13
  91. package/dist/opLifecycle/opSplitter.js.map +1 -1
  92. package/dist/opLifecycle/outbox.d.ts +19 -3
  93. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  94. package/dist/opLifecycle/outbox.js +78 -45
  95. package/dist/opLifecycle/outbox.js.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  97. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  98. package/dist/opProperties.d.ts.map +1 -1
  99. package/dist/opProperties.js +1 -3
  100. package/dist/opProperties.js.map +1 -1
  101. package/dist/packageVersion.d.ts +1 -1
  102. package/dist/packageVersion.js +1 -1
  103. package/dist/packageVersion.js.map +1 -1
  104. package/dist/pendingStateManager.d.ts +8 -2
  105. package/dist/pendingStateManager.d.ts.map +1 -1
  106. package/dist/pendingStateManager.js +21 -13
  107. package/dist/pendingStateManager.js.map +1 -1
  108. package/dist/scheduleManager.d.ts.map +1 -1
  109. package/dist/scheduleManager.js +3 -2
  110. package/dist/scheduleManager.js.map +1 -1
  111. package/dist/serializedSnapshotStorage.d.ts +2 -2
  112. package/dist/serializedSnapshotStorage.d.ts.map +1 -1
  113. package/dist/serializedSnapshotStorage.js +5 -3
  114. package/dist/serializedSnapshotStorage.js.map +1 -1
  115. package/dist/summary/index.d.ts +17 -0
  116. package/dist/summary/index.d.ts.map +1 -0
  117. package/dist/summary/index.js +47 -0
  118. package/dist/summary/index.js.map +1 -0
  119. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  120. package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  121. package/dist/summary/orderedClientElection.js.map +1 -0
  122. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  123. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  124. package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
  125. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  126. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -76
  127. package/dist/summary/runningSummarizer.js.map +1 -0
  128. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -6
  129. package/dist/summary/summarizer.d.ts.map +1 -0
  130. package/dist/{summarizer.js → summary/summarizer.js} +31 -71
  131. package/dist/summary/summarizer.js.map +1 -0
  132. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  133. package/dist/summary/summarizerClientElection.js.map +1 -0
  134. package/dist/summary/summarizerHandle.d.ts.map +1 -0
  135. package/dist/summary/summarizerHandle.js.map +1 -0
  136. package/{lib → dist/summary}/summarizerHeuristics.d.ts +1 -1
  137. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  138. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -9
  139. package/dist/summary/summarizerHeuristics.js.map +1 -0
  140. package/{lib → dist/summary}/summarizerTypes.d.ts +22 -22
  141. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  142. package/dist/summary/summarizerTypes.js.map +1 -0
  143. package/dist/summary/summaryCollection.d.ts.map +1 -0
  144. package/dist/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  145. package/dist/summary/summaryCollection.js.map +1 -0
  146. package/{lib → dist/summary}/summaryFormat.d.ts +1 -40
  147. package/dist/summary/summaryFormat.d.ts.map +1 -0
  148. package/dist/{summaryFormat.js → summary/summaryFormat.js} +19 -20
  149. package/dist/summary/summaryFormat.js.map +1 -0
  150. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  151. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +33 -15
  152. package/dist/summary/summaryGenerator.js.map +1 -0
  153. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  154. package/dist/summary/summaryManager.d.ts.map +1 -0
  155. package/dist/{summaryManager.js → summary/summaryManager.js} +21 -9
  156. package/dist/summary/summaryManager.js.map +1 -0
  157. package/dist/throttler.d.ts +2 -2
  158. package/dist/throttler.d.ts.map +1 -1
  159. package/dist/throttler.js +4 -4
  160. package/dist/throttler.js.map +1 -1
  161. package/lib/batchTracker.d.ts.map +1 -1
  162. package/lib/batchTracker.js +2 -1
  163. package/lib/batchTracker.js.map +1 -1
  164. package/lib/blobManager.d.ts +15 -2
  165. package/lib/blobManager.d.ts.map +1 -1
  166. package/lib/blobManager.js +109 -37
  167. package/lib/blobManager.js.map +1 -1
  168. package/lib/connectionTelemetry.d.ts.map +1 -1
  169. package/lib/connectionTelemetry.js +11 -9
  170. package/lib/connectionTelemetry.js.map +1 -1
  171. package/lib/containerHandleContext.d.ts.map +1 -1
  172. package/lib/containerHandleContext.js +3 -1
  173. package/lib/containerHandleContext.js.map +1 -1
  174. package/lib/containerRuntime.d.ts +23 -11
  175. package/lib/containerRuntime.d.ts.map +1 -1
  176. package/lib/containerRuntime.js +201 -108
  177. package/lib/containerRuntime.js.map +1 -1
  178. package/lib/dataStore.d.ts.map +1 -1
  179. package/lib/dataStore.js +11 -9
  180. package/lib/dataStore.js.map +1 -1
  181. package/lib/dataStoreContext.d.ts +27 -13
  182. package/lib/dataStoreContext.d.ts.map +1 -1
  183. package/lib/dataStoreContext.js +84 -45
  184. package/lib/dataStoreContext.js.map +1 -1
  185. package/lib/dataStoreContexts.d.ts.map +1 -1
  186. package/lib/dataStoreContexts.js +7 -3
  187. package/lib/dataStoreContexts.js.map +1 -1
  188. package/lib/dataStoreRegistry.d.ts.map +1 -1
  189. package/lib/dataStoreRegistry.js +3 -1
  190. package/lib/dataStoreRegistry.js.map +1 -1
  191. package/lib/dataStores.d.ts +28 -4
  192. package/lib/dataStores.d.ts.map +1 -1
  193. package/lib/dataStores.js +120 -42
  194. package/lib/dataStores.js.map +1 -1
  195. package/lib/deltaScheduler.d.ts.map +1 -1
  196. package/lib/deltaScheduler.js +9 -4
  197. package/lib/deltaScheduler.js.map +1 -1
  198. package/lib/{garbageCollection.d.ts → gc/garbageCollection.d.ts} +27 -203
  199. package/lib/gc/garbageCollection.d.ts.map +1 -0
  200. package/lib/{garbageCollection.js → gc/garbageCollection.js} +190 -379
  201. package/lib/gc/garbageCollection.js.map +1 -0
  202. package/lib/gc/gcDefinitions.d.ts +189 -0
  203. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  204. package/lib/{garbageCollectionConstants.js → gc/gcDefinitions.js} +26 -1
  205. package/lib/gc/gcDefinitions.js.map +1 -0
  206. package/lib/gc/gcHelpers.d.ts +30 -0
  207. package/lib/gc/gcHelpers.d.ts.map +1 -0
  208. package/lib/gc/gcHelpers.js +58 -0
  209. package/lib/gc/gcHelpers.js.map +1 -0
  210. package/lib/gc/gcSummaryStateTracker.d.ts +86 -0
  211. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  212. package/lib/gc/gcSummaryStateTracker.js +242 -0
  213. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  214. package/{dist → lib/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  215. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  216. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  217. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  218. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  219. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  220. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  221. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  222. package/lib/gc/index.d.ts +11 -0
  223. package/lib/gc/index.d.ts.map +1 -0
  224. package/lib/gc/index.js +11 -0
  225. package/lib/gc/index.js.map +1 -0
  226. package/lib/index.d.ts +2 -5
  227. package/lib/index.d.ts.map +1 -1
  228. package/lib/index.js +1 -4
  229. package/lib/index.js.map +1 -1
  230. package/lib/opLifecycle/batchManager.d.ts +2 -13
  231. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  232. package/lib/opLifecycle/batchManager.js +19 -41
  233. package/lib/opLifecycle/batchManager.js.map +1 -1
  234. package/lib/opLifecycle/definitions.d.ts +4 -0
  235. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  236. package/lib/opLifecycle/definitions.js.map +1 -1
  237. package/lib/opLifecycle/index.d.ts.map +1 -1
  238. package/lib/opLifecycle/index.js.map +1 -1
  239. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  240. package/lib/opLifecycle/opCompressor.js +1 -0
  241. package/lib/opLifecycle/opCompressor.js.map +1 -1
  242. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  243. package/lib/opLifecycle/opDecompressor.js +5 -2
  244. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  245. package/lib/opLifecycle/opSplitter.d.ts +1 -1
  246. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  247. package/lib/opLifecycle/opSplitter.js +25 -14
  248. package/lib/opLifecycle/opSplitter.js.map +1 -1
  249. package/lib/opLifecycle/outbox.d.ts +19 -3
  250. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  251. package/lib/opLifecycle/outbox.js +79 -46
  252. package/lib/opLifecycle/outbox.js.map +1 -1
  253. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  254. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  255. package/lib/opProperties.d.ts.map +1 -1
  256. package/lib/opProperties.js +1 -3
  257. package/lib/opProperties.js.map +1 -1
  258. package/lib/packageVersion.d.ts +1 -1
  259. package/lib/packageVersion.js +1 -1
  260. package/lib/packageVersion.js.map +1 -1
  261. package/lib/pendingStateManager.d.ts +8 -2
  262. package/lib/pendingStateManager.d.ts.map +1 -1
  263. package/lib/pendingStateManager.js +21 -13
  264. package/lib/pendingStateManager.js.map +1 -1
  265. package/lib/scheduleManager.d.ts.map +1 -1
  266. package/lib/scheduleManager.js +3 -2
  267. package/lib/scheduleManager.js.map +1 -1
  268. package/lib/serializedSnapshotStorage.d.ts +2 -2
  269. package/lib/serializedSnapshotStorage.d.ts.map +1 -1
  270. package/lib/serializedSnapshotStorage.js +5 -3
  271. package/lib/serializedSnapshotStorage.js.map +1 -1
  272. package/lib/summary/index.d.ts +17 -0
  273. package/lib/summary/index.d.ts.map +1 -0
  274. package/lib/summary/index.js +16 -0
  275. package/lib/summary/index.js.map +1 -0
  276. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  277. package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  278. package/lib/summary/orderedClientElection.js.map +1 -0
  279. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  280. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  281. package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
  282. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  283. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +193 -78
  284. package/lib/summary/runningSummarizer.js.map +1 -0
  285. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -6
  286. package/lib/summary/summarizer.d.ts.map +1 -0
  287. package/lib/{summarizer.js → summary/summarizer.js} +33 -73
  288. package/lib/summary/summarizer.js.map +1 -0
  289. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  290. package/lib/summary/summarizerClientElection.js.map +1 -0
  291. package/lib/summary/summarizerHandle.d.ts.map +1 -0
  292. package/lib/summary/summarizerHandle.js.map +1 -0
  293. package/{dist → lib/summary}/summarizerHeuristics.d.ts +1 -1
  294. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  295. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -9
  296. package/lib/summary/summarizerHeuristics.js.map +1 -0
  297. package/{dist → lib/summary}/summarizerTypes.d.ts +22 -22
  298. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  299. package/lib/summary/summarizerTypes.js.map +1 -0
  300. package/lib/summary/summaryCollection.d.ts.map +1 -0
  301. package/lib/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  302. package/lib/summary/summaryCollection.js.map +1 -0
  303. package/{dist → lib/summary}/summaryFormat.d.ts +1 -40
  304. package/lib/summary/summaryFormat.d.ts.map +1 -0
  305. package/lib/{summaryFormat.js → summary/summaryFormat.js} +20 -20
  306. package/lib/summary/summaryFormat.js.map +1 -0
  307. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  308. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +33 -15
  309. package/lib/summary/summaryGenerator.js.map +1 -0
  310. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  311. package/lib/summary/summaryManager.d.ts.map +1 -0
  312. package/lib/{summaryManager.js → summary/summaryManager.js} +21 -9
  313. package/lib/summary/summaryManager.js.map +1 -0
  314. package/lib/throttler.d.ts +2 -2
  315. package/lib/throttler.d.ts.map +1 -1
  316. package/lib/throttler.js +4 -4
  317. package/lib/throttler.js.map +1 -1
  318. package/package.json +60 -51
  319. package/prettier.config.cjs +1 -1
  320. package/src/batchTracker.ts +54 -49
  321. package/src/blobManager.ts +825 -674
  322. package/src/connectionTelemetry.ts +280 -249
  323. package/src/containerHandleContext.ts +27 -29
  324. package/src/containerRuntime.ts +3249 -2978
  325. package/src/dataStore.ts +172 -159
  326. package/src/dataStoreContext.ts +1141 -1057
  327. package/src/dataStoreContexts.ts +178 -161
  328. package/src/dataStoreRegistry.ts +25 -20
  329. package/src/dataStores.ts +880 -731
  330. package/src/deltaScheduler.ts +158 -150
  331. package/{garbageCollection.md → src/gc/garbageCollection.md} +16 -3
  332. package/src/gc/garbageCollection.ts +1506 -0
  333. package/src/gc/gcDefinitions.ts +244 -0
  334. package/src/gc/gcHelpers.ts +86 -0
  335. package/src/gc/gcSummaryStateTracker.ts +339 -0
  336. package/src/gc/gcSweepReadyUsageDetection.ts +145 -0
  337. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  338. package/src/gc/index.ts +40 -0
  339. package/src/index.ts +67 -70
  340. package/src/opLifecycle/README.md +152 -0
  341. package/src/opLifecycle/batchManager.ts +101 -144
  342. package/src/opLifecycle/definitions.ts +33 -29
  343. package/src/opLifecycle/index.ts +5 -5
  344. package/src/opLifecycle/opCompressor.ts +55 -53
  345. package/src/opLifecycle/opDecompressor.ts +100 -81
  346. package/src/opLifecycle/opSplitter.ts +233 -188
  347. package/src/opLifecycle/outbox.ts +251 -195
  348. package/src/opLifecycle/remoteMessageProcessor.ts +62 -62
  349. package/src/opProperties.ts +11 -9
  350. package/src/packageVersion.ts +1 -1
  351. package/src/pendingStateManager.ts +396 -338
  352. package/src/scheduleManager.ts +299 -269
  353. package/src/serializedSnapshotStorage.ts +126 -112
  354. package/src/summary/index.ts +99 -0
  355. package/src/summary/orderedClientElection.ts +564 -0
  356. package/src/summary/runWhileConnectedCoordinator.ts +113 -0
  357. package/src/summary/runningSummarizer.ts +788 -0
  358. package/src/summary/summarizer.ts +386 -0
  359. package/src/summary/summarizerClientElection.ts +139 -0
  360. package/src/{summarizerHandle.ts → summary/summarizerHandle.ts} +11 -9
  361. package/src/summary/summarizerHeuristics.ts +219 -0
  362. package/src/summary/summarizerTypes.ts +521 -0
  363. package/src/summary/summaryCollection.ts +450 -0
  364. package/src/summary/summaryFormat.ts +226 -0
  365. package/src/summary/summaryGenerator.ts +505 -0
  366. package/src/summary/summaryManager.ts +423 -0
  367. package/src/throttler.ts +131 -122
  368. package/tsconfig.esnext.json +6 -6
  369. package/tsconfig.json +9 -13
  370. package/dist/garbageCollection.d.ts.map +0 -1
  371. package/dist/garbageCollection.js.map +0 -1
  372. package/dist/garbageCollectionConstants.d.ts +0 -25
  373. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  374. package/dist/garbageCollectionConstants.js.map +0 -1
  375. package/dist/garbageCollectionTombstoneUtils.d.ts +0 -14
  376. package/dist/garbageCollectionTombstoneUtils.d.ts.map +0 -1
  377. package/dist/garbageCollectionTombstoneUtils.js +0 -23
  378. package/dist/garbageCollectionTombstoneUtils.js.map +0 -1
  379. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  380. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  381. package/dist/orderedClientElection.d.ts.map +0 -1
  382. package/dist/orderedClientElection.js.map +0 -1
  383. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  384. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  385. package/dist/runningSummarizer.d.ts.map +0 -1
  386. package/dist/runningSummarizer.js.map +0 -1
  387. package/dist/summarizer.d.ts.map +0 -1
  388. package/dist/summarizer.js.map +0 -1
  389. package/dist/summarizerClientElection.d.ts.map +0 -1
  390. package/dist/summarizerClientElection.js.map +0 -1
  391. package/dist/summarizerHandle.d.ts.map +0 -1
  392. package/dist/summarizerHandle.js.map +0 -1
  393. package/dist/summarizerHeuristics.d.ts.map +0 -1
  394. package/dist/summarizerHeuristics.js.map +0 -1
  395. package/dist/summarizerTypes.d.ts.map +0 -1
  396. package/dist/summarizerTypes.js.map +0 -1
  397. package/dist/summaryCollection.d.ts.map +0 -1
  398. package/dist/summaryCollection.js.map +0 -1
  399. package/dist/summaryFormat.d.ts.map +0 -1
  400. package/dist/summaryFormat.js.map +0 -1
  401. package/dist/summaryGenerator.d.ts.map +0 -1
  402. package/dist/summaryGenerator.js.map +0 -1
  403. package/dist/summaryManager.d.ts.map +0 -1
  404. package/dist/summaryManager.js.map +0 -1
  405. package/lib/garbageCollection.d.ts.map +0 -1
  406. package/lib/garbageCollection.js.map +0 -1
  407. package/lib/garbageCollectionConstants.d.ts +0 -25
  408. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  409. package/lib/garbageCollectionConstants.js.map +0 -1
  410. package/lib/garbageCollectionTombstoneUtils.d.ts +0 -14
  411. package/lib/garbageCollectionTombstoneUtils.d.ts.map +0 -1
  412. package/lib/garbageCollectionTombstoneUtils.js +0 -19
  413. package/lib/garbageCollectionTombstoneUtils.js.map +0 -1
  414. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  415. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  416. package/lib/orderedClientElection.d.ts.map +0 -1
  417. package/lib/orderedClientElection.js.map +0 -1
  418. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  419. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  420. package/lib/runningSummarizer.d.ts.map +0 -1
  421. package/lib/runningSummarizer.js.map +0 -1
  422. package/lib/summarizer.d.ts.map +0 -1
  423. package/lib/summarizer.js.map +0 -1
  424. package/lib/summarizerClientElection.d.ts.map +0 -1
  425. package/lib/summarizerClientElection.js.map +0 -1
  426. package/lib/summarizerHandle.d.ts.map +0 -1
  427. package/lib/summarizerHandle.js.map +0 -1
  428. package/lib/summarizerHeuristics.d.ts.map +0 -1
  429. package/lib/summarizerHeuristics.js.map +0 -1
  430. package/lib/summarizerTypes.d.ts.map +0 -1
  431. package/lib/summarizerTypes.js.map +0 -1
  432. package/lib/summaryCollection.d.ts.map +0 -1
  433. package/lib/summaryCollection.js.map +0 -1
  434. package/lib/summaryFormat.d.ts.map +0 -1
  435. package/lib/summaryFormat.js.map +0 -1
  436. package/lib/summaryGenerator.d.ts.map +0 -1
  437. package/lib/summaryGenerator.js.map +0 -1
  438. package/lib/summaryManager.d.ts.map +0 -1
  439. package/lib/summaryManager.js.map +0 -1
  440. package/src/garbageCollection.ts +0 -1800
  441. package/src/garbageCollectionConstants.ts +0 -41
  442. package/src/garbageCollectionTombstoneUtils.ts +0 -28
  443. package/src/gcSweepReadyUsageDetection.ts +0 -139
  444. package/src/orderedClientElection.ts +0 -532
  445. package/src/runWhileConnectedCoordinator.ts +0 -106
  446. package/src/runningSummarizer.ts +0 -610
  447. package/src/summarizer.ts +0 -421
  448. package/src/summarizerClientElection.ts +0 -132
  449. package/src/summarizerHeuristics.ts +0 -222
  450. package/src/summarizerTypes.ts +0 -507
  451. package/src/summaryCollection.ts +0 -421
  452. package/src/summaryFormat.ts +0 -256
  453. package/src/summaryGenerator.ts +0 -450
  454. package/src/summaryManager.ts +0 -394
  455. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  456. /package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
  457. /package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
  458. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  459. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  460. /package/dist/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
  461. /package/dist/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
  462. /package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
  463. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  464. /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  465. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  466. /package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +0 -0
  467. /package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +0 -0
  468. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  469. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  470. /package/lib/{summarizerHandle.d.ts → summary/summarizerHandle.d.ts} +0 -0
  471. /package/lib/{summarizerHandle.js → summary/summarizerHandle.js} +0 -0
  472. /package/lib/{summarizerTypes.js → summary/summarizerTypes.js} +0 -0
  473. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  474. /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
@@ -7,9 +7,7 @@ import { IDisposable } from "@fluidframework/common-definitions";
7
7
  import { assert, Lazy } from "@fluidframework/common-utils";
8
8
  import { ICriticalContainerError } from "@fluidframework/container-definitions";
9
9
  import { DataProcessingError } from "@fluidframework/container-utils";
10
- import {
11
- ISequencedDocumentMessage,
12
- } from "@fluidframework/protocol-definitions";
10
+ import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
13
11
  import Deque from "double-ended-queue";
14
12
  import { ContainerMessageType } from "./containerRuntime";
15
13
  import { pkgVersion } from "./packageVersion";
@@ -17,15 +15,16 @@ import { pkgVersion } from "./packageVersion";
17
15
  /**
18
16
  * This represents a message that has been submitted and is added to the pending queue when `submit` is called on the
19
17
  * ContainerRuntime. This message has either not been ack'd by the server or has not been submitted to the server yet.
18
+ * @deprecated - This interface will no longer be exported in a future version
20
19
  */
21
20
  export interface IPendingMessage {
22
- type: "message";
23
- messageType: ContainerMessageType;
24
- clientSequenceNumber: number;
25
- referenceSequenceNumber: number;
26
- content: any;
27
- localOpMetadata: unknown;
28
- opMetadata: Record<string, unknown> | undefined;
21
+ type: "message";
22
+ messageType: ContainerMessageType;
23
+ clientSequenceNumber: number;
24
+ referenceSequenceNumber: number;
25
+ content: any;
26
+ localOpMetadata: unknown;
27
+ opMetadata: Record<string, unknown> | undefined;
29
28
  }
30
29
 
31
30
  /**
@@ -34,33 +33,40 @@ export interface IPendingMessage {
34
33
  * @deprecated Use batch metadata on IPendingMessage instead. To be removed in 2.0.0-internal.4.0.0 (AB#2496)
35
34
  */
36
35
  export interface IPendingFlush {
37
- type: "flush";
36
+ type: "flush";
38
37
  }
39
38
 
39
+ /**
40
+ * @deprecated - This interface will no longer be exported in a future version
41
+ */
40
42
  export type IPendingState = IPendingMessage | IPendingFlush;
41
43
 
44
+ /**
45
+ * @deprecated - This interface will no longer be exported in a future version
46
+ */
42
47
  export interface IPendingLocalState {
43
- /**
44
- * list of pending states, including ops and batch information
45
- */
46
- pendingStates: IPendingState[];
48
+ /**
49
+ * list of pending states, including ops and batch information
50
+ */
51
+ pendingStates: IPendingState[];
47
52
  }
48
53
 
49
54
  export interface IRuntimeStateHandler {
50
- connected(): boolean;
51
- clientId(): string | undefined;
52
- close(error?: ICriticalContainerError): void;
53
- applyStashedOp: (type: ContainerMessageType, content: ISequencedDocumentMessage) => Promise<unknown>;
54
- reSubmit(
55
- type: ContainerMessageType,
56
- content: any,
57
- localOpMetadata: unknown,
58
- opMetadata: Record<string, unknown> | undefined): void;
59
- rollback(
60
- type: ContainerMessageType,
61
- content: any,
62
- localOpMetadata: unknown): void;
63
- orderSequentially(callback: () => void): void;
55
+ connected(): boolean;
56
+ clientId(): string | undefined;
57
+ close(error?: ICriticalContainerError): void;
58
+ applyStashedOp: (
59
+ type: ContainerMessageType,
60
+ content: ISequencedDocumentMessage,
61
+ ) => Promise<unknown>;
62
+ reSubmit(
63
+ type: ContainerMessageType,
64
+ content: any,
65
+ localOpMetadata: unknown,
66
+ opMetadata: Record<string, unknown> | undefined,
67
+ ): void;
68
+ rollback(type: ContainerMessageType, content: any, localOpMetadata: unknown): void;
69
+ orderSequentially(callback: () => void): void;
64
70
  }
65
71
 
66
72
  /**
@@ -73,313 +79,365 @@ export interface IRuntimeStateHandler {
73
79
  * It verifies that all the ops are acked, are received in the right order and batch information is correct.
74
80
  */
75
81
  export class PendingStateManager implements IDisposable {
76
- private readonly pendingMessages = new Deque<IPendingMessage>();
77
- private readonly initialMessages = new Deque<IPendingMessage>();
78
- private readonly disposeOnce = new Lazy<void>(() => {
79
- this.initialMessages.clear();
80
- this.pendingMessages.clear();
81
- });
82
-
83
- public get pendingMessagesCount(): number {
84
- return this.pendingMessages.length;
85
- }
86
-
87
- // Indicates whether we are processing a batch.
88
- private isProcessingBatch: boolean = false;
89
-
90
- // This stores the first message in the batch that we are processing. This is used to verify that we get
91
- // the correct batch metadata.
92
- private pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;
93
-
94
- private clientId: string | undefined;
95
-
96
- /**
97
- * Called to check if there are any pending messages in the pending message queue.
98
- * @returns A boolean indicating whether there are messages or not.
99
- */
100
- public hasPendingMessages(): boolean {
101
- return !this.pendingMessages.isEmpty() || !this.initialMessages.isEmpty();
102
- }
103
-
104
- public getLocalState(): IPendingLocalState | undefined {
105
- assert(this.initialMessages.isEmpty(), 0x2e9 /* "Must call getLocalState() after applying initial states" */);
106
- if (!this.pendingMessages.isEmpty()) {
107
- return {
108
- pendingStates: this.pendingMessages.toArray().reduce((arr, message) => {
109
- // delete localOpMetadata since it may not be serializable
110
- // and will be regenerated by applyStashedOp()
111
- arr.push({ ...message, localOpMetadata: undefined });
112
-
113
- // TODO: Remove in 2.0.0-internal.4.0.0 (AB#2496)
114
- if (message.opMetadata?.batch === false) {
115
- arr.push({ type: "flush" });
116
- }
117
- return arr;
118
- }, new Array<IPendingState>()),
119
- };
120
- }
121
- }
122
-
123
- constructor(
124
- private readonly stateHandler: IRuntimeStateHandler,
125
- initialLocalState: IPendingLocalState | undefined,
126
- ) {
127
- /**
128
- * Convert old local state format to the new format
129
- * The old format contained "flush" messages as the indicator of batch ends
130
- * The new format instead uses batch metadata on the last message to indicate batch ends
131
- * ! TODO: Remove this conversion in "2.0.0-internal.4.0.0" as rollback from future version will be new format
132
- * AB#2496 tracks removal
133
- */
134
- if (initialLocalState?.pendingStates) {
135
- const pendingStates = initialLocalState?.pendingStates;
136
- let currentlyBatching = false;
137
- for (let i = 0; i < pendingStates.length; i++) {
138
- const initialState = pendingStates[i];
139
-
140
- // Skip over "flush" messages
141
- if (initialState.type === "message") {
142
- if (initialState.opMetadata?.batch) {
143
- currentlyBatching = true;
144
- } else if (initialState.opMetadata?.batch === false) {
145
- currentlyBatching = false;
146
- } else if (
147
- // End of batch if we are currently batching and this is last message or next message is flush
148
- currentlyBatching
149
- && (i === pendingStates.length - 1 || pendingStates[i + 1].type === "flush")
150
- ) {
151
- currentlyBatching = false;
152
- initialState.opMetadata = { ...initialState.opMetadata, batch: false };
153
- }
154
- this.initialMessages.push(initialState);
155
- }
156
- }
157
- }
158
- }
159
-
160
- public get disposed() { return this.disposeOnce.evaluated; }
161
- public readonly dispose = () => this.disposeOnce.value;
162
-
163
- /**
164
- * Called when a message is submitted locally. Adds the message and the associated details to the pending state
165
- * queue.
166
- * @param type - The container message type.
167
- * @param clientSequenceNumber - The clientSequenceNumber associated with the message.
168
- * @param content - The message content.
169
- * @param localOpMetadata - The local metadata associated with the message.
170
- */
171
- public onSubmitMessage(
172
- type: ContainerMessageType,
173
- clientSequenceNumber: number,
174
- referenceSequenceNumber: number,
175
- content: any,
176
- localOpMetadata: unknown,
177
- opMetadata: Record<string, unknown> | undefined,
178
- ) {
179
- const pendingMessage: IPendingMessage = {
180
- type: "message",
181
- messageType: type,
182
- clientSequenceNumber,
183
- referenceSequenceNumber,
184
- content,
185
- localOpMetadata,
186
- opMetadata,
187
- };
188
-
189
- this.pendingMessages.push(pendingMessage);
190
- }
191
-
192
- /**
193
- * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted
194
- * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
195
- */
196
- public async applyStashedOpsAt(seqNum?: number) {
197
- // apply stashed ops at sequence number
198
- while (!this.initialMessages.isEmpty()) {
199
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
200
- const nextMessage = this.initialMessages.peekFront()!;
201
- if (seqNum !== undefined) {
202
- if (nextMessage.referenceSequenceNumber > seqNum) {
203
- break; // nothing left to do at this sequence number
204
- }
205
- if (nextMessage.referenceSequenceNumber < seqNum) {
206
- throw new Error("loaded from snapshot too recent to apply stashed ops");
207
- }
208
- }
209
-
210
- // applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it
211
- const localOpMetadata =
212
- await this.stateHandler.applyStashedOp(nextMessage.messageType, nextMessage.content);
213
- nextMessage.localOpMetadata = localOpMetadata;
214
-
215
- // then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect
216
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
217
- this.pendingMessages.push(this.initialMessages.shift()!);
218
- }
219
- }
220
-
221
- /**
222
- * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that
223
- * the batch information was preserved for batch messages.
224
- * @param message - The message that got ack'd and needs to be processed.
225
- */
226
- public processPendingLocalMessage(message: ISequencedDocumentMessage): unknown {
227
- // Pre-processing part - This may be the start of a batch.
228
- this.maybeProcessBatchBegin(message);
229
-
230
- // Get the next message from the pending queue. Verify a message exists.
231
- const pendingMessage = this.pendingMessages.peekFront();
232
- assert(pendingMessage !== undefined, 0x169 /* "No pending message found for this remote message" */);
233
- this.pendingMessages.shift();
234
-
235
- // Processing part - Verify that there has been no data corruption.
236
- // The clientSequenceNumber of the incoming message must match that of the pending message.
237
- if (pendingMessage.clientSequenceNumber !== message.clientSequenceNumber) {
238
- // Close the container because this could indicate data corruption.
239
- const error = DataProcessingError.create(
240
- "pending local message clientSequenceNumber mismatch",
241
- "unexpectedAckReceived",
242
- message,
243
- { expectedClientSequenceNumber: pendingMessage.clientSequenceNumber },
244
- );
245
-
246
- this.stateHandler.close(error);
247
- return;
248
- }
249
-
250
- // Post-processing part - If we are processing a batch then this could be the last message in the batch.
251
- this.maybeProcessBatchEnd(message);
252
-
253
- return pendingMessage.localOpMetadata;
254
- }
255
-
256
- /**
257
- * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.
258
- * @param message - The message that is being processed.
259
- */
260
- private maybeProcessBatchBegin(message: ISequencedDocumentMessage) {
261
- // This message is the first in a batch if the "batch" property on the metadata is set to true
262
- if (message.metadata?.batch) {
263
- // We should not already be processing a batch and there should be no pending batch begin message.
264
- assert(!this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,
265
- 0x16b /* "The pending batch state indicates we are already processing a batch" */);
266
-
267
- // Set the pending batch state indicating we have started processing a batch.
268
- this.pendingBatchBeginMessage = message;
269
- this.isProcessingBatch = true;
270
- }
271
- }
272
-
273
- /**
274
- * This message could be the last message in batch. If so, clear batch state since the batch is complete.
275
- * @param message - The message that is being processed.
276
- */
277
- private maybeProcessBatchEnd(message: ISequencedDocumentMessage) {
278
- if (!this.isProcessingBatch) {
279
- return;
280
- }
281
-
282
- // There should be a pending batch begin message.
283
- assert(this.pendingBatchBeginMessage !== undefined, 0x16d /* "There is no pending batch begin message" */);
284
-
285
- const batchEndMetadata = message.metadata?.batch;
286
- if (this.pendingMessages.isEmpty() || batchEndMetadata === false) {
287
- // Get the batch begin metadata from the first message in the batch.
288
- const batchBeginMetadata = this.pendingBatchBeginMessage.metadata?.batch;
289
-
290
- // There could be just a single message in the batch. If so, it should not have any batch metadata. If there
291
- // are multiple messages in the batch, verify that we got the correct batch begin and end metadata.
292
- if (this.pendingBatchBeginMessage === message) {
293
- assert(batchBeginMetadata === undefined,
294
- 0x16e /* "Batch with single message should not have batch metadata" */);
295
- } else {
296
- if (batchBeginMetadata !== true || batchEndMetadata !== false) {
297
- this.stateHandler.close(DataProcessingError.create(
298
- "Pending batch inconsistency", // Formerly known as asserts 0x16f and 0x170
299
- "processPendingLocalMessage",
300
- message,
301
- {
302
- runtimeVersion: pkgVersion,
303
- batchClientId: this.pendingBatchBeginMessage.clientId,
304
- clientId: this.stateHandler.clientId(),
305
- hasBatchStart: batchBeginMetadata === true,
306
- hasBatchEnd: batchEndMetadata === false,
307
- messageType: message.type,
308
- batchStartSequenceNumber: this.pendingBatchBeginMessage.clientSequenceNumber,
309
- pendingMessagesCount: this.pendingMessagesCount,
310
- }));
311
- }
312
- }
313
-
314
- // Clear the pending batch state now that we have processed the entire batch.
315
- this.pendingBatchBeginMessage = undefined;
316
- this.isProcessingBatch = false;
317
- }
318
- }
319
-
320
- /**
321
- * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending
322
- * states in its queue. This includes triggering resubmission of unacked ops.
323
- */
324
- public replayPendingStates() {
325
- assert(this.stateHandler.connected(), 0x172 /* "The connection state is not consistent with the runtime" */);
326
-
327
- // This assert suggests we are about to send same ops twice, which will result in data loss.
328
- assert(this.clientId !== this.stateHandler.clientId(),
329
- 0x173 /* "replayPendingStates called twice for same clientId!" */);
330
- this.clientId = this.stateHandler.clientId();
331
-
332
- assert(this.initialMessages.isEmpty(), 0x174 /* "initial states should be empty before replaying pending" */);
333
-
334
- let pendingMessagesCount = this.pendingMessages.length;
335
- if (pendingMessagesCount === 0) {
336
- return;
337
- }
338
-
339
- // Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were
340
- // pending when we connected. This is important because the `reSubmitFn` might add more items in the queue
341
- // which must not be replayed.
342
- while (pendingMessagesCount > 0) {
343
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
344
- let pendingMessage = this.pendingMessages.shift()!;
345
- pendingMessagesCount--;
346
- assert(pendingMessage.opMetadata?.batch !== false, 0x41b /* We cannot process batches in chunks */);
347
-
348
- /**
349
- * We want to ensure grouped messages get processed in a batch.
350
- * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will
351
- * either receive the whole batch ack or nothing at all.
352
- */
353
- if (pendingMessage.opMetadata?.batch) {
354
- assert(pendingMessagesCount > 0, 0x554 /* Last pending message cannot be a batch begin */);
355
-
356
- this.stateHandler.orderSequentially(() => {
357
- while (pendingMessagesCount >= 0) { // check is >= because batch end may be last pending message
358
- this.stateHandler.reSubmit(
359
- pendingMessage.messageType,
360
- pendingMessage.content,
361
- pendingMessage.localOpMetadata,
362
- pendingMessage.opMetadata);
363
-
364
- if (pendingMessage.opMetadata?.batch === false) {
365
- break;
366
- }
367
- assert(pendingMessagesCount > 0, 0x555 /* No batch end found */);
368
-
369
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
370
- pendingMessage = this.pendingMessages.shift()!;
371
- pendingMessagesCount--;
372
- assert(pendingMessage.opMetadata?.batch !== true,
373
- 0x556 /* Batch start needs a corresponding batch end */);
374
- }
375
- });
376
- } else {
377
- this.stateHandler.reSubmit(
378
- pendingMessage.messageType,
379
- pendingMessage.content,
380
- pendingMessage.localOpMetadata,
381
- pendingMessage.opMetadata);
382
- }
383
- }
384
- }
82
+ private readonly pendingMessages = new Deque<IPendingMessage>();
83
+ private readonly initialMessages = new Deque<IPendingMessage>();
84
+ private readonly disposeOnce = new Lazy<void>(() => {
85
+ this.initialMessages.clear();
86
+ this.pendingMessages.clear();
87
+ });
88
+
89
+ public get pendingMessagesCount(): number {
90
+ return this.pendingMessages.length;
91
+ }
92
+
93
+ // Indicates whether we are processing a batch.
94
+ private isProcessingBatch: boolean = false;
95
+
96
+ // This stores the first message in the batch that we are processing. This is used to verify that we get
97
+ // the correct batch metadata.
98
+ private pendingBatchBeginMessage: ISequencedDocumentMessage | undefined;
99
+
100
+ private clientId: string | undefined;
101
+
102
+ /**
103
+ * Called to check if there are any pending messages in the pending message queue.
104
+ * @returns A boolean indicating whether there are messages or not.
105
+ */
106
+ public hasPendingMessages(): boolean {
107
+ return !this.pendingMessages.isEmpty() || !this.initialMessages.isEmpty();
108
+ }
109
+
110
+ public getLocalState(): IPendingLocalState | undefined {
111
+ assert(
112
+ this.initialMessages.isEmpty(),
113
+ 0x2e9 /* "Must call getLocalState() after applying initial states" */,
114
+ );
115
+ if (!this.pendingMessages.isEmpty()) {
116
+ return {
117
+ pendingStates: this.pendingMessages.toArray().reduce((arr, message) => {
118
+ // delete localOpMetadata since it may not be serializable
119
+ // and will be regenerated by applyStashedOp()
120
+ arr.push({ ...message, localOpMetadata: undefined });
121
+
122
+ // TODO: Remove in 2.0.0-internal.4.0.0 (AB#2496)
123
+ if (message.opMetadata?.batch === false) {
124
+ arr.push({ type: "flush" });
125
+ }
126
+ return arr;
127
+ }, new Array<IPendingState>()),
128
+ };
129
+ }
130
+ }
131
+
132
+ constructor(
133
+ private readonly stateHandler: IRuntimeStateHandler,
134
+ initialLocalState: IPendingLocalState | undefined,
135
+ ) {
136
+ /**
137
+ * Convert old local state format to the new format
138
+ * The old format contained "flush" messages as the indicator of batch ends
139
+ * The new format instead uses batch metadata on the last message to indicate batch ends
140
+ * ! TODO: Remove this conversion in "2.0.0-internal.4.0.0" as rollback from future version will be new format
141
+ * AB#2496 tracks removal
142
+ */
143
+ if (initialLocalState?.pendingStates) {
144
+ const pendingStates = initialLocalState?.pendingStates;
145
+ let currentlyBatching = false;
146
+ for (let i = 0; i < pendingStates.length; i++) {
147
+ const initialState = pendingStates[i];
148
+
149
+ // Skip over "flush" messages
150
+ if (initialState.type === "message") {
151
+ if (initialState.opMetadata?.batch) {
152
+ currentlyBatching = true;
153
+ } else if (initialState.opMetadata?.batch === false) {
154
+ currentlyBatching = false;
155
+ } else if (
156
+ // End of batch if we are currently batching and this is last message or next message is flush
157
+ currentlyBatching &&
158
+ (i === pendingStates.length - 1 || pendingStates[i + 1].type === "flush")
159
+ ) {
160
+ currentlyBatching = false;
161
+ initialState.opMetadata = { ...initialState.opMetadata, batch: false };
162
+ }
163
+ this.initialMessages.push(initialState);
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ public get disposed() {
170
+ return this.disposeOnce.evaluated;
171
+ }
172
+ public readonly dispose = () => this.disposeOnce.value;
173
+
174
+ /**
175
+ * Called when a message is submitted locally. Adds the message and the associated details to the pending state
176
+ * queue.
177
+ * @param type - The container message type.
178
+ * @param content - The message content.
179
+ * @param localOpMetadata - The local metadata associated with the message.
180
+ */
181
+ public onSubmitMessage(
182
+ type: ContainerMessageType,
183
+ referenceSequenceNumber: number,
184
+ content: any,
185
+ localOpMetadata: unknown,
186
+ opMetadata: Record<string, unknown> | undefined,
187
+ ) {
188
+ const pendingMessage: IPendingMessage = {
189
+ type: "message",
190
+ messageType: type,
191
+ clientSequenceNumber: -1, // dummy value (not to be used anywhere)
192
+ referenceSequenceNumber,
193
+ content,
194
+ localOpMetadata,
195
+ opMetadata,
196
+ };
197
+
198
+ this.pendingMessages.push(pendingMessage);
199
+ }
200
+
201
+ /**
202
+ * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted
203
+ * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
204
+ */
205
+ public async applyStashedOpsAt(seqNum?: number) {
206
+ // apply stashed ops at sequence number
207
+ while (!this.initialMessages.isEmpty()) {
208
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
209
+ const nextMessage = this.initialMessages.peekFront()!;
210
+ if (seqNum !== undefined) {
211
+ if (nextMessage.referenceSequenceNumber > seqNum) {
212
+ break; // nothing left to do at this sequence number
213
+ }
214
+ if (nextMessage.referenceSequenceNumber < seqNum) {
215
+ throw new Error("loaded from snapshot too recent to apply stashed ops");
216
+ }
217
+ }
218
+
219
+ // applyStashedOp will cause the DDS to behave as if it has sent the op but not actually send it
220
+ const localOpMetadata = await this.stateHandler.applyStashedOp(
221
+ nextMessage.messageType,
222
+ nextMessage.content,
223
+ );
224
+ nextMessage.localOpMetadata = localOpMetadata;
225
+
226
+ // then we push onto pendingMessages which will cause PendingStateManager to resubmit when we connect
227
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
228
+ this.pendingMessages.push(this.initialMessages.shift()!);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Processes a local message once its ack'd by the server. It verifies that there was no data corruption and that
234
+ * the batch information was preserved for batch messages.
235
+ * @param message - The message that got ack'd and needs to be processed.
236
+ */
237
+ public processPendingLocalMessage(message: ISequencedDocumentMessage): unknown {
238
+ // Pre-processing part - This may be the start of a batch.
239
+ this.maybeProcessBatchBegin(message);
240
+
241
+ // Get the next message from the pending queue. Verify a message exists.
242
+ const pendingMessage = this.pendingMessages.peekFront();
243
+ assert(
244
+ pendingMessage !== undefined,
245
+ 0x169 /* "No pending message found for this remote message" */,
246
+ );
247
+ this.pendingMessages.shift();
248
+
249
+ if (pendingMessage.messageType !== message.type) {
250
+ // Close the container because this could indicate data corruption.
251
+ this.stateHandler.close(
252
+ DataProcessingError.create(
253
+ "pending local message type mismatch",
254
+ "unexpectedAckReceived",
255
+ message,
256
+ {
257
+ expectedMessageType: pendingMessage.messageType,
258
+ },
259
+ ),
260
+ );
261
+ return;
262
+ }
263
+
264
+ const pendingMessageContent = JSON.stringify(pendingMessage.content);
265
+ const messageContent = JSON.stringify(message.contents);
266
+
267
+ // Stringified content does not match
268
+ if (pendingMessageContent !== messageContent) {
269
+ // Close the container because this could indicate data corruption.
270
+ this.stateHandler.close(
271
+ DataProcessingError.create(
272
+ "pending local message content mismatch",
273
+ "unexpectedAckReceived",
274
+ message,
275
+ ),
276
+ );
277
+ return;
278
+ }
279
+
280
+ // Post-processing part - If we are processing a batch then this could be the last message in the batch.
281
+ this.maybeProcessBatchEnd(message);
282
+
283
+ return pendingMessage.localOpMetadata;
284
+ }
285
+
286
+ /**
287
+ * This message could be the first message in batch. If so, set batch state marking the beginning of a batch.
288
+ * @param message - The message that is being processed.
289
+ */
290
+ private maybeProcessBatchBegin(message: ISequencedDocumentMessage) {
291
+ // This message is the first in a batch if the "batch" property on the metadata is set to true
292
+ if (message.metadata?.batch) {
293
+ // We should not already be processing a batch and there should be no pending batch begin message.
294
+ assert(
295
+ !this.isProcessingBatch && this.pendingBatchBeginMessage === undefined,
296
+ 0x16b /* "The pending batch state indicates we are already processing a batch" */,
297
+ );
298
+
299
+ // Set the pending batch state indicating we have started processing a batch.
300
+ this.pendingBatchBeginMessage = message;
301
+ this.isProcessingBatch = true;
302
+ }
303
+ }
304
+
305
+ /**
306
+ * This message could be the last message in batch. If so, clear batch state since the batch is complete.
307
+ * @param message - The message that is being processed.
308
+ */
309
+ private maybeProcessBatchEnd(message: ISequencedDocumentMessage) {
310
+ if (!this.isProcessingBatch) {
311
+ return;
312
+ }
313
+
314
+ // There should be a pending batch begin message.
315
+ assert(
316
+ this.pendingBatchBeginMessage !== undefined,
317
+ 0x16d /* "There is no pending batch begin message" */,
318
+ );
319
+
320
+ const batchEndMetadata = message.metadata?.batch;
321
+ if (this.pendingMessages.isEmpty() || batchEndMetadata === false) {
322
+ // Get the batch begin metadata from the first message in the batch.
323
+ const batchBeginMetadata = this.pendingBatchBeginMessage.metadata?.batch;
324
+
325
+ // There could be just a single message in the batch. If so, it should not have any batch metadata. If there
326
+ // are multiple messages in the batch, verify that we got the correct batch begin and end metadata.
327
+ if (this.pendingBatchBeginMessage === message) {
328
+ assert(
329
+ batchBeginMetadata === undefined,
330
+ 0x16e /* "Batch with single message should not have batch metadata" */,
331
+ );
332
+ } else {
333
+ if (batchBeginMetadata !== true || batchEndMetadata !== false) {
334
+ this.stateHandler.close(
335
+ DataProcessingError.create(
336
+ "Pending batch inconsistency", // Formerly known as asserts 0x16f and 0x170
337
+ "processPendingLocalMessage",
338
+ message,
339
+ {
340
+ runtimeVersion: pkgVersion,
341
+ batchClientId: this.pendingBatchBeginMessage.clientId,
342
+ clientId: this.stateHandler.clientId(),
343
+ hasBatchStart: batchBeginMetadata === true,
344
+ hasBatchEnd: batchEndMetadata === false,
345
+ messageType: message.type,
346
+ pendingMessagesCount: this.pendingMessagesCount,
347
+ },
348
+ ),
349
+ );
350
+ }
351
+ }
352
+
353
+ // Clear the pending batch state now that we have processed the entire batch.
354
+ this.pendingBatchBeginMessage = undefined;
355
+ this.isProcessingBatch = false;
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Called when the Container's connection state changes. If the Container gets connected, it replays all the pending
361
+ * states in its queue. This includes triggering resubmission of unacked ops.
362
+ */
363
+ public replayPendingStates() {
364
+ assert(
365
+ this.stateHandler.connected(),
366
+ 0x172 /* "The connection state is not consistent with the runtime" */,
367
+ );
368
+
369
+ // This assert suggests we are about to send same ops twice, which will result in data loss.
370
+ assert(
371
+ this.clientId !== this.stateHandler.clientId(),
372
+ 0x173 /* "replayPendingStates called twice for same clientId!" */,
373
+ );
374
+ this.clientId = this.stateHandler.clientId();
375
+
376
+ assert(
377
+ this.initialMessages.isEmpty(),
378
+ 0x174 /* "initial states should be empty before replaying pending" */,
379
+ );
380
+
381
+ let pendingMessagesCount = this.pendingMessages.length;
382
+ if (pendingMessagesCount === 0) {
383
+ return;
384
+ }
385
+
386
+ // Process exactly `pendingMessagesCount` items in the queue as it represents the number of messages that were
387
+ // pending when we connected. This is important because the `reSubmitFn` might add more items in the queue
388
+ // which must not be replayed.
389
+ while (pendingMessagesCount > 0) {
390
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
391
+ let pendingMessage = this.pendingMessages.shift()!;
392
+ pendingMessagesCount--;
393
+ assert(
394
+ pendingMessage.opMetadata?.batch !== false,
395
+ 0x41b /* We cannot process batches in chunks */,
396
+ );
397
+
398
+ /**
399
+ * We want to ensure grouped messages get processed in a batch.
400
+ * Note: It is not possible for the PendingStateManager to receive a partially acked batch. It will
401
+ * either receive the whole batch ack or nothing at all.
402
+ */
403
+ if (pendingMessage.opMetadata?.batch) {
404
+ assert(
405
+ pendingMessagesCount > 0,
406
+ 0x554 /* Last pending message cannot be a batch begin */,
407
+ );
408
+
409
+ this.stateHandler.orderSequentially(() => {
410
+ while (pendingMessagesCount >= 0) {
411
+ // check is >= because batch end may be last pending message
412
+ this.stateHandler.reSubmit(
413
+ pendingMessage.messageType,
414
+ pendingMessage.content,
415
+ pendingMessage.localOpMetadata,
416
+ pendingMessage.opMetadata,
417
+ );
418
+
419
+ if (pendingMessage.opMetadata?.batch === false) {
420
+ break;
421
+ }
422
+ assert(pendingMessagesCount > 0, 0x555 /* No batch end found */);
423
+
424
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
425
+ pendingMessage = this.pendingMessages.shift()!;
426
+ pendingMessagesCount--;
427
+ assert(
428
+ pendingMessage.opMetadata?.batch !== true,
429
+ 0x556 /* Batch start needs a corresponding batch end */,
430
+ );
431
+ }
432
+ });
433
+ } else {
434
+ this.stateHandler.reSubmit(
435
+ pendingMessage.messageType,
436
+ pendingMessage.content,
437
+ pendingMessage.localOpMetadata,
438
+ pendingMessage.opMetadata,
439
+ );
440
+ }
441
+ }
442
+ }
385
443
  }