@fluidframework/container-runtime 2.0.0-dev.3.1.0.125672 → 2.0.0-dev.4.2.0.153917

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 (486) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +69 -0
  3. package/dist/blobManager.d.ts +29 -24
  4. package/dist/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager.js +162 -92
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +74 -76
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +328 -264
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +39 -13
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js +112 -49
  14. package/dist/dataStoreContext.js.map +1 -1
  15. package/dist/dataStores.d.ts +28 -4
  16. package/dist/dataStores.d.ts.map +1 -1
  17. package/dist/dataStores.js +107 -41
  18. package/dist/dataStores.js.map +1 -1
  19. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  20. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  21. package/dist/deltaManagerSummarizerProxy.js +40 -0
  22. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  23. package/dist/gc/garbageCollection.d.ts +204 -0
  24. package/dist/gc/garbageCollection.d.ts.map +1 -0
  25. package/dist/{garbageCollection.js → gc/garbageCollection.js} +190 -554
  26. package/dist/gc/garbageCollection.js.map +1 -0
  27. package/dist/gc/gcConfigs.d.ts +22 -0
  28. package/dist/gc/gcConfigs.d.ts.map +1 -0
  29. package/dist/gc/gcConfigs.js +143 -0
  30. package/dist/gc/gcConfigs.js.map +1 -0
  31. package/dist/gc/gcDefinitions.d.ts +320 -0
  32. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  33. package/dist/gc/gcDefinitions.js +81 -0
  34. package/dist/gc/gcDefinitions.js.map +1 -0
  35. package/dist/gc/gcHelpers.d.ts +86 -0
  36. package/dist/gc/gcHelpers.d.ts.map +1 -0
  37. package/dist/gc/gcHelpers.js +268 -0
  38. package/dist/gc/gcHelpers.js.map +1 -0
  39. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  40. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  41. package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
  42. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  43. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  44. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  45. package/dist/gc/gcSummaryDefinitions.js +7 -0
  46. package/dist/gc/gcSummaryDefinitions.js.map +1 -0
  47. package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
  48. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  49. package/dist/gc/gcSummaryStateTracker.js +239 -0
  50. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  51. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  52. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
  53. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  54. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  55. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  56. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  57. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  58. package/dist/gc/index.d.ts +13 -0
  59. package/dist/gc/index.d.ts.map +1 -0
  60. package/dist/gc/index.js +50 -0
  61. package/dist/gc/index.js.map +1 -0
  62. package/dist/index.d.ts +3 -7
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +5 -9
  65. package/dist/index.js.map +1 -1
  66. package/dist/opLifecycle/batchManager.d.ts +11 -13
  67. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  68. package/dist/opLifecycle/batchManager.js +26 -38
  69. package/dist/opLifecycle/batchManager.js.map +1 -1
  70. package/dist/opLifecycle/definitions.d.ts +4 -0
  71. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  72. package/dist/opLifecycle/definitions.js.map +1 -1
  73. package/dist/opLifecycle/index.d.ts +2 -1
  74. package/dist/opLifecycle/index.d.ts.map +1 -1
  75. package/dist/opLifecycle/index.js +4 -1
  76. package/dist/opLifecycle/index.js.map +1 -1
  77. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  78. package/dist/opLifecycle/opCompressor.js +25 -10
  79. package/dist/opLifecycle/opCompressor.js.map +1 -1
  80. package/dist/opLifecycle/opDecompressor.d.ts +4 -0
  81. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.js +43 -4
  83. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  84. package/dist/opLifecycle/opGroupingManager.d.ts +14 -0
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
  86. package/dist/opLifecycle/opGroupingManager.js +56 -0
  87. package/dist/opLifecycle/opGroupingManager.js.map +1 -0
  88. package/dist/opLifecycle/opSplitter.d.ts +16 -4
  89. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  90. package/dist/opLifecycle/opSplitter.js +39 -15
  91. package/dist/opLifecycle/opSplitter.js.map +1 -1
  92. package/dist/opLifecycle/outbox.d.ts +21 -3
  93. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  94. package/dist/opLifecycle/outbox.js +90 -51
  95. package/dist/opLifecycle/outbox.js.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  97. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  98. package/dist/opLifecycle/remoteMessageProcessor.js +30 -20
  99. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  100. package/dist/packageVersion.d.ts +1 -1
  101. package/dist/packageVersion.js +1 -1
  102. package/dist/packageVersion.js.map +1 -1
  103. package/dist/pendingStateManager.d.ts +3 -3
  104. package/dist/pendingStateManager.d.ts.map +1 -1
  105. package/dist/pendingStateManager.js +20 -21
  106. package/dist/pendingStateManager.js.map +1 -1
  107. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  108. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  109. package/dist/storageServiceWithAttachBlobs.js +32 -0
  110. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  111. package/dist/summary/index.d.ts +17 -0
  112. package/dist/summary/index.d.ts.map +1 -0
  113. package/dist/summary/index.js +48 -0
  114. package/dist/summary/index.js.map +1 -0
  115. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  116. package/dist/summary/orderedClientElection.js.map +1 -0
  117. package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  118. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  119. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  120. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  121. package/{lib → dist/summary}/runningSummarizer.d.ts +23 -20
  122. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  123. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -74
  124. package/dist/summary/runningSummarizer.js.map +1 -0
  125. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  126. package/dist/summary/summarizer.d.ts.map +1 -0
  127. package/dist/{summarizer.js → summary/summarizer.js} +10 -79
  128. package/dist/summary/summarizer.js.map +1 -0
  129. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  130. package/dist/summary/summarizerClientElection.js.map +1 -0
  131. package/dist/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
  132. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  133. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
  134. package/dist/summary/summarizerHeuristics.js.map +1 -0
  135. package/dist/summary/summarizerNode/index.d.ts +8 -0
  136. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  137. package/dist/summary/summarizerNode/index.js +12 -0
  138. package/dist/summary/summarizerNode/index.js.map +1 -0
  139. package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
  140. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  141. package/dist/summary/summarizerNode/summarizerNode.js +531 -0
  142. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
  143. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  144. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  145. package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
  146. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  147. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
  148. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  149. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +424 -0
  150. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  151. package/{lib → dist/summary}/summarizerTypes.d.ts +21 -19
  152. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  153. package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
  154. package/dist/summary/summarizerTypes.js.map +1 -0
  155. package/dist/summary/summaryCollection.d.ts.map +1 -0
  156. package/dist/summary/summaryCollection.js.map +1 -0
  157. package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
  158. package/dist/summary/summaryFormat.d.ts.map +1 -0
  159. package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
  160. package/dist/summary/summaryFormat.js.map +1 -0
  161. package/{lib → dist/summary}/summaryGenerator.d.ts +28 -2
  162. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  163. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +23 -20
  164. package/dist/summary/summaryGenerator.js.map +1 -0
  165. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  166. package/dist/summary/summaryManager.d.ts.map +1 -0
  167. package/dist/summary/summaryManager.js.map +1 -0
  168. package/lib/blobManager.d.ts +29 -24
  169. package/lib/blobManager.d.ts.map +1 -1
  170. package/lib/blobManager.js +159 -89
  171. package/lib/blobManager.js.map +1 -1
  172. package/lib/containerRuntime.d.ts +74 -76
  173. package/lib/containerRuntime.d.ts.map +1 -1
  174. package/lib/containerRuntime.js +301 -237
  175. package/lib/containerRuntime.js.map +1 -1
  176. package/lib/dataStoreContext.d.ts +39 -13
  177. package/lib/dataStoreContext.d.ts.map +1 -1
  178. package/lib/dataStoreContext.js +101 -38
  179. package/lib/dataStoreContext.js.map +1 -1
  180. package/lib/dataStores.d.ts +28 -4
  181. package/lib/dataStores.d.ts.map +1 -1
  182. package/lib/dataStores.js +100 -34
  183. package/lib/dataStores.js.map +1 -1
  184. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  185. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  186. package/lib/deltaManagerSummarizerProxy.js +36 -0
  187. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  188. package/lib/gc/garbageCollection.d.ts +204 -0
  189. package/lib/gc/garbageCollection.d.ts.map +1 -0
  190. package/lib/{garbageCollection.js → gc/garbageCollection.js} +172 -535
  191. package/lib/gc/garbageCollection.js.map +1 -0
  192. package/lib/gc/gcConfigs.d.ts +22 -0
  193. package/lib/gc/gcConfigs.d.ts.map +1 -0
  194. package/lib/gc/gcConfigs.js +139 -0
  195. package/lib/gc/gcConfigs.js.map +1 -0
  196. package/lib/gc/gcDefinitions.d.ts +320 -0
  197. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  198. package/lib/gc/gcDefinitions.js +78 -0
  199. package/lib/gc/gcDefinitions.js.map +1 -0
  200. package/lib/gc/gcHelpers.d.ts +86 -0
  201. package/lib/gc/gcHelpers.d.ts.map +1 -0
  202. package/lib/gc/gcHelpers.js +254 -0
  203. package/lib/gc/gcHelpers.js.map +1 -0
  204. package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  205. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  206. package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
  207. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  208. package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
  209. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  210. package/lib/gc/gcSummaryDefinitions.js +6 -0
  211. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  212. package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
  213. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  214. package/lib/gc/gcSummaryStateTracker.js +235 -0
  215. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  216. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  217. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
  218. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  219. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  220. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  221. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  222. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  223. package/lib/gc/index.d.ts +13 -0
  224. package/lib/gc/index.d.ts.map +1 -0
  225. package/lib/gc/index.js +12 -0
  226. package/lib/gc/index.js.map +1 -0
  227. package/lib/index.d.ts +3 -7
  228. package/lib/index.d.ts.map +1 -1
  229. package/lib/index.js +1 -4
  230. package/lib/index.js.map +1 -1
  231. package/lib/opLifecycle/batchManager.d.ts +11 -13
  232. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  233. package/lib/opLifecycle/batchManager.js +24 -37
  234. package/lib/opLifecycle/batchManager.js.map +1 -1
  235. package/lib/opLifecycle/definitions.d.ts +4 -0
  236. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  237. package/lib/opLifecycle/definitions.js.map +1 -1
  238. package/lib/opLifecycle/index.d.ts +2 -1
  239. package/lib/opLifecycle/index.d.ts.map +1 -1
  240. package/lib/opLifecycle/index.js +2 -1
  241. package/lib/opLifecycle/index.js.map +1 -1
  242. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  243. package/lib/opLifecycle/opCompressor.js +26 -11
  244. package/lib/opLifecycle/opCompressor.js.map +1 -1
  245. package/lib/opLifecycle/opDecompressor.d.ts +4 -0
  246. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  247. package/lib/opLifecycle/opDecompressor.js +43 -4
  248. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  249. package/lib/opLifecycle/opGroupingManager.d.ts +14 -0
  250. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
  251. package/lib/opLifecycle/opGroupingManager.js +52 -0
  252. package/lib/opLifecycle/opGroupingManager.js.map +1 -0
  253. package/lib/opLifecycle/opSplitter.d.ts +16 -4
  254. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  255. package/lib/opLifecycle/opSplitter.js +39 -15
  256. package/lib/opLifecycle/opSplitter.js.map +1 -1
  257. package/lib/opLifecycle/outbox.d.ts +21 -3
  258. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  259. package/lib/opLifecycle/outbox.js +92 -53
  260. package/lib/opLifecycle/outbox.js.map +1 -1
  261. package/lib/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  262. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  263. package/lib/opLifecycle/remoteMessageProcessor.js +30 -20
  264. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  265. package/lib/packageVersion.d.ts +1 -1
  266. package/lib/packageVersion.js +1 -1
  267. package/lib/packageVersion.js.map +1 -1
  268. package/lib/pendingStateManager.d.ts +3 -3
  269. package/lib/pendingStateManager.d.ts.map +1 -1
  270. package/lib/pendingStateManager.js +20 -21
  271. package/lib/pendingStateManager.js.map +1 -1
  272. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  273. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  274. package/lib/storageServiceWithAttachBlobs.js +28 -0
  275. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  276. package/lib/summary/index.d.ts +17 -0
  277. package/lib/summary/index.d.ts.map +1 -0
  278. package/lib/summary/index.js +16 -0
  279. package/lib/summary/index.js.map +1 -0
  280. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  281. package/lib/summary/orderedClientElection.js.map +1 -0
  282. package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  283. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  284. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  285. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  286. package/{dist → lib/summary}/runningSummarizer.d.ts +23 -20
  287. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  288. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +192 -75
  289. package/lib/summary/runningSummarizer.js.map +1 -0
  290. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  291. package/lib/summary/summarizer.d.ts.map +1 -0
  292. package/lib/{summarizer.js → summary/summarizer.js} +12 -81
  293. package/lib/summary/summarizer.js.map +1 -0
  294. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  295. package/lib/summary/summarizerClientElection.js.map +1 -0
  296. package/lib/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
  297. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  298. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
  299. package/lib/summary/summarizerHeuristics.js.map +1 -0
  300. package/lib/summary/summarizerNode/index.d.ts +8 -0
  301. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  302. package/lib/summary/summarizerNode/index.js +7 -0
  303. package/lib/summary/summarizerNode/index.js.map +1 -0
  304. package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
  305. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  306. package/lib/summary/summarizerNode/summarizerNode.js +526 -0
  307. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  308. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  309. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  310. package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
  311. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  312. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
  313. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  314. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
  315. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  316. package/{dist → lib/summary}/summarizerTypes.d.ts +21 -19
  317. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  318. package/lib/summary/summarizerTypes.js +6 -0
  319. package/lib/summary/summarizerTypes.js.map +1 -0
  320. package/lib/summary/summaryCollection.d.ts.map +1 -0
  321. package/lib/summary/summaryCollection.js.map +1 -0
  322. package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
  323. package/lib/summary/summaryFormat.d.ts.map +1 -0
  324. package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
  325. package/lib/summary/summaryFormat.js.map +1 -0
  326. package/{dist → lib/summary}/summaryGenerator.d.ts +28 -2
  327. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  328. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +21 -19
  329. package/lib/summary/summaryGenerator.js.map +1 -0
  330. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  331. package/lib/summary/summaryManager.d.ts.map +1 -0
  332. package/lib/summary/summaryManager.js.map +1 -0
  333. package/package.json +66 -60
  334. package/src/blobManager.ts +196 -110
  335. package/src/containerRuntime.ts +491 -391
  336. package/src/dataStoreContext.ts +140 -49
  337. package/src/dataStores.ts +139 -41
  338. package/src/deltaManagerSummarizerProxy.ts +46 -0
  339. package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
  340. package/src/{garbageCollection.ts → gc/garbageCollection.ts} +245 -890
  341. package/src/gc/gcConfigs.ts +193 -0
  342. package/src/gc/gcDefinitions.ts +387 -0
  343. package/src/gc/gcHelpers.ts +335 -0
  344. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  345. package/src/gc/gcSummaryDefinitions.ts +54 -0
  346. package/src/gc/gcSummaryStateTracker.ts +329 -0
  347. package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
  348. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  349. package/src/gc/index.ts +65 -0
  350. package/src/index.ts +10 -22
  351. package/src/opLifecycle/README.md +263 -0
  352. package/src/opLifecycle/batchManager.ts +26 -55
  353. package/src/opLifecycle/definitions.ts +4 -0
  354. package/src/opLifecycle/index.ts +2 -1
  355. package/src/opLifecycle/opCompressor.ts +32 -12
  356. package/src/opLifecycle/opDecompressor.ts +50 -5
  357. package/src/opLifecycle/opGroupingManager.ts +78 -0
  358. package/src/opLifecycle/opSplitter.ts +56 -17
  359. package/src/opLifecycle/outbox.ts +126 -62
  360. package/src/opLifecycle/remoteMessageProcessor.ts +38 -22
  361. package/src/packageVersion.ts +1 -1
  362. package/src/pendingStateManager.ts +34 -27
  363. package/src/storageServiceWithAttachBlobs.ts +38 -0
  364. package/src/summary/index.ts +105 -0
  365. package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +7 -7
  366. package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +318 -156
  367. package/src/{summarizer.ts → summary/summarizer.ts} +12 -105
  368. package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +13 -4
  369. package/src/summary/summarizerNode/index.ts +12 -0
  370. package/src/summary/summarizerNode/summarizerNode.ts +766 -0
  371. package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
  372. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
  373. package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +28 -25
  374. package/src/{summaryFormat.ts → summary/summaryFormat.ts} +3 -29
  375. package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +34 -27
  376. package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
  377. package/dist/garbageCollection.d.ts +0 -411
  378. package/dist/garbageCollection.d.ts.map +0 -1
  379. package/dist/garbageCollection.js.map +0 -1
  380. package/dist/garbageCollectionConstants.d.ts +0 -23
  381. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  382. package/dist/garbageCollectionConstants.js +0 -36
  383. package/dist/garbageCollectionConstants.js.map +0 -1
  384. package/dist/garbageCollectionHelpers.d.ts +0 -15
  385. package/dist/garbageCollectionHelpers.d.ts.map +0 -1
  386. package/dist/garbageCollectionHelpers.js +0 -27
  387. package/dist/garbageCollectionHelpers.js.map +0 -1
  388. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  389. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  390. package/dist/orderedClientElection.d.ts.map +0 -1
  391. package/dist/orderedClientElection.js.map +0 -1
  392. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  393. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  394. package/dist/runningSummarizer.d.ts.map +0 -1
  395. package/dist/runningSummarizer.js.map +0 -1
  396. package/dist/serializedSnapshotStorage.d.ts +0 -58
  397. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  398. package/dist/serializedSnapshotStorage.js +0 -110
  399. package/dist/serializedSnapshotStorage.js.map +0 -1
  400. package/dist/summarizer.d.ts.map +0 -1
  401. package/dist/summarizer.js.map +0 -1
  402. package/dist/summarizerClientElection.d.ts.map +0 -1
  403. package/dist/summarizerClientElection.js.map +0 -1
  404. package/dist/summarizerHandle.d.ts +0 -12
  405. package/dist/summarizerHandle.d.ts.map +0 -1
  406. package/dist/summarizerHandle.js +0 -22
  407. package/dist/summarizerHandle.js.map +0 -1
  408. package/dist/summarizerHeuristics.d.ts.map +0 -1
  409. package/dist/summarizerHeuristics.js.map +0 -1
  410. package/dist/summarizerTypes.d.ts.map +0 -1
  411. package/dist/summarizerTypes.js.map +0 -1
  412. package/dist/summaryCollection.d.ts.map +0 -1
  413. package/dist/summaryCollection.js.map +0 -1
  414. package/dist/summaryFormat.d.ts.map +0 -1
  415. package/dist/summaryFormat.js.map +0 -1
  416. package/dist/summaryGenerator.d.ts.map +0 -1
  417. package/dist/summaryGenerator.js.map +0 -1
  418. package/dist/summaryManager.d.ts.map +0 -1
  419. package/dist/summaryManager.js.map +0 -1
  420. package/lib/garbageCollection.d.ts +0 -411
  421. package/lib/garbageCollection.d.ts.map +0 -1
  422. package/lib/garbageCollection.js.map +0 -1
  423. package/lib/garbageCollectionConstants.d.ts +0 -23
  424. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  425. package/lib/garbageCollectionConstants.js +0 -33
  426. package/lib/garbageCollectionConstants.js.map +0 -1
  427. package/lib/garbageCollectionHelpers.d.ts +0 -15
  428. package/lib/garbageCollectionHelpers.d.ts.map +0 -1
  429. package/lib/garbageCollectionHelpers.js +0 -23
  430. package/lib/garbageCollectionHelpers.js.map +0 -1
  431. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  432. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  433. package/lib/orderedClientElection.d.ts.map +0 -1
  434. package/lib/orderedClientElection.js.map +0 -1
  435. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  436. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  437. package/lib/runningSummarizer.d.ts.map +0 -1
  438. package/lib/runningSummarizer.js.map +0 -1
  439. package/lib/serializedSnapshotStorage.d.ts +0 -58
  440. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  441. package/lib/serializedSnapshotStorage.js +0 -106
  442. package/lib/serializedSnapshotStorage.js.map +0 -1
  443. package/lib/summarizer.d.ts.map +0 -1
  444. package/lib/summarizer.js.map +0 -1
  445. package/lib/summarizerClientElection.d.ts.map +0 -1
  446. package/lib/summarizerClientElection.js.map +0 -1
  447. package/lib/summarizerHandle.d.ts +0 -12
  448. package/lib/summarizerHandle.d.ts.map +0 -1
  449. package/lib/summarizerHandle.js +0 -18
  450. package/lib/summarizerHandle.js.map +0 -1
  451. package/lib/summarizerHeuristics.d.ts.map +0 -1
  452. package/lib/summarizerHeuristics.js.map +0 -1
  453. package/lib/summarizerTypes.d.ts.map +0 -1
  454. package/lib/summarizerTypes.js +0 -9
  455. package/lib/summarizerTypes.js.map +0 -1
  456. package/lib/summaryCollection.d.ts.map +0 -1
  457. package/lib/summaryCollection.js.map +0 -1
  458. package/lib/summaryFormat.d.ts.map +0 -1
  459. package/lib/summaryFormat.js.map +0 -1
  460. package/lib/summaryGenerator.d.ts.map +0 -1
  461. package/lib/summaryGenerator.js.map +0 -1
  462. package/lib/summaryManager.d.ts.map +0 -1
  463. package/lib/summaryManager.js.map +0 -1
  464. package/src/garbageCollectionConstants.ts +0 -38
  465. package/src/garbageCollectionHelpers.ts +0 -37
  466. package/src/serializedSnapshotStorage.ts +0 -151
  467. package/src/summarizerHandle.ts +0 -23
  468. /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  469. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  470. /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  471. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  472. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  473. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  474. /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  475. /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
  476. /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  477. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  478. /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  479. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  480. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  481. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  482. /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  483. /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
  484. /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
  485. /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
  486. /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
