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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +69 -0
  3. package/dist/blobManager.d.ts +29 -24
  4. package/dist/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager.js +162 -92
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +74 -76
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +328 -264
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +39 -13
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js +112 -49
  14. package/dist/dataStoreContext.js.map +1 -1
  15. package/dist/dataStores.d.ts +28 -4
  16. package/dist/dataStores.d.ts.map +1 -1
  17. package/dist/dataStores.js +107 -41
  18. package/dist/dataStores.js.map +1 -1
  19. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  20. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  21. package/dist/deltaManagerSummarizerProxy.js +40 -0
  22. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  23. package/dist/gc/garbageCollection.d.ts +204 -0
  24. package/dist/gc/garbageCollection.d.ts.map +1 -0
  25. package/dist/{garbageCollection.js → gc/garbageCollection.js} +190 -554
  26. package/dist/gc/garbageCollection.js.map +1 -0
  27. package/dist/gc/gcConfigs.d.ts +22 -0
  28. package/dist/gc/gcConfigs.d.ts.map +1 -0
  29. package/dist/gc/gcConfigs.js +143 -0
  30. package/dist/gc/gcConfigs.js.map +1 -0
  31. package/dist/gc/gcDefinitions.d.ts +320 -0
  32. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  33. package/dist/gc/gcDefinitions.js +81 -0
  34. package/dist/gc/gcDefinitions.js.map +1 -0
  35. package/dist/gc/gcHelpers.d.ts +86 -0
  36. package/dist/gc/gcHelpers.d.ts.map +1 -0
  37. package/dist/gc/gcHelpers.js +268 -0
  38. package/dist/gc/gcHelpers.js.map +1 -0
  39. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  40. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  41. package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
  42. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  43. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  44. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  45. package/dist/gc/gcSummaryDefinitions.js +7 -0
  46. package/dist/gc/gcSummaryDefinitions.js.map +1 -0
  47. package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
  48. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  49. package/dist/gc/gcSummaryStateTracker.js +239 -0
  50. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  51. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  52. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
  53. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  54. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  55. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  56. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  57. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  58. package/dist/gc/index.d.ts +13 -0
  59. package/dist/gc/index.d.ts.map +1 -0
  60. package/dist/gc/index.js +50 -0
  61. package/dist/gc/index.js.map +1 -0
  62. package/dist/index.d.ts +3 -7
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +5 -9
  65. package/dist/index.js.map +1 -1
  66. package/dist/opLifecycle/batchManager.d.ts +11 -13
  67. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  68. package/dist/opLifecycle/batchManager.js +26 -38
  69. package/dist/opLifecycle/batchManager.js.map +1 -1
  70. package/dist/opLifecycle/definitions.d.ts +4 -0
  71. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  72. package/dist/opLifecycle/definitions.js.map +1 -1
  73. package/dist/opLifecycle/index.d.ts +2 -1
  74. package/dist/opLifecycle/index.d.ts.map +1 -1
  75. package/dist/opLifecycle/index.js +4 -1
  76. package/dist/opLifecycle/index.js.map +1 -1
  77. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  78. package/dist/opLifecycle/opCompressor.js +25 -10
  79. package/dist/opLifecycle/opCompressor.js.map +1 -1
  80. package/dist/opLifecycle/opDecompressor.d.ts +4 -0
  81. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  82. package/dist/opLifecycle/opDecompressor.js +43 -4
  83. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  84. package/dist/opLifecycle/opGroupingManager.d.ts +14 -0
  85. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
  86. package/dist/opLifecycle/opGroupingManager.js +56 -0
  87. package/dist/opLifecycle/opGroupingManager.js.map +1 -0
  88. package/dist/opLifecycle/opSplitter.d.ts +16 -4
  89. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  90. package/dist/opLifecycle/opSplitter.js +39 -15
  91. package/dist/opLifecycle/opSplitter.js.map +1 -1
  92. package/dist/opLifecycle/outbox.d.ts +21 -3
  93. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  94. package/dist/opLifecycle/outbox.js +90 -51
  95. package/dist/opLifecycle/outbox.js.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  97. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  98. package/dist/opLifecycle/remoteMessageProcessor.js +30 -20
  99. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  100. package/dist/packageVersion.d.ts +1 -1
  101. package/dist/packageVersion.js +1 -1
  102. package/dist/packageVersion.js.map +1 -1
  103. package/dist/pendingStateManager.d.ts +3 -3
  104. package/dist/pendingStateManager.d.ts.map +1 -1
  105. package/dist/pendingStateManager.js +20 -21
  106. package/dist/pendingStateManager.js.map +1 -1
  107. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  108. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  109. package/dist/storageServiceWithAttachBlobs.js +32 -0
  110. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  111. package/dist/summary/index.d.ts +17 -0
  112. package/dist/summary/index.d.ts.map +1 -0
  113. package/dist/summary/index.js +48 -0
  114. package/dist/summary/index.js.map +1 -0
  115. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  116. package/dist/summary/orderedClientElection.js.map +1 -0
  117. package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  118. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  119. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  120. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  121. package/{lib → dist/summary}/runningSummarizer.d.ts +23 -20
  122. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  123. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -74
  124. package/dist/summary/runningSummarizer.js.map +1 -0
  125. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  126. package/dist/summary/summarizer.d.ts.map +1 -0
  127. package/dist/{summarizer.js → summary/summarizer.js} +10 -79
  128. package/dist/summary/summarizer.js.map +1 -0
  129. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  130. package/dist/summary/summarizerClientElection.js.map +1 -0
  131. package/dist/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
  132. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  133. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
  134. package/dist/summary/summarizerHeuristics.js.map +1 -0
  135. package/dist/summary/summarizerNode/index.d.ts +8 -0
  136. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  137. package/dist/summary/summarizerNode/index.js +12 -0
  138. package/dist/summary/summarizerNode/index.js.map +1 -0
  139. package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
  140. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  141. package/dist/summary/summarizerNode/summarizerNode.js +531 -0
  142. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
  143. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  144. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  145. package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
  146. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  147. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
  148. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  149. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +424 -0
  150. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  151. package/{lib → dist/summary}/summarizerTypes.d.ts +21 -19
  152. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  153. package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
  154. package/dist/summary/summarizerTypes.js.map +1 -0
  155. package/dist/summary/summaryCollection.d.ts.map +1 -0
  156. package/dist/summary/summaryCollection.js.map +1 -0
  157. package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
  158. package/dist/summary/summaryFormat.d.ts.map +1 -0
  159. package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
  160. package/dist/summary/summaryFormat.js.map +1 -0
  161. package/{lib → dist/summary}/summaryGenerator.d.ts +28 -2
  162. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  163. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +23 -20
  164. package/dist/summary/summaryGenerator.js.map +1 -0
  165. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  166. package/dist/summary/summaryManager.d.ts.map +1 -0
  167. package/dist/summary/summaryManager.js.map +1 -0
  168. package/lib/blobManager.d.ts +29 -24
  169. package/lib/blobManager.d.ts.map +1 -1
  170. package/lib/blobManager.js +159 -89
  171. package/lib/blobManager.js.map +1 -1
  172. package/lib/containerRuntime.d.ts +74 -76
  173. package/lib/containerRuntime.d.ts.map +1 -1
  174. package/lib/containerRuntime.js +301 -237
  175. package/lib/containerRuntime.js.map +1 -1
  176. package/lib/dataStoreContext.d.ts +39 -13
  177. package/lib/dataStoreContext.d.ts.map +1 -1
  178. package/lib/dataStoreContext.js +101 -38
  179. package/lib/dataStoreContext.js.map +1 -1
  180. package/lib/dataStores.d.ts +28 -4
  181. package/lib/dataStores.d.ts.map +1 -1
  182. package/lib/dataStores.js +100 -34
  183. package/lib/dataStores.js.map +1 -1
  184. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  185. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  186. package/lib/deltaManagerSummarizerProxy.js +36 -0
  187. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  188. package/lib/gc/garbageCollection.d.ts +204 -0
  189. package/lib/gc/garbageCollection.d.ts.map +1 -0
  190. package/lib/{garbageCollection.js → gc/garbageCollection.js} +172 -535
  191. package/lib/gc/garbageCollection.js.map +1 -0
  192. package/lib/gc/gcConfigs.d.ts +22 -0
  193. package/lib/gc/gcConfigs.d.ts.map +1 -0
  194. package/lib/gc/gcConfigs.js +139 -0
  195. package/lib/gc/gcConfigs.js.map +1 -0
  196. package/lib/gc/gcDefinitions.d.ts +320 -0
  197. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  198. package/lib/gc/gcDefinitions.js +78 -0
  199. package/lib/gc/gcDefinitions.js.map +1 -0
  200. package/lib/gc/gcHelpers.d.ts +86 -0
  201. package/lib/gc/gcHelpers.d.ts.map +1 -0
  202. package/lib/gc/gcHelpers.js +254 -0
  203. package/lib/gc/gcHelpers.js.map +1 -0
  204. package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  205. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  206. package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
  207. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  208. package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
  209. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  210. package/lib/gc/gcSummaryDefinitions.js +6 -0
  211. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  212. package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
  213. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  214. package/lib/gc/gcSummaryStateTracker.js +235 -0
  215. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  216. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  217. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
  218. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  219. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  220. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  221. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  222. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  223. package/lib/gc/index.d.ts +13 -0
  224. package/lib/gc/index.d.ts.map +1 -0
  225. package/lib/gc/index.js +12 -0
  226. package/lib/gc/index.js.map +1 -0
  227. package/lib/index.d.ts +3 -7
  228. package/lib/index.d.ts.map +1 -1
  229. package/lib/index.js +1 -4
  230. package/lib/index.js.map +1 -1
  231. package/lib/opLifecycle/batchManager.d.ts +11 -13
  232. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  233. package/lib/opLifecycle/batchManager.js +24 -37
  234. package/lib/opLifecycle/batchManager.js.map +1 -1
  235. package/lib/opLifecycle/definitions.d.ts +4 -0
  236. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  237. package/lib/opLifecycle/definitions.js.map +1 -1
  238. package/lib/opLifecycle/index.d.ts +2 -1
  239. package/lib/opLifecycle/index.d.ts.map +1 -1
  240. package/lib/opLifecycle/index.js +2 -1
  241. package/lib/opLifecycle/index.js.map +1 -1
  242. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  243. package/lib/opLifecycle/opCompressor.js +26 -11
  244. package/lib/opLifecycle/opCompressor.js.map +1 -1
  245. package/lib/opLifecycle/opDecompressor.d.ts +4 -0
  246. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  247. package/lib/opLifecycle/opDecompressor.js +43 -4
  248. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  249. package/lib/opLifecycle/opGroupingManager.d.ts +14 -0
  250. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
  251. package/lib/opLifecycle/opGroupingManager.js +52 -0
  252. package/lib/opLifecycle/opGroupingManager.js.map +1 -0
  253. package/lib/opLifecycle/opSplitter.d.ts +16 -4
  254. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  255. package/lib/opLifecycle/opSplitter.js +39 -15
  256. package/lib/opLifecycle/opSplitter.js.map +1 -1
  257. package/lib/opLifecycle/outbox.d.ts +21 -3
  258. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  259. package/lib/opLifecycle/outbox.js +92 -53
  260. package/lib/opLifecycle/outbox.js.map +1 -1
  261. package/lib/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  262. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  263. package/lib/opLifecycle/remoteMessageProcessor.js +30 -20
  264. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  265. package/lib/packageVersion.d.ts +1 -1
  266. package/lib/packageVersion.js +1 -1
  267. package/lib/packageVersion.js.map +1 -1
  268. package/lib/pendingStateManager.d.ts +3 -3
  269. package/lib/pendingStateManager.d.ts.map +1 -1
  270. package/lib/pendingStateManager.js +20 -21
  271. package/lib/pendingStateManager.js.map +1 -1
  272. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  273. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  274. package/lib/storageServiceWithAttachBlobs.js +28 -0
  275. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  276. package/lib/summary/index.d.ts +17 -0
  277. package/lib/summary/index.d.ts.map +1 -0
  278. package/lib/summary/index.js +16 -0
  279. package/lib/summary/index.js.map +1 -0
  280. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  281. package/lib/summary/orderedClientElection.js.map +1 -0
  282. package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  283. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  284. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  285. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  286. package/{dist → lib/summary}/runningSummarizer.d.ts +23 -20
  287. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  288. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +192 -75
  289. package/lib/summary/runningSummarizer.js.map +1 -0
  290. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  291. package/lib/summary/summarizer.d.ts.map +1 -0
  292. package/lib/{summarizer.js → summary/summarizer.js} +12 -81
  293. package/lib/summary/summarizer.js.map +1 -0
  294. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  295. package/lib/summary/summarizerClientElection.js.map +1 -0
  296. package/lib/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
  297. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  298. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
  299. package/lib/summary/summarizerHeuristics.js.map +1 -0
  300. package/lib/summary/summarizerNode/index.d.ts +8 -0
  301. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  302. package/lib/summary/summarizerNode/index.js +7 -0
  303. package/lib/summary/summarizerNode/index.js.map +1 -0
  304. package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
  305. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  306. package/lib/summary/summarizerNode/summarizerNode.js +526 -0
  307. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  308. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  309. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  310. package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
  311. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  312. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
  313. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  314. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
  315. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  316. package/{dist → lib/summary}/summarizerTypes.d.ts +21 -19
  317. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  318. package/lib/summary/summarizerTypes.js +6 -0
  319. package/lib/summary/summarizerTypes.js.map +1 -0
  320. package/lib/summary/summaryCollection.d.ts.map +1 -0
  321. package/lib/summary/summaryCollection.js.map +1 -0
  322. package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
  323. package/lib/summary/summaryFormat.d.ts.map +1 -0
  324. package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
  325. package/lib/summary/summaryFormat.js.map +1 -0
  326. package/{dist → lib/summary}/summaryGenerator.d.ts +28 -2
  327. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  328. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +21 -19
  329. package/lib/summary/summaryGenerator.js.map +1 -0
  330. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  331. package/lib/summary/summaryManager.d.ts.map +1 -0
  332. package/lib/summary/summaryManager.js.map +1 -0
  333. package/package.json +66 -60
  334. package/src/blobManager.ts +196 -110
  335. package/src/containerRuntime.ts +491 -391
  336. package/src/dataStoreContext.ts +140 -49
  337. package/src/dataStores.ts +139 -41
  338. package/src/deltaManagerSummarizerProxy.ts +46 -0
  339. package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
  340. package/src/{garbageCollection.ts → gc/garbageCollection.ts} +245 -890
  341. package/src/gc/gcConfigs.ts +193 -0
  342. package/src/gc/gcDefinitions.ts +387 -0
  343. package/src/gc/gcHelpers.ts +335 -0
  344. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  345. package/src/gc/gcSummaryDefinitions.ts +54 -0
  346. package/src/gc/gcSummaryStateTracker.ts +329 -0
  347. package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
  348. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  349. package/src/gc/index.ts +65 -0
  350. package/src/index.ts +10 -22
  351. package/src/opLifecycle/README.md +263 -0
  352. package/src/opLifecycle/batchManager.ts +26 -55
  353. package/src/opLifecycle/definitions.ts +4 -0
  354. package/src/opLifecycle/index.ts +2 -1
  355. package/src/opLifecycle/opCompressor.ts +32 -12
  356. package/src/opLifecycle/opDecompressor.ts +50 -5
  357. package/src/opLifecycle/opGroupingManager.ts +78 -0
  358. package/src/opLifecycle/opSplitter.ts +56 -17
  359. package/src/opLifecycle/outbox.ts +126 -62
  360. package/src/opLifecycle/remoteMessageProcessor.ts +38 -22
  361. package/src/packageVersion.ts +1 -1
  362. package/src/pendingStateManager.ts +34 -27
  363. package/src/storageServiceWithAttachBlobs.ts +38 -0
  364. package/src/summary/index.ts +105 -0
  365. package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +7 -7
  366. package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +318 -156
  367. package/src/{summarizer.ts → summary/summarizer.ts} +12 -105
  368. package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +13 -4
  369. package/src/summary/summarizerNode/index.ts +12 -0
  370. package/src/summary/summarizerNode/summarizerNode.ts +766 -0
  371. package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
  372. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
  373. package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +28 -25
  374. package/src/{summaryFormat.ts → summary/summaryFormat.ts} +3 -29
  375. package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +34 -27
  376. package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
  377. package/dist/garbageCollection.d.ts +0 -411
  378. package/dist/garbageCollection.d.ts.map +0 -1
  379. package/dist/garbageCollection.js.map +0 -1
  380. package/dist/garbageCollectionConstants.d.ts +0 -23
  381. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  382. package/dist/garbageCollectionConstants.js +0 -36
  383. package/dist/garbageCollectionConstants.js.map +0 -1
  384. package/dist/garbageCollectionHelpers.d.ts +0 -15
  385. package/dist/garbageCollectionHelpers.d.ts.map +0 -1
  386. package/dist/garbageCollectionHelpers.js +0 -27
  387. package/dist/garbageCollectionHelpers.js.map +0 -1
  388. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  389. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  390. package/dist/orderedClientElection.d.ts.map +0 -1
  391. package/dist/orderedClientElection.js.map +0 -1
  392. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  393. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  394. package/dist/runningSummarizer.d.ts.map +0 -1
  395. package/dist/runningSummarizer.js.map +0 -1
  396. package/dist/serializedSnapshotStorage.d.ts +0 -58
  397. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  398. package/dist/serializedSnapshotStorage.js +0 -110
  399. package/dist/serializedSnapshotStorage.js.map +0 -1
  400. package/dist/summarizer.d.ts.map +0 -1
  401. package/dist/summarizer.js.map +0 -1
  402. package/dist/summarizerClientElection.d.ts.map +0 -1
  403. package/dist/summarizerClientElection.js.map +0 -1
  404. package/dist/summarizerHandle.d.ts +0 -12
  405. package/dist/summarizerHandle.d.ts.map +0 -1
  406. package/dist/summarizerHandle.js +0 -22
  407. package/dist/summarizerHandle.js.map +0 -1
  408. package/dist/summarizerHeuristics.d.ts.map +0 -1
  409. package/dist/summarizerHeuristics.js.map +0 -1
  410. package/dist/summarizerTypes.d.ts.map +0 -1
  411. package/dist/summarizerTypes.js.map +0 -1
  412. package/dist/summaryCollection.d.ts.map +0 -1
  413. package/dist/summaryCollection.js.map +0 -1
  414. package/dist/summaryFormat.d.ts.map +0 -1
  415. package/dist/summaryFormat.js.map +0 -1
  416. package/dist/summaryGenerator.d.ts.map +0 -1
  417. package/dist/summaryGenerator.js.map +0 -1
  418. package/dist/summaryManager.d.ts.map +0 -1
  419. package/dist/summaryManager.js.map +0 -1
  420. package/lib/garbageCollection.d.ts +0 -411
  421. package/lib/garbageCollection.d.ts.map +0 -1
  422. package/lib/garbageCollection.js.map +0 -1
  423. package/lib/garbageCollectionConstants.d.ts +0 -23
  424. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  425. package/lib/garbageCollectionConstants.js +0 -33
  426. package/lib/garbageCollectionConstants.js.map +0 -1
  427. package/lib/garbageCollectionHelpers.d.ts +0 -15
  428. package/lib/garbageCollectionHelpers.d.ts.map +0 -1
  429. package/lib/garbageCollectionHelpers.js +0 -23
  430. package/lib/garbageCollectionHelpers.js.map +0 -1
  431. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  432. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  433. package/lib/orderedClientElection.d.ts.map +0 -1
  434. package/lib/orderedClientElection.js.map +0 -1
  435. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  436. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  437. package/lib/runningSummarizer.d.ts.map +0 -1
  438. package/lib/runningSummarizer.js.map +0 -1
  439. package/lib/serializedSnapshotStorage.d.ts +0 -58
  440. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  441. package/lib/serializedSnapshotStorage.js +0 -106
  442. package/lib/serializedSnapshotStorage.js.map +0 -1
  443. package/lib/summarizer.d.ts.map +0 -1
  444. package/lib/summarizer.js.map +0 -1
  445. package/lib/summarizerClientElection.d.ts.map +0 -1
  446. package/lib/summarizerClientElection.js.map +0 -1
  447. package/lib/summarizerHandle.d.ts +0 -12
  448. package/lib/summarizerHandle.d.ts.map +0 -1
  449. package/lib/summarizerHandle.js +0 -18
  450. package/lib/summarizerHandle.js.map +0 -1
  451. package/lib/summarizerHeuristics.d.ts.map +0 -1
  452. package/lib/summarizerHeuristics.js.map +0 -1
  453. package/lib/summarizerTypes.d.ts.map +0 -1
  454. package/lib/summarizerTypes.js +0 -9
  455. package/lib/summarizerTypes.js.map +0 -1
  456. package/lib/summaryCollection.d.ts.map +0 -1
  457. package/lib/summaryCollection.js.map +0 -1
  458. package/lib/summaryFormat.d.ts.map +0 -1
  459. package/lib/summaryFormat.js.map +0 -1
  460. package/lib/summaryGenerator.d.ts.map +0 -1
  461. package/lib/summaryGenerator.js.map +0 -1
  462. package/lib/summaryManager.d.ts.map +0 -1
  463. package/lib/summaryManager.js.map +0 -1
  464. package/src/garbageCollectionConstants.ts +0 -38
  465. package/src/garbageCollectionHelpers.ts +0 -37
  466. package/src/serializedSnapshotStorage.ts +0 -151
  467. package/src/summarizerHandle.ts +0 -23
  468. /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  469. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  470. /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  471. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  472. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  473. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  474. /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  475. /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
  476. /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  477. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  478. /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  479. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  480. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  481. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  482. /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  483. /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
  484. /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
  485. /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
  486. /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
