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

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 (465) hide show
  1. package/dist/blobManager.d.ts +24 -11
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +112 -55
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +60 -75
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +295 -256
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStoreContext.d.ts +39 -13
  10. package/dist/dataStoreContext.d.ts.map +1 -1
  11. package/dist/dataStoreContext.js +112 -49
  12. package/dist/dataStoreContext.js.map +1 -1
  13. package/dist/dataStores.d.ts +28 -4
  14. package/dist/dataStores.d.ts.map +1 -1
  15. package/dist/dataStores.js +107 -41
  16. package/dist/dataStores.js.map +1 -1
  17. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  18. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  19. package/dist/deltaManagerSummarizerProxy.js +40 -0
  20. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  21. package/dist/gc/garbageCollection.d.ts +204 -0
  22. package/dist/gc/garbageCollection.d.ts.map +1 -0
  23. package/dist/{garbageCollection.js → gc/garbageCollection.js} +190 -554
  24. package/dist/gc/garbageCollection.js.map +1 -0
  25. package/dist/gc/gcConfigs.d.ts +22 -0
  26. package/dist/gc/gcConfigs.d.ts.map +1 -0
  27. package/dist/gc/gcConfigs.js +143 -0
  28. package/dist/gc/gcConfigs.js.map +1 -0
  29. package/dist/gc/gcDefinitions.d.ts +320 -0
  30. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  31. package/dist/gc/gcDefinitions.js +81 -0
  32. package/dist/gc/gcDefinitions.js.map +1 -0
  33. package/dist/gc/gcHelpers.d.ts +86 -0
  34. package/dist/gc/gcHelpers.d.ts.map +1 -0
  35. package/dist/gc/gcHelpers.js +268 -0
  36. package/dist/gc/gcHelpers.js.map +1 -0
  37. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  38. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  39. package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
  40. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  41. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  42. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  43. package/dist/gc/gcSummaryDefinitions.js +7 -0
  44. package/dist/gc/gcSummaryDefinitions.js.map +1 -0
  45. package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
  46. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  47. package/dist/gc/gcSummaryStateTracker.js +239 -0
  48. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  49. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  50. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
  51. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  52. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  53. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  54. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  55. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  56. package/dist/gc/index.d.ts +13 -0
  57. package/dist/gc/index.d.ts.map +1 -0
  58. package/dist/gc/index.js +50 -0
  59. package/dist/gc/index.js.map +1 -0
  60. package/dist/index.d.ts +3 -7
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +5 -9
  63. package/dist/index.js.map +1 -1
  64. package/dist/opLifecycle/batchManager.d.ts +11 -13
  65. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  66. package/dist/opLifecycle/batchManager.js +26 -38
  67. package/dist/opLifecycle/batchManager.js.map +1 -1
  68. package/dist/opLifecycle/definitions.d.ts +4 -0
  69. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  70. package/dist/opLifecycle/definitions.js.map +1 -1
  71. package/dist/opLifecycle/index.d.ts +1 -1
  72. package/dist/opLifecycle/index.d.ts.map +1 -1
  73. package/dist/opLifecycle/index.js +2 -1
  74. package/dist/opLifecycle/index.js.map +1 -1
  75. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  76. package/dist/opLifecycle/opCompressor.js +25 -10
  77. package/dist/opLifecycle/opCompressor.js.map +1 -1
  78. package/dist/opLifecycle/opDecompressor.d.ts +4 -0
  79. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  80. package/dist/opLifecycle/opDecompressor.js +42 -4
  81. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  82. package/dist/opLifecycle/opSplitter.d.ts +15 -3
  83. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  84. package/dist/opLifecycle/opSplitter.js +35 -10
  85. package/dist/opLifecycle/opSplitter.js.map +1 -1
  86. package/dist/opLifecycle/outbox.d.ts +19 -3
  87. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  88. package/dist/opLifecycle/outbox.js +88 -49
  89. package/dist/opLifecycle/outbox.js.map +1 -1
  90. package/dist/packageVersion.d.ts +1 -1
  91. package/dist/packageVersion.js +1 -1
  92. package/dist/packageVersion.js.map +1 -1
  93. package/dist/pendingStateManager.d.ts +3 -3
  94. package/dist/pendingStateManager.d.ts.map +1 -1
  95. package/dist/pendingStateManager.js +20 -21
  96. package/dist/pendingStateManager.js.map +1 -1
  97. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  98. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  99. package/dist/storageServiceWithAttachBlobs.js +32 -0
  100. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  101. package/dist/summary/index.d.ts +17 -0
  102. package/dist/summary/index.d.ts.map +1 -0
  103. package/dist/summary/index.js +46 -0
  104. package/dist/summary/index.js.map +1 -0
  105. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  106. package/dist/summary/orderedClientElection.js.map +1 -0
  107. package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  108. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  109. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  110. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  111. package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
  112. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  113. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +158 -56
  114. package/dist/summary/runningSummarizer.js.map +1 -0
  115. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  116. package/dist/summary/summarizer.d.ts.map +1 -0
  117. package/dist/{summarizer.js → summary/summarizer.js} +9 -74
  118. package/dist/summary/summarizer.js.map +1 -0
  119. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  120. package/dist/summary/summarizerClientElection.js.map +1 -0
  121. package/{lib → dist/summary}/summarizerHeuristics.d.ts +1 -1
  122. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  123. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +3 -3
  124. package/dist/summary/summarizerHeuristics.js.map +1 -0
  125. package/dist/summary/summarizerNode/index.d.ts +8 -0
  126. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  127. package/dist/summary/summarizerNode/index.js +12 -0
  128. package/dist/summary/summarizerNode/index.js.map +1 -0
  129. package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
  130. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  131. package/dist/summary/summarizerNode/summarizerNode.js +531 -0
  132. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
  133. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  134. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  135. package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
  136. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  137. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  138. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  139. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +423 -0
  140. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  141. package/{lib → dist/summary}/summarizerTypes.d.ts +7 -17
  142. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  143. package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
  144. package/dist/summary/summarizerTypes.js.map +1 -0
  145. package/dist/summary/summaryCollection.d.ts.map +1 -0
  146. package/dist/summary/summaryCollection.js.map +1 -0
  147. package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
  148. package/dist/summary/summaryFormat.d.ts.map +1 -0
  149. package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
  150. package/dist/summary/summaryFormat.js.map +1 -0
  151. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  152. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +4 -4
  153. package/dist/summary/summaryGenerator.js.map +1 -0
  154. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  155. package/dist/summary/summaryManager.d.ts.map +1 -0
  156. package/dist/summary/summaryManager.js.map +1 -0
  157. package/lib/blobManager.d.ts +24 -11
  158. package/lib/blobManager.d.ts.map +1 -1
  159. package/lib/blobManager.js +109 -52
  160. package/lib/blobManager.js.map +1 -1
  161. package/lib/containerRuntime.d.ts +60 -75
  162. package/lib/containerRuntime.d.ts.map +1 -1
  163. package/lib/containerRuntime.js +267 -228
  164. package/lib/containerRuntime.js.map +1 -1
  165. package/lib/dataStoreContext.d.ts +39 -13
  166. package/lib/dataStoreContext.d.ts.map +1 -1
  167. package/lib/dataStoreContext.js +101 -38
  168. package/lib/dataStoreContext.js.map +1 -1
  169. package/lib/dataStores.d.ts +28 -4
  170. package/lib/dataStores.d.ts.map +1 -1
  171. package/lib/dataStores.js +100 -34
  172. package/lib/dataStores.js.map +1 -1
  173. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  174. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  175. package/lib/deltaManagerSummarizerProxy.js +36 -0
  176. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  177. package/lib/gc/garbageCollection.d.ts +204 -0
  178. package/lib/gc/garbageCollection.d.ts.map +1 -0
  179. package/lib/{garbageCollection.js → gc/garbageCollection.js} +172 -535
  180. package/lib/gc/garbageCollection.js.map +1 -0
  181. package/lib/gc/gcConfigs.d.ts +22 -0
  182. package/lib/gc/gcConfigs.d.ts.map +1 -0
  183. package/lib/gc/gcConfigs.js +139 -0
  184. package/lib/gc/gcConfigs.js.map +1 -0
  185. package/lib/gc/gcDefinitions.d.ts +320 -0
  186. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  187. package/lib/gc/gcDefinitions.js +78 -0
  188. package/lib/gc/gcDefinitions.js.map +1 -0
  189. package/lib/gc/gcHelpers.d.ts +86 -0
  190. package/lib/gc/gcHelpers.d.ts.map +1 -0
  191. package/lib/gc/gcHelpers.js +254 -0
  192. package/lib/gc/gcHelpers.js.map +1 -0
  193. package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  194. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  195. package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
  196. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  197. package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
  198. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  199. package/lib/gc/gcSummaryDefinitions.js +6 -0
  200. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  201. package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
  202. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  203. package/lib/gc/gcSummaryStateTracker.js +235 -0
  204. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  205. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  206. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
  207. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  208. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  209. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  210. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  211. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  212. package/lib/gc/index.d.ts +13 -0
  213. package/lib/gc/index.d.ts.map +1 -0
  214. package/lib/gc/index.js +12 -0
  215. package/lib/gc/index.js.map +1 -0
  216. package/lib/index.d.ts +3 -7
  217. package/lib/index.d.ts.map +1 -1
  218. package/lib/index.js +1 -4
  219. package/lib/index.js.map +1 -1
  220. package/lib/opLifecycle/batchManager.d.ts +11 -13
  221. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  222. package/lib/opLifecycle/batchManager.js +24 -37
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +4 -0
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/index.d.ts +1 -1
  228. package/lib/opLifecycle/index.d.ts.map +1 -1
  229. package/lib/opLifecycle/index.js +1 -1
  230. package/lib/opLifecycle/index.js.map +1 -1
  231. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  232. package/lib/opLifecycle/opCompressor.js +26 -11
  233. package/lib/opLifecycle/opCompressor.js.map +1 -1
  234. package/lib/opLifecycle/opDecompressor.d.ts +4 -0
  235. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  236. package/lib/opLifecycle/opDecompressor.js +42 -4
  237. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  238. package/lib/opLifecycle/opSplitter.d.ts +15 -3
  239. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  240. package/lib/opLifecycle/opSplitter.js +35 -10
  241. package/lib/opLifecycle/opSplitter.js.map +1 -1
  242. package/lib/opLifecycle/outbox.d.ts +19 -3
  243. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  244. package/lib/opLifecycle/outbox.js +90 -51
  245. package/lib/opLifecycle/outbox.js.map +1 -1
  246. package/lib/packageVersion.d.ts +1 -1
  247. package/lib/packageVersion.js +1 -1
  248. package/lib/packageVersion.js.map +1 -1
  249. package/lib/pendingStateManager.d.ts +3 -3
  250. package/lib/pendingStateManager.d.ts.map +1 -1
  251. package/lib/pendingStateManager.js +20 -21
  252. package/lib/pendingStateManager.js.map +1 -1
  253. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  254. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  255. package/lib/storageServiceWithAttachBlobs.js +28 -0
  256. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  257. package/lib/summary/index.d.ts +17 -0
  258. package/lib/summary/index.d.ts.map +1 -0
  259. package/lib/summary/index.js +15 -0
  260. package/lib/summary/index.js.map +1 -0
  261. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  262. package/lib/summary/orderedClientElection.js.map +1 -0
  263. package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  264. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  265. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  266. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  267. package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
  268. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  269. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +159 -57
  270. package/lib/summary/runningSummarizer.js.map +1 -0
  271. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  272. package/lib/summary/summarizer.d.ts.map +1 -0
  273. package/lib/{summarizer.js → summary/summarizer.js} +11 -76
  274. package/lib/summary/summarizer.js.map +1 -0
  275. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  276. package/lib/summary/summarizerClientElection.js.map +1 -0
  277. package/{dist → lib/summary}/summarizerHeuristics.d.ts +1 -1
  278. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  279. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +3 -3
  280. package/lib/summary/summarizerHeuristics.js.map +1 -0
  281. package/lib/summary/summarizerNode/index.d.ts +8 -0
  282. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  283. package/lib/summary/summarizerNode/index.js +7 -0
  284. package/lib/summary/summarizerNode/index.js.map +1 -0
  285. package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
  286. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  287. package/lib/summary/summarizerNode/summarizerNode.js +526 -0
  288. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  289. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  290. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  291. package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
  292. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  293. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  294. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  295. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
  296. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  297. package/{dist → lib/summary}/summarizerTypes.d.ts +7 -17
  298. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  299. package/lib/summary/summarizerTypes.js +6 -0
  300. package/{dist → lib/summary}/summarizerTypes.js.map +1 -1
  301. package/lib/summary/summaryCollection.d.ts.map +1 -0
  302. package/lib/summary/summaryCollection.js.map +1 -0
  303. package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
  304. package/lib/summary/summaryFormat.d.ts.map +1 -0
  305. package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
  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} +4 -4
  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/summary/summaryManager.js.map +1 -0
  313. package/package.json +63 -60
  314. package/src/blobManager.ts +132 -69
  315. package/src/containerRuntime.ts +421 -382
  316. package/src/dataStoreContext.ts +140 -49
  317. package/src/dataStores.ts +139 -41
  318. package/src/deltaManagerSummarizerProxy.ts +46 -0
  319. package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
  320. package/src/{garbageCollection.ts → gc/garbageCollection.ts} +245 -890
  321. package/src/gc/gcConfigs.ts +193 -0
  322. package/src/gc/gcDefinitions.ts +387 -0
  323. package/src/gc/gcHelpers.ts +332 -0
  324. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  325. package/src/gc/gcSummaryDefinitions.ts +54 -0
  326. package/src/gc/gcSummaryStateTracker.ts +329 -0
  327. package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
  328. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  329. package/src/gc/index.ts +65 -0
  330. package/src/index.ts +10 -22
  331. package/src/opLifecycle/README.md +157 -0
  332. package/src/opLifecycle/batchManager.ts +26 -55
  333. package/src/opLifecycle/definitions.ts +4 -0
  334. package/src/opLifecycle/index.ts +1 -1
  335. package/src/opLifecycle/opCompressor.ts +32 -12
  336. package/src/opLifecycle/opDecompressor.ts +49 -5
  337. package/src/opLifecycle/opSplitter.ts +55 -12
  338. package/src/opLifecycle/outbox.ts +120 -60
  339. package/src/packageVersion.ts +1 -1
  340. package/src/pendingStateManager.ts +34 -27
  341. package/src/storageServiceWithAttachBlobs.ts +38 -0
  342. package/src/summary/index.ts +105 -0
  343. package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +7 -7
  344. package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +279 -139
  345. package/src/{summarizer.ts → summary/summarizer.ts} +12 -97
  346. package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +9 -4
  347. package/src/summary/summarizerNode/index.ts +12 -0
  348. package/src/summary/summarizerNode/summarizerNode.ts +766 -0
  349. package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
  350. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
  351. package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +8 -22
  352. package/src/{summaryFormat.ts → summary/summaryFormat.ts} +3 -29
  353. package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +12 -11
  354. package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
  355. package/dist/garbageCollection.d.ts +0 -411
  356. package/dist/garbageCollection.d.ts.map +0 -1
  357. package/dist/garbageCollection.js.map +0 -1
  358. package/dist/garbageCollectionConstants.d.ts +0 -23
  359. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  360. package/dist/garbageCollectionConstants.js +0 -36
  361. package/dist/garbageCollectionConstants.js.map +0 -1
  362. package/dist/garbageCollectionHelpers.d.ts +0 -15
  363. package/dist/garbageCollectionHelpers.d.ts.map +0 -1
  364. package/dist/garbageCollectionHelpers.js +0 -27
  365. package/dist/garbageCollectionHelpers.js.map +0 -1
  366. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  367. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  368. package/dist/orderedClientElection.d.ts.map +0 -1
  369. package/dist/orderedClientElection.js.map +0 -1
  370. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  371. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  372. package/dist/runningSummarizer.d.ts.map +0 -1
  373. package/dist/runningSummarizer.js.map +0 -1
  374. package/dist/serializedSnapshotStorage.d.ts +0 -58
  375. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  376. package/dist/serializedSnapshotStorage.js +0 -110
  377. package/dist/serializedSnapshotStorage.js.map +0 -1
  378. package/dist/summarizer.d.ts.map +0 -1
  379. package/dist/summarizer.js.map +0 -1
  380. package/dist/summarizerClientElection.d.ts.map +0 -1
  381. package/dist/summarizerClientElection.js.map +0 -1
  382. package/dist/summarizerHandle.d.ts +0 -12
  383. package/dist/summarizerHandle.d.ts.map +0 -1
  384. package/dist/summarizerHandle.js +0 -22
  385. package/dist/summarizerHandle.js.map +0 -1
  386. package/dist/summarizerHeuristics.d.ts.map +0 -1
  387. package/dist/summarizerHeuristics.js.map +0 -1
  388. package/dist/summarizerTypes.d.ts.map +0 -1
  389. package/dist/summaryCollection.d.ts.map +0 -1
  390. package/dist/summaryCollection.js.map +0 -1
  391. package/dist/summaryFormat.d.ts.map +0 -1
  392. package/dist/summaryFormat.js.map +0 -1
  393. package/dist/summaryGenerator.d.ts.map +0 -1
  394. package/dist/summaryGenerator.js.map +0 -1
  395. package/dist/summaryManager.d.ts.map +0 -1
  396. package/dist/summaryManager.js.map +0 -1
  397. package/lib/garbageCollection.d.ts +0 -411
  398. package/lib/garbageCollection.d.ts.map +0 -1
  399. package/lib/garbageCollection.js.map +0 -1
  400. package/lib/garbageCollectionConstants.d.ts +0 -23
  401. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  402. package/lib/garbageCollectionConstants.js +0 -33
  403. package/lib/garbageCollectionConstants.js.map +0 -1
  404. package/lib/garbageCollectionHelpers.d.ts +0 -15
  405. package/lib/garbageCollectionHelpers.d.ts.map +0 -1
  406. package/lib/garbageCollectionHelpers.js +0 -23
  407. package/lib/garbageCollectionHelpers.js.map +0 -1
  408. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  409. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  410. package/lib/orderedClientElection.d.ts.map +0 -1
  411. package/lib/orderedClientElection.js.map +0 -1
  412. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  413. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  414. package/lib/runningSummarizer.d.ts.map +0 -1
  415. package/lib/runningSummarizer.js.map +0 -1
  416. package/lib/serializedSnapshotStorage.d.ts +0 -58
  417. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  418. package/lib/serializedSnapshotStorage.js +0 -106
  419. package/lib/serializedSnapshotStorage.js.map +0 -1
  420. package/lib/summarizer.d.ts.map +0 -1
  421. package/lib/summarizer.js.map +0 -1
  422. package/lib/summarizerClientElection.d.ts.map +0 -1
  423. package/lib/summarizerClientElection.js.map +0 -1
  424. package/lib/summarizerHandle.d.ts +0 -12
  425. package/lib/summarizerHandle.d.ts.map +0 -1
  426. package/lib/summarizerHandle.js +0 -18
  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 +0 -9
  432. package/lib/summarizerTypes.js.map +0 -1
  433. package/lib/summaryCollection.d.ts.map +0 -1
  434. package/lib/summaryCollection.js.map +0 -1
  435. package/lib/summaryFormat.d.ts.map +0 -1
  436. package/lib/summaryFormat.js.map +0 -1
  437. package/lib/summaryGenerator.d.ts.map +0 -1
  438. package/lib/summaryGenerator.js.map +0 -1
  439. package/lib/summaryManager.d.ts.map +0 -1
  440. package/lib/summaryManager.js.map +0 -1
  441. package/src/garbageCollectionConstants.ts +0 -38
  442. package/src/garbageCollectionHelpers.ts +0 -37
  443. package/src/serializedSnapshotStorage.ts +0 -151
  444. package/src/summarizerHandle.ts +0 -23
  445. /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  446. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  447. /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  448. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  449. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  450. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  451. /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  452. /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  453. /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
  454. /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  455. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  456. /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  457. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  458. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  459. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  460. /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  461. /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  462. /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
  463. /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
  464. /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
  465. /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