@@ -13,6 +13,7 @@ import {
13
13
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
14
14
  import { ChildLogger } from "@fluidframework/telemetry-utils";
15
15
  import { ContainerMessageType, ContainerRuntimeMessage } from "../containerRuntime";
16
+ import { estimateSocketSize } from "./batchManager";
16
17
  import { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from "./definitions";
17
18
 
18
19
  /**
@@ -25,8 +26,10 @@ export class OpSplitter {
25
26
 
26
27
  constructor(
27
28
  chunks: [string, string[]][],
28
- private readonly submitBatchFn: ((batch: IBatchMessage[]) => number) | undefined,
29
- private readonly chunkSizeInBytes: number,
29
+ private readonly submitBatchFn:
30
+ | ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)
31
+ | undefined,
32
+ public readonly chunkSizeInBytes: number,
30
33
  private readonly maxBatchSizeInBytes: number,
31
34
  logger: ITelemetryLogger,
32
35
  ) {
@@ -132,12 +135,16 @@ export class OpSplitter {
132
135
  * @param batch - the compressed batch which needs to be processed
133
136
  * @returns A new adjusted batch which can be sent over the wire
134
137
  */
135
- public splitCompressedBatch(batch: IBatch): IBatch {
138
+ public splitFirstBatchMessage(batch: IBatch): IBatch {
136
139
  assert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);
137
140
  assert(
138
141
  batch.contentSizeInBytes > 0 && batch.content.length > 0,
139
142
  0x514 /* Batch needs to be non-empty */,
140
143
  );
144
+ assert(
145
+ batch.referenceSequenceNumber !== undefined,
146
+ 0x58a /* Batch must have a reference sequence number if non-empty */,
147
+ );
141
148
  assert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);
142
149
  assert(
143
150
  this.chunkSizeInBytes < this.maxBatchSizeInBytes,
@@ -145,43 +152,53 @@ export class OpSplitter {
145
152
  );
146
153
 
147
154
  const firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split
148
- assert(
149
- firstMessage.metadata?.compressed === true || firstMessage.compression !== undefined,
150
- 0x517 /* Batch needs to be compressed */,
151
- );
152
155
  assert(
153
156
  (firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,
154
157
  0x518 /* First message in the batch needs to be chunkable */,
155
158
  );
156
159
 
157
160
  const restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers
158
- const chunks = splitOp(firstMessage, this.chunkSizeInBytes);
161
+ const socketSize = estimateSocketSize(batch);
162
+ const chunks = splitOp(
163
+ firstMessage,
164
+ this.chunkSizeInBytes,
165
+ // If we estimate that the socket batch size will exceed the batch limit
166
+ // we will inject an empty op to minimize the risk of the payload failing due to
167
+ // the overhead from the trailing empty ops in the batch.
168
+ socketSize >= this.maxBatchSizeInBytes,
169
+ );
159
170
 
160
171
  assert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);
161
172
  // Send the first N-1 chunks immediately
162
173
  for (const chunk of chunks.slice(0, -1)) {
163
- this.submitBatchFn([chunkToBatchMessage(chunk, firstMessage.referenceSequenceNumber)]);
174
+ this.submitBatchFn(
175
+ [chunkToBatchMessage(chunk, batch.referenceSequenceNumber)],
176
+ batch.referenceSequenceNumber,
177
+ );
164
178
  }
165
179
 
166
180
  // The last chunk will be part of the new batch and needs to
167
181
  // preserve the batch metadata of the original batch
168
182
  const lastChunk = chunkToBatchMessage(
169
183
  chunks[chunks.length - 1],
170
- firstMessage.referenceSequenceNumber,
184
+ batch.referenceSequenceNumber,
171
185
  { batch: firstMessage.metadata?.batch },
172
186
  );
173
187
 
174
188
  this.logger.sendPerformanceEvent({
175
- eventName: "Chunked compressed batch",
189
+ // Used to be "Chunked compressed batch"
190
+ eventName: "CompressedChunkedBatch",
176
191
  length: batch.content.length,
177
192
  sizeInBytes: batch.contentSizeInBytes,
178
193
  chunks: chunks.length,
179
194
  chunkSizeInBytes: this.chunkSizeInBytes,
195
+ socketSize,
180
196
  });
181
197
 
182
198
  return {
183
199
  content: [lastChunk, ...restOfMessages],
184
200
  contentSizeInBytes: lastChunk.contents?.length ?? 0,
201
+ referenceSequenceNumber: batch.referenceSequenceNumber,
185
202
  };
186
203
  }
187
204
  }
@@ -204,7 +221,23 @@ const chunkToBatchMessage = (
204
221
  };
205
222
  };