@@ -1,35 +1,28 @@
1
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
- import { assert, Trace, TypedEventEmitter, unreachableCase } from "@fluidframework/common-utils";
2
+ import { assert, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
3
3
  import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
4
4
  import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
5
5
  import { readAndParse } from "@fluidframework/driver-utils";
6
6
  import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
7
7
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
8
- import { FlushMode, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
- import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
10
- import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
8
+ import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
+ import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
11
10
  import { v4 as uuid } from "uuid";
12
11
  import { ContainerFluidHandleContext } from "./containerHandleContext";
13
12
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
14
- import { Summarizer } from "./summarizer";
15
- import { SummaryManager } from "./summaryManager";
16
13
  import { ReportOpPerfTelemetry } from "./connectionTelemetry";
17
14
  import { PendingStateManager } from "./pendingStateManager";
18
15
  import { pkgVersion } from "./packageVersion";
19
16
  import { BlobManager } from "./blobManager";
20
17
  import { DataStores, getSummaryForDatastores } from "./dataStores";
21
- import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
22
- import { SummaryCollection } from "./summaryCollection";
23
- import { OrderedClientCollection, OrderedClientElection, } from "./orderedClientElection";
24
- import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
18
+ import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
25
19
  import { formExponentialFn, Throttler } from "./throttler";
26
- import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
27
- import { GarbageCollector, GCNodeType, } from "./garbageCollection";
20
+ import { GarbageCollector, GCNodeType, gcTombstoneGenerationOptionName, shouldAllowGcTombstoneEnforcement, trimLeadingAndTrailingSlashes, } from "./gc";
28
21
  import { channelToDataStore, isDataStoreAliasMessage } from "./dataStore";
29
22
  import { BindBatchTracker } from "./batchTracker";
30
- import { SerializedSnapshotStorage, } from "./serializedSnapshotStorage";
31
23
  import { ScheduleManager } from "./scheduleManager";
32
- import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, } from "./opLifecycle";
24
+ import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, OpGroupingManager, } from "./opLifecycle";
25
+ import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
33
26
  export var ContainerMessageType;