@@ -6,6 +6,7 @@ import { assert } from "@fluidframework/common-utils";
6
6
  import { DataCorruptionError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
7
7
  import { ChildLogger } from "@fluidframework/telemetry-utils";
8
8
  import { ContainerMessageType } from "../containerRuntime";
9
+ import { estimateSocketSize } from "./batchManager";
9
10
  /**
10
11
  * Responsible for creating and reconstructing chunked messages.
11
12
  */
@@ -99,31 +100,40 @@ export class OpSplitter {
99
100
  var _a, _b, _c, _d, _e, _f;
100
101
  assert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);
101
102
  assert(batch.contentSizeInBytes > 0 && batch.content.length > 0, 0x514 /* Batch needs to be non-empty */);
103
+ assert(batch.referenceSequenceNumber !== undefined, 0x58a /* Batch must have a reference sequence number if non-empty */);
102
104
  assert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);
103
105
  assert(this.chunkSizeInBytes < this.maxBatchSizeInBytes, 0x516 /* Chunk size needs to be smaller than the max batch size */);
104
106
  const firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split
105
107
  assert(((_a = firstMessage.metadata) === null || _a === void 0 ? void 0 : _a.compressed) === true || firstMessage.compression !== undefined, 0x517 /* Batch needs to be compressed */);