206
223
 
207
- export const splitOp = (op: BatchMessage, chunkSizeInBytes: number): IChunkedOp[] => {
224
+ /**
225
+ * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.
226
+ *
227
+ * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload
228
+ * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.
229
+ * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.
230
+ *
231
+ * @param op - the op to be split
232
+ * @param chunkSizeInBytes - how large should the chunks be
233
+ * @param extraOp - should an extra empty op be added to the result
234
+ * @returns an array of chunked ops
235
+ */
236
+ export const splitOp = (
237
+ op: BatchMessage,
238
+ chunkSizeInBytes: number,
239
+ extraOp: boolean = false,
240
+ ): IChunkedOp[] => {
208
241
  const chunks: IChunkedOp[] = [];
209
242
  assert(
210
243
  op.contents !== undefined && op.contents !== null,
@@ -212,17 +245,17 @@ export const splitOp = (op: BatchMessage, chunkSizeInBytes: number): IChunkedOp[
212
245
  );
213
246
 
214
247
  const contentLength = op.contents.length;
215
- const chunkN = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1;
248
+ const chunkCount = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);
216
249
  let offset = 0;
217
- for (let i = 1; i <= chunkN; i++) {
250
+ for (let chunkId = 1; chunkId <= chunkCount; chunkId++) {
218
251
  const chunk: IChunkedOp = {
219
- chunkId: i,
252
+ chunkId,
220
253
  contents: op.contents.substr(offset, chunkSizeInBytes),
221
254
  originalType: op.deserializedContent.type,
222
- totalChunks: chunkN,
255
+ totalChunks: chunkCount,
223
256
  };
224
257
 
225
- if (i === chunkN) {
258
+ if (chunkId === chunkCount) {
226
259
  // We don't need to port these to all the chunks,
227
260
  // as we rebuild the original op when we process the
228
261
  // last chunk, therefore it is the only one that needs it.
@@ -232,7 +265,13 @@ export const splitOp = (op: BatchMessage, chunkSizeInBytes: number): IChunkedOp[
232
265
 
233
266
  chunks.push(chunk);
234
267
  offset += chunkSizeInBytes;
268
+ assert(
269
+ chunkId >= chunkCount - 1 || offset <= contentLength,
270
+ 0x58b /* Content offset within bounds */,
271
+ );
235
272
  }
236
273
 
274
+ assert(offset >= contentLength, 0x58c /* Content offset equal or larger than content length */);
275
+ assert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);
237
276
  return chunks;
238
277
  };
@@ -6,20 +6,26 @@
6
6
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
7
7
  import { assert } from "@fluidframework/common-utils";
8
8
  import { IContainerContext } from "@fluidframework/container-definitions";
9
- import { GenericError } from "@fluidframework/container-utils";
9
+ import { GenericError, UsageError } from "@fluidframework/container-utils";
10
10
  import { MessageType } from "@fluidframework/protocol-definitions";
11
+ import {
12
+ ChildLogger,
13
+ loggerToMonitoringContext,
14
+ MonitoringContext,
15
+ } from "@fluidframework/telemetry-utils";
11
16
  import { ICompressionRuntimeOptions } from "../containerRuntime";
12
17
  import { PendingStateManager } from "../pendingStateManager";
13
- import { BatchManager } from "./batchManager";
18
+ import { BatchManager, estimateSocketSize } from "./batchManager";
14
19
  import { BatchMessage, IBatch } from "./definitions";
15
20
  import { OpCompressor } from "./opCompressor";
21
+ import { OpGroupingManager } from "./opGroupingManager";
16
22
  import { OpSplitter } from "./opSplitter";
17
23
 
18
24
  export interface IOutboxConfig {
19
25
  readonly compressionOptions: ICompressionRuntimeOptions;
20
26
  // The maximum size of a batch that we can send over the wire.
21
27
  readonly maxBatchSizeInBytes: number;
22
- readonly enableOpReentryCheck?: boolean;
28
+ readonly disablePartialFlush: boolean;
23
29
  }
24
30
 
25
31
  export interface IOutboxParameters {
@@ -30,14 +36,26 @@ export interface IOutboxParameters {
30
36
  readonly compressor: OpCompressor;
31
37
  readonly splitter: OpSplitter;
32
38
  readonly logger: ITelemetryLogger;
39
+ readonly groupingManager: OpGroupingManager;
33
40
  }
34
41
 
35
42
  export class Outbox {
43
+ private readonly mc: MonitoringContext;
36
44
  private readonly attachFlowBatch: BatchManager;
37
45
  private readonly mainBatch: BatchManager;
38
- private readonly defaultAttachFlowSoftLimitInBytes = 64 * 1024;
46
+ private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
47
+
48
+ /**
49
+ * Track the number of ops which were detected to have a mismatched
50
+ * reference sequence number, in order to self-throttle the telemetry events.
51
+ *
52
+ * This should be removed as part of ADO:2322
53
+ */
54
+ private readonly maxMismatchedOpsToReport = 3;
55
+ private mismatchedOpsReported = 0;
39
56
 
40
57
  constructor(private readonly params: IOutboxParameters) {
58
+ this.mc = loggerToMonitoringContext(ChildLogger.create(params.logger, "Outbox"));
41
59
  const isCompressionEnabled =
42
60
  this.params.config.compressionOptions.minimumBatchSizeInBytes !==
43
61
  Number.POSITIVE_INFINITY;
@@ -45,28 +63,63 @@ export class Outbox {
45
63
  const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
46
64
  const softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;
47
65
 
48
- this.attachFlowBatch = new BatchManager(
49
- {
50
- hardLimit,
51
- softLimit,
52
- enableOpReentryCheck: params.config.enableOpReentryCheck,
53
- },
54
- params.logger,
55
- );
56
- this.mainBatch = new BatchManager(
57
- {
58
- hardLimit,
59
- enableOpReentryCheck: params.config.enableOpReentryCheck,
60
- },
61
- params.logger,
62
- );
66
+ this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
67
+ this.mainBatch = new BatchManager({ hardLimit });
63
68
  }
64
69
 
65
70
  public get isEmpty(): boolean {
66
71
  return this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;
67
72
  }
68
73
 
74
+ /**
75
+ * If we detect that the reference sequence number of the incoming message does not match
76
+ * what was already in the batch managers, this means that batching has been interrupted so
77
+ * we will flush the accumulated messages to account for that and create a new batch with the new
78
+ * message as the first message.
79
+ *
80
+ * @param message - the incoming message
81
+ */
82
+ private maybeFlushPartialBatch(message: BatchMessage) {
83
+ const mainBatchReference = this.mainBatch.referenceSequenceNumber;
84
+ const attachFlowBatchReference = this.attachFlowBatch.referenceSequenceNumber;
85
+ assert(
86
+ this.params.config.disablePartialFlush ||
87
+ mainBatchReference === undefined ||
88
+ attachFlowBatchReference === undefined ||
89
+ mainBatchReference === attachFlowBatchReference,
90
+ 0x58d /* Reference sequence numbers from both batches must be in sync */,
91
+ );
92
+
93
+ if (
94
+ (mainBatchReference === undefined ||
95
+ mainBatchReference === message.referenceSequenceNumber) &&
96
+ (attachFlowBatchReference === undefined ||
97
+ attachFlowBatchReference === message.referenceSequenceNumber)
98
+ ) {
99
+ // The reference sequence numbers are stable, there is nothing to do
100
+ return;
101
+ }
102
+
103
+ if (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {
104
+ this.mc.logger.sendErrorEvent(
105
+ {
106
+ eventName: "ReferenceSequenceNumberMismatch",
107
+ mainReferenceSequenceNumber: mainBatchReference,
108
+ attachReferenceSequenceNumber: attachFlowBatchReference,
109
+ messageReferenceSequenceNumber: message.referenceSequenceNumber,
110
+ },
111
+ new UsageError("Submission of an out of order message"),
112
+ );
113
+ }
114
+
115
+ if (!this.params.config.disablePartialFlush) {
116
+ this.flush();
117
+ }
118
+ }
119
+
69
120
  public submit(message: BatchMessage) {
121
+ this.maybeFlushPartialBatch(message);
122
+
70
123
  if (!this.mainBatch.push(message)) {
71
124
  throw new GenericError("BatchTooLarge", /* error */ undefined, {
72
125
  opSize: message.contents?.length ?? 0,
@@ -78,6 +131,8 @@ export class Outbox {
78
131
  }
79
132
 
80
133
  public submitAttach(message: BatchMessage) {
134
+ this.maybeFlushPartialBatch(message);
135
+
81
136
  if (!this.attachFlowBatch.push(message)) {
82
137
  // BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
83
138
  // when queue is not empty.
@@ -113,69 +168,82 @@ export class Outbox {
113
168
 
114
169
  private flushInternal(rawBatch: IBatch) {
115
170
  const processedBatch = this.compressBatch(rawBatch);
116
- const clientSequenceNumber = this.sendBatch(processedBatch);
171
+ this.sendBatch(processedBatch);
117
172
 
118
- this.persistBatch(clientSequenceNumber, rawBatch.content);
173
+ this.persistBatch(rawBatch.content);
119
174
  }
120
175
 
121
176
  private compressBatch(batch: IBatch): IBatch {
122
177
  if (
123
178
  batch.content.length === 0 ||
124
179
  this.params.config.compressionOptions === undefined ||
125
- this.params.config.compressionOptions.minimumBatchSizeInBytes > batch.contentSizeInBytes
180
+ this.params.config.compressionOptions.minimumBatchSizeInBytes >
181
+ batch.contentSizeInBytes ||
182
+ this.params.containerContext.submitBatchFn === undefined
126
183
  ) {
127
- // Nothing to do if the batch is empty or if compression is disabled or if we don't need to compress
128
- return batch;
184
+ // Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress
185
+ return this.params.groupingManager.groupBatch(batch);
129
186
  }
130
187
 
131
- const compressedBatch = this.params.compressor.compressBatch(batch);
132
- if (compressedBatch.contentSizeInBytes <= this.params.config.maxBatchSizeInBytes) {
133
- // If we don't reach the maximum supported size of a batch, it can safely be sent as is
134
- return compressedBatch;
135
- }
188
+ const compressedBatch = this.params.groupingManager.groupBatch(
189
+ this.params.compressor.compressBatch(batch),
190
+ );
136
191
 
137
192
  if (this.params.splitter.isBatchChunkingEnabled) {
138
- return this.params.splitter.splitCompressedBatch(compressedBatch);
193
+ return compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes
194
+ ? compressedBatch
195
+ : this.params.splitter.splitFirstBatchMessage(compressedBatch);
196
+ }
197
+
198
+ if (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {
199
+ throw new GenericError("BatchTooLarge", /* error */ undefined, {
200
+ batchSize: batch.contentSizeInBytes,
201
+ compressedBatchSize: compressedBatch.contentSizeInBytes,
202
+ count: compressedBatch.content.length,
203
+ limit: this.params.config.maxBatchSizeInBytes,
204
+ chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
205
+ compressionOptions: JSON.stringify(this.params.config.compressionOptions),
206
+ socketSize: estimateSocketSize(batch),
207
+ });
139
208
  }
140
209
 
141
- // If we've reached this point, the runtime would attempt to send a batch larger than the allowed size
142
- throw new GenericError("BatchTooLarge", /* error */ undefined, {
143
- batchSize: batch.contentSizeInBytes,
144
- compressedBatchSize: compressedBatch.contentSizeInBytes,
145
- count: compressedBatch.content.length,
146
- limit: this.params.config.maxBatchSizeInBytes,
147
- chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
148
- compressionOptions: JSON.stringify(this.params.config.compressionOptions),
149
- });
210
+ return compressedBatch;
150
211
  }
151
212
 
152
213
  /**
153
214
  * Sends the batch object to the container context to be sent over the wire.
154
215
  *
155
216
  * @param batch - batch to be sent
156
- * @returns the client sequence number of the last batched op which was sent and
157
- * -1 if there are no ops or the container cannot send ops.
158
217
  */
159
- private sendBatch(batch: IBatch): number {
160
- let clientSequenceNumber: number = -1;
218
+ private sendBatch(batch: IBatch) {
161
219
  const length = batch.content.length;
162
220
 
163
221
  // Did we disconnect in the middle of turn-based batch?
164
222
  // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
165
223
  if (length === 0 || !this.params.shouldSend()) {
166
- return clientSequenceNumber;
224
+ return;
225
+ }
226
+
227
+ const socketSize = estimateSocketSize(batch);
228
+ if (socketSize >= this.params.config.maxBatchSizeInBytes) {
229
+ this.mc.logger.sendPerformanceEvent({
230
+ eventName: "LargeBatch",
231
+ length: batch.content.length,
232
+ sizeInBytes: batch.contentSizeInBytes,
233
+ socketSize,
234
+ });
167
235
  }
168
236
 
169
237
  if (this.params.containerContext.submitBatchFn === undefined) {
170
238
  // Legacy path - supporting old loader versions. Can be removed only when LTS moves above
171
239
  // version that has support for batches (submitBatchFn)
172
- for (const message of batch.content) {
173
- // Legacy path doesn't support compressed payloads and will submit uncompressed payload anyways
174
- if (message.metadata?.compressed) {
175
- delete message.metadata.compressed;
176
- }
240
+ assert(
241
+ batch.content[0].compression === undefined,
242
+ 0x5a6 /* Compression should not have happened if the loader does not support it */,
243
+ );
177
244
 
178
- clientSequenceNumber = this.params.containerContext.submitFn(
245
+ for (const message of batch.content) {
246
+ this.params.containerContext.submitFn(
179
247
  MessageType.Operation,
180
248
  message.deserializedContent,
181
249
  true, // batch
@@ -185,37 +253,33 @@ export class Outbox {
185
253
 
186
254
  this.params.containerContext.deltaManager.flush();
187
255
  } else {
188
- // returns clientSequenceNumber of last message in a batch
189
- clientSequenceNumber = this.params.containerContext.submitBatchFn(
256
+ assert(
257
+ batch.referenceSequenceNumber !== undefined,
258
+ 0x58e /* Batch must not be empty */,
259
+ );
260
+ this.params.containerContext.submitBatchFn(
190
261
  batch.content.map((message) => ({
191
262
  contents: message.contents,
192
263
  metadata: message.metadata,
193
264
  compression: message.compression,
265
+ referenceSequenceNumber: message.referenceSequenceNumber,
194
266
  })),
267
+ batch.referenceSequenceNumber,
195
268
  );
196
269
  }
197
-
198
- // Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.
199
- clientSequenceNumber -= length - 1;
200
- assert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);
201
- return clientSequenceNumber;
202
270
  }
203
271
 
204
- private persistBatch(initialClientSequenceNumber: number, batch: BatchMessage[]) {
205
- let clientSequenceNumber = initialClientSequenceNumber;
272
+ private persistBatch(batch: BatchMessage[]) {
206
273
  // Let the PendingStateManager know that a message was submitted.
207
274
  // In future, need to shift toward keeping batch as a whole!
208
275
  for (const message of batch) {
209
276
  this.params.pendingStateManager.onSubmitMessage(
210
277
  message.deserializedContent.type,
211
- clientSequenceNumber,
212
278
  message.referenceSequenceNumber,
213
279
  message.deserializedContent.contents,
214
280
  message.localOpMetadata,
215
281
  message.metadata,
216
282
  );
217
-
218
- clientSequenceNumber++;
219
283
  }
220
284
  }
221
285
 
@@ -6,12 +6,14 @@
6
6
  import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
7
7
  import { ContainerMessageType, ContainerRuntimeMessage } from "../containerRuntime";
8
8
  import { OpDecompressor } from "./opDecompressor";
9
+ import { OpGroupingManager } from "./opGroupingManager";
9
10
  import { OpSplitter } from "./opSplitter";
10
11
 
11
12
  export class RemoteMessageProcessor {
12
13
  constructor(
13
14
  private readonly opSplitter: OpSplitter,
14
15
  private readonly opDecompressor: OpDecompressor,
16
+ private readonly opGroupingManager: OpGroupingManager,
15
17
  ) {}
16
18
 
17
19
  public get partialMessages(): ReadonlyMap<string, string[]> {
@@ -22,30 +24,44 @@ export class RemoteMessageProcessor {
22
24
  this.opSplitter.clearPartialChunks(clientId);
23
25
  }
24
26
 
25
- public process(remoteMessage: ISequencedDocumentMessage): ISequencedDocumentMessage {
26
- let message = copy(remoteMessage);
27
- message = this.opDecompressor.processMessage(message).message;
28
- unpackRuntimeMessage(message);
29
-
30
- const chunkProcessingResult = this.opSplitter.processRemoteMessage(message);
31
- message = chunkProcessingResult.message;
32
- if (chunkProcessingResult.state !== "Processed") {
33
- // If the message is not chunked or if the splitter is still rebuilding the original message,
34
- // there is no need to continue processing
35
- return message;
36
- }
27
+ public process(remoteMessage: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
28
+ const result: ISequencedDocumentMessage[] = [];
37
29
 
38
- const decompressionAfterChunking = this.opDecompressor.processMessage(message);
39
- message = decompressionAfterChunking.message;
40
- if (decompressionAfterChunking.state === "Skipped") {
41
- // After chunking, if the original message was not compressed,
42
- // there is no need to continue processing
43
- return message;
44
- }
30
+ // Ungroup before processing chunks
31
+ for (let ungroupedMessage of this.opGroupingManager.ungroupOp(copy(remoteMessage))) {
32
+ ungroupedMessage = this.opDecompressor.processMessage(ungroupedMessage).message;
33
+ unpackRuntimeMessage(ungroupedMessage);
45
34
 
46
- // The message needs to be unpacked after chunking + decompression
47
- unpack(message);
48
- return message;
35
+ const chunkProcessingResult = this.opSplitter.processRemoteMessage(ungroupedMessage);
36
+ ungroupedMessage = chunkProcessingResult.message;
37
+ if (chunkProcessingResult.state !== "Processed") {
38
+ // If the message is not chunked or if the splitter is still rebuilding the original message,
39
+ // there is no need to continue processing
40
+ result.push(ungroupedMessage);
41
+ continue;
42
+ }
43
+
44
+ // Ungroup the chunked message before decompressing
45
+ for (let ungroupedMessageAfterChunking of this.opGroupingManager.ungroupOp(
46
+ ungroupedMessage,
47
+ )) {
48
+ const decompressionAfterChunking = this.opDecompressor.processMessage(
49
+ ungroupedMessageAfterChunking,
50
+ );
51
+ ungroupedMessageAfterChunking = decompressionAfterChunking.message;
52
+ if (decompressionAfterChunking.state === "Skipped") {
53
+ // After chunking, if the original message was not compressed,
54
+ // there is no need to continue processing
55
+ result.push(ungroupedMessageAfterChunking);
56
+ continue;
57
+ }
58
+
59
+ // The message needs to be unpacked after chunking + decompression
60
+ unpack(ungroupedMessageAfterChunking);
61
+ result.push(ungroupedMessageAfterChunking);
62
+ }
63
+ }
64
+ return result;
49
65
  }
50
66
  }
51
67
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-dev.3.1.0.125672";
9
+ export const pkgVersion = "2.0.0-dev.4.2.0.153917";
@@ -29,12 +29,13 @@ export interface IPendingMessage {
29
29
  /**
30
30
  * This represents an explicit flush call and is added to the pending queue when flush is called on the ContainerRuntime
31
31
  * to flush pending messages.
32
- * @deprecated Use batch metadata on IPendingMessage instead. To be removed in 2.0.0-internal.4.0.0 (AB#2496)
32
+ * ! TODO: Remove in "2.0.0-internal.5.0.0" AB#2496
33
33
  */
34
34
  export interface IPendingFlush {
35
35
  type: "flush";
36
36
  }
37
37
 
38
+ /** ! TODO: Remove in "2.0.0-internal.5.0.0" AB#2496 */
38
39
  export type IPendingState = IPendingMessage | IPendingFlush;
39
40
 
40
41
  export interface IPendingLocalState {
@@ -107,17 +108,11 @@ export class PendingStateManager implements IDisposable {
107
108
  );
108
109
  if (!this.pendingMessages.isEmpty()) {
109
110
  return {
110
- pendingStates: this.pendingMessages.toArray().reduce((arr, message) => {
111
- // delete localOpMetadata since it may not be serializable
112
- // and will be regenerated by applyStashedOp()
113
- arr.push({ ...message, localOpMetadata: undefined });
114
-
115
- // TODO: Remove in 2.0.0-internal.4.0.0 (AB#2496)
116
- if (message.opMetadata?.batch === false) {
117
- arr.push({ type: "flush" });
118
- }
119
- return arr;
120
- }, new Array<IPendingState>()),
111
+ // delete localOpMetadata since it may not be serializable
112
+ // and will be regenerated by applyStashedOp()
113
+ pendingStates: this.pendingMessages
114
+ .toArray()
115
+ .map((message) => ({ ...message, localOpMetadata: undefined })),
121
116
  };
122
117
  }
123
118
  }
@@ -130,7 +125,7 @@ export class PendingStateManager implements IDisposable {
130
125
  * Convert old local state format to the new format
131
126
  * The old format contained "flush" messages as the indicator of batch ends
132
127
  * The new format instead uses batch metadata on the last message to indicate batch ends
133
- * ! TODO: Remove this conversion in "2.0.0-internal.4.0.0" as rollback from future version will be new format
128
+ * ! TODO: Remove this conversion in "2.0.0-internal.5.0.0" as version from "2.0.0-internal.4.0.0" will be new format
134
129
  * AB#2496 tracks removal
135
130
  */
136
131
  if (initialLocalState?.pendingStates) {
@@ -168,13 +163,11 @@ export class PendingStateManager implements IDisposable {
168
163
  * Called when a message is submitted locally. Adds the message and the associated details to the pending state
169
164
  * queue.
170
165
  * @param type - The container message type.
171
- * @param clientSequenceNumber - The clientSequenceNumber associated with the message.
172
166
  * @param content - The message content.
173
167
  * @param localOpMetadata - The local metadata associated with the message.
174
168
  */
175
169
  public onSubmitMessage(
176
170
  type: ContainerMessageType,
177
- clientSequenceNumber: number,
178
171
  referenceSequenceNumber: number,
179
172
  content: any,
180
173
  localOpMetadata: unknown,
@@ -183,7 +176,7 @@ export class PendingStateManager implements IDisposable {
183
176
  const pendingMessage: IPendingMessage = {
184
177
  type: "message",
185
178
  messageType: type,
186
- clientSequenceNumber,
179
+ clientSequenceNumber: -1, // dummy value (not to be used anywhere)
187
180
  referenceSequenceNumber,
188
181
  content,
189
182
  localOpMetadata,
@@ -241,18 +234,34 @@ export class PendingStateManager implements IDisposable {
241
234
  );
242
235
  this.pendingMessages.shift();
243
236
 
244
- // Processing part - Verify that there has been no data corruption.
245
- // The clientSequenceNumber of the incoming message must match that of the pending message.
246
- if (pendingMessage.clientSequenceNumber !== message.clientSequenceNumber) {
237
+ if (pendingMessage.messageType !== message.type) {
247
238
  // Close the container because this could indicate data corruption.
248
- const error = DataProcessingError.create(
249
- "pending local message clientSequenceNumber mismatch",
250
- "unexpectedAckReceived",
251
- message,
252
- { expectedClientSequenceNumber: pendingMessage.clientSequenceNumber },
239
+ this.stateHandler.close(
240
+ DataProcessingError.create(
241
+ "pending local message type mismatch",
242
+ "unexpectedAckReceived",
243
+ message,
244
+ {
245
+ expectedMessageType: pendingMessage.messageType,
246
+ },
247
+ ),
253
248
  );
249
+ return;
250
+ }
254
251
 
255
- this.stateHandler.close(error);
252
+ const pendingMessageContent = JSON.stringify(pendingMessage.content);
253
+ const messageContent = JSON.stringify(message.contents);
254
+
255
+ // Stringified content does not match
256
+ if (pendingMessageContent !== messageContent) {
257
+ // Close the container because this could indicate data corruption.
258
+ this.stateHandler.close(
259
+ DataProcessingError.create(
260
+ "pending local message content mismatch",
261
+ "unexpectedAckReceived",
262
+ message,
263
+ ),
264
+ );
256
265
  return;
257
266
  }
258
267
 
@@ -322,8 +331,6 @@ export class PendingStateManager implements IDisposable {
322
331
  hasBatchStart: batchBeginMetadata === true,
323
332
  hasBatchEnd: batchEndMetadata === false,
324
333
  messageType: message.type,
325
- batchStartSequenceNumber:
326
- this.pendingBatchBeginMessage.clientSequenceNumber,
327
334
  pendingMessagesCount: this.pendingMessagesCount,
328
335
  },
329
336
  ),