34
27
  (function (ContainerMessageType) {
35
28
  // An op to be delivered to store
@@ -52,7 +45,7 @@ export const DefaultSummaryConfiguration = {
52
45
  maxTime: 60 * 1000,
53
46
  maxOps: 100,
54
47
  minOpsForLastSummaryAttempt: 10,
55
- maxAckWaitTime: 10 * 60 * 1000,
48
+ maxAckWaitTime: 3 * 60 * 1000,
56
49
  maxOpsSinceLastSummary: 7000,
57
50
  initialSummarizerDelayMs: 5 * 1000,
58
51
  nonRuntimeOpWeight: 0.1,
@@ -66,11 +59,6 @@ export var RuntimeHeaders;
66
59
  (function (RuntimeHeaders) {
67
60
  /** True to wait for a data store to be created and loaded before returning it. */
68
61
  RuntimeHeaders["wait"] = "wait";
69
- /**
70
- * True if the request is from an external app. Used for GC to handle scenarios where a data store
71
- * is deleted and requested via an external app.
72
- */
73
- RuntimeHeaders["externalRequest"] = "externalRequest";
74
62
  /** True if the request is coming from an IFluidHandle. */
75
63
  RuntimeHeaders["viaHandle"] = "viaHandle";
76
64
  })(RuntimeHeaders || (RuntimeHeaders = {}));
@@ -81,7 +69,6 @@ export const TombstoneResponseHeaderKey = "isTombstoned";
81
69
  /** Default values for Runtime Headers */
82
70
  export const defaultRuntimeHeaderData = {
83
71
  wait: true,
84
- externalRequest: false,
85
72
  viaHandle: false,
86
73
  allowTombstone: false,
87
74
  };
@@ -98,7 +85,13 @@ const defaultFlushMode = FlushMode.TurnBased;
98
85
  // We can't estimate it fully, as we
99
86
  // - do not know what properties relay service will add
100
87
  // - we do not stringify final op, thus we do not know how much escaping will be added.
101
- const defaultMaxBatchSizeInBytes = 950 * 1024;
88
+ const defaultMaxBatchSizeInBytes = 700 * 1024;
89
+ const defaultCompressionConfig = {
90
+ // Batches with content size exceeding this value will be compressed
91
+ minimumBatchSizeInBytes: 614400,
92
+ compressionAlgorithm: CompressionAlgorithms.lz4,
93
+ };
94
+ const defaultChunkSizeInBytes = 204800;
102
95
  /**
103
96
  * @deprecated - use ContainerRuntimeMessage instead
104
97
  */
@@ -145,8 +138,8 @@ export class ContainerRuntime extends TypedEventEmitter {
145
138
  /**
146
139
  * @internal
147
140
  */
148
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
149
- var _a, _b, _c, _d, _e, _f;
141
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
142
+ var _a, _b, _c, _d, _e, _f, _g, _h;
150
143
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
151
144
  super();
152
145
  this.context = context;
@@ -159,8 +152,7 @@ export class ContainerRuntime extends TypedEventEmitter {
159
152
  this.summaryConfiguration = summaryConfiguration;
160
153
  this.defaultMaxConsecutiveReconnects = 7;
161
154
  this._orderSequentiallyCalls = 0;
162
- this.flushMicroTaskExists = false;
163
- this.savedOps = [];
155
+ this.flushTaskExists = false;
164
156
  this.consecutiveReconnects = 0;
165
157
  this.ensureNoDataModelChangesCalls = 0;
166
158
  /**
@@ -207,6 +199,8 @@ export class ContainerRuntime extends TypedEventEmitter {
207
199
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
208
200
  }
209
201
  };
202
+ this.innerDeltaManager = context.deltaManager;
203
+ this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
210
204
  let loadSummaryNumber;
211
205
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
212
206
  // get the values from the metadata blob.
@@ -229,29 +223,47 @@ export class ContainerRuntime extends TypedEventEmitter {
229
223
  this.nextSummaryNumber = loadSummaryNumber + 1;
230
224
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
231
225
  this._connected = this.context.connected;
226
+ this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
232
227
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
233
- const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompressionChunking") === true
234
- ? Number.POSITIVE_INFINITY
235
- : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
236
- this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor());
228
+ this.mc.logger.sendTelemetryEvent({
229
+ eventName: "GCFeatureMatrix",
230
+ metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
231
+ inputs: JSON.stringify({
232
+ gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
233
+ }),
234
+ });
235
+ this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : uuid();
236
+ this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
237
+ const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
238
+ const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
239
+ const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
240
+ this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
237
241
  this.handleContext = new ContainerFluidHandleContext("", this);
238
242
  if (this.summaryConfiguration.state === "enabled") {
239
243
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
240
244
  }
245
+ const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
241
246
  this.enableOpReentryCheck =
242
247
  runtimeOptions.enableOpReentryCheck === true &&
243
248
  // Allow for a break-glass config to override the options
244
- this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck") !== true;
249
+ disableOpReentryCheck !== true;
245
250
  this.summariesDisabled = this.isSummariesDisabled();
246
251
  this.heuristicsDisabled = this.isHeuristicsDisabled();
247
252
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
248
253
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
249
254
  this.maxConsecutiveReconnects =
250
- (_c = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _c !== void 0 ? _c : this.defaultMaxConsecutiveReconnects;
251
- this._flushMode = runtimeOptions.flushMode;
255
+ (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
256
+ if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
257
+ ((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
258
+ // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
259
+ this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
260
+ this._flushMode = FlushMode.TurnBased;
261
+ }
262
+ else {
263
+ this._flushMode = runtimeOptions.flushMode;
264
+ }
252
265
  const pendingRuntimeState = context.pendingLocalState;
253
- const baseSnapshot = (_d = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _d !== void 0 ? _d : context.baseSnapshot;
254
- const maxSnapshotCacheDurationMs = (_f = (_e = this._storage) === null || _e === void 0 ? void 0 : _e.policies) === null || _f === void 0 ? void 0 : _f.maximumCacheDurationMs;
266
+ const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
255
267
  if (maxSnapshotCacheDurationMs !== undefined &&
256
268
  maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
257
269
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
@@ -262,7 +274,7 @@ export class ContainerRuntime extends TypedEventEmitter {
262
274
  this.garbageCollector = GarbageCollector.create({
263
275
  runtime: this,
264
276
  gcOptions: this.runtimeOptions.gcOptions,
265
- baseSnapshot,
277
+ baseSnapshot: context.baseSnapshot,
266
278
  baseLogger: this.mc.logger,
267
279
  existing,
268
280
  metadata,
@@ -272,7 +284,9 @@ export class ContainerRuntime extends TypedEventEmitter {
272
284
  getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
273
285
  readAndParseBlob: async (id) => readAndParse(this.storage, id),
274
286
  getContainerDiagnosticId: () => this.context.id,
275
- activeConnection: () => this.deltaManager.active,
287
+ // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
288
+ // delta manager would always return false for summarizer client.
289
+ activeConnection: () => this.innerDeltaManager.active,
276
290
  });
277
291
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
278
292
  this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
@@ -281,7 +295,7 @@ export class ContainerRuntime extends TypedEventEmitter {
281
295
  // Latest change sequence number, no changes since summary applied yet
282
296
  loadedFromSequenceNumber,
283
297
  // Summary reference sequence number, undefined if no summary yet
284
- baseSnapshot ? loadedFromSequenceNumber : undefined, {
298
+ context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
285
299
  // Must set to false to prevent sending summary handle which would be pointing to
286
300
  // a summary with an older protocol state.
287
301
  canReuseHandle: false,
@@ -295,18 +309,24 @@ export class ContainerRuntime extends TypedEventEmitter {
295
309
  async (fullGC) => this.getGCDataInternal(fullGC),
296
310
  // Function to get the GC details from the base snapshot we loaded from.
297
311
  async () => this.garbageCollector.getBaseGCDetails());
298
- if (baseSnapshot) {
299
- this.summarizerNode.updateBaseSummaryState(baseSnapshot);
312
+ if (context.baseSnapshot) {
313
+ this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
300
314
  }
301
- this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap));
315
+ this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
302
316
  this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
303
317
  if (!this.disposed) {
304
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
305
- localId,
306
- blobId,
318
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
319
+ Promise.resolve().then(() => {
320
+ // Blob attaches need to be in their own batch (grouped batching would hide metadata)
321
+ this.flush();
322
+ this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
323
+ localId,
324
+ blobId,
325
+ });
326
+ this.flush();
307
327
  });
308
328
  }
309
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (fromPath, toPath) => this.garbageCollector.addedOutboundReference(fromPath, toPath), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, () => this.getCurrentReferenceTimestampMs());
329
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, (error) => this.closeFn(error));
310
330
  this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
311
331
  this.pendingStateManager = new PendingStateManager({
312
332
  applyStashedOp: this.applyStashedOp.bind(this),
@@ -317,12 +337,14 @@ export class ContainerRuntime extends TypedEventEmitter {
317
337
  rollback: this.rollback.bind(this),
318
338
  orderSequentially: this.orderSequentially.bind(this),
319
339
  }, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
320
- const compressionOptions = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompression") === true
340
+ const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
341
+ const compressionOptions = disableCompression === true
321
342
  ? {
322
343
  minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
323
344
  compressionAlgorithm: CompressionAlgorithms.lz4,
324
345
  }
325
346
  : runtimeOptions.compressionOptions;
347
+ const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
326
348
  this.outbox = new Outbox({
327
349
  shouldSend: () => this.canSendOps(),
328
350
  pendingStateManager: this.pendingStateManager,
@@ -332,9 +354,10 @@ export class ContainerRuntime extends TypedEventEmitter {
332
354
  config: {
333
355
  compressionOptions,
334
356
  maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
335
- enableOpReentryCheck: this.enableOpReentryCheck,
357
+ disablePartialFlush: disablePartialFlush === true,
336
358
  },
337
359
  logger: this.mc.logger,
360
+ groupingManager: opGroupingManager,
338
361
  });
339
362
  this.context.quorum.on("removeMember", (clientId) => {
340
363
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
@@ -353,7 +376,10 @@ export class ContainerRuntime extends TypedEventEmitter {
353
376
  const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
354
377
  this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
355
378
  if (this.context.clientDetails.type === summarizerClientType) {
356
- this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
379
+ this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
380
+ // Summarization runs in summarizer client and needs access to the real (non-proxy) active
381
+ // information. The proxy delta manager would always return false for summarizer client.
382
+ () => this.innerDeltaManager.active));
357
383
  }
358
384
  else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
359
385
  // Only create a SummaryManager and SummarizerClientElection
@@ -388,7 +414,8 @@ export class ContainerRuntime extends TypedEventEmitter {
388
414
  this.deltaManager.on("readonly", (readonly) => {
389
415
  // we accumulate ops while being in read-only state.
390
416
  // once user gets write permissions and we have active connection, flush all pending ops.
391
- assert(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
417
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
418
+ assert(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
392
419
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
393
420
  // when we either never send an op, or attempted to send it but we know for sure it was not
394
421
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -406,9 +433,22 @@ export class ContainerRuntime extends TypedEventEmitter {
406
433
  });
407
434
  // logging hardware telemetry
408
435
  logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
409
- this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
436
+ this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
437
+ disableCompression,
438
+ disableOpReentryCheck,
439
+ disableChunking,
440
+ disableAttachReorder: this.disableAttachReorder,
441
+ disablePartialFlush,
442
+ }), telemetryDocumentId: this.telemetryDocumentId, groupedBatchingEnabled: this.groupedBatchingEnabled }));
410
443
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
411
444
  BindBatchTracker(this, this.logger);
445
+ this.entryPoint = new LazyPromise(async () => {
446
+ if (this.context.clientDetails.type === summarizerClientType) {
447
+ assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
448
+ return this._summarizer;
449
+ }
450
+ return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
451
+ });
412
452
  }
413
453
  get IContainerRuntime() {
414
454
  return this;
@@ -446,17 +486,20 @@ export class ContainerRuntime extends TypedEventEmitter {
446
486
  * Load the stores from a snapshot and returns the runtime.
447
487
  * @param params - An object housing the runtime properties:
448
488
  * - context - Context of the container.
449
- * - registryEntries - Mapping to the stores.
450
- * - existing - When loading from an existing snapshot
451
- * - requestHandler - Request handlers for the container runtime
489
+ * - registryEntries - Mapping from data store types to their corresponding factories.
490
+ * - existing - Pass 'true' if loading from an existing snapshot.
491
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
492
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
452
493
  * - runtimeOptions - Additional options to be passed to the runtime
453
494
  * - containerScope - runtime services provided with context
454
495
  * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
455
496
  * This allows mixin classes to leverage this method to define their own async initializer.
497
+ * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
498
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
456
499
  */
457
500
  static async loadRuntime(params) {
458
501
  var _a, _b, _c, _d;
459
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
502
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
460
503
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
461
504
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
462
505
  const backCompatContext = context;
@@ -466,25 +509,16 @@ export class ContainerRuntime extends TypedEventEmitter {
466
509
  runtimeVersion: pkgVersion,
467
510
  },
468
511
  });
469
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, compressionOptions = {
470
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
471
- compressionAlgorithm: CompressionAlgorithms.lz4,
472
- }, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = Number.POSITIVE_INFINITY, enableOpReentryCheck = false, } = runtimeOptions;
473
- const pendingRuntimeState = context.pendingLocalState;
474
- const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
475
- const storage = !pendingRuntimeState
476
- ? context.storage
477
- : new SerializedSnapshotStorage(() => {
478
- return context.storage;
479
- }, pendingRuntimeState.snapshotBlobs);
512
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
480
513
  const registry = new FluidDataStoreRegistry(registryEntries);
481
514
  const tryFetchBlob = async (blobName) => {
482
- const blobId = baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.blobs[blobName];
483
- if (baseSnapshot && blobId) {
515
+ var _a;
516
+ const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
517
+ if (context.baseSnapshot && blobId) {
484
518
  // IContainerContext storage api return type still has undefined in 0.39 package version.
485
519
  // So once we release 0.40 container-defn package we can remove this check.
486
- assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
487
- return readAndParse(storage, blobId);
520
+ assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
521
+ return readAndParse(context.storage, blobId);
488
522
  }
489
523
  };
490
524
  const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
@@ -495,16 +529,16 @@ export class ContainerRuntime extends TypedEventEmitter {
495
529
  ]);
496
530
  const loadExisting = existing === true || context.existing === true;
497
531
  // read snapshot blobs needed for BlobManager to load
498
- const blobManagerSnapshot = await BlobManager.load(baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[blobsTreeName], async (id) => {
532
+ const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
499
533
  // IContainerContext storage api return type still has undefined in 0.39 package version.
500
534
  // So once we release 0.40 container-defn package we can remove this check.
501
- assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
502
- return readAndParse(storage, id);
535
+ assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
536
+ return readAndParse(context.storage, id);
503
537
  });
504
538
  // Verify summary runtime sequence number matches protocol sequence number.
505
539
  const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
506
540
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
507
- if (!pendingRuntimeState && runtimeSequenceNumber !== undefined) {
541
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
508
542
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
509
543
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
510
544
  if (loadSequenceNumberVerification !== "bypass" &&
@@ -528,17 +562,16 @@ export class ContainerRuntime extends TypedEventEmitter {
528
562
  gcOptions,
529
563
  loadSequenceNumberVerification,
530
564
  flushMode,
531
- enableOfflineLoad,
532
565
  compressionOptions,
533
566
  maxBatchSizeInBytes,
534
567
  chunkSizeInBytes,
535
568
  enableOpReentryCheck,
536
- }, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
537
- if (pendingRuntimeState) {
538
- await runtime.processSavedOps(pendingRuntimeState);
539
- // delete these once runtime has seen them to save space
540
- pendingRuntimeState.savedOps = [];
541
- }
569
+ enableGroupedBatching,
570
+ }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
571
+ initializeEntryPoint);
572
+ // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
573
+ // at 1, so we won't see a replayed saved op with a sequence number of 0.
574
+ await runtime.pendingStateManager.applyStashedOpsAt(0);
542
575
  // Initialize the base state of the runtime before it's returned.
543
576
  await runtime.initializeBaseState();
544
577
  return runtime;
@@ -552,9 +585,6 @@ export class ContainerRuntime extends TypedEventEmitter {
552
585
  get clientDetails() {
553
586
  return this.context.clientDetails;
554
587
  }
555
- get deltaManager() {
556
- return this.context.deltaManager;
557
- }
558
588
  get storage() {
559
589
  return this._storage;
560
590
  }
@@ -647,7 +677,6 @@ export class ContainerRuntime extends TypedEventEmitter {
647
677
  * Initializes the state from the base snapshot this container runtime loaded from.
648
678
  */
649
679
  async initializeBaseState() {
650
- await this.initializeBaseSnapshotBlobs();
651
680
  await this.garbageCollector.initializeBaseState();
652
681
  }
653
682
  dispose(error) {
@@ -672,16 +701,6 @@ export class ContainerRuntime extends TypedEventEmitter {
672
701
  this.emit("dispose");
673
702
  this.removeAllListeners();
674
703
  }
675
- get IFluidTokenProvider() {
676
- var _a;
677
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
678
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
679
- return {
680
- intelligence: this.options.intelligence,
681
- };
682
- }
683
- return undefined;
684
- }
685
704
  /**
686
705
  * Notifies this object about the request made to the container.
687
706
  * @param request - Request made to the handler.
@@ -744,12 +763,18 @@ export class ContainerRuntime extends TypedEventEmitter {
744
763
  return exceptionToResponse(error);
745
764
  }
746
765
  }
766
+ /**
767
+ * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
768
+ */
769
+ async getEntryPoint() {
770
+ return this.entryPoint;
771
+ }
747
772
  internalId(maybeAlias) {
748
773
  var _a;
749
774
  return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
750
775
  }
751
776
  async getDataStoreFromRequest(id, request) {
752
- var _a, _b, _c, _d;
777
+ var _a, _b, _c;
753
778
  const headerData = {};
754
779
  if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
755
780
  headerData.wait = request.headers[RuntimeHeaders.wait];
@@ -763,23 +788,6 @@ export class ContainerRuntime extends TypedEventEmitter {
763
788
  await this.dataStores.waitIfPendingAlias(id);
764
789
  const internalId = this.internalId(id);
765
790
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
766
- /**
767
- * If GC should run and this an external app request with "externalRequest" header, we need to return
768
- * an error if the data store being requested is marked as unreferenced as per the data store's base
769
- * GC data.
770
- *
771
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
772
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
773
- */
774
- if (((_d = request.headers) === null || _d === void 0 ? void 0 : _d[RuntimeHeaders.externalRequest]) &&
775
- this.garbageCollector.shouldRunGC) {
776
- // The data store is referenced if used routes in the base summary has a route to self.
777
- // Older documents may not have used routes in the summary. They are considered referenced.
778
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
779
- if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
780
- throw responseToException(create404Response(request), request);
781
- }
782
- }
783
791
  const dataStoreChannel = await dataStoreContext.realize();
784
792
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
785
793
  // the same as GC nodes id.
@@ -795,7 +803,7 @@ export class ContainerRuntime extends TypedEventEmitter {
795
803
  summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
796
804
  // The last message processed at the time of summary. If there are no new messages, use the message from the
797
805
  // last summary.
798
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
806
+ message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
799
807
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
800
808
  }
801
809
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
@@ -911,7 +919,8 @@ export class ContainerRuntime extends TypedEventEmitter {
911
919
  // If attachment blobs were added while disconnected, we need to delay
912
920
  // propagation of the "connected" event until we have uploaded them to
913
921
  // ensure we don't submit ops referencing a blob that has not been uploaded
914
- const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
922
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
923
+ const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
915
924
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
916
925
  assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
917
926
  assert(!!clientId, 0x393 /* Must have clientId when connecting */);
@@ -961,19 +970,23 @@ export class ContainerRuntime extends TypedEventEmitter {
961
970
  this.garbageCollector.setConnectionState(connected, clientId);
962
971
  raiseConnectedEvent(this.mc.logger, this, connected, clientId);
963
972
  }
973
+ async notifyOpReplay(message) {
974
+ await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
975
+ }
964
976
  process(messageArg, local) {
965
- var _a;
966
977
  this.verifyNotClosed();
967
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
968
- this.savedOps.push(messageArg);
969
- }
970
978
  // Whether or not the message is actually a runtime message.
971
979
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
972
980
  // or something different, like a system message.
973
981
  const runtimeMessage = messageArg.type === MessageType.Operation;
974
982
  // Do shallow copy of message, as the processing flow will modify it.
975
983
  const messageCopy = Object.assign({}, messageArg);
976
- const message = this.remoteMessageProcessor.process(messageCopy);
984
+ for (const message of this.remoteMessageProcessor.process(messageCopy)) {
985
+ this.processCore(message, local, runtimeMessage);
986
+ }
987
+ }
988
+ processCore(message, local, runtimeMessage) {
989
+ var _a;
977
990
  // Surround the actual processing of the operation with messages to the schedule manager indicating
978
991
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
979
992
  // messages once a batch has been fully processed.
@@ -1006,10 +1019,21 @@ export class ContainerRuntime extends TypedEventEmitter {
1006
1019
  case ContainerMessageType.Rejoin:
1007
1020
  break;
1008
1021
  default:
1009
- assert(!runtimeMessage, 0x3ce /* Runtime message of unknown type */);
1022
+ if (runtimeMessage) {
1023
+ const error = DataProcessingError.create(
1024
+ // Former assert 0x3ce
1025
+ "Runtime message of unknown type", "OpProcessing", message, {
1026
+ local,
1027
+ type: message.type,
1028
+ contentType: typeof message.contents,
1029
+ batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
1030
+ compression: message.compression,
1031
+ });
1032
+ this.closeFn(error);
1033
+ throw error;
1034
+ }
1010
1035
  }
1011
- // For back-compat, notify only about runtime messages for now.
1012
- if (runtimeMessage) {
1036
+ if (runtimeMessage || this.groupedBatchingEnabled) {
1013
1037
  this.emit("op", message, runtimeMessage);
1014
1038
  }
1015
1039
  this.scheduleManager.afterOpProcessing(undefined, message);
@@ -1067,7 +1091,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1067
1091
  }
1068
1092
  else if (envelope.clientSignalSequenceNumber ===
1069
1093
  this._perfSignalData.trackingSignalSequenceNumber) {
1070
- this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1094
+ // only logging for the first connection and the trackingSignalSequenceNUmber.
1095
+ if (this.consecutiveReconnects === 0) {
1096
+ this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1097
+ }
1071
1098
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1072
1099
  }
1073
1100
  }
@@ -1164,13 +1191,15 @@ export class ContainerRuntime extends TypedEventEmitter {
1164
1191
  .realize();
1165
1192
  }
1166
1193
  canSendOps() {
1167
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
1194
+ // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
1195
+ // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
1196
+ return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1168
1197
  }
1169
1198
  /**
1170
1199
  * Are we in the middle of batching ops together?
1171
1200
  */
1172
1201
  currentlyBatching() {
1173
- return this.flushMode === FlushMode.TurnBased || this._orderSequentiallyCalls !== 0;
1202
+ return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
1174
1203
  }
1175
1204
  getQuorum() {
1176
1205
  return this.context.quorum;
@@ -1286,11 +1315,19 @@ export class ContainerRuntime extends TypedEventEmitter {
1286
1315
  async summarize(options) {
1287
1316
  this.verifyNotClosed();
1288
1317
  const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
1318
+ const telemetryContext = new TelemetryContext();
1319
+ // Add the options that are used to generate this summary to the telemetry context.
1320
+ telemetryContext.setMultiple("fluid_Summarize", "Options", {
1321
+ fullTree,
1322
+ trackState,
1323
+ runGC,
1324
+ fullGC,
1325
+ runSweep,
1326
+ });
1289
1327
  let gcStats;
1290
1328
  if (runGC) {
1291
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1329
+ gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1292
1330
  }
1293
- const telemetryContext = new TelemetryContext();
1294
1331
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1295
1332
  this.logger.sendTelemetryEvent({
1296
1333
  eventName: "SummarizeTelemetry",
@@ -1300,10 +1337,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1300
1337
  return { stats, summary, gcStats };
1301
1338
  }
1302
1339
  /**
1303
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
1304
1340
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
1305
1341
  * the garbage collector of references detected since the last GC run. Most references are notified immediately
1306
1342
  * but there can be some for which async operation is required (such as detecting new root data stores).
1343
+ * @see IGarbageCollectionRuntime.updateStateBeforeGC
1307
1344
  */
1308
1345
  async updateStateBeforeGC() {
1309
1346
  return this.dataStores.updateStateBeforeGC();
@@ -1312,9 +1349,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1312
1349
  return this.dataStores.getGCData(fullGC);
1313
1350
  }
1314
1351
  /**
1315
- * Implementation of IGarbageCollectionRuntime::getGCData.
1316
1352
  * Generates and returns the GC data for this container.
1317
1353
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
1354
+ * @see IGarbageCollectionRuntime.getGCData
1318
1355
  */
1319
1356
  async getGCData(fullGC) {
1320
1357
  const builder = new GCDataBuilder();
@@ -1325,9 +1362,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1325
1362
  return builder.getGCData();
1326
1363
  }
1327
1364
  /**
1328
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
1329
1365
  * After GC has run, called to notify this container's nodes of routes that are used in it.
1330
1366
  * @param usedRoutes - The routes that are used in all nodes in this Container.
1367
+ * @see IGarbageCollectionRuntime.updateUsedRoutes
1331
1368
  */
1332
1369
  updateUsedRoutes(usedRoutes) {
1333
1370
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
@@ -1346,6 +1383,22 @@ export class ContainerRuntime extends TypedEventEmitter {
1346
1383
  this.blobManager.updateUnusedRoutes(blobManagerRoutes);
1347
1384
  this.dataStores.updateUnusedRoutes(dataStoreRoutes);
1348
1385
  }
1386
+ /**
1387
+ * @deprecated - Replaced by deleteSweepReadyNodes.
1388
+ */
1389
+ deleteUnusedNodes(unusedRoutes) {
1390
+ throw new Error("deleteUnusedRoutes should not be called");
1391
+ }
1392
+ /**
1393
+ * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
1394
+ * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
1395
+ * @returns - The routes of nodes that were deleted.
1396
+ */
1397
+ deleteSweepReadyNodes(sweepReadyRoutes) {
1398
+ const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
1399
+ const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
1400
+ return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
1401
+ }
1349
1402
  /**
1350
1403
  * This is called to update objects that are tombstones.
1351
1404
  * @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
@@ -1423,8 +1476,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1423
1476
  * Runs garbage collection and updates the reference / used state of the nodes in the container.
1424
1477
  * @returns the statistics of the garbage collection run; undefined if GC did not run.
1425
1478
  */
1426
- async collectGarbage(options) {
1427
- return this.garbageCollector.collectGarbage(options);
1479
+ async collectGarbage(options, telemetryContext) {
1480
+ return this.garbageCollector.collectGarbage(options, telemetryContext);
1428
1481
  }
1429
1482
  /**
1430
1483
  * Called when a new outbound reference is added to another node. This is used by garbage collection to identify
@@ -1445,7 +1498,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1445
1498
  */
1446
1499
  async submitSummary(options) {
1447
1500
  var _a, _b;
1448
- const { fullTree, refreshLatestAck, summaryLogger } = options;
1501
+ const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1449
1502
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1450
1503
  // use it for all events logged during this summary.
1451
1504
  const summaryNumber = this.nextSummaryNumber;
@@ -1461,8 +1514,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1461
1514
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1462
1515
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1463
1516
  }
1517
+ const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1464
1518
  try {
1465
1519
  await this.deltaManager.inbound.pause();
1520
+ if (shouldPauseInboundSignal) {
1521
+ await this.deltaManager.inboundSignal.pause();
1522
+ }
1466
1523
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1467
1524
  const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1468
1525
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
@@ -1518,7 +1575,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1518
1575
  const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
1519
1576
  try {
1520
1577
  summarizeResult = await this.summarize({
1521
- fullTree: fullTree !== null && fullTree !== void 0 ? fullTree : forcedFullTree,
1578
+ fullTree: fullTree || forcedFullTree,
1522
1579
  trackState: true,
1523
1580
  summaryLogger: summaryNumberLogger,
1524
1581
  runGC: this.garbageCollector.shouldRunGC,
@@ -1607,7 +1664,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1607
1664
  }
1608
1665
  let clientSequenceNumber;
1609
1666
  try {
1610
- clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
1667
+ clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
1611
1668
  }
1612
1669
  catch (error) {
1613
1670
  return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
@@ -1621,6 +1678,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1621
1678
  this.summarizerNode.clearSummary();
1622
1679
  // Restart the delta manager
1623
1680
  this.deltaManager.inbound.resume();
1681
+ if (shouldPauseInboundSignal) {
1682
+ this.deltaManager.inboundSignal.resume();
1683
+ }
1624
1684
  }
1625
1685
  }
1626
1686
  hasPendingMessages() {
@@ -1666,9 +1726,10 @@ export class ContainerRuntime extends TypedEventEmitter {
1666
1726
  this.verifyCanSubmitOps();
1667
1727
  // There should be no ops in detached container state!
1668
1728
  assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1669
- const deserializedContent = { type, contents };
1670
- const serializedContent = JSON.stringify(deserializedContent);
1671
- if (this.deltaManager.readOnlyInfo.readonly) {
1729
+ const serializedContent = JSON.stringify({ type, contents });
1730
+ // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
1731
+ // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
1732
+ if (this.innerDeltaManager.readOnlyInfo.readonly) {
1672
1733
  this.logger.sendTelemetryEvent({
1673
1734
  eventName: "SubmitOpInReadonly",
1674
1735
  connected: this.connected,
@@ -1676,7 +1737,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1676
1737
  }
1677
1738
  const message = {
1678
1739
  contents: serializedContent,
1679
- deserializedContent,
1740
+ deserializedContent: JSON.parse(serializedContent),
1680
1741
  metadata,
1681
1742
  localOpMetadata,
1682
1743
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -1704,7 +1765,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1704
1765
  // optimization no longer makes sense (for example, batch compression may make it less appealing).
1705
1766
  if (this.currentlyBatching() &&
1706
1767
  type === ContainerMessageType.Attach &&
1707
- this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder") !== true) {
1768
+ this.disableAttachReorder !== true) {
1708
1769
  this.outbox.submitAttach(message);
1709
1770
  }
1710
1771
  else {
@@ -1713,17 +1774,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1713
1774
  if (!this.currentlyBatching()) {
1714
1775
  this.flush();
1715
1776
  }
1716
- else if (!this.flushMicroTaskExists) {
1717
- this.flushMicroTaskExists = true;
1718
- // Queue a microtask to detect the end of the turn and force a flush.
1719
- Promise.resolve()
1720
- .then(() => {
1721
- this.flushMicroTaskExists = false;
1722
- this.flush();
1723
- })
1724
- .catch((error) => {
1725
- this.closeFn(error);
1726
- });
1777
+ else {
1778
+ this.scheduleFlush();
1727
1779
  }
1728
1780
  }
1729
1781
  catch (error) {
@@ -1734,14 +1786,47 @@ export class ContainerRuntime extends TypedEventEmitter {
1734
1786
  this.updateDocumentDirtyState(true);
1735
1787
  }
1736
1788
  }
1737
- submitSummaryMessage(contents) {
1789
+ scheduleFlush() {
1790
+ if (this.flushTaskExists) {
1791
+ return;
1792
+ }
1793
+ this.flushTaskExists = true;
1794
+ const flush = () => {
1795
+ this.flushTaskExists = false;
1796
+ try {
1797
+ this.flush();
1798
+ }
1799
+ catch (error) {
1800
+ this.closeFn(error);
1801
+ }
1802
+ };
1803
+ switch (this.flushMode) {
1804
+ case FlushMode.TurnBased:
1805
+ // When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
1806
+ // batch at the end of the turn
1807
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1808
+ Promise.resolve().then(flush);
1809
+ break;
1810
+ // FlushModeExperimental is experimental and not exposed directly in the runtime APIs
1811
+ case FlushModeExperimental.Async:
1812
+ // When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
1813
+ // batch when all micro-tasks are complete.
1814
+ // Compared to TurnBased, this flush mode will capture more ops into the same batch.
1815
+ setTimeout(flush, 0);
1816
+ break;
1817
+ default:
1818
+ assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
1819
+ break;
1820
+ }
1821
+ }
1822
+ submitSummaryMessage(contents, referenceSequenceNumber) {
1738
1823
  this.verifyNotClosed();
1739
1824
  assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
1740
1825
  // System message should not be sent in the middle of the batch.
1741
1826
  assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
1742
1827
  // back-compat: ADO #1385: Make this call unconditional in the future
1743
1828
  return this.context.submitSummaryFn !== undefined
1744
- ? this.context.submitSummaryFn(contents)
1829
+ ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
1745
1830
  : this.context.submitFn(MessageType.Summarize, contents, false);
1746
1831
  }
1747
1832
  /**
@@ -1837,14 +1922,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1837
1922
  // The call to fetch the snapshot is very expensive and not always needed.
1838
1923
  // It should only be done by the summarizerNode, if required.
1839
1924
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
1840
- const snapshotTreeFetcher = async () => {
1841
- const fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1842
- eventName: "RefreshLatestSummaryGetSnapshot",
1925
+ const fetchLatestSnapshot = async () => {
1926
+ let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1927
+ eventName: "RefreshLatestSummaryAckFetch",
1843
1928
  ackHandle,
1844
- summaryRefSeq,
1845
- fetchLatest: true,
1846
- });
1847
- const latestSnapshotRefSeq = await seqFromTree(fetchResult.snapshotTree, readAndParseBlob);
1929
+ targetSequenceNumber: summaryRefSeq,
1930
+ }, readAndParseBlob);
1848
1931
  /**
1849
1932
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
1850
1933
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -1855,29 +1938,34 @@ export class ContainerRuntime extends TypedEventEmitter {
1855
1938
  * such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
1856
1939
  * state.
1857
1940
  */
1858
- if (latestSnapshotRefSeq < summaryRefSeq) {
1859
- const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1941
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1942
+ /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
1943
+ fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
1944
+ eventName: "RefreshLatestSummaryAckFetch",
1860
1945
  ackHandle,
1861
- summaryRefSeq,
1862
- latestSnapshotRefSeq,
1863
- });
1864
- this.closeFn(error);
1865
- throw error;
1946
+ targetSequenceNumber: summaryRefSeq,
1947
+ }, readAndParseBlob, ackHandle);
1948
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1949
+ const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1950
+ ackHandle,
1951
+ summaryRefSeq,
1952
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1953
+ });
1954
+ this.closeFn(error);
1955
+ throw error;
1956
+ }
1866
1957
  }
1867
- summaryLogger.sendTelemetryEvent({
1868
- eventName: "LatestSummaryRetrieved",
1869
- ackHandle,
1870
- lastSequenceNumber: latestSnapshotRefSeq,
1871
- targetSequenceNumber: summaryRefSeq,
1872
- });
1873
1958
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
1874
1959
  // wait for the delta manager to catch up before refreshing the latest Summary.
1875
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
1876
- return fetchResult.snapshotTree;
1960
+ await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
1961
+ return {
1962
+ snapshotTree: fetchResult.snapshotTree,
1963
+ snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1964
+ };
1877
1965
  };
1878
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, snapshotTreeFetcher, readAndParseBlob, summaryLogger);
1966
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1879
1967
  // Notify the garbage collector so it can update its latest summary state.
1880
- await this.garbageCollector.refreshLatestSummary(result, proposalHandle, summaryRefSeq, readAndParseBlob);
1968
+ await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
1881
1969
  }
1882
1970
  /**
1883
1971
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -1886,53 +1974,54 @@ export class ContainerRuntime extends TypedEventEmitter {
1886
1974
  * @returns downloaded snapshot's reference sequence number
1887
1975
  */
1888
1976
  async refreshLatestSummaryAckFromServer(summaryLogger) {
1889
- const { snapshotTree, versionId } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1890
- eventName: "RefreshLatestSummaryGetSnapshot",
1891
- fetchLatest: true,
1892
- });
1893
1977
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
1894
- const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
1895
- const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
1978
+ const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1979
+ eventName: "RefreshLatestSummaryFromServerFetch",
1980
+ }, readAndParseBlob);
1981
+ const fetchLatestSnapshot = {
1982
+ snapshotTree,
1983
+ snapshotRefSeq: latestSnapshotRefSeq,
1984
+ };
1985
+ const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1896
1986
  // Notify the garbage collector so it can update its latest summary state.
1897
- await this.garbageCollector.refreshLatestSummary(result, undefined, latestSnapshotRefSeq, readAndParseBlob);
1987
+ await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
1898
1988
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
1899
1989
  }
1900
- async fetchLatestSnapshotFromStorage(logger, event) {
1990
+ async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
1991
+ return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
1992
+ }
1993
+ async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
1994
+ var _a;
1995
+ const recoveryMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummarizationRecoveryMethod");
1996
+ if (recoveryMethod === "restart") {
1997
+ const error = new GenericError("Restarting summarizer instead of refreshing");
1998
+ this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined }), error);
1999
+ (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
2000
+ this.closeFn();
2001
+ throw error;
2002
+ }
1901
2003
  return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
1902
2004
  const stats = {};
1903
2005
  const trace = Trace.start();
1904
- const versions = await this.storage.getVersions(null, 1, "refreshLatestSummaryAckFromServer", FetchSource.noCache);
2006
+ const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
1905
2007
  assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
1906
2008
  stats.getVersionDuration = trace.trace().duration;
1907
2009
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
1908
2010
  assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
1909
2011
  stats.getSnapshotDuration = trace.trace().duration;
2012
+ const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
2013
+ stats.snapshotRefSeq = latestSnapshotRefSeq;
2014
+ stats.snapshotVersion = versions[0].id;
1910
2015
  perfEvent.end(stats);
1911
- return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
2016
+ return {
2017
+ snapshotTree: maybeSnapshot,
2018
+ versionId: versions[0].id,
2019
+ latestSnapshotRefSeq,
2020
+ };
1912
2021
  });
1913
2022
  }
1914
- notifyAttaching(snapshot) {
1915
- var _a;
1916
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
1917
- this.baseSnapshotBlobs =
1918
- SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
1919
- }
1920
- }
1921
- async initializeBaseSnapshotBlobs() {
1922
- var _a;
1923
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
1924
- this.attachState !== AttachState.Attached ||
1925
- this.context.pendingLocalState) {
1926
- return;
1927
- }
1928
- assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
1929
- this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
1930
- }
2023
+ notifyAttaching() { } // do nothing (deprecated method)
1931
2024
  getPendingLocalState() {
1932
- var _a;
1933
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
1934
- throw new UsageError("can't get state when offline load disabled");
1935
- }
1936
2025
  if (this._orderSequentiallyCalls !== 0) {
1937
2026
  throw new UsageError("can't get state during orderSequentially");
1938
2027
  }
@@ -1940,24 +2029,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1940
2029
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
1941
2030
  // to close current batch.
1942
2031
  this.flush();
1943
- const previousPendingState = this.context.pendingLocalState;
1944
- if (previousPendingState) {
1945
- return {
1946
- pending: this.pendingStateManager.getLocalState(),
1947
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1948
- snapshotBlobs: previousPendingState.snapshotBlobs,
1949
- baseSnapshot: previousPendingState.baseSnapshot,
1950
- savedOps: this.savedOps,
1951
- };
1952
- }
1953
- assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
1954
- assert(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
1955
2032
  return {
1956
2033
  pending: this.pendingStateManager.getLocalState(),
1957
2034
  pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1958
- snapshotBlobs: this.baseSnapshotBlobs,
1959
- baseSnapshot: this.context.baseSnapshot,
1960
- savedOps: this.savedOps,
1961
2035
  };
1962
2036
  }
1963
2037
  /**
@@ -1986,20 +2060,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1986
2060
  return summarizer;
1987
2061
  };
1988
2062
  }
1989
- async processSavedOps(state) {
1990
- for (const op of state.savedOps) {
1991
- this.process(op, false);
1992
- await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
1993
- }
1994
- // we may not have seen every sequence number (because of system ops) so apply everything once we
1995
- // don't have any more saved ops
1996
- await this.pendingStateManager.applyStashedOpsAt();
1997
- // If it's not the case, we should take it into account when calculating dirty state.
1998
- assert(this.context.attachState === AttachState.Attached, 0x3d5 /* this function is called for attached containers only */);
1999
- if (!this.hasPendingMessages()) {
2000
- this.updateDocumentDirtyState(false);
2001
- }
2002
- }
2003
2063
  validateSummaryHeuristicConfiguration(configuration) {
2004
2064
  // eslint-disable-next-line no-restricted-syntax
2005
2065
  for (const prop in configuration) {
@@ -2011,6 +2071,10 @@ export class ContainerRuntime extends TypedEventEmitter {
2011
2071
  throw new UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
2012
2072
  }
2013
2073
  }
2074
+ get groupedBatchingEnabled() {
2075
+ const killSwitch = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
2076
+ return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
2077
+ }
2014
2078
  }
2015
2079
  /**
2016
2080
  * Wait for a specific sequence number. Promise should resolve when we reach that number,