106
108
  assert(((_c = (_b = firstMessage.contents) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) >= this.chunkSizeInBytes, 0x518 /* First message in the batch needs to be chunkable */);
107
109
  const restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers
108
- const chunks = splitOp(firstMessage, this.chunkSizeInBytes);
110
+ const socketSize = estimateSocketSize(batch);
111
+ const chunks = splitOp(firstMessage, this.chunkSizeInBytes,
112
+ // If we estimate that the socket batch size will exceed the batch limit
113
+ // we will inject an empty op to minimize the risk of the payload failing due to
114
+ // the overhead from the trailing empty ops in the batch.
115
+ socketSize >= this.maxBatchSizeInBytes);
109
116
  assert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);
110
117
  // Send the first N-1 chunks immediately
111
118
  for (const chunk of chunks.slice(0, -1)) {
112
- this.submitBatchFn([chunkToBatchMessage(chunk, firstMessage.referenceSequenceNumber)]);
119
+ this.submitBatchFn([chunkToBatchMessage(chunk, batch.referenceSequenceNumber)], batch.referenceSequenceNumber);
113
120
  }
114
121
  // The last chunk will be part of the new batch and needs to
115
122
  // preserve the batch metadata of the original batch
116
- const lastChunk = chunkToBatchMessage(chunks[chunks.length - 1], firstMessage.referenceSequenceNumber, { batch: (_d = firstMessage.metadata) === null || _d === void 0 ? void 0 : _d.batch });
123
+ const lastChunk = chunkToBatchMessage(chunks[chunks.length - 1], batch.referenceSequenceNumber, { batch: (_d = firstMessage.metadata) === null || _d === void 0 ? void 0 : _d.batch });
117
124
  this.logger.sendPerformanceEvent({
118
- eventName: "Chunked compressed batch",
125
+ // Used to be "Chunked compressed batch"
126
+ eventName: "CompressedChunkedBatch",
119
127
  length: batch.content.length,
120
128
  sizeInBytes: batch.contentSizeInBytes,
121
129
  chunks: chunks.length,
122
130
  chunkSizeInBytes: this.chunkSizeInBytes,
131
+ socketSize,
123
132
  });
124
133
  return {
125
134
  content: [lastChunk, ...restOfMessages],
126
135
  contentSizeInBytes: (_f = (_e = lastChunk.contents) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0,
136
+ referenceSequenceNumber: batch.referenceSequenceNumber,
127
137
  };
128
138
  }
129
139
  }
@@ -140,20 +150,32 @@ const chunkToBatchMessage = (chunk, referenceSequenceNumber, metadata = undefine
140
150
  referenceSequenceNumber,
141
151
  };
142
152
  };
143
- export const splitOp = (op, chunkSizeInBytes) => {
153
+ /**
154
+ * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.
155
+ *
156
+ * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload
157
+ * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.
158
+ * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.
159
+ *
160
+ * @param op - the op to be split
161
+ * @param chunkSizeInBytes - how large should the chunks be
162
+ * @param extraOp - should an extra empty op be added to the result
163
+ * @returns an array of chunked ops
164
+ */
165
+ export const splitOp = (op, chunkSizeInBytes, extraOp = false) => {
144
166
  const chunks = [];
145
167
  assert(op.contents !== undefined && op.contents !== null, 0x51a /* We should have something to chunk */);
146
168
  const contentLength = op.contents.length;
147
- const chunkN = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1;
169
+ const chunkCount = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);
148
170
  let offset = 0;
149
- for (let i = 1; i <= chunkN; i++) {
171
+ for (let chunkId = 1; chunkId <= chunkCount; chunkId++) {
150
172
  const chunk = {
151
- chunkId: i,
173
+ chunkId,
152
174
  contents: op.contents.substr(offset, chunkSizeInBytes),
153
175
  originalType: op.deserializedContent.type,
154
- totalChunks: chunkN,
176
+ totalChunks: chunkCount,
155
177
  };
156
- if (i === chunkN) {
178
+ if (chunkId === chunkCount) {
157
179
  // We don't need to port these to all the chunks,
158
180
  // as we rebuild the original op when we process the
159
181
  // last chunk, therefore it is the only one that needs it.
@@ -162,7 +184,10 @@ export const splitOp = (op, chunkSizeInBytes) => {
162
184
  }
163
185
  chunks.push(chunk);
164
186
  offset += chunkSizeInBytes;
187
+ assert(chunkId >= chunkCount - 1 || offset <= contentLength, 0x58b /* Content offset within bounds */);
165
188
  }
189
+ assert(offset >= contentLength, 0x58c /* Content offset equal or larger than content length */);
190
+ assert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);
166
191
  return chunks;
167
192
  };
168
193
  //# sourceMappingURL=opSplitter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"opSplitter.js","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions\";\nimport {\n\tDataCorruptionError,\n\textractSafePropertiesFromMessage,\n} from \"@fluidframework/container-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { ContainerMessageType, ContainerRuntimeMessage } from \"../containerRuntime\";\nimport { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from \"./definitions\";\n\n/**\n * Responsible for creating and reconstructing chunked messages.\n */\nexport class OpSplitter {\n\t// Local copy of incomplete received chunks.\n\tprivate readonly chunkMap: Map<string, string[]>;\n\tprivate readonly logger;\n\n\tconstructor(\n\t\tchunks: [string, string[]][],\n\t\tprivate readonly submitBatchFn: ((batch: IBatchMessage[]) => number) | undefined,\n\t\tprivate readonly chunkSizeInBytes: number,\n\t\tprivate readonly maxBatchSizeInBytes: number,\n\t\tlogger: ITelemetryLogger,\n\t) {\n\t\tthis.chunkMap = new Map<string, string[]>(chunks);\n\t\tthis.logger = ChildLogger.create(logger, \"OpSplitter\");\n\t}\n\n\tpublic get isBatchChunkingEnabled(): boolean {\n\t\treturn this.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined;\n\t}\n\n\tpublic get chunks(): ReadonlyMap<string, string[]> {\n\t\treturn this.chunkMap;\n\t}\n\n\tpublic processRemoteMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tif (message.type !== ContainerMessageType.ChunkedOp) {\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Skipped\",\n\t\t\t};\n\t\t}\n\n\t\tconst clientId = message.clientId;\n\t\tconst chunkedContent = message.contents as IChunkedOp;\n\t\tthis.addChunk(clientId, chunkedContent, message);\n\n\t\tif (chunkedContent.chunkId < chunkedContent.totalChunks) {\n\t\t\t// We are processing the op in chunks but haven't reached\n\t\t\t// the last chunk yet in order to reconstruct the original op\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst serializedContent = this.chunkMap.get(clientId)!.join(\"\");\n\t\tthis.clearPartialChunks(clientId);\n\n\t\tconst newMessage = { ...message };\n\t\tnewMessage.contents = serializedContent === \"\" ? undefined : JSON.parse(serializedContent);\n\t\tnewMessage.type = chunkedContent.originalType;\n\t\tnewMessage.metadata = chunkedContent.originalMetadata;\n\t\tnewMessage.compression = chunkedContent.originalCompression;\n\t\treturn {\n\t\t\tmessage: newMessage,\n\t\t\tstate: \"Processed\",\n\t\t};\n\t}\n\n\tpublic clearPartialChunks(clientId: string) {\n\t\tif (this.chunkMap.has(clientId)) {\n\t\t\tthis.chunkMap.delete(clientId);\n\t\t}\n\t}\n\n\tprivate addChunk(\n\t\tclientId: string,\n\t\tchunkedContent: IChunkedOp,\n\t\toriginalMessage: ISequencedDocumentMessage,\n\t) {\n\t\tlet map = this.chunkMap.get(clientId);\n\t\tif (map === undefined) {\n\t\t\tmap = [];\n\t\t\tthis.chunkMap.set(clientId, map);\n\t\t}\n\n\t\tif (chunkedContent.chunkId !== map.length + 1) {\n\t\t\t// We are expecting the chunks to be processed sequentially, in the same order as they are sent.\n\t\t\t// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)\n\t\t\t// holding the existing chunks for that particular clientId.\n\t\t\tthrow new DataCorruptionError(\"Chunk Id mismatch\", {\n\t\t\t\t...extractSafePropertiesFromMessage(originalMessage),\n\t\t\t\tchunkMapLength: map.length,\n\t\t\t\tchunkId: chunkedContent.chunkId,\n\t\t\t\ttotalChunks: chunkedContent.totalChunks,\n\t\t\t});\n\t\t}\n\n\t\tmap.push(chunkedContent.contents);\n\t}\n\n\t/**\n\t * Splits the first op of a compressed batch in chunks, sends the chunks separately and\n\t * returns a new batch composed of the last chunk and the rest of the ops in the original batch.\n\t *\n\t * A compressed batch is formed by one large op at the first position, followed by a series of placeholder ops\n\t * which are used in order to reserve the sequence numbers for when the first op gets unrolled into the original\n\t * uncompressed ops at ingestion in the runtime.\n\t *\n\t * If the first op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire\n\t * and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.\n\t *\n\t * This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch\n\t * and then appends the original placeholder ops. This will ensure that the batch semantics of the original (non-compressed) batch\n\t * are preserved, as the original chunked op will be unrolled by the runtime when the first message in the batch is processed\n\t * (as it is the last chunk).\n\t *\n\t * To illustrate, if the input is `[largeOp, emptyOp, emptyOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.\n\t * `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4, emptyOp, emptyOp]` will be returned.\n\t *\n\t * @param batch - the compressed batch which needs to be processed\n\t * @returns A new adjusted batch which can be sent over the wire\n\t */\n\tpublic splitCompressedBatch(batch: IBatch): IBatch {\n\t\tassert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.content.length > 0,\n\t\t\t0x514 /* Batch needs to be non-empty */,\n\t\t);\n\t\tassert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);\n\t\tassert(\n\t\t\tthis.chunkSizeInBytes < this.maxBatchSizeInBytes,\n\t\t\t0x516 /* Chunk size needs to be smaller than the max batch size */,\n\t\t);\n\n\t\tconst firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split\n\t\tassert(\n\t\t\tfirstMessage.metadata?.compressed === true || firstMessage.compression !== undefined,\n\t\t\t0x517 /* Batch needs to be compressed */,\n\t\t);\n\t\tassert(\n\t\t\t(firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,\n\t\t\t0x518 /* First message in the batch needs to be chunkable */,\n\t\t);\n\n\t\tconst restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers\n\t\tconst chunks = splitOp(firstMessage, this.chunkSizeInBytes);\n\n\t\tassert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);\n\t\t// Send the first N-1 chunks immediately\n\t\tfor (const chunk of chunks.slice(0, -1)) {\n\t\t\tthis.submitBatchFn([chunkToBatchMessage(chunk, firstMessage.referenceSequenceNumber)]);\n\t\t}\n\n\t\t// The last chunk will be part of the new batch and needs to\n\t\t// preserve the batch metadata of the original batch\n\t\tconst lastChunk = chunkToBatchMessage(\n\t\t\tchunks[chunks.length - 1],\n\t\t\tfirstMessage.referenceSequenceNumber,\n\t\t\t{ batch: firstMessage.metadata?.batch },\n\t\t);\n\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName: \"Chunked compressed batch\",\n\t\t\tlength: batch.content.length,\n\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\tchunks: chunks.length,\n\t\t\tchunkSizeInBytes: this.chunkSizeInBytes,\n\t\t});\n\n\t\treturn {\n\t\t\tcontent: [lastChunk, ...restOfMessages],\n\t\t\tcontentSizeInBytes: lastChunk.contents?.length ?? 0,\n\t\t};\n\t}\n}\n\nconst chunkToBatchMessage = (\n\tchunk: IChunkedOp,\n\treferenceSequenceNumber: number,\n\tmetadata: Record<string, unknown> | undefined = undefined,\n): BatchMessage => {\n\tconst payload: ContainerRuntimeMessage = {\n\t\ttype: ContainerMessageType.ChunkedOp,\n\t\tcontents: chunk,\n\t};\n\treturn {\n\t\tcontents: JSON.stringify(payload),\n\t\tdeserializedContent: payload,\n\t\tmetadata,\n\t\tlocalOpMetadata: undefined,\n\t\treferenceSequenceNumber,\n\t};\n};\n\nexport const splitOp = (op: BatchMessage, chunkSizeInBytes: number): IChunkedOp[] => {\n\tconst chunks: IChunkedOp[] = [];\n\tassert(\n\t\top.contents !== undefined && op.contents !== null,\n\t\t0x51a /* We should have something to chunk */,\n\t);\n\n\tconst contentLength = op.contents.length;\n\tconst chunkN = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1;\n\tlet offset = 0;\n\tfor (let i = 1; i <= chunkN; i++) {\n\t\tconst chunk: IChunkedOp = {\n\t\t\tchunkId: i,\n\t\t\tcontents: op.contents.substr(offset, chunkSizeInBytes),\n\t\t\toriginalType: op.deserializedContent.type,\n\t\t\ttotalChunks: chunkN,\n\t\t};\n\n\t\tif (i === chunkN) {\n\t\t\t// We don't need to port these to all the chunks,\n\t\t\t// as we rebuild the original op when we process the\n\t\t\t// last chunk, therefore it is the only one that needs it.\n\t\t\tchunk.originalMetadata = op.metadata;\n\t\t\tchunk.originalCompression = op.compression;\n\t\t}\n\n\t\tchunks.push(chunk);\n\t\toffset += chunkSizeInBytes;\n\t}\n\n\treturn chunks;\n};\n"]}
1
+ {"version":3,"file":"opSplitter.js","sourceRoot":"","sources":["../../src/opLifecycle/opSplitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEtD,OAAO,EACN,mBAAmB,EACnB,gCAAgC,GAChC,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAA2B,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;GAEG;AACH,MAAM,OAAO,UAAU;IAKtB,YACC,MAA4B,EACX,aAEL,EACI,gBAAwB,EACvB,mBAA2B,EAC5C,MAAwB;QALP,kBAAa,GAAb,aAAa,CAElB;QACI,qBAAgB,GAAhB,gBAAgB,CAAQ;QACvB,wBAAmB,GAAnB,mBAAmB,CAAQ;QAG5C,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAmB,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,IAAW,sBAAsB;QAChC,OAAO,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,iBAAiB,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC;IAC7F,CAAC;IAED,IAAW,MAAM;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,oBAAoB,CAAC,OAAkC;QAC7D,IAAI,OAAO,CAAC,IAAI,KAAK,oBAAoB,CAAC,SAAS,EAAE;YACpD,OAAO;gBACN,OAAO;gBACP,KAAK,EAAE,SAAS;aAChB,CAAC;SACF;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,MAAM,cAAc,GAAG,OAAO,CAAC,QAAsB,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEjD,IAAI,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,WAAW,EAAE;YACxD,yDAAyD;YACzD,6DAA6D;YAC7D,OAAO;gBACN,OAAO;gBACP,KAAK,EAAE,UAAU;aACjB,CAAC;SACF;QAED,oEAAoE;QACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAElC,MAAM,UAAU,qBAAQ,OAAO,CAAE,CAAC;QAClC,UAAU,CAAC,QAAQ,GAAG,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC3F,UAAU,CAAC,IAAI,GAAG,cAAc,CAAC,YAAY,CAAC;QAC9C,UAAU,CAAC,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC;QACtD,UAAU,CAAC,WAAW,GAAG,cAAc,CAAC,mBAAmB,CAAC;QAC5D,OAAO;YACN,OAAO,EAAE,UAAU;YACnB,KAAK,EAAE,WAAW;SAClB,CAAC;IACH,CAAC;IAEM,kBAAkB,CAAC,QAAgB;QACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAChC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;SAC/B;IACF,CAAC;IAEO,QAAQ,CACf,QAAgB,EAChB,cAA0B,EAC1B,eAA0C;QAE1C,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS,EAAE;YACtB,GAAG,GAAG,EAAE,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;SACjC;QAED,IAAI,cAAc,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9C,gGAAgG;YAChG,sGAAsG;YACtG,4DAA4D;YAC5D,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,kCAC7C,gCAAgC,CAAC,eAAe,CAAC,KACpD,cAAc,EAAE,GAAG,CAAC,MAAM,EAC1B,OAAO,EAAE,cAAc,CAAC,OAAO,EAC/B,WAAW,EAAE,cAAc,CAAC,WAAW,IACtC,CAAC;SACH;QAED,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,oBAAoB,CAAC,KAAa;;QACxC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC9E,MAAM,CACL,KAAK,CAAC,kBAAkB,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EACxD,KAAK,CAAC,iCAAiC,CACvC,CAAC;QACF,MAAM,CACL,KAAK,CAAC,uBAAuB,KAAK,SAAS,EAC3C,KAAK,CAAC,8DAA8D,CACpE,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,EAAE,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACjF,MAAM,CACL,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,EAChD,KAAK,CAAC,4DAA4D,CAClE,CAAC;QAEF,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,wEAAwE;QAC/G,MAAM,CACL,CAAA,MAAA,YAAY,CAAC,QAAQ,0CAAE,UAAU,MAAK,IAAI,IAAI,YAAY,CAAC,WAAW,KAAK,SAAS,EACpF,KAAK,CAAC,kCAAkC,CACxC,CAAC;QACF,MAAM,CACL,CAAC,MAAA,MAAA,YAAY,CAAC,QAAQ,0CAAE,MAAM,mCAAI,CAAC,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAC7D,KAAK,CAAC,sDAAsD,CAC5D,CAAC;QAEF,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,uEAAuE;QACtH,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,OAAO,CACrB,YAAY,EACZ,IAAI,CAAC,gBAAgB;QACrB,wEAAwE;QACxE,gFAAgF;QAChF,yDAAyD;QACzD,UAAU,IAAI,IAAI,CAAC,mBAAmB,CACtC,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACnF,wCAAwC;QACxC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACxC,IAAI,CAAC,aAAa,CACjB,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC,EAC3D,KAAK,CAAC,uBAAuB,CAC7B,CAAC;SACF;QAED,4DAA4D;QAC5D,oDAAoD;QACpD,MAAM,SAAS,GAAG,mBAAmB,CACpC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EACzB,KAAK,CAAC,uBAAuB,EAC7B,EAAE,KAAK,EAAE,MAAA,YAAY,CAAC,QAAQ,0CAAE,KAAK,EAAE,CACvC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,wCAAwC;YACxC,SAAS,EAAE,wBAAwB;YACnC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;YAC5B,WAAW,EAAE,KAAK,CAAC,kBAAkB;YACrC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,UAAU;SACV,CAAC,CAAC;QAEH,OAAO;YACN,OAAO,EAAE,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC;YACvC,kBAAkB,EAAE,MAAA,MAAA,SAAS,CAAC,QAAQ,0CAAE,MAAM,mCAAI,CAAC;YACnD,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;SACtD,CAAC;IACH,CAAC;CACD;AAED,MAAM,mBAAmB,GAAG,CAC3B,KAAiB,EACjB,uBAA+B,EAC/B,WAAgD,SAAS,EAC1C,EAAE;IACjB,MAAM,OAAO,GAA4B;QACxC,IAAI,EAAE,oBAAoB,CAAC,SAAS;QACpC,QAAQ,EAAE,KAAK;KACf,CAAC;IACF,OAAO;QACN,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QACjC,mBAAmB,EAAE,OAAO;QAC5B,QAAQ;QACR,eAAe,EAAE,SAAS;QAC1B,uBAAuB;KACvB,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACtB,EAAgB,EAChB,gBAAwB,EACxB,UAAmB,KAAK,EACT,EAAE;IACjB,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,MAAM,CACL,EAAE,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,CAAC,QAAQ,KAAK,IAAI,EACjD,KAAK,CAAC,uCAAuC,CAC7C,CAAC;IAEF,MAAM,aAAa,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE;QACvD,MAAM,KAAK,GAAe;YACzB,OAAO;YACP,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC;YACtD,YAAY,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI;YACzC,WAAW,EAAE,UAAU;SACvB,CAAC;QAEF,IAAI,OAAO,KAAK,UAAU,EAAE;YAC3B,iDAAiD;YACjD,oDAAoD;YACpD,0DAA0D;YAC1D,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,QAAQ,CAAC;YACrC,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,WAAW,CAAC;SAC3C;QAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,MAAM,IAAI,gBAAgB,CAAC;QAC3B,MAAM,CACL,OAAO,IAAI,UAAU,GAAG,CAAC,IAAI,MAAM,IAAI,aAAa,EACpD,KAAK,CAAC,kCAAkC,CACxC,CAAC;KACF;IAED,MAAM,CAAC,MAAM,IAAI,aAAa,EAAE,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAChG,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions\";\nimport {\n\tDataCorruptionError,\n\textractSafePropertiesFromMessage,\n} from \"@fluidframework/container-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { ContainerMessageType, ContainerRuntimeMessage } from \"../containerRuntime\";\nimport { estimateSocketSize } from \"./batchManager\";\nimport { BatchMessage, IBatch, IChunkedOp, IMessageProcessingResult } from \"./definitions\";\n\n/**\n * Responsible for creating and reconstructing chunked messages.\n */\nexport class OpSplitter {\n\t// Local copy of incomplete received chunks.\n\tprivate readonly chunkMap: Map<string, string[]>;\n\tprivate readonly logger;\n\n\tconstructor(\n\t\tchunks: [string, string[]][],\n\t\tprivate readonly submitBatchFn:\n\t\t\t| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)\n\t\t\t| undefined,\n\t\tpublic readonly chunkSizeInBytes: number,\n\t\tprivate readonly maxBatchSizeInBytes: number,\n\t\tlogger: ITelemetryLogger,\n\t) {\n\t\tthis.chunkMap = new Map<string, string[]>(chunks);\n\t\tthis.logger = ChildLogger.create(logger, \"OpSplitter\");\n\t}\n\n\tpublic get isBatchChunkingEnabled(): boolean {\n\t\treturn this.chunkSizeInBytes < Number.POSITIVE_INFINITY && this.submitBatchFn !== undefined;\n\t}\n\n\tpublic get chunks(): ReadonlyMap<string, string[]> {\n\t\treturn this.chunkMap;\n\t}\n\n\tpublic processRemoteMessage(message: ISequencedDocumentMessage): IMessageProcessingResult {\n\t\tif (message.type !== ContainerMessageType.ChunkedOp) {\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Skipped\",\n\t\t\t};\n\t\t}\n\n\t\tconst clientId = message.clientId;\n\t\tconst chunkedContent = message.contents as IChunkedOp;\n\t\tthis.addChunk(clientId, chunkedContent, message);\n\n\t\tif (chunkedContent.chunkId < chunkedContent.totalChunks) {\n\t\t\t// We are processing the op in chunks but haven't reached\n\t\t\t// the last chunk yet in order to reconstruct the original op\n\t\t\treturn {\n\t\t\t\tmessage,\n\t\t\t\tstate: \"Accepted\",\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst serializedContent = this.chunkMap.get(clientId)!.join(\"\");\n\t\tthis.clearPartialChunks(clientId);\n\n\t\tconst newMessage = { ...message };\n\t\tnewMessage.contents = serializedContent === \"\" ? undefined : JSON.parse(serializedContent);\n\t\tnewMessage.type = chunkedContent.originalType;\n\t\tnewMessage.metadata = chunkedContent.originalMetadata;\n\t\tnewMessage.compression = chunkedContent.originalCompression;\n\t\treturn {\n\t\t\tmessage: newMessage,\n\t\t\tstate: \"Processed\",\n\t\t};\n\t}\n\n\tpublic clearPartialChunks(clientId: string) {\n\t\tif (this.chunkMap.has(clientId)) {\n\t\t\tthis.chunkMap.delete(clientId);\n\t\t}\n\t}\n\n\tprivate addChunk(\n\t\tclientId: string,\n\t\tchunkedContent: IChunkedOp,\n\t\toriginalMessage: ISequencedDocumentMessage,\n\t) {\n\t\tlet map = this.chunkMap.get(clientId);\n\t\tif (map === undefined) {\n\t\t\tmap = [];\n\t\t\tthis.chunkMap.set(clientId, map);\n\t\t}\n\n\t\tif (chunkedContent.chunkId !== map.length + 1) {\n\t\t\t// We are expecting the chunks to be processed sequentially, in the same order as they are sent.\n\t\t\t// Therefore, the chunkId of the incoming op needs to match the length of the array (1-based indexing)\n\t\t\t// holding the existing chunks for that particular clientId.\n\t\t\tthrow new DataCorruptionError(\"Chunk Id mismatch\", {\n\t\t\t\t...extractSafePropertiesFromMessage(originalMessage),\n\t\t\t\tchunkMapLength: map.length,\n\t\t\t\tchunkId: chunkedContent.chunkId,\n\t\t\t\ttotalChunks: chunkedContent.totalChunks,\n\t\t\t});\n\t\t}\n\n\t\tmap.push(chunkedContent.contents);\n\t}\n\n\t/**\n\t * Splits the first op of a compressed batch in chunks, sends the chunks separately and\n\t * returns a new batch composed of the last chunk and the rest of the ops in the original batch.\n\t *\n\t * A compressed batch is formed by one large op at the first position, followed by a series of placeholder ops\n\t * which are used in order to reserve the sequence numbers for when the first op gets unrolled into the original\n\t * uncompressed ops at ingestion in the runtime.\n\t *\n\t * If the first op is too large, it can be chunked (split into smaller op) which can be sent individually over the wire\n\t * and accumulate at ingestion, until the last op in the chunk is processed, when the original op is unrolled.\n\t *\n\t * This method will send the first N - 1 chunks separately and use the last chunk as the first message in the result batch\n\t * and then appends the original placeholder ops. This will ensure that the batch semantics of the original (non-compressed) batch\n\t * are preserved, as the original chunked op will be unrolled by the runtime when the first message in the batch is processed\n\t * (as it is the last chunk).\n\t *\n\t * To illustrate, if the input is `[largeOp, emptyOp, emptyOp]`, `largeOp` will be split into `[chunk1, chunk2, chunk3, chunk4]`.\n\t * `chunk1`, `chunk2` and `chunk3` will be sent individually and `[chunk4, emptyOp, emptyOp]` will be returned.\n\t *\n\t * @param batch - the compressed batch which needs to be processed\n\t * @returns A new adjusted batch which can be sent over the wire\n\t */\n\tpublic splitCompressedBatch(batch: IBatch): IBatch {\n\t\tassert(this.isBatchChunkingEnabled, 0x513 /* Chunking needs to be enabled */);\n\t\tassert(\n\t\t\tbatch.contentSizeInBytes > 0 && batch.content.length > 0,\n\t\t\t0x514 /* Batch needs to be non-empty */,\n\t\t);\n\t\tassert(\n\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t0x58a /* Batch must have a reference sequence number if non-empty */,\n\t\t);\n\t\tassert(this.chunkSizeInBytes !== 0, 0x515 /* Chunk size needs to be non-zero */);\n\t\tassert(\n\t\t\tthis.chunkSizeInBytes < this.maxBatchSizeInBytes,\n\t\t\t0x516 /* Chunk size needs to be smaller than the max batch size */,\n\t\t);\n\n\t\tconst firstMessage = batch.content[0]; // we expect this to be the large compressed op, which needs to be split\n\t\tassert(\n\t\t\tfirstMessage.metadata?.compressed === true || firstMessage.compression !== undefined,\n\t\t\t0x517 /* Batch needs to be compressed */,\n\t\t);\n\t\tassert(\n\t\t\t(firstMessage.contents?.length ?? 0) >= this.chunkSizeInBytes,\n\t\t\t0x518 /* First message in the batch needs to be chunkable */,\n\t\t);\n\n\t\tconst restOfMessages = batch.content.slice(1); // we expect these to be empty ops, created to reserve sequence numbers\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tconst chunks = splitOp(\n\t\t\tfirstMessage,\n\t\t\tthis.chunkSizeInBytes,\n\t\t\t// If we estimate that the socket batch size will exceed the batch limit\n\t\t\t// we will inject an empty op to minimize the risk of the payload failing due to\n\t\t\t// the overhead from the trailing empty ops in the batch.\n\t\t\tsocketSize >= this.maxBatchSizeInBytes,\n\t\t);\n\n\t\tassert(this.submitBatchFn !== undefined, 0x519 /* We don't support old loaders */);\n\t\t// Send the first N-1 chunks immediately\n\t\tfor (const chunk of chunks.slice(0, -1)) {\n\t\t\tthis.submitBatchFn(\n\t\t\t\t[chunkToBatchMessage(chunk, batch.referenceSequenceNumber)],\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\n\t\t// The last chunk will be part of the new batch and needs to\n\t\t// preserve the batch metadata of the original batch\n\t\tconst lastChunk = chunkToBatchMessage(\n\t\t\tchunks[chunks.length - 1],\n\t\t\tbatch.referenceSequenceNumber,\n\t\t\t{ batch: firstMessage.metadata?.batch },\n\t\t);\n\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\t// Used to be \"Chunked compressed batch\"\n\t\t\teventName: \"CompressedChunkedBatch\",\n\t\t\tlength: batch.content.length,\n\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\tchunks: chunks.length,\n\t\t\tchunkSizeInBytes: this.chunkSizeInBytes,\n\t\t\tsocketSize,\n\t\t});\n\n\t\treturn {\n\t\t\tcontent: [lastChunk, ...restOfMessages],\n\t\t\tcontentSizeInBytes: lastChunk.contents?.length ?? 0,\n\t\t\treferenceSequenceNumber: batch.referenceSequenceNumber,\n\t\t};\n\t}\n}\n\nconst chunkToBatchMessage = (\n\tchunk: IChunkedOp,\n\treferenceSequenceNumber: number,\n\tmetadata: Record<string, unknown> | undefined = undefined,\n): BatchMessage => {\n\tconst payload: ContainerRuntimeMessage = {\n\t\ttype: ContainerMessageType.ChunkedOp,\n\t\tcontents: chunk,\n\t};\n\treturn {\n\t\tcontents: JSON.stringify(payload),\n\t\tdeserializedContent: payload,\n\t\tmetadata,\n\t\tlocalOpMetadata: undefined,\n\t\treferenceSequenceNumber,\n\t};\n};\n\n/**\n * Splits an op into smaller ops (chunks), based on the size of the op and the `chunkSizeInBytes` parameter.\n *\n * The last op of the result will be bundled with empty ops in the same batch. There is a risk of the batch payload\n * exceeding the 1MB limit due to the overhead from the empty ops. If the last op is large, the risk is even higher.\n * To minimize the odds, an extra empty op can be added to the result using the `extraOp` parameter.\n *\n * @param op - the op to be split\n * @param chunkSizeInBytes - how large should the chunks be\n * @param extraOp - should an extra empty op be added to the result\n * @returns an array of chunked ops\n */\nexport const splitOp = (\n\top: BatchMessage,\n\tchunkSizeInBytes: number,\n\textraOp: boolean = false,\n): IChunkedOp[] => {\n\tconst chunks: IChunkedOp[] = [];\n\tassert(\n\t\top.contents !== undefined && op.contents !== null,\n\t\t0x51a /* We should have something to chunk */,\n\t);\n\n\tconst contentLength = op.contents.length;\n\tconst chunkCount = Math.floor((contentLength - 1) / chunkSizeInBytes) + 1 + (extraOp ? 1 : 0);\n\tlet offset = 0;\n\tfor (let chunkId = 1; chunkId <= chunkCount; chunkId++) {\n\t\tconst chunk: IChunkedOp = {\n\t\t\tchunkId,\n\t\t\tcontents: op.contents.substr(offset, chunkSizeInBytes),\n\t\t\toriginalType: op.deserializedContent.type,\n\t\t\ttotalChunks: chunkCount,\n\t\t};\n\n\t\tif (chunkId === chunkCount) {\n\t\t\t// We don't need to port these to all the chunks,\n\t\t\t// as we rebuild the original op when we process the\n\t\t\t// last chunk, therefore it is the only one that needs it.\n\t\t\tchunk.originalMetadata = op.metadata;\n\t\t\tchunk.originalCompression = op.compression;\n\t\t}\n\n\t\tchunks.push(chunk);\n\t\toffset += chunkSizeInBytes;\n\t\tassert(\n\t\t\tchunkId >= chunkCount - 1 || offset <= contentLength,\n\t\t\t0x58b /* Content offset within bounds */,\n\t\t);\n\t}\n\n\tassert(offset >= contentLength, 0x58c /* Content offset equal or larger than content length */);\n\tassert(chunks.length === chunkCount, 0x5a5 /* Expected number of chunks */);\n\treturn chunks;\n};\n"]}
@@ -12,7 +12,7 @@ import { OpSplitter } from "./opSplitter";
12
12
  export interface IOutboxConfig {
13
13
  readonly compressionOptions: ICompressionRuntimeOptions;
14
14
  readonly maxBatchSizeInBytes: number;
15
- readonly enableOpReentryCheck?: boolean;
15
+ readonly disablePartialFlush: boolean;
16
16
  }
17
17
  export interface IOutboxParameters {
18
18
  readonly shouldSend: () => boolean;
@@ -25,11 +25,29 @@ export interface IOutboxParameters {
25
25
  }
26
26
  export declare class Outbox {
27
27
  private readonly params;
28
+ private readonly mc;
28
29
  private readonly attachFlowBatch;
29
30
  private readonly mainBatch;
30
31
  private readonly defaultAttachFlowSoftLimitInBytes;
32
+ /**
33
+ * Track the number of ops which were detected to have a mismatched
34
+ * reference sequence number, in order to self-throttle the telemetry events.
35
+ *
36
+ * This should be removed as part of ADO:2322
37
+ */
38
+ private readonly maxMismatchedOpsToReport;
39
+ private mismatchedOpsReported;
31
40
  constructor(params: IOutboxParameters);
32
41
  get isEmpty(): boolean;
42
+ /**
43
+ * If we detect that the reference sequence number of the incoming message does not match
44
+ * what was already in the batch managers, this means that batching has been interrupted so
45
+ * we will flush the accumulated messages to account for that and create a new batch with the new
46
+ * message as the first message.
47
+ *
48
+ * @param message - the incoming message
49
+ */
50
+ private maybeFlushPartialBatch;
33
51
  submit(message: BatchMessage): void;
34
52
  submitAttach(message: BatchMessage): void;
35
53
  flush(): void;
@@ -39,8 +57,6 @@ export declare class Outbox {
39
57
  * Sends the batch object to the container context to be sent over the wire.
40
58
  *
41
59
  * @param batch - batch to be sent
42
- * @returns the client sequence number of the last batched op which was sent and
43
- * -1 if there are no ops or the container cannot send ops.
44
60
  */
45
61
  private sendBatch;
46
62
  private persistBatch;
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAG1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IAExD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CAClC;AAED,qBAAa,MAAM;IAKN,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAa;gBAElC,MAAM,EAAE,iBAAiB;IAyBtD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAEM,MAAM,CAAC,OAAO,EAAE,YAAY;IAW5B,YAAY,CAAC,OAAO,EAAE,YAAY;IA6BlC,KAAK;IAKZ,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IA+BrB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IA6CjB,OAAO,CAAC,YAAY;IAkBb,UAAU;;;;CAMjB"}
1
+ {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAQ1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IAExD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CAClC;AAED,qBAAa,MAAM;IAeN,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAc;IAEhE;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IAC9C,OAAO,CAAC,qBAAqB,CAAK;gBAEL,MAAM,EAAE,iBAAiB;IAatD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAsCvB,MAAM,CAAC,OAAO,EAAE,YAAY;IAa5B,YAAY,CAAC,OAAO,EAAE,YAAY;IA+BlC,KAAK;IAKZ,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IAmCrB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAsDjB,OAAO,CAAC,YAAY;IAcb,UAAU;;;;CAMjB"}
@@ -3,33 +3,71 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { assert } from "@fluidframework/common-utils";
6
- import { GenericError } from "@fluidframework/container-utils";
6
+ import { GenericError, UsageError } from "@fluidframework/container-utils";
7
7
  import { MessageType } from "@fluidframework/protocol-definitions";
8
- import { BatchManager } from "./batchManager";
8
+ import { ChildLogger, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
9
+ import { BatchManager, estimateSocketSize } from "./batchManager";
9
10
  export class Outbox {
10
11
  constructor(params) {
11
12
  this.params = params;
12
- this.defaultAttachFlowSoftLimitInBytes = 64 * 1024;
13
+ this.defaultAttachFlowSoftLimitInBytes = 320 * 1024;
14
+ /**
15
+ * Track the number of ops which were detected to have a mismatched
16
+ * reference sequence number, in order to self-throttle the telemetry events.
17
+ *
18
+ * This should be removed as part of ADO:2322
19
+ */
20
+ this.maxMismatchedOpsToReport = 3;
21
+ this.mismatchedOpsReported = 0;
22
+ this.mc = loggerToMonitoringContext(ChildLogger.create(params.logger, "Outbox"));
13
23
  const isCompressionEnabled = this.params.config.compressionOptions.minimumBatchSizeInBytes !==
14
24
  Number.POSITIVE_INFINITY;
15
25
  // We need to allow infinite size batches if we enable compression
16
26
  const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
17
27
  const softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;
18
- this.attachFlowBatch = new BatchManager({
19
- hardLimit,
20
- softLimit,
21
- enableOpReentryCheck: params.config.enableOpReentryCheck,
22
- }, params.logger);
23
- this.mainBatch = new BatchManager({
24
- hardLimit,
25
- enableOpReentryCheck: params.config.enableOpReentryCheck,
26
- }, params.logger);
28
+ this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
29
+ this.mainBatch = new BatchManager({ hardLimit });
27
30
  }
28
31
  get isEmpty() {
29
32
  return this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;
30
33
  }
34
+ /**
35
+ * If we detect that the reference sequence number of the incoming message does not match
36
+ * what was already in the batch managers, this means that batching has been interrupted so
37
+ * we will flush the accumulated messages to account for that and create a new batch with the new
38
+ * message as the first message.
39
+ *
40
+ * @param message - the incoming message
41
+ */
42
+ maybeFlushPartialBatch(message) {
43
+ const mainBatchReference = this.mainBatch.referenceSequenceNumber;
44
+ const attachFlowBatchReference = this.attachFlowBatch.referenceSequenceNumber;
45
+ assert(this.params.config.disablePartialFlush ||
46
+ mainBatchReference === undefined ||
47
+ attachFlowBatchReference === undefined ||
48
+ mainBatchReference === attachFlowBatchReference, 0x58d /* Reference sequence numbers from both batches must be in sync */);
49
+ if ((mainBatchReference === undefined ||
50
+ mainBatchReference === message.referenceSequenceNumber) &&
51
+ (attachFlowBatchReference === undefined ||
52
+ attachFlowBatchReference === message.referenceSequenceNumber)) {
53
+ // The reference sequence numbers are stable, there is nothing to do
54
+ return;
55
+ }
56
+ if (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {
57
+ this.mc.logger.sendErrorEvent({
58
+ eventName: "ReferenceSequenceNumberMismatch",
59
+ mainReferenceSequenceNumber: mainBatchReference,
60
+ attachReferenceSequenceNumber: attachFlowBatchReference,
61
+ messageReferenceSequenceNumber: message.referenceSequenceNumber,
62
+ }, new UsageError("Submission of an out of order message"));
63
+ }
64
+ if (!this.params.config.disablePartialFlush) {
65
+ this.flush();
66
+ }
67
+ }
31
68
  submit(message) {
32
69
  var _a, _b;
70
+ this.maybeFlushPartialBatch(message);
33
71
  if (!this.mainBatch.push(message)) {
34
72
  throw new GenericError("BatchTooLarge", /* error */ undefined, {
35
73
  opSize: (_b = (_a = message.contents) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
@@ -41,6 +79,7 @@ export class Outbox {
41
79
  }
42
80
  submitAttach(message) {
43
81
  var _a, _b;
82
+ this.maybeFlushPartialBatch(message);
44
83
  if (!this.attachFlowBatch.push(message)) {
45
84
  // BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
46
85
  // when queue is not empty.
@@ -71,83 +110,83 @@ export class Outbox {
71
110
  }
72
111
  flushInternal(rawBatch) {
73
112
  const processedBatch = this.compressBatch(rawBatch);
74
- const clientSequenceNumber = this.sendBatch(processedBatch);
75
- this.persistBatch(clientSequenceNumber, rawBatch.content);
113
+ this.sendBatch(processedBatch);
114
+ this.persistBatch(rawBatch.content);
76
115
  }
77
116
  compressBatch(batch) {
78
117
  if (batch.content.length === 0 ||
79
118
  this.params.config.compressionOptions === undefined ||
80
- this.params.config.compressionOptions.minimumBatchSizeInBytes > batch.contentSizeInBytes) {
81
- // Nothing to do if the batch is empty or if compression is disabled or if we don't need to compress
119
+ this.params.config.compressionOptions.minimumBatchSizeInBytes >
120
+ batch.contentSizeInBytes ||
121
+ this.params.containerContext.submitBatchFn === undefined) {
122
+ // Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress
82
123
  return batch;
83
124
  }
84
125
  const compressedBatch = this.params.compressor.compressBatch(batch);
85
- if (compressedBatch.contentSizeInBytes <= this.params.config.maxBatchSizeInBytes) {
86
- // If we don't reach the maximum supported size of a batch, it can safely be sent as is
87
- return compressedBatch;
88
- }
89
126
  if (this.params.splitter.isBatchChunkingEnabled) {
90
- return this.params.splitter.splitCompressedBatch(compressedBatch);
127
+ return compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes
128
+ ? compressedBatch
129
+ : this.params.splitter.splitCompressedBatch(compressedBatch);
130
+ }
131
+ if (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {
132
+ throw new GenericError("BatchTooLarge", /* error */ undefined, {
133
+ batchSize: batch.contentSizeInBytes,
134
+ compressedBatchSize: compressedBatch.contentSizeInBytes,
135
+ count: compressedBatch.content.length,
136
+ limit: this.params.config.maxBatchSizeInBytes,
137
+ chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
138
+ compressionOptions: JSON.stringify(this.params.config.compressionOptions),
139
+ socketSize: estimateSocketSize(batch),
140
+ });
91
141
  }
92
- // If we've reached this point, the runtime would attempt to send a batch larger than the allowed size
93
- throw new GenericError("BatchTooLarge", /* error */ undefined, {
94
- batchSize: batch.contentSizeInBytes,
95
- compressedBatchSize: compressedBatch.contentSizeInBytes,
96
- count: compressedBatch.content.length,
97
- limit: this.params.config.maxBatchSizeInBytes,
98
- chunkingEnabled: this.params.splitter.isBatchChunkingEnabled,
99
- compressionOptions: JSON.stringify(this.params.config.compressionOptions),
100
- });
142
+ return compressedBatch;
101
143
  }
102
144
  /**
103
145
  * Sends the batch object to the container context to be sent over the wire.
104
146
  *
105
147
  * @param batch - batch to be sent
106
- * @returns the client sequence number of the last batched op which was sent and
107
- * -1 if there are no ops or the container cannot send ops.
108
148
  */
109
149
  sendBatch(batch) {
110
- var _a;
111
- let clientSequenceNumber = -1;
112
150
  const length = batch.content.length;
113
151
  // Did we disconnect in the middle of turn-based batch?
114
152
  // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
115
153
  if (length === 0 || !this.params.shouldSend()) {
116
- return clientSequenceNumber;
154
+ return;
155
+ }
156
+ const socketSize = estimateSocketSize(batch);
157
+ if (socketSize >= this.params.config.maxBatchSizeInBytes) {
158
+ this.mc.logger.sendPerformanceEvent({
159
+ eventName: "LargeBatch",
160
+ length: batch.content.length,
161
+ sizeInBytes: batch.contentSizeInBytes,
162
+ socketSize,
163
+ });
117
164
  }
118
165
  if (this.params.containerContext.submitBatchFn === undefined) {
119
166
  // Legacy path - supporting old loader versions. Can be removed only when LTS moves above
120
167
  // version that has support for batches (submitBatchFn)
168
+ assert(batch.content[0].compression === undefined, 0x5a6 /* Compression should not have happened if the loader does not support it */);
121
169
  for (const message of batch.content) {
122
- // Legacy path doesn't support compressed payloads and will submit uncompressed payload anyways
123
- if ((_a = message.metadata) === null || _a === void 0 ? void 0 : _a.compressed) {
124
- delete message.metadata.compressed;
125
- }
126
- clientSequenceNumber = this.params.containerContext.submitFn(MessageType.Operation, message.deserializedContent, true, // batch
170
+ this.params.containerContext.submitFn(MessageType.Operation, message.deserializedContent, true, // batch
127
171
  message.metadata);
128
172
  }
129
173
  this.params.containerContext.deltaManager.flush();
130
174
  }
131
175
  else {
132
- // returns clientSequenceNumber of last message in a batch
133
- clientSequenceNumber = this.params.containerContext.submitBatchFn(batch.content.map((message) => ({
176
+ assert(batch.referenceSequenceNumber !== undefined, 0x58e /* Batch must not be empty */);
177
+ this.params.containerContext.submitBatchFn(batch.content.map((message) => ({
134
178
  contents: message.contents,
135
179
  metadata: message.metadata,
136
180
  compression: message.compression,
137
- })));
181
+ referenceSequenceNumber: message.referenceSequenceNumber,
182
+ })), batch.referenceSequenceNumber);
138
183
  }
139
- // Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.
140
- clientSequenceNumber -= length - 1;
141
- assert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);
142
- return clientSequenceNumber;
143
184
  }
144
- persistBatch(initialClientSequenceNumber, batch) {
145
- let clientSequenceNumber = initialClientSequenceNumber;
185
+ persistBatch(batch) {
146
186
  // Let the PendingStateManager know that a message was submitted.
147
187
  // In future, need to shift toward keeping batch as a whole!
148
188
  for (const message of batch) {
149
- this.params.pendingStateManager.onSubmitMessage(message.deserializedContent.type, clientSequenceNumber, message.referenceSequenceNumber, message.deserializedContent.contents, message.localOpMetadata, message.metadata);
150
- clientSequenceNumber++;
189
+ this.params.pendingStateManager.onSubmitMessage(message.deserializedContent.type, message.referenceSequenceNumber, message.deserializedContent.contents, message.localOpMetadata, message.metadata);
151
190
  }
152
191
  }
153
192
  checkpoint() {
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainerContext } from \"@fluidframework/container-definitions\";\nimport { GenericError } from \"@fluidframework/container-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { PendingStateManager } from \"../pendingStateManager\";\nimport { BatchManager } from \"./batchManager\";\nimport { BatchMessage, IBatch } from \"./definitions\";\nimport { OpCompressor } from \"./opCompressor\";\nimport { OpSplitter } from \"./opSplitter\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly enableOpReentryCheck?: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly containerContext: IContainerContext;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryLogger;\n}\n\nexport class Outbox {\n\tprivate readonly attachFlowBatch: BatchManager;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly defaultAttachFlowSoftLimitInBytes = 64 * 1024;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\t\tconst softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;\n\n\t\tthis.attachFlowBatch = new BatchManager(\n\t\t\t{\n\t\t\t\thardLimit,\n\t\t\t\tsoftLimit,\n\t\t\t\tenableOpReentryCheck: params.config.enableOpReentryCheck,\n\t\t\t},\n\t\t\tparams.logger,\n\t\t);\n\t\tthis.mainBatch = new BatchManager(\n\t\t\t{\n\t\t\t\thardLimit,\n\t\t\t\tenableOpReentryCheck: params.config.enableOpReentryCheck,\n\t\t\t},\n\t\t\tparams.logger,\n\t\t);\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tif (!this.mainBatch.push(message)) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: this.mainBatch.contentSizeInBytes,\n\t\t\t\tcount: this.mainBatch.length,\n\t\t\t\tlimit: this.mainBatch.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic submitAttach(message: BatchMessage) {\n\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\t\tbatchSize: this.attachFlowBatch.contentSizeInBytes,\n\t\t\t\t\tcount: this.attachFlowBatch.length,\n\t\t\t\t\tlimit: this.attachFlowBatch.options.hardLimit,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.attachFlowBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\tthis.flushInternal(this.mainBatch.popBatch());\n\t}\n\n\tprivate flushInternal(rawBatch: IBatch) {\n\t\tconst processedBatch = this.compressBatch(rawBatch);\n\t\tconst clientSequenceNumber = this.sendBatch(processedBatch);\n\n\t\tthis.persistBatch(clientSequenceNumber, rawBatch.content);\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes > batch.contentSizeInBytes\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\t\tif (compressedBatch.contentSizeInBytes <= this.params.config.maxBatchSizeInBytes) {\n\t\t\t// If we don't reach the maximum supported size of a batch, it can safely be sent as is\n\t\t\treturn compressedBatch;\n\t\t}\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn this.params.splitter.splitCompressedBatch(compressedBatch);\n\t\t}\n\n\t\t// If we've reached this point, the runtime would attempt to send a batch larger than the allowed size\n\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\tcount: compressedBatch.content.length,\n\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t});\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t * @returns the client sequence number of the last batched op which was sent and\n\t * -1 if there are no ops or the container cannot send ops.\n\t */\n\tprivate sendBatch(batch: IBatch): number {\n\t\tlet clientSequenceNumber: number = -1;\n\t\tconst length = batch.content.length;\n\n\t\t// Did we disconnect in the middle of turn-based batch?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\tif (length === 0 || !this.params.shouldSend()) {\n\t\t\treturn clientSequenceNumber;\n\t\t}\n\n\t\tif (this.params.containerContext.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tfor (const message of batch.content) {\n\t\t\t\t// Legacy path doesn't support compressed payloads and will submit uncompressed payload anyways\n\t\t\t\tif (message.metadata?.compressed) {\n\t\t\t\t\tdelete message.metadata.compressed;\n\t\t\t\t}\n\n\t\t\t\tclientSequenceNumber = this.params.containerContext.submitFn(\n\t\t\t\t\tMessageType.Operation,\n\t\t\t\t\tmessage.deserializedContent,\n\t\t\t\t\ttrue, // batch\n\t\t\t\t\tmessage.metadata,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.params.containerContext.deltaManager.flush();\n\t\t} else {\n\t\t\t// returns clientSequenceNumber of last message in a batch\n\t\t\tclientSequenceNumber = this.params.containerContext.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t})),\n\t\t\t);\n\t\t}\n\n\t\t// Convert from clientSequenceNumber of last message in the batch to clientSequenceNumber of first message.\n\t\tclientSequenceNumber -= length - 1;\n\t\tassert(clientSequenceNumber >= 0, 0x3d0 /* clientSequenceNumber can't be negative */);\n\t\treturn clientSequenceNumber;\n\t}\n\n\tprivate persistBatch(initialClientSequenceNumber: number, batch: BatchMessage[]) {\n\t\tlet clientSequenceNumber = initialClientSequenceNumber;\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\tmessage.deserializedContent.type,\n\t\t\t\tclientSequenceNumber,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.deserializedContent.contents,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\n\t\t\tclientSequenceNumber++;\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\treturn {\n\t\t\tmainBatch: this.mainBatch.checkpoint(),\n\t\t\tattachFlowBatch: this.attachFlowBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/opLifecycle/outbox.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainerContext } from \"@fluidframework/container-definitions\";\nimport { GenericError, UsageError } from \"@fluidframework/container-utils\";\nimport { MessageType } from \"@fluidframework/protocol-definitions\";\nimport {\n\tChildLogger,\n\tloggerToMonitoringContext,\n\tMonitoringContext,\n} from \"@fluidframework/telemetry-utils\";\nimport { ICompressionRuntimeOptions } from \"../containerRuntime\";\nimport { PendingStateManager } from \"../pendingStateManager\";\nimport { BatchManager, estimateSocketSize } from \"./batchManager\";\nimport { BatchMessage, IBatch } from \"./definitions\";\nimport { OpCompressor } from \"./opCompressor\";\nimport { OpSplitter } from \"./opSplitter\";\n\nexport interface IOutboxConfig {\n\treadonly compressionOptions: ICompressionRuntimeOptions;\n\t// The maximum size of a batch that we can send over the wire.\n\treadonly maxBatchSizeInBytes: number;\n\treadonly disablePartialFlush: boolean;\n}\n\nexport interface IOutboxParameters {\n\treadonly shouldSend: () => boolean;\n\treadonly pendingStateManager: PendingStateManager;\n\treadonly containerContext: IContainerContext;\n\treadonly config: IOutboxConfig;\n\treadonly compressor: OpCompressor;\n\treadonly splitter: OpSplitter;\n\treadonly logger: ITelemetryLogger;\n}\n\nexport class Outbox {\n\tprivate readonly mc: MonitoringContext;\n\tprivate readonly attachFlowBatch: BatchManager;\n\tprivate readonly mainBatch: BatchManager;\n\tprivate readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;\n\n\t/**\n\t * Track the number of ops which were detected to have a mismatched\n\t * reference sequence number, in order to self-throttle the telemetry events.\n\t *\n\t * This should be removed as part of ADO:2322\n\t */\n\tprivate readonly maxMismatchedOpsToReport = 3;\n\tprivate mismatchedOpsReported = 0;\n\n\tconstructor(private readonly params: IOutboxParameters) {\n\t\tthis.mc = loggerToMonitoringContext(ChildLogger.create(params.logger, \"Outbox\"));\n\t\tconst isCompressionEnabled =\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes !==\n\t\t\tNumber.POSITIVE_INFINITY;\n\t\t// We need to allow infinite size batches if we enable compression\n\t\tconst hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;\n\t\tconst softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;\n\n\t\tthis.attachFlowBatch = new BatchManager({ hardLimit, softLimit });\n\t\tthis.mainBatch = new BatchManager({ hardLimit });\n\t}\n\n\tpublic get isEmpty(): boolean {\n\t\treturn this.attachFlowBatch.length === 0 && this.mainBatch.length === 0;\n\t}\n\n\t/**\n\t * If we detect that the reference sequence number of the incoming message does not match\n\t * what was already in the batch managers, this means that batching has been interrupted so\n\t * we will flush the accumulated messages to account for that and create a new batch with the new\n\t * message as the first message.\n\t *\n\t * @param message - the incoming message\n\t */\n\tprivate maybeFlushPartialBatch(message: BatchMessage) {\n\t\tconst mainBatchReference = this.mainBatch.referenceSequenceNumber;\n\t\tconst attachFlowBatchReference = this.attachFlowBatch.referenceSequenceNumber;\n\t\tassert(\n\t\t\tthis.params.config.disablePartialFlush ||\n\t\t\t\tmainBatchReference === undefined ||\n\t\t\t\tattachFlowBatchReference === undefined ||\n\t\t\t\tmainBatchReference === attachFlowBatchReference,\n\t\t\t0x58d /* Reference sequence numbers from both batches must be in sync */,\n\t\t);\n\n\t\tif (\n\t\t\t(mainBatchReference === undefined ||\n\t\t\t\tmainBatchReference === message.referenceSequenceNumber) &&\n\t\t\t(attachFlowBatchReference === undefined ||\n\t\t\t\tattachFlowBatchReference === message.referenceSequenceNumber)\n\t\t) {\n\t\t\t// The reference sequence numbers are stable, there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (++this.mismatchedOpsReported <= this.maxMismatchedOpsToReport) {\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"ReferenceSequenceNumberMismatch\",\n\t\t\t\t\tmainReferenceSequenceNumber: mainBatchReference,\n\t\t\t\t\tattachReferenceSequenceNumber: attachFlowBatchReference,\n\t\t\t\t\tmessageReferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t},\n\t\t\t\tnew UsageError(\"Submission of an out of order message\"),\n\t\t\t);\n\t\t}\n\n\t\tif (!this.params.config.disablePartialFlush) {\n\t\t\tthis.flush();\n\t\t}\n\t}\n\n\tpublic submit(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch(message);\n\n\t\tif (!this.mainBatch.push(message)) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\tbatchSize: this.mainBatch.contentSizeInBytes,\n\t\t\t\tcount: this.mainBatch.length,\n\t\t\t\tlimit: this.mainBatch.options.hardLimit,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic submitAttach(message: BatchMessage) {\n\t\tthis.maybeFlushPartialBatch(message);\n\n\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t// BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged\n\t\t\t// when queue is not empty.\n\t\t\t// Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t\tif (!this.attachFlowBatch.push(message)) {\n\t\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\t\topSize: message.contents?.length ?? 0,\n\t\t\t\t\tbatchSize: this.attachFlowBatch.contentSizeInBytes,\n\t\t\t\t\tcount: this.attachFlowBatch.length,\n\t\t\t\t\tlimit: this.attachFlowBatch.options.hardLimit,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// If compression is enabled, we will always successfully receive\n\t\t// attach ops and compress then send them at the next JS turn, regardless\n\t\t// of the overall size of the accumulated ops in the batch.\n\t\t// However, it is more efficient to flush these ops faster, preferably\n\t\t// after they reach a size which would benefit from compression.\n\t\tif (\n\t\t\tthis.attachFlowBatch.contentSizeInBytes >=\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes\n\t\t) {\n\t\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\t}\n\t}\n\n\tpublic flush() {\n\t\tthis.flushInternal(this.attachFlowBatch.popBatch());\n\t\tthis.flushInternal(this.mainBatch.popBatch());\n\t}\n\n\tprivate flushInternal(rawBatch: IBatch) {\n\t\tconst processedBatch = this.compressBatch(rawBatch);\n\t\tthis.sendBatch(processedBatch);\n\n\t\tthis.persistBatch(rawBatch.content);\n\t}\n\n\tprivate compressBatch(batch: IBatch): IBatch {\n\t\tif (\n\t\t\tbatch.content.length === 0 ||\n\t\t\tthis.params.config.compressionOptions === undefined ||\n\t\t\tthis.params.config.compressionOptions.minimumBatchSizeInBytes >\n\t\t\t\tbatch.contentSizeInBytes ||\n\t\t\tthis.params.containerContext.submitBatchFn === undefined\n\t\t) {\n\t\t\t// Nothing to do if the batch is empty or if compression is disabled or not supported, or if we don't need to compress\n\t\t\treturn batch;\n\t\t}\n\n\t\tconst compressedBatch = this.params.compressor.compressBatch(batch);\n\n\t\tif (this.params.splitter.isBatchChunkingEnabled) {\n\t\t\treturn compressedBatch.contentSizeInBytes <= this.params.splitter.chunkSizeInBytes\n\t\t\t\t? compressedBatch\n\t\t\t\t: this.params.splitter.splitCompressedBatch(compressedBatch);\n\t\t}\n\n\t\tif (compressedBatch.contentSizeInBytes >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthrow new GenericError(\"BatchTooLarge\", /* error */ undefined, {\n\t\t\t\tbatchSize: batch.contentSizeInBytes,\n\t\t\t\tcompressedBatchSize: compressedBatch.contentSizeInBytes,\n\t\t\t\tcount: compressedBatch.content.length,\n\t\t\t\tlimit: this.params.config.maxBatchSizeInBytes,\n\t\t\t\tchunkingEnabled: this.params.splitter.isBatchChunkingEnabled,\n\t\t\t\tcompressionOptions: JSON.stringify(this.params.config.compressionOptions),\n\t\t\t\tsocketSize: estimateSocketSize(batch),\n\t\t\t});\n\t\t}\n\n\t\treturn compressedBatch;\n\t}\n\n\t/**\n\t * Sends the batch object to the container context to be sent over the wire.\n\t *\n\t * @param batch - batch to be sent\n\t */\n\tprivate sendBatch(batch: IBatch) {\n\t\tconst length = batch.content.length;\n\n\t\t// Did we disconnect in the middle of turn-based batch?\n\t\t// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.\n\t\tif (length === 0 || !this.params.shouldSend()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst socketSize = estimateSocketSize(batch);\n\t\tif (socketSize >= this.params.config.maxBatchSizeInBytes) {\n\t\t\tthis.mc.logger.sendPerformanceEvent({\n\t\t\t\teventName: \"LargeBatch\",\n\t\t\t\tlength: batch.content.length,\n\t\t\t\tsizeInBytes: batch.contentSizeInBytes,\n\t\t\t\tsocketSize,\n\t\t\t});\n\t\t}\n\n\t\tif (this.params.containerContext.submitBatchFn === undefined) {\n\t\t\t// Legacy path - supporting old loader versions. Can be removed only when LTS moves above\n\t\t\t// version that has support for batches (submitBatchFn)\n\t\t\tassert(\n\t\t\t\tbatch.content[0].compression === undefined,\n\t\t\t\t0x5a6 /* Compression should not have happened if the loader does not support it */,\n\t\t\t);\n\n\t\t\tfor (const message of batch.content) {\n\t\t\t\tthis.params.containerContext.submitFn(\n\t\t\t\t\tMessageType.Operation,\n\t\t\t\t\tmessage.deserializedContent,\n\t\t\t\t\ttrue, // batch\n\t\t\t\t\tmessage.metadata,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.params.containerContext.deltaManager.flush();\n\t\t} else {\n\t\t\tassert(\n\t\t\t\tbatch.referenceSequenceNumber !== undefined,\n\t\t\t\t0x58e /* Batch must not be empty */,\n\t\t\t);\n\t\t\tthis.params.containerContext.submitBatchFn(\n\t\t\t\tbatch.content.map((message) => ({\n\t\t\t\t\tcontents: message.contents,\n\t\t\t\t\tmetadata: message.metadata,\n\t\t\t\t\tcompression: message.compression,\n\t\t\t\t\treferenceSequenceNumber: message.referenceSequenceNumber,\n\t\t\t\t})),\n\t\t\t\tbatch.referenceSequenceNumber,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate persistBatch(batch: BatchMessage[]) {\n\t\t// Let the PendingStateManager know that a message was submitted.\n\t\t// In future, need to shift toward keeping batch as a whole!\n\t\tfor (const message of batch) {\n\t\t\tthis.params.pendingStateManager.onSubmitMessage(\n\t\t\t\tmessage.deserializedContent.type,\n\t\t\t\tmessage.referenceSequenceNumber,\n\t\t\t\tmessage.deserializedContent.contents,\n\t\t\t\tmessage.localOpMetadata,\n\t\t\t\tmessage.metadata,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic checkpoint() {\n\t\treturn {\n\t\t\tmainBatch: this.mainBatch.checkpoint(),\n\t\t\tattachFlowBatch: this.attachFlowBatch.checkpoint(),\n\t\t};\n\t}\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "2.0.0-dev.3.1.0.125672";
8
+ export declare const pkgVersion = "2.0.0-dev.4.1.0.148229";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-runtime";
8
- export const pkgVersion = "2.0.0-dev.3.1.0.125672";
8
+ export const pkgVersion = "2.0.0-dev.4.1.0.148229";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.3.1.0.125672\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.4.1.0.148229\";\n"]}
@@ -22,11 +22,12 @@ export interface IPendingMessage {
22
22
  /**
23
23
  * This represents an explicit flush call and is added to the pending queue when flush is called on the ContainerRuntime
24
24
  * to flush pending messages.
25
- * @deprecated Use batch metadata on IPendingMessage instead. To be removed in 2.0.0-internal.4.0.0 (AB#2496)
25
+ * ! TODO: Remove in "2.0.0-internal.5.0.0" AB#2496
26
26
  */
27
27
  export interface IPendingFlush {
28
28
  type: "flush";
29
29
  }
30
+ /** ! TODO: Remove in "2.0.0-internal.5.0.0" AB#2496 */
30
31
  export declare type IPendingState = IPendingMessage | IPendingFlush;
31
32
  export interface IPendingLocalState {
32
33
  /**
@@ -74,11 +75,10 @@ export declare class PendingStateManager implements IDisposable {
74
75
  * Called when a message is submitted locally. Adds the message and the associated details to the pending state
75
76
  * queue.
76
77
  * @param type - The container message type.
77
- * @param clientSequenceNumber - The clientSequenceNumber associated with the message.
78
78
  * @param content - The message content.
79
79
  * @param localOpMetadata - The local metadata associated with the message.
80
80
  */
81
- onSubmitMessage(type: ContainerMessageType, clientSequenceNumber: number, referenceSequenceNumber: number, content: any, localOpMetadata: unknown, opMetadata: Record<string, unknown> | undefined): void;
81
+ onSubmitMessage(type: ContainerMessageType, referenceSequenceNumber: number, content: any, localOpMetadata: unknown, opMetadata: Record<string, unknown> | undefined): void;
82
82
  /**
83
83
  * Applies stashed ops at their reference sequence number so they are ready to be ACKed or resubmitted
84
84
  * @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
@@ -1 +1 @@
1
- {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pendingStateManager.d.ts","sourceRoot":"","sources":["../src/pendingStateManager.ts"],"names":[],"mappings":"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"}