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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. package/dist/blobManager.d.ts +24 -11
  2. package/dist/blobManager.d.ts.map +1 -1
  3. package/dist/blobManager.js +112 -55
  4. package/dist/blobManager.js.map +1 -1
  5. package/dist/containerRuntime.d.ts +60 -75
  6. package/dist/containerRuntime.d.ts.map +1 -1
  7. package/dist/containerRuntime.js +295 -256
  8. package/dist/containerRuntime.js.map +1 -1
  9. package/dist/dataStoreContext.d.ts +39 -13
  10. package/dist/dataStoreContext.d.ts.map +1 -1
  11. package/dist/dataStoreContext.js +112 -49
  12. package/dist/dataStoreContext.js.map +1 -1
  13. package/dist/dataStores.d.ts +28 -4
  14. package/dist/dataStores.d.ts.map +1 -1
  15. package/dist/dataStores.js +107 -41
  16. package/dist/dataStores.js.map +1 -1
  17. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  18. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  19. package/dist/deltaManagerSummarizerProxy.js +40 -0
  20. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  21. package/dist/gc/garbageCollection.d.ts +204 -0
  22. package/dist/gc/garbageCollection.d.ts.map +1 -0
  23. package/dist/{garbageCollection.js → gc/garbageCollection.js} +190 -554
  24. package/dist/gc/garbageCollection.js.map +1 -0
  25. package/dist/gc/gcConfigs.d.ts +22 -0
  26. package/dist/gc/gcConfigs.d.ts.map +1 -0
  27. package/dist/gc/gcConfigs.js +143 -0
  28. package/dist/gc/gcConfigs.js.map +1 -0
  29. package/dist/gc/gcDefinitions.d.ts +320 -0
  30. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  31. package/dist/gc/gcDefinitions.js +81 -0
  32. package/dist/gc/gcDefinitions.js.map +1 -0
  33. package/dist/gc/gcHelpers.d.ts +86 -0
  34. package/dist/gc/gcHelpers.d.ts.map +1 -0
  35. package/dist/gc/gcHelpers.js +268 -0
  36. package/dist/gc/gcHelpers.js.map +1 -0
  37. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  38. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  39. package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
  40. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  41. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  42. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  43. package/dist/gc/gcSummaryDefinitions.js +7 -0
  44. package/dist/gc/gcSummaryDefinitions.js.map +1 -0
  45. package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
  46. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  47. package/dist/gc/gcSummaryStateTracker.js +239 -0
  48. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  49. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  50. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
  51. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  52. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  53. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  54. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  55. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  56. package/dist/gc/index.d.ts +13 -0
  57. package/dist/gc/index.d.ts.map +1 -0
  58. package/dist/gc/index.js +50 -0
  59. package/dist/gc/index.js.map +1 -0
  60. package/dist/index.d.ts +3 -7
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +5 -9
  63. package/dist/index.js.map +1 -1
  64. package/dist/opLifecycle/batchManager.d.ts +11 -13
  65. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  66. package/dist/opLifecycle/batchManager.js +26 -38
  67. package/dist/opLifecycle/batchManager.js.map +1 -1
  68. package/dist/opLifecycle/definitions.d.ts +4 -0
  69. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  70. package/dist/opLifecycle/definitions.js.map +1 -1
  71. package/dist/opLifecycle/index.d.ts +1 -1
  72. package/dist/opLifecycle/index.d.ts.map +1 -1
  73. package/dist/opLifecycle/index.js +2 -1
  74. package/dist/opLifecycle/index.js.map +1 -1
  75. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  76. package/dist/opLifecycle/opCompressor.js +25 -10
  77. package/dist/opLifecycle/opCompressor.js.map +1 -1
  78. package/dist/opLifecycle/opDecompressor.d.ts +4 -0
  79. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  80. package/dist/opLifecycle/opDecompressor.js +42 -4
  81. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  82. package/dist/opLifecycle/opSplitter.d.ts +15 -3
  83. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  84. package/dist/opLifecycle/opSplitter.js +35 -10
  85. package/dist/opLifecycle/opSplitter.js.map +1 -1
  86. package/dist/opLifecycle/outbox.d.ts +19 -3
  87. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  88. package/dist/opLifecycle/outbox.js +88 -49
  89. package/dist/opLifecycle/outbox.js.map +1 -1
  90. package/dist/packageVersion.d.ts +1 -1
  91. package/dist/packageVersion.js +1 -1
  92. package/dist/packageVersion.js.map +1 -1
  93. package/dist/pendingStateManager.d.ts +3 -3
  94. package/dist/pendingStateManager.d.ts.map +1 -1
  95. package/dist/pendingStateManager.js +20 -21
  96. package/dist/pendingStateManager.js.map +1 -1
  97. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  98. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  99. package/dist/storageServiceWithAttachBlobs.js +32 -0
  100. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  101. package/dist/summary/index.d.ts +17 -0
  102. package/dist/summary/index.d.ts.map +1 -0
  103. package/dist/summary/index.js +46 -0
  104. package/dist/summary/index.js.map +1 -0
  105. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  106. package/dist/summary/orderedClientElection.js.map +1 -0
  107. package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  108. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  109. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  110. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  111. package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
  112. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  113. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +158 -56
  114. package/dist/summary/runningSummarizer.js.map +1 -0
  115. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  116. package/dist/summary/summarizer.d.ts.map +1 -0
  117. package/dist/{summarizer.js → summary/summarizer.js} +9 -74
  118. package/dist/summary/summarizer.js.map +1 -0
  119. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  120. package/dist/summary/summarizerClientElection.js.map +1 -0
  121. package/{lib → dist/summary}/summarizerHeuristics.d.ts +1 -1
  122. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  123. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +3 -3
  124. package/dist/summary/summarizerHeuristics.js.map +1 -0
  125. package/dist/summary/summarizerNode/index.d.ts +8 -0
  126. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  127. package/dist/summary/summarizerNode/index.js +12 -0
  128. package/dist/summary/summarizerNode/index.js.map +1 -0
  129. package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
  130. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  131. package/dist/summary/summarizerNode/summarizerNode.js +531 -0
  132. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
  133. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  134. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  135. package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
  136. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  137. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  138. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  139. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +423 -0
  140. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  141. package/{lib → dist/summary}/summarizerTypes.d.ts +7 -17
  142. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  143. package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
  144. package/dist/summary/summarizerTypes.js.map +1 -0
  145. package/dist/summary/summaryCollection.d.ts.map +1 -0
  146. package/dist/summary/summaryCollection.js.map +1 -0
  147. package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
  148. package/dist/summary/summaryFormat.d.ts.map +1 -0
  149. package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
  150. package/dist/summary/summaryFormat.js.map +1 -0
  151. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  152. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +4 -4
  153. package/dist/summary/summaryGenerator.js.map +1 -0
  154. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  155. package/dist/summary/summaryManager.d.ts.map +1 -0
  156. package/dist/summary/summaryManager.js.map +1 -0
  157. package/lib/blobManager.d.ts +24 -11
  158. package/lib/blobManager.d.ts.map +1 -1
  159. package/lib/blobManager.js +109 -52
  160. package/lib/blobManager.js.map +1 -1
  161. package/lib/containerRuntime.d.ts +60 -75
  162. package/lib/containerRuntime.d.ts.map +1 -1
  163. package/lib/containerRuntime.js +267 -228
  164. package/lib/containerRuntime.js.map +1 -1
  165. package/lib/dataStoreContext.d.ts +39 -13
  166. package/lib/dataStoreContext.d.ts.map +1 -1
  167. package/lib/dataStoreContext.js +101 -38
  168. package/lib/dataStoreContext.js.map +1 -1
  169. package/lib/dataStores.d.ts +28 -4
  170. package/lib/dataStores.d.ts.map +1 -1
  171. package/lib/dataStores.js +100 -34
  172. package/lib/dataStores.js.map +1 -1
  173. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  174. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  175. package/lib/deltaManagerSummarizerProxy.js +36 -0
  176. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  177. package/lib/gc/garbageCollection.d.ts +204 -0
  178. package/lib/gc/garbageCollection.d.ts.map +1 -0
  179. package/lib/{garbageCollection.js → gc/garbageCollection.js} +172 -535
  180. package/lib/gc/garbageCollection.js.map +1 -0
  181. package/lib/gc/gcConfigs.d.ts +22 -0
  182. package/lib/gc/gcConfigs.d.ts.map +1 -0
  183. package/lib/gc/gcConfigs.js +139 -0
  184. package/lib/gc/gcConfigs.js.map +1 -0
  185. package/lib/gc/gcDefinitions.d.ts +320 -0
  186. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  187. package/lib/gc/gcDefinitions.js +78 -0
  188. package/lib/gc/gcDefinitions.js.map +1 -0
  189. package/lib/gc/gcHelpers.d.ts +86 -0
  190. package/lib/gc/gcHelpers.d.ts.map +1 -0
  191. package/lib/gc/gcHelpers.js +254 -0
  192. package/lib/gc/gcHelpers.js.map +1 -0
  193. package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  194. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  195. package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
  196. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  197. package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
  198. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  199. package/lib/gc/gcSummaryDefinitions.js +6 -0
  200. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  201. package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
  202. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  203. package/lib/gc/gcSummaryStateTracker.js +235 -0
  204. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  205. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  206. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
  207. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  208. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  209. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  210. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  211. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  212. package/lib/gc/index.d.ts +13 -0
  213. package/lib/gc/index.d.ts.map +1 -0
  214. package/lib/gc/index.js +12 -0
  215. package/lib/gc/index.js.map +1 -0
  216. package/lib/index.d.ts +3 -7
  217. package/lib/index.d.ts.map +1 -1
  218. package/lib/index.js +1 -4
  219. package/lib/index.js.map +1 -1
  220. package/lib/opLifecycle/batchManager.d.ts +11 -13
  221. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  222. package/lib/opLifecycle/batchManager.js +24 -37
  223. package/lib/opLifecycle/batchManager.js.map +1 -1
  224. package/lib/opLifecycle/definitions.d.ts +4 -0
  225. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  226. package/lib/opLifecycle/definitions.js.map +1 -1
  227. package/lib/opLifecycle/index.d.ts +1 -1
  228. package/lib/opLifecycle/index.d.ts.map +1 -1
  229. package/lib/opLifecycle/index.js +1 -1
  230. package/lib/opLifecycle/index.js.map +1 -1
  231. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  232. package/lib/opLifecycle/opCompressor.js +26 -11
  233. package/lib/opLifecycle/opCompressor.js.map +1 -1
  234. package/lib/opLifecycle/opDecompressor.d.ts +4 -0
  235. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  236. package/lib/opLifecycle/opDecompressor.js +42 -4
  237. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  238. package/lib/opLifecycle/opSplitter.d.ts +15 -3
  239. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  240. package/lib/opLifecycle/opSplitter.js +35 -10
  241. package/lib/opLifecycle/opSplitter.js.map +1 -1
  242. package/lib/opLifecycle/outbox.d.ts +19 -3
  243. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  244. package/lib/opLifecycle/outbox.js +90 -51
  245. package/lib/opLifecycle/outbox.js.map +1 -1
  246. package/lib/packageVersion.d.ts +1 -1
  247. package/lib/packageVersion.js +1 -1
  248. package/lib/packageVersion.js.map +1 -1
  249. package/lib/pendingStateManager.d.ts +3 -3
  250. package/lib/pendingStateManager.d.ts.map +1 -1
  251. package/lib/pendingStateManager.js +20 -21
  252. package/lib/pendingStateManager.js.map +1 -1
  253. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  254. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  255. package/lib/storageServiceWithAttachBlobs.js +28 -0
  256. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  257. package/lib/summary/index.d.ts +17 -0
  258. package/lib/summary/index.d.ts.map +1 -0
  259. package/lib/summary/index.js +15 -0
  260. package/lib/summary/index.js.map +1 -0
  261. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  262. package/lib/summary/orderedClientElection.js.map +1 -0
  263. package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
  264. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  265. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  266. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  267. package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
  268. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  269. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +159 -57
  270. package/lib/summary/runningSummarizer.js.map +1 -0
  271. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
  272. package/lib/summary/summarizer.d.ts.map +1 -0
  273. package/lib/{summarizer.js → summary/summarizer.js} +11 -76
  274. package/lib/summary/summarizer.js.map +1 -0
  275. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  276. package/lib/summary/summarizerClientElection.js.map +1 -0
  277. package/{dist → lib/summary}/summarizerHeuristics.d.ts +1 -1
  278. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  279. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +3 -3
  280. package/lib/summary/summarizerHeuristics.js.map +1 -0
  281. package/lib/summary/summarizerNode/index.d.ts +8 -0
  282. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  283. package/lib/summary/summarizerNode/index.js +7 -0
  284. package/lib/summary/summarizerNode/index.js.map +1 -0
  285. package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
  286. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  287. package/lib/summary/summarizerNode/summarizerNode.js +526 -0
  288. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  289. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  290. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  291. package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
  292. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  293. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  294. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  295. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
  296. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  297. package/{dist → lib/summary}/summarizerTypes.d.ts +7 -17
  298. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  299. package/lib/summary/summarizerTypes.js +6 -0
  300. package/{dist → lib/summary}/summarizerTypes.js.map +1 -1
  301. package/lib/summary/summaryCollection.d.ts.map +1 -0
  302. package/lib/summary/summaryCollection.js.map +1 -0
  303. package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
  304. package/lib/summary/summaryFormat.d.ts.map +1 -0
  305. package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
  306. package/lib/summary/summaryFormat.js.map +1 -0
  307. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  308. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +4 -4
  309. package/lib/summary/summaryGenerator.js.map +1 -0
  310. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  311. package/lib/summary/summaryManager.d.ts.map +1 -0
  312. package/lib/summary/summaryManager.js.map +1 -0
  313. package/package.json +63 -60
  314. package/src/blobManager.ts +132 -69
  315. package/src/containerRuntime.ts +421 -382
  316. package/src/dataStoreContext.ts +140 -49
  317. package/src/dataStores.ts +139 -41
  318. package/src/deltaManagerSummarizerProxy.ts +46 -0
  319. package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
  320. package/src/{garbageCollection.ts → gc/garbageCollection.ts} +245 -890
  321. package/src/gc/gcConfigs.ts +193 -0
  322. package/src/gc/gcDefinitions.ts +387 -0
  323. package/src/gc/gcHelpers.ts +332 -0
  324. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  325. package/src/gc/gcSummaryDefinitions.ts +54 -0
  326. package/src/gc/gcSummaryStateTracker.ts +329 -0
  327. package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
  328. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  329. package/src/gc/index.ts +65 -0
  330. package/src/index.ts +10 -22
  331. package/src/opLifecycle/README.md +157 -0
  332. package/src/opLifecycle/batchManager.ts +26 -55
  333. package/src/opLifecycle/definitions.ts +4 -0
  334. package/src/opLifecycle/index.ts +1 -1
  335. package/src/opLifecycle/opCompressor.ts +32 -12
  336. package/src/opLifecycle/opDecompressor.ts +49 -5
  337. package/src/opLifecycle/opSplitter.ts +55 -12
  338. package/src/opLifecycle/outbox.ts +120 -60
  339. package/src/packageVersion.ts +1 -1
  340. package/src/pendingStateManager.ts +34 -27
  341. package/src/storageServiceWithAttachBlobs.ts +38 -0
  342. package/src/summary/index.ts +105 -0
  343. package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +7 -7
  344. package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +279 -139
  345. package/src/{summarizer.ts → summary/summarizer.ts} +12 -97
  346. package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +9 -4
  347. package/src/summary/summarizerNode/index.ts +12 -0
  348. package/src/summary/summarizerNode/summarizerNode.ts +766 -0
  349. package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
  350. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
  351. package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +8 -22
  352. package/src/{summaryFormat.ts → summary/summaryFormat.ts} +3 -29
  353. package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +12 -11
  354. package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
  355. package/dist/garbageCollection.d.ts +0 -411
  356. package/dist/garbageCollection.d.ts.map +0 -1
  357. package/dist/garbageCollection.js.map +0 -1
  358. package/dist/garbageCollectionConstants.d.ts +0 -23
  359. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  360. package/dist/garbageCollectionConstants.js +0 -36
  361. package/dist/garbageCollectionConstants.js.map +0 -1
  362. package/dist/garbageCollectionHelpers.d.ts +0 -15
  363. package/dist/garbageCollectionHelpers.d.ts.map +0 -1
  364. package/dist/garbageCollectionHelpers.js +0 -27
  365. package/dist/garbageCollectionHelpers.js.map +0 -1
  366. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  367. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  368. package/dist/orderedClientElection.d.ts.map +0 -1
  369. package/dist/orderedClientElection.js.map +0 -1
  370. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  371. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  372. package/dist/runningSummarizer.d.ts.map +0 -1
  373. package/dist/runningSummarizer.js.map +0 -1
  374. package/dist/serializedSnapshotStorage.d.ts +0 -58
  375. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  376. package/dist/serializedSnapshotStorage.js +0 -110
  377. package/dist/serializedSnapshotStorage.js.map +0 -1
  378. package/dist/summarizer.d.ts.map +0 -1
  379. package/dist/summarizer.js.map +0 -1
  380. package/dist/summarizerClientElection.d.ts.map +0 -1
  381. package/dist/summarizerClientElection.js.map +0 -1
  382. package/dist/summarizerHandle.d.ts +0 -12
  383. package/dist/summarizerHandle.d.ts.map +0 -1
  384. package/dist/summarizerHandle.js +0 -22
  385. package/dist/summarizerHandle.js.map +0 -1
  386. package/dist/summarizerHeuristics.d.ts.map +0 -1
  387. package/dist/summarizerHeuristics.js.map +0 -1
  388. package/dist/summarizerTypes.d.ts.map +0 -1
  389. package/dist/summaryCollection.d.ts.map +0 -1
  390. package/dist/summaryCollection.js.map +0 -1
  391. package/dist/summaryFormat.d.ts.map +0 -1
  392. package/dist/summaryFormat.js.map +0 -1
  393. package/dist/summaryGenerator.d.ts.map +0 -1
  394. package/dist/summaryGenerator.js.map +0 -1
  395. package/dist/summaryManager.d.ts.map +0 -1
  396. package/dist/summaryManager.js.map +0 -1
  397. package/lib/garbageCollection.d.ts +0 -411
  398. package/lib/garbageCollection.d.ts.map +0 -1
  399. package/lib/garbageCollection.js.map +0 -1
  400. package/lib/garbageCollectionConstants.d.ts +0 -23
  401. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  402. package/lib/garbageCollectionConstants.js +0 -33
  403. package/lib/garbageCollectionConstants.js.map +0 -1
  404. package/lib/garbageCollectionHelpers.d.ts +0 -15
  405. package/lib/garbageCollectionHelpers.d.ts.map +0 -1
  406. package/lib/garbageCollectionHelpers.js +0 -23
  407. package/lib/garbageCollectionHelpers.js.map +0 -1
  408. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  409. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  410. package/lib/orderedClientElection.d.ts.map +0 -1
  411. package/lib/orderedClientElection.js.map +0 -1
  412. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  413. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  414. package/lib/runningSummarizer.d.ts.map +0 -1
  415. package/lib/runningSummarizer.js.map +0 -1
  416. package/lib/serializedSnapshotStorage.d.ts +0 -58
  417. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  418. package/lib/serializedSnapshotStorage.js +0 -106
  419. package/lib/serializedSnapshotStorage.js.map +0 -1
  420. package/lib/summarizer.d.ts.map +0 -1
  421. package/lib/summarizer.js.map +0 -1
  422. package/lib/summarizerClientElection.d.ts.map +0 -1
  423. package/lib/summarizerClientElection.js.map +0 -1
  424. package/lib/summarizerHandle.d.ts +0 -12
  425. package/lib/summarizerHandle.d.ts.map +0 -1
  426. package/lib/summarizerHandle.js +0 -18
  427. package/lib/summarizerHandle.js.map +0 -1
  428. package/lib/summarizerHeuristics.d.ts.map +0 -1
  429. package/lib/summarizerHeuristics.js.map +0 -1
  430. package/lib/summarizerTypes.d.ts.map +0 -1
  431. package/lib/summarizerTypes.js +0 -9
  432. package/lib/summarizerTypes.js.map +0 -1
  433. package/lib/summaryCollection.d.ts.map +0 -1
  434. package/lib/summaryCollection.js.map +0 -1
  435. package/lib/summaryFormat.d.ts.map +0 -1
  436. package/lib/summaryFormat.js.map +0 -1
  437. package/lib/summaryGenerator.d.ts.map +0 -1
  438. package/lib/summaryGenerator.js.map +0 -1
  439. package/lib/summaryManager.d.ts.map +0 -1
  440. package/lib/summaryManager.js.map +0 -1
  441. package/src/garbageCollectionConstants.ts +0 -38
  442. package/src/garbageCollectionHelpers.ts +0 -37
  443. package/src/serializedSnapshotStorage.ts +0 -151
  444. package/src/summarizerHandle.ts +0 -23
  445. /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  446. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  447. /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  448. /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  449. /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  450. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  451. /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  452. /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  453. /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
  454. /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
  455. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  456. /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
  457. /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
  458. /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
  459. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  460. /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
  461. /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  462. /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
  463. /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
  464. /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
  465. /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
@@ -17,7 +17,6 @@ import {
17
17
  } from "@fluidframework/core-interfaces";
18
18
  import {
19
19
  IAudience,
20
- IFluidTokenProvider,
21
20
  IContainerContext,
22
21
  IDeltaManager,
23
22
  IRuntime,
@@ -25,13 +24,18 @@ import {
25
24
  AttachState,
26
25
  ILoaderOptions,
27
26
  LoaderHeader,
28
- ISnapshotTreeWithBlobContents,
29
27
  } from "@fluidframework/container-definitions";
30
28
  import {
31
29
  IContainerRuntime,
32
30
  IContainerRuntimeEvents,
33
31
  } from "@fluidframework/container-runtime-definitions";
34
- import { assert, Trace, TypedEventEmitter, unreachableCase } from "@fluidframework/common-utils";
32
+ import {
33
+ assert,
34
+ LazyPromise,
35
+ Trace,
36
+ TypedEventEmitter,
37
+ unreachableCase,
38
+ } from "@fluidframework/common-utils";
35
39
  import {
36
40
  ChildLogger,
37
41
  raiseConnectedEvent,
@@ -68,13 +72,13 @@ import {
68
72
  } from "@fluidframework/protocol-definitions";
69
73
  import {
70
74
  FlushMode,
75
+ FlushModeExperimental,
71
76
  gcTreeKey,
72
77
  InboundAttachMessage,
73
78
  IFluidDataStoreContextDetached,
74
79
  IFluidDataStoreRegistry,
75
80
  IFluidDataStoreChannel,
76
81
  IGarbageCollectionData,
77
- IGarbageCollectionDetailsBase,
78
82
  IEnvelope,
79
83
  IInboundSignalMessage,
80
84
  ISignalEnvelope,
@@ -92,23 +96,19 @@ import {
92
96
  addBlobToSummary,
93
97
  addSummarizeResultToSummary,
94
98
  addTreeToSummary,
95
- createRootSummarizerNodeWithGC,
96
- IRootSummarizerNodeWithGC,
97
99
  RequestParser,
98
100
  create404Response,
99
101
  exceptionToResponse,
102
+ GCDataBuilder,
100
103
  requestFluidObject,
101
- responseToException,
102
104
  seqFromTree,
103
105
  calculateStats,
104
106
  TelemetryContext,
107
+ ReadAndParseBlob,
105
108
  } from "@fluidframework/runtime-utils";
106
- import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
107
109
  import { v4 as uuid } from "uuid";
108
110
  import { ContainerFluidHandleContext } from "./containerHandleContext";
109
111
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
110
- import { Summarizer } from "./summarizer";
111
- import { SummaryManager } from "./summaryManager";
112
112
  import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
113
113
  import { IPendingLocalState, PendingStateManager } from "./pendingStateManager";
114
114
  import { pkgVersion } from "./packageVersion";
@@ -118,22 +118,24 @@ import {
118
118
  aliasBlobName,
119
119
  blobsTreeName,
120
120
  chunksBlobName,
121
+ createRootSummarizerNodeWithGC,
121
122
  electedSummarizerBlobName,
122
123
  extractSummaryMetadataMessage,
123
124
  IContainerRuntimeMetadata,
124
125
  ICreateContainerMetadata,
126
+ IFetchSnapshotResult,
127
+ IRootSummarizerNodeWithGC,
125
128
  ISummaryMetadataMessage,
126
129
  metadataBlobName,
130
+ Summarizer,
131
+ SummaryManager,
127
132
  wrapSummaryInChannelsTree,
128
- } from "./summaryFormat";
129
- import { SummaryCollection } from "./summaryCollection";
130
- import {
133
+ SummaryCollection,
131
134
  ISerializedElection,
132
135
  OrderedClientCollection,
133
136
  OrderedClientElection,
134
- } from "./orderedClientElection";
135
- import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
136
- import {
137
+ SummarizerClientElection,
138
+ summarizerClientType,
137
139
  SubmitSummaryResult,
138
140
  IConnectableRuntime,
139
141
  IGeneratedSummaryStats,
@@ -142,22 +144,21 @@ import {
142
144
  ISummarizerInternalsProvider,
143
145
  ISummarizerRuntime,
144
146
  IRefreshSummaryAckOptions,
145
- } from "./summarizerTypes";
147
+ RunWhileConnectedCoordinator,
148
+ } from "./summary";
146
149
  import { formExponentialFn, Throttler } from "./throttler";
147
- import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
148
150
  import {
149
151
  GarbageCollector,
150
152
  GCNodeType,
151
- IGarbageCollectionRuntime,
153
+ gcTombstoneGenerationOptionName,
152
154
  IGarbageCollector,
155
+ IGCRuntimeOptions,
153
156
  IGCStats,
154
- } from "./garbageCollection";
157
+ shouldAllowGcTombstoneEnforcement,
158
+ trimLeadingAndTrailingSlashes,
159
+ } from "./gc";
155
160
  import { channelToDataStore, IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
156
161
  import { BindBatchTracker } from "./batchTracker";
157
- import {
158
- ISerializedBaseSnapshotBlobs,
159
- SerializedSnapshotStorage,
160
- } from "./serializedSnapshotStorage";
161
162
  import { ScheduleManager } from "./scheduleManager";
162
163
  import {
163
164
  BatchMessage,
@@ -168,6 +169,7 @@ import {
168
169
  OpSplitter,
169
170
  RemoteMessageProcessor,
170
171
  } from "./opLifecycle";
172
+ import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
171
173
 
172
174
  export enum ContainerMessageType {
173
175
  // An op to be delivered to store
@@ -312,54 +314,6 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
312
314
  nonRuntimeHeuristicThreshold: 20,
313
315
  };
314
316
 
315
- export interface IGCRuntimeOptions {
316
- /**
317
- * Flag that if true, will enable running garbage collection (GC) for a new container.
318
- *
319
- * GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
320
- * and marked as such in the summary. This option enables the mark phase.
321
- * In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
322
- * Sweep phase can be enabled via the "sweepAllowed" option.
323
- *
324
- * Note: This setting is persisted in the container's summary and cannot be changed.
325
- */
326
- gcAllowed?: boolean;
327
-
328
- /**
329
- * Flag that if true, enables GC's sweep phase for a new container.
330
- *
331
- * This will allow GC to eventually delete unreferenced objects from the container.
332
- * This flag should only be set to true if "gcAllowed" is true.
333
- *
334
- * Note: This setting is persisted in the container's summary and cannot be changed.
335
- */
336
- sweepAllowed?: boolean;
337
-
338
- /**
339
- * Flag that if true, will disable garbage collection for the session.
340
- * Can be used to disable running GC on containers where it is allowed via the gcAllowed option.
341
- */
342
- disableGC?: boolean;
343
-
344
- /**
345
- * Flag that will bypass optimizations and generate GC data for all nodes irrespective of whether a node
346
- * changed or not.
347
- */
348
- runFullGC?: boolean;
349
-
350
- /**
351
- * Maximum session duration for a new container. If not present, a default value will be used.
352
- *
353
- * Note: This setting is persisted in the container's summary and cannot be changed.
354
- */
355
- sessionExpiryTimeoutMs?: number;
356
-
357
- /**
358
- * Allows additional GC options to be passed.
359
- */
360
- [key: string]: any;
361
- }
362
-
363
317
  export interface ISummaryRuntimeOptions {
364
318
  /** Override summary configurations set by the server. */
365
319
  summaryConfigOverrides?: ISummaryConfiguration;
@@ -411,10 +365,6 @@ export interface IContainerRuntimeOptions {
411
365
  * By default, flush mode is TurnBased.
412
366
  */
413
367
  readonly flushMode?: FlushMode;
414
- /**
415
- * Save enough runtime state to be able to serialize upon request and load to the same state in a new container.
416
- */
417
- readonly enableOfflineLoad?: boolean;
418
368
  /**
419
369
  * Enables the runtime to compress ops. Compression is disabled when undefined.
420
370
  * @experimental Not ready for use.
@@ -433,7 +383,8 @@ export interface IContainerRuntimeOptions {
433
383
  readonly maxBatchSizeInBytes?: number;
434
384
  /**
435
385
  * If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
436
- * how large the individual chunks will be. This is only supported when compression is enabled.
386
+ * how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
387
+ * batch size exceeds this value, it will be chunked into smaller ops of this size.
437
388
  *
438
389
  * If unspecified, if a batch exceeds `maxBatchSizeInBytes` after compression, the container will close with an instance
439
390
  * of `GenericError` with the `BatchTooLarge` message.
@@ -467,11 +418,6 @@ export interface IRootSummaryTreeWithStats extends ISummaryTreeWithStats {
467
418
  export enum RuntimeHeaders {
468
419
  /** True to wait for a data store to be created and loaded before returning it. */
469
420
  wait = "wait",
470
- /**
471
- * True if the request is from an external app. Used for GC to handle scenarios where a data store
472
- * is deleted and requested via an external app.
473
- */
474
- externalRequest = "externalRequest",
475
421
  /** True if the request is coming from an IFluidHandle. */
476
422
  viaHandle = "viaHandle",
477
423
  }
@@ -487,7 +433,6 @@ export const TombstoneResponseHeaderKey = "isTombstoned";
487
433
  */
488
434
  export interface RuntimeHeaderData {
489
435
  wait?: boolean;
490
- externalRequest?: boolean;
491
436
  viaHandle?: boolean;
492
437
  allowTombstone?: boolean;
493
438
  }
@@ -495,7 +440,6 @@ export interface RuntimeHeaderData {
495
440
  /** Default values for Runtime Headers */
496
441
  export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
497
442
  wait: true,
498
- externalRequest: false,
499
443
  viaHandle: false,
500
444
  allowTombstone: false,
501
445
  };
@@ -532,21 +476,6 @@ interface IPendingRuntimeState {
532
476
  * Pending blobs from BlobManager
533
477
  */
534
478
  pendingAttachmentBlobs?: IPendingBlobs;
535
- /**
536
- * A base snapshot at a sequence number prior to the first pending op
537
- */
538
- baseSnapshot: ISnapshotTree;
539
- /**
540
- * Serialized blobs from the base snapshot. Used to load offline since
541
- * storage is not available.
542
- */
543
- snapshotBlobs: ISerializedBaseSnapshotBlobs;
544
- /**
545
- * All runtime ops since base snapshot sequence number up to the latest op
546
- * seen when the container was closed. Used to apply stashed (saved pending)
547
- * ops at the same sequence number at which they were made.
548
- */
549
- savedOps: ISequencedDocumentMessage[];
550
479
  }
551
480
 
552
481
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
@@ -557,7 +486,15 @@ const defaultFlushMode = FlushMode.TurnBased;
557
486
  // We can't estimate it fully, as we
558
487
  // - do not know what properties relay service will add
559
488
  // - we do not stringify final op, thus we do not know how much escaping will be added.
560
- const defaultMaxBatchSizeInBytes = 950 * 1024;
489
+ const defaultMaxBatchSizeInBytes = 700 * 1024;
490
+
491
+ const defaultCompressionConfig = {
492
+ // Batches with content size exceeding this value will be compressed
493
+ minimumBatchSizeInBytes: 614400,
494
+ compressionAlgorithm: CompressionAlgorithms.lz4,
495
+ };
496
+
497
+ const defaultChunkSizeInBytes = 204800;
561
498
 
562
499
  /**
563
500
  * @deprecated - use ContainerRuntimeMessage instead
@@ -605,12 +542,7 @@ export function getDeviceSpec() {
605
542
  */
606
543
  export class ContainerRuntime
607
544
  extends TypedEventEmitter<IContainerRuntimeEvents>
608
- implements
609
- IContainerRuntime,
610
- IGarbageCollectionRuntime,
611
- IRuntime,
612
- ISummarizerRuntime,
613
- ISummarizerInternalsProvider
545
+ implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
614
546
  {
615
547
  public get IContainerRuntime() {
616
548
  return this;
@@ -658,13 +590,16 @@ export class ContainerRuntime
658
590
  * Load the stores from a snapshot and returns the runtime.
659
591
  * @param params - An object housing the runtime properties:
660
592
  * - context - Context of the container.
661
- * - registryEntries - Mapping to the stores.
662
- * - existing - When loading from an existing snapshot
663
- * - requestHandler - Request handlers for the container runtime
593
+ * - registryEntries - Mapping from data store types to their corresponding factories.
594
+ * - existing - Pass 'true' if loading from an existing snapshot.
595
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
596
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
664
597
  * - runtimeOptions - Additional options to be passed to the runtime
665
598
  * - containerScope - runtime services provided with context
666
599
  * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
667
600
  * This allows mixin classes to leverage this method to define their own async initializer.
601
+ * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
602
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
668
603
  */
669
604
  public static async loadRuntime(params: {
670
605
  context: IContainerContext;
@@ -674,6 +609,7 @@ export class ContainerRuntime
674
609
  runtimeOptions?: IContainerRuntimeOptions;
675
610
  containerScope?: FluidObject;
676
611
  containerRuntimeCtor?: typeof ContainerRuntime;
612
+ initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
677
613
  }): Promise<ContainerRuntime> {
678
614
  const {
679
615
  context,
@@ -683,6 +619,7 @@ export class ContainerRuntime
683
619
  runtimeOptions = {},
684
620
  containerScope = {},
685
621
  containerRuntimeCtor = ContainerRuntime,
622
+ initializeEntryPoint,
686
623
  } = params;
687
624
 
688
625
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
@@ -702,34 +639,24 @@ export class ContainerRuntime
702
639
  gcOptions = {},
703
640
  loadSequenceNumberVerification = "close",
704
641
  flushMode = defaultFlushMode,
705
- enableOfflineLoad = false,
706
- compressionOptions = {
707
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
708
- compressionAlgorithm: CompressionAlgorithms.lz4,
709
- },
642
+ compressionOptions = defaultCompressionConfig,
710
643
  maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
711
- chunkSizeInBytes = Number.POSITIVE_INFINITY,
644
+ chunkSizeInBytes = defaultChunkSizeInBytes,
712
645
  enableOpReentryCheck = false,
713
646
  } = runtimeOptions;
714
647
 
715
- const pendingRuntimeState = context.pendingLocalState as IPendingRuntimeState | undefined;
716
- const baseSnapshot: ISnapshotTree | undefined =
717
- pendingRuntimeState?.baseSnapshot ?? context.baseSnapshot;
718
- const storage = !pendingRuntimeState
719
- ? context.storage
720
- : new SerializedSnapshotStorage(() => {
721
- return context.storage;
722
- }, pendingRuntimeState.snapshotBlobs);
723
-
724
648
  const registry = new FluidDataStoreRegistry(registryEntries);
725
649
 
726
650
  const tryFetchBlob = async <T>(blobName: string): Promise<T | undefined> => {
727
- const blobId = baseSnapshot?.blobs[blobName];
728
- if (baseSnapshot && blobId) {
651
+ const blobId = context.baseSnapshot?.blobs[blobName];
652
+ if (context.baseSnapshot && blobId) {
729
653
  // IContainerContext storage api return type still has undefined in 0.39 package version.
730
654
  // So once we release 0.40 container-defn package we can remove this check.
731
- assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
732
- return readAndParse<T>(storage, blobId);
655
+ assert(
656
+ context.storage !== undefined,
657
+ 0x1f5 /* "Attached state should have storage" */,
658
+ );
659
+ return readAndParse<T>(context.storage, blobId);
733
660
  }
734
661
  };
735
662
 
@@ -744,22 +671,22 @@ export class ContainerRuntime
744
671
 
745
672
  // read snapshot blobs needed for BlobManager to load
746
673
  const blobManagerSnapshot = await BlobManager.load(
747
- baseSnapshot?.trees[blobsTreeName],
674
+ context.baseSnapshot?.trees[blobsTreeName],
748
675
  async (id) => {
749
676
  // IContainerContext storage api return type still has undefined in 0.39 package version.
750
677
  // So once we release 0.40 container-defn package we can remove this check.
751
678
  assert(
752
- storage !== undefined,
679
+ context.storage !== undefined,
753
680
  0x256 /* "storage undefined in attached container" */,
754
681
  );
755
- return readAndParse(storage, id);
682
+ return readAndParse(context.storage, id);
756
683
  },
757
684
  );
758
685
 
759
686
  // Verify summary runtime sequence number matches protocol sequence number.
760
687
  const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
761
688
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
762
- if (!pendingRuntimeState && runtimeSequenceNumber !== undefined) {
689
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
763
690
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
764
691
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
765
692
  if (
@@ -795,7 +722,6 @@ export class ContainerRuntime
795
722
  gcOptions,
796
723
  loadSequenceNumberVerification,
797
724
  flushMode,
798
- enableOfflineLoad,
799
725
  compressionOptions,
800
726
  maxBatchSizeInBytes,
801
727
  chunkSizeInBytes,
@@ -805,15 +731,15 @@ export class ContainerRuntime
805
731
  logger,
806
732
  loadExisting,
807
733
  blobManagerSnapshot,
808
- storage,
734
+ context.storage,
809
735
  requestHandler,
736
+ undefined, // summaryConfiguration
737
+ initializeEntryPoint,
810
738
  );
811
739
 
812
- if (pendingRuntimeState) {
813
- await runtime.processSavedOps(pendingRuntimeState);
814
- // delete these once runtime has seen them to save space
815
- pendingRuntimeState.savedOps = [];
816
- }
740
+ // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
741
+ // at 1, so we won't see a replayed saved op with a sequence number of 0.
742
+ await runtime.pendingStateManager.applyStashedOpsAt(0);
817
743
 
818
744
  // Initialize the base state of the runtime before it's returned.
819
745
  await runtime.initializeBaseState();
@@ -833,10 +759,6 @@ export class ContainerRuntime
833
759
  return this.context.clientDetails;
834
760
  }
835
761
 
836
- public get deltaManager(): IDeltaManager<ISequencedDocumentMessage, IDocumentMessage> {
837
- return this.context.deltaManager;
838
- }
839
-
840
762
  public get storage(): IDocumentStorageService {
841
763
  return this._storage;
842
764
  }
@@ -885,6 +807,19 @@ export class ContainerRuntime
885
807
  }
886
808
  private readonly handleContext: ContainerFluidHandleContext;
887
809
 
810
+ /**
811
+ * This is a proxy to the delta manager provided by the container context (innerDeltaManager). It restricts certain
812
+ * accesses such as sets "read-only" mode for the summarizer client. This is the default delta manager that should
813
+ * be used unless the innerDeltaManager is required.
814
+ */
815
+ public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
816
+ /**
817
+ * The delta manager provided by the container context. By default, using the default delta manager (proxy)
818
+ * should be sufficient. This should be used only if necessary. For example, for validating and propagating connected
819
+ * events which requires access to the actual real only info, this is needed.
820
+ */
821
+ private readonly innerDeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
822
+
888
823
  // internal logger for ContainerRuntime. Use this.logger for stores, summaries, etc.
889
824
  private readonly mc: MonitoringContext;
890
825
 
@@ -904,13 +839,10 @@ export class ContainerRuntime
904
839
 
905
840
  private _orderSequentiallyCalls: number = 0;
906
841
  private readonly _flushMode: FlushMode;
907
- private flushMicroTaskExists = false;
842
+ private flushTaskExists = false;
908
843
 
909
844
  private _connected: boolean;
910
845
 
911
- private readonly savedOps: ISequencedDocumentMessage[] = [];
912
- private baseSnapshotBlobs?: ISerializedBaseSnapshotBlobs;
913
-
914
846
  private consecutiveReconnects = 0;
915
847
 
916
848
  /**
@@ -963,6 +895,7 @@ export class ContainerRuntime
963
895
  private dirtyContainer: boolean;
964
896
  private emitDirtyDocumentEvent = true;
965
897
  private readonly enableOpReentryCheck: boolean;
898
+ private readonly disableAttachReorder: boolean | undefined;
966
899
 
967
900
  private readonly defaultTelemetrySignalSampleCount = 100;
968
901
  private _perfSignalData: IPerfSignalReport = {
@@ -982,7 +915,6 @@ export class ContainerRuntime
982
915
  private readonly blobManager: BlobManager;
983
916
  private readonly pendingStateManager: PendingStateManager;
984
917
  private readonly outbox: Outbox;
985
-
986
918
  private readonly garbageCollector: IGarbageCollector;
987
919
 
988
920
  private readonly dataStores: DataStores;
@@ -1032,6 +964,17 @@ export class ContainerRuntime
1032
964
  */
1033
965
  private nextSummaryNumber: number;
1034
966
 
967
+ /**
968
+ * If false, loading or using a Tombstoned object should merely log, not fail
969
+ */
970
+ public readonly gcTombstoneEnforcementAllowed: boolean;
971
+
972
+ /**
973
+ * GUID to identify a document in telemetry
974
+ * ! Note: should not be used for anything other than telemetry and is not considered a stable GUID
975
+ */
976
+ private readonly telemetryDocumentId: string;
977
+
1035
978
  /**
1036
979
  * @internal
1037
980
  */
@@ -1058,9 +1001,13 @@ export class ContainerRuntime
1058
1001
  // the runtime configuration overrides
1059
1002
  ...runtimeOptions.summaryOptions?.summaryConfigOverrides,
1060
1003
  },
1004
+ initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1061
1005
  ) {
1062
1006
  super();
1063
1007
 
1008
+ this.innerDeltaManager = context.deltaManager;
1009
+ this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
1010
+
1064
1011
  let loadSummaryNumber: number;
1065
1012
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
1066
1013
  // get the values from the metadata blob.
@@ -1085,18 +1032,41 @@ export class ContainerRuntime
1085
1032
 
1086
1033
  this._connected = this.context.connected;
1087
1034
 
1035
+ this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
1036
+ metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
1037
+ this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */,
1038
+ );
1039
+
1088
1040
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
1089
1041
 
1042
+ this.mc.logger.sendTelemetryEvent({
1043
+ eventName: "GCFeatureMatrix",
1044
+ metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
1045
+ inputs: JSON.stringify({
1046
+ gcOptions_gcTombstoneGeneration:
1047
+ this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
1048
+ }),
1049
+ });
1050
+
1051
+ this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
1052
+
1053
+ this.disableAttachReorder = this.mc.config.getBoolean(
1054
+ "Fluid.ContainerRuntime.disableAttachOpReorder",
1055
+ );
1056
+ const disableChunking = this.mc.config.getBoolean(
1057
+ "Fluid.ContainerRuntime.CompressionChunkingDisabled",
1058
+ );
1090
1059
  const opSplitter = new OpSplitter(
1091
1060
  chunks,
1092
1061
  this.context.submitBatchFn,
1093
- this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompressionChunking") === true
1094
- ? Number.POSITIVE_INFINITY
1095
- : runtimeOptions.chunkSizeInBytes,
1062
+ disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes,
1096
1063
  runtimeOptions.maxBatchSizeInBytes,
1097
1064
  this.mc.logger,
1098
1065
  );
1099
- this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor());
1066
+ this.remoteMessageProcessor = new RemoteMessageProcessor(
1067
+ opSplitter,
1068
+ new OpDecompressor(this.mc.logger),
1069
+ );
1100
1070
 
1101
1071
  this.handleContext = new ContainerFluidHandleContext("", this);
1102
1072
 
@@ -1104,10 +1074,13 @@ export class ContainerRuntime
1104
1074
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
1105
1075
  }
1106
1076
 
1077
+ const disableOpReentryCheck = this.mc.config.getBoolean(
1078
+ "Fluid.ContainerRuntime.DisableOpReentryCheck",
1079
+ );
1107
1080
  this.enableOpReentryCheck =
1108
1081
  runtimeOptions.enableOpReentryCheck === true &&
1109
1082
  // Allow for a break-glass config to override the options
1110
- this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck") !== true;
1083
+ disableOpReentryCheck !== true;
1111
1084
 
1112
1085
  this.summariesDisabled = this.isSummariesDisabled();
1113
1086
  this.heuristicsDisabled = this.isHeuristicsDisabled();
@@ -1118,11 +1091,18 @@ export class ContainerRuntime
1118
1091
  this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
1119
1092
  this.defaultMaxConsecutiveReconnects;
1120
1093
 
1121
- this._flushMode = runtimeOptions.flushMode;
1094
+ if (
1095
+ runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
1096
+ context.supportedFeatures?.get("referenceSequenceNumbers") !== true
1097
+ ) {
1098
+ // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
1099
+ this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
1100
+ this._flushMode = FlushMode.TurnBased;
1101
+ } else {
1102
+ this._flushMode = runtimeOptions.flushMode;
1103
+ }
1122
1104
 
1123
1105
  const pendingRuntimeState = context.pendingLocalState as IPendingRuntimeState | undefined;
1124
- const baseSnapshot: ISnapshotTree | undefined =
1125
- pendingRuntimeState?.baseSnapshot ?? context.baseSnapshot;
1126
1106
 
1127
1107
  const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
1128
1108
  if (
@@ -1138,7 +1118,7 @@ export class ContainerRuntime
1138
1118
  this.garbageCollector = GarbageCollector.create({
1139
1119
  runtime: this,
1140
1120
  gcOptions: this.runtimeOptions.gcOptions,
1141
- baseSnapshot,
1121
+ baseSnapshot: context.baseSnapshot,
1142
1122
  baseLogger: this.mc.logger,
1143
1123
  existing,
1144
1124
  metadata,
@@ -1148,7 +1128,9 @@ export class ContainerRuntime
1148
1128
  getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
1149
1129
  readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
1150
1130
  getContainerDiagnosticId: () => this.context.id,
1151
- activeConnection: () => this.deltaManager.active,
1131
+ // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
1132
+ // delta manager would always return false for summarizer client.
1133
+ activeConnection: () => this.innerDeltaManager.active,
1152
1134
  });
1153
1135
 
1154
1136
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
@@ -1160,7 +1142,7 @@ export class ContainerRuntime
1160
1142
  // Latest change sequence number, no changes since summary applied yet
1161
1143
  loadedFromSequenceNumber,
1162
1144
  // Summary reference sequence number, undefined if no summary yet
1163
- baseSnapshot ? loadedFromSequenceNumber : undefined,
1145
+ context.baseSnapshot ? loadedFromSequenceNumber : undefined,
1164
1146
  {
1165
1147
  // Must set to false to prevent sending summary handle which would be pointing to
1166
1148
  // a summary with an older protocol state.
@@ -1177,19 +1159,18 @@ export class ContainerRuntime
1177
1159
  async () => this.garbageCollector.getBaseGCDetails(),
1178
1160
  );
1179
1161
 
1180
- if (baseSnapshot) {
1181
- this.summarizerNode.updateBaseSummaryState(baseSnapshot);
1162
+ if (context.baseSnapshot) {
1163
+ this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
1182
1164
  }
1183
1165
 
1184
1166
  this.dataStores = new DataStores(
1185
- getSummaryForDatastores(baseSnapshot, metadata),
1167
+ getSummaryForDatastores(context.baseSnapshot, metadata),
1186
1168
  this,
1187
1169
  (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg),
1188
1170
  (id: string, createParam: CreateChildSummarizerNodeParam) =>
1189
1171
  (
1190
1172
  summarizeInternal: SummarizeInternalFn,
1191
1173
  getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
1192
- getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,
1193
1174
  ) =>
1194
1175
  this.summarizerNode.createChild(
1195
1176
  summarizeInternal,
@@ -1197,13 +1178,12 @@ export class ContainerRuntime
1197
1178
  createParam,
1198
1179
  undefined,
1199
1180
  getGCDataFn,
1200
- getBaseGCDetailsFn,
1201
1181
  ),
1202
1182
  (id: string) => this.summarizerNode.deleteChild(id),
1203
1183
  this.mc.logger,
1204
- async () => this.garbageCollector.getBaseGCDetails(),
1205
1184
  (path: string, timestampMs: number, packagePath?: readonly string[]) =>
1206
1185
  this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath),
1186
+ (path: string) => this.garbageCollector.isNodeDeleted(path),
1207
1187
  new Map<string, string>(dataStoreAliasMap),
1208
1188
  );
1209
1189
 
@@ -1220,8 +1200,6 @@ export class ContainerRuntime
1220
1200
  }
1221
1201
  },
1222
1202
  (blobPath: string) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
1223
- (fromPath: string, toPath: string) =>
1224
- this.garbageCollector.addedOutboundReference(fromPath, toPath),
1225
1203
  (blobPath: string) => this.garbageCollector.isNodeDeleted(blobPath),
1226
1204
  this,
1227
1205
  pendingRuntimeState?.pendingAttachmentBlobs,
@@ -1248,14 +1226,20 @@ export class ContainerRuntime
1248
1226
  pendingRuntimeState?.pending,
1249
1227
  );
1250
1228
 
1229
+ const disableCompression = this.mc.config.getBoolean(
1230
+ "Fluid.ContainerRuntime.CompressionDisabled",
1231
+ );
1251
1232
  const compressionOptions =
1252
- this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableCompression") === true
1233
+ disableCompression === true
1253
1234
  ? {
1254
1235
  minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
1255
1236
  compressionAlgorithm: CompressionAlgorithms.lz4,
1256
1237
  }
1257
1238
  : runtimeOptions.compressionOptions;
1258
1239
 
1240
+ const disablePartialFlush = this.mc.config.getBoolean(
1241
+ "Fluid.ContainerRuntime.DisablePartialFlush",
1242
+ );
1259
1243
  this.outbox = new Outbox({
1260
1244
  shouldSend: () => this.canSendOps(),
1261
1245
  pendingStateManager: this.pendingStateManager,
@@ -1265,7 +1249,7 @@ export class ContainerRuntime
1265
1249
  config: {
1266
1250
  compressionOptions,
1267
1251
  maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
1268
- enableOpReentryCheck: this.enableOpReentryCheck,
1252
+ disablePartialFlush: disablePartialFlush === true,
1269
1253
  },
1270
1254
  logger: this.mc.logger,
1271
1255
  });
@@ -1306,14 +1290,18 @@ export class ContainerRuntime
1306
1290
 
1307
1291
  if (this.context.clientDetails.type === summarizerClientType) {
1308
1292
  this._summarizer = new Summarizer(
1309
- "/_summarizer",
1310
1293
  this /* ISummarizerRuntime */,
1311
1294
  () => this.summaryConfiguration,
1312
1295
  this /* ISummarizerInternalsProvider */,
1313
1296
  this.handleContext,
1314
1297
  this.summaryCollection,
1315
1298
  async (runtime: IConnectableRuntime) =>
1316
- RunWhileConnectedCoordinator.create(runtime),
1299
+ RunWhileConnectedCoordinator.create(
1300
+ runtime,
1301
+ // Summarization runs in summarizer client and needs access to the real (non-proxy) active
1302
+ // information. The proxy delta manager would always return false for summarizer client.
1303
+ () => this.innerDeltaManager.active,
1304
+ ),
1317
1305
  );
1318
1306
  } else if (
1319
1307
  SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)
@@ -1363,8 +1351,9 @@ export class ContainerRuntime
1363
1351
  this.deltaManager.on("readonly", (readonly: boolean) => {
1364
1352
  // we accumulate ops while being in read-only state.
1365
1353
  // once user gets write permissions and we have active connection, flush all pending ops.
1354
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1366
1355
  assert(
1367
- readonly === this.deltaManager.readOnlyInfo.readonly,
1356
+ readonly === this.innerDeltaManager.readOnlyInfo.readonly,
1368
1357
  0x124 /* "inconsistent readonly property/event state" */,
1369
1358
  );
1370
1359
 
@@ -1402,17 +1391,36 @@ export class ContainerRuntime
1402
1391
  summaryFormatVersion: metadata?.summaryFormatVersion,
1403
1392
  disableIsolatedChannels: metadata?.disableIsolatedChannels,
1404
1393
  gcVersion: metadata?.gcFeature,
1394
+ options: JSON.stringify(runtimeOptions),
1395
+ featureGates: JSON.stringify({
1396
+ disableCompression,
1397
+ disableOpReentryCheck,
1398
+ disableChunking,
1399
+ disableAttachReorder: this.disableAttachReorder,
1400
+ disablePartialFlush,
1401
+ }),
1402
+ telemetryDocumentId: this.telemetryDocumentId,
1405
1403
  });
1406
1404
 
1407
1405
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
1408
1406
  BindBatchTracker(this, this.logger);
1407
+
1408
+ this.entryPoint = new LazyPromise(async () => {
1409
+ if (this.context.clientDetails.type === summarizerClientType) {
1410
+ assert(
1411
+ this._summarizer !== undefined,
1412
+ 0x5bf /* Summarizer object is undefined in a summarizer client */,
1413
+ );
1414
+ return this._summarizer;
1415
+ }
1416
+ return initializeEntryPoint?.(this);
1417
+ });
1409
1418
  }
1410
1419
 
1411
1420
  /**
1412
1421
  * Initializes the state from the base snapshot this container runtime loaded from.
1413
1422
  */
1414
1423
  private async initializeBaseState(): Promise<void> {
1415
- await this.initializeBaseSnapshotBlobs();
1416
1424
  await this.garbageCollector.initializeBaseState();
1417
1425
  }
1418
1426
 
@@ -1443,16 +1451,6 @@ export class ContainerRuntime
1443
1451
  this.removeAllListeners();
1444
1452
  }
1445
1453
 
1446
- public get IFluidTokenProvider() {
1447
- if (this.options?.intelligence) {
1448
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1449
- return {
1450
- intelligence: this.options.intelligence,
1451
- } as IFluidTokenProvider;
1452
- }
1453
- return undefined;
1454
- }
1455
-
1456
1454
  /**
1457
1455
  * Notifies this object about the request made to the container.
1458
1456
  * @param request - Request made to the handler.
@@ -1522,6 +1520,14 @@ export class ContainerRuntime
1522
1520
  }
1523
1521
  }
1524
1522
 
1523
+ /**
1524
+ * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
1525
+ */
1526
+ public async getEntryPoint?(): Promise<FluidObject | undefined> {
1527
+ return this.entryPoint;
1528
+ }
1529
+ private readonly entryPoint: LazyPromise<FluidObject | undefined>;
1530
+
1525
1531
  private internalId(maybeAlias: string): string {
1526
1532
  return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
1527
1533
  }
@@ -1541,29 +1547,6 @@ export class ContainerRuntime
1541
1547
  await this.dataStores.waitIfPendingAlias(id);
1542
1548
  const internalId = this.internalId(id);
1543
1549
  const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
1544
-
1545
- /**
1546
- * If GC should run and this an external app request with "externalRequest" header, we need to return
1547
- * an error if the data store being requested is marked as unreferenced as per the data store's base
1548
- * GC data.
1549
- *
1550
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
1551
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
1552
- */
1553
- if (
1554
- request.headers?.[RuntimeHeaders.externalRequest] &&
1555
- this.garbageCollector.shouldRunGC
1556
- ) {
1557
- // The data store is referenced if used routes in the base summary has a route to self.
1558
- // Older documents may not have used routes in the summary. They are considered referenced.
1559
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
1560
- if (
1561
- !(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))
1562
- ) {
1563
- throw responseToException(create404Response(request), request);
1564
- }
1565
- }
1566
-
1567
1550
  const dataStoreChannel = await dataStoreContext.realize();
1568
1551
 
1569
1552
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
@@ -1592,6 +1575,7 @@ export class ContainerRuntime
1592
1575
  message:
1593
1576
  extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
1594
1577
  this.messageAtLastSummary,
1578
+ telemetryDocumentId: this.telemetryDocumentId,
1595
1579
  };
1596
1580
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
1597
1581
  }
@@ -1736,8 +1720,9 @@ export class ContainerRuntime
1736
1720
  // If attachment blobs were added while disconnected, we need to delay
1737
1721
  // propagation of the "connected" event until we have uploaded them to
1738
1722
  // ensure we don't submit ops referencing a blob that has not been uploaded
1723
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1739
1724
  const connecting =
1740
- connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
1725
+ connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1741
1726
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
1742
1727
  assert(
1743
1728
  !this.delayConnectClientId,
@@ -1815,16 +1800,13 @@ export class ContainerRuntime
1815
1800
  raiseConnectedEvent(this.mc.logger, this, connected, clientId);
1816
1801
  }
1817
1802
 
1803
+ public async notifyOpReplay(message: ISequencedDocumentMessage) {
1804
+ await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
1805
+ }
1806
+
1818
1807
  public process(messageArg: ISequencedDocumentMessage, local: boolean) {
1819
1808
  this.verifyNotClosed();
1820
1809
 
1821
- if (
1822
- this.mc.config.getBoolean("enableOfflineLoad") ??
1823
- this.runtimeOptions.enableOfflineLoad
1824
- ) {
1825
- this.savedOps.push(messageArg);
1826
- }
1827
-
1828
1810
  // Whether or not the message is actually a runtime message.
1829
1811
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
1830
1812
  // or something different, like a system message.
@@ -1869,7 +1851,23 @@ export class ContainerRuntime
1869
1851
  case ContainerMessageType.Rejoin:
1870
1852
  break;
1871
1853
  default:
1872
- assert(!runtimeMessage, 0x3ce /* Runtime message of unknown type */);
1854
+ if (runtimeMessage) {
1855
+ const error = DataProcessingError.create(
1856
+ // Former assert 0x3ce
1857
+ "Runtime message of unknown type",
1858
+ "OpProcessing",
1859
+ message,
1860
+ {
1861
+ local,
1862
+ type: message.type,
1863
+ contentType: typeof message.contents,
1864
+ batch: message.metadata?.batch,
1865
+ compression: message.compression,
1866
+ },
1867
+ );
1868
+ this.closeFn(error);
1869
+ throw error;
1870
+ }
1873
1871
  }
1874
1872
 
1875
1873
  // For back-compat, notify only about runtime messages for now.
@@ -1944,7 +1942,10 @@ export class ContainerRuntime
1944
1942
  envelope.clientSignalSequenceNumber ===
1945
1943
  this._perfSignalData.trackingSignalSequenceNumber
1946
1944
  ) {
1947
- this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1945
+ // only logging for the first connection and the trackingSignalSequenceNUmber.
1946
+ if (this.consecutiveReconnects === 0) {
1947
+ this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1948
+ }
1948
1949
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1949
1950
  }
1950
1951
  }
@@ -2084,14 +2085,16 @@ export class ContainerRuntime
2084
2085
  }
2085
2086
 
2086
2087
  private canSendOps() {
2087
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
2088
+ // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
2089
+ // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
2090
+ return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
2088
2091
  }
2089
2092
 
2090
2093
  /**
2091
2094
  * Are we in the middle of batching ops together?
2092
2095
  */
2093
2096
  private currentlyBatching() {
2094
- return this.flushMode === FlushMode.TurnBased || this._orderSequentiallyCalls !== 0;
2097
+ return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
2095
2098
  }
2096
2099
 
2097
2100
  public getQuorum(): IQuorumClients {
@@ -2278,12 +2281,24 @@ export class ContainerRuntime
2278
2281
  fullGC,
2279
2282
  } = options;
2280
2283
 
2284
+ const telemetryContext = new TelemetryContext();
2285
+ // Add the options that are used to generate this summary to the telemetry context.
2286
+ telemetryContext.setMultiple("fluid_Summarize", "Options", {
2287
+ fullTree,
2288
+ trackState,
2289
+ runGC,
2290
+ fullGC,
2291
+ runSweep,
2292
+ });
2293
+
2281
2294
  let gcStats: IGCStats | undefined;
2282
2295
  if (runGC) {
2283
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
2296
+ gcStats = await this.collectGarbage(
2297
+ { logger: summaryLogger, runSweep, fullGC },
2298
+ telemetryContext,
2299
+ );
2284
2300
  }
2285
2301
 
2286
- const telemetryContext = new TelemetryContext();
2287
2302
  const { stats, summary } = await this.summarizerNode.summarize(
2288
2303
  fullTree,
2289
2304
  trackState,
@@ -2304,10 +2319,10 @@ export class ContainerRuntime
2304
2319
  }
2305
2320
 
2306
2321
  /**
2307
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
2308
2322
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
2309
2323
  * the garbage collector of references detected since the last GC run. Most references are notified immediately
2310
2324
  * but there can be some for which async operation is required (such as detecting new root data stores).
2325
+ * @see IGarbageCollectionRuntime.updateStateBeforeGC
2311
2326
  */
2312
2327
  public async updateStateBeforeGC() {
2313
2328
  return this.dataStores.updateStateBeforeGC();
@@ -2318,9 +2333,9 @@ export class ContainerRuntime
2318
2333
  }
2319
2334
 
2320
2335
  /**
2321
- * Implementation of IGarbageCollectionRuntime::getGCData.
2322
2336
  * Generates and returns the GC data for this container.
2323
2337
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
2338
+ * @see IGarbageCollectionRuntime.getGCData
2324
2339
  */
2325
2340
  public async getGCData(fullGC?: boolean): Promise<IGarbageCollectionData> {
2326
2341
  const builder = new GCDataBuilder();
@@ -2333,9 +2348,9 @@ export class ContainerRuntime
2333
2348
  }
2334
2349
 
2335
2350
  /**
2336
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
2337
2351
  * After GC has run, called to notify this container's nodes of routes that are used in it.
2338
2352
  * @param usedRoutes - The routes that are used in all nodes in this Container.
2353
+ * @see IGarbageCollectionRuntime.updateUsedRoutes
2339
2354
  */
2340
2355
  public updateUsedRoutes(usedRoutes: string[]) {
2341
2356
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
@@ -2358,6 +2373,26 @@ export class ContainerRuntime
2358
2373
  this.dataStores.updateUnusedRoutes(dataStoreRoutes);
2359
2374
  }
2360
2375
 
2376
+ /**
2377
+ * @deprecated - Replaced by deleteSweepReadyNodes.
2378
+ */
2379
+ public deleteUnusedNodes(unusedRoutes: string[]): string[] {
2380
+ throw new Error("deleteUnusedRoutes should not be called");
2381
+ }
2382
+
2383
+ /**
2384
+ * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
2385
+ * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
2386
+ * @returns - The routes of nodes that were deleted.
2387
+ */
2388
+ public deleteSweepReadyNodes(sweepReadyRoutes: string[]): string[] {
2389
+ const { dataStoreRoutes, blobManagerRoutes } =
2390
+ this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
2391
+
2392
+ const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
2393
+ return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
2394
+ }
2395
+
2361
2396
  /**
2362
2397
  * This is called to update objects that are tombstones.
2363
2398
  * @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
@@ -2439,15 +2474,18 @@ export class ContainerRuntime
2439
2474
  * Runs garbage collection and updates the reference / used state of the nodes in the container.
2440
2475
  * @returns the statistics of the garbage collection run; undefined if GC did not run.
2441
2476
  */
2442
- public async collectGarbage(options: {
2443
- /** Logger to use for logging GC events */
2444
- logger?: ITelemetryLogger;
2445
- /** True to run GC sweep phase after the mark phase */
2446
- runSweep?: boolean;
2447
- /** True to generate full GC data */
2448
- fullGC?: boolean;
2449
- }): Promise<IGCStats | undefined> {
2450
- return this.garbageCollector.collectGarbage(options);
2477
+ public async collectGarbage(
2478
+ options: {
2479
+ /** Logger to use for logging GC events */
2480
+ logger?: ITelemetryLogger;
2481
+ /** True to run GC sweep phase after the mark phase */
2482
+ runSweep?: boolean;
2483
+ /** True to generate full GC data */
2484
+ fullGC?: boolean;
2485
+ },
2486
+ telemetryContext?: ITelemetryContext,
2487
+ ): Promise<IGCStats | undefined> {
2488
+ return this.garbageCollector.collectGarbage(options, telemetryContext);
2451
2489
  }
2452
2490
 
2453
2491
  /**
@@ -2472,7 +2510,7 @@ export class ContainerRuntime
2472
2510
  * @param options - options controlling how the summary is generated or submitted
2473
2511
  */
2474
2512
  public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
2475
- const { fullTree, refreshLatestAck, summaryLogger } = options;
2513
+ const { fullTree = false, refreshLatestAck, summaryLogger } = options;
2476
2514
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2477
2515
  // use it for all events logged during this summary.
2478
2516
  const summaryNumber = this.nextSummaryNumber;
@@ -2494,8 +2532,15 @@ export class ContainerRuntime
2494
2532
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
2495
2533
  }
2496
2534
 
2535
+ const shouldPauseInboundSignal =
2536
+ this.mc.config.getBoolean(
2537
+ "Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
2538
+ ) !== true;
2497
2539
  try {
2498
2540
  await this.deltaManager.inbound.pause();
2541
+ if (shouldPauseInboundSignal) {
2542
+ await this.deltaManager.inboundSignal.pause();
2543
+ }
2499
2544
 
2500
2545
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
2501
2546
  const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
@@ -2560,7 +2605,7 @@ export class ContainerRuntime
2560
2605
  const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
2561
2606
  try {
2562
2607
  summarizeResult = await this.summarize({
2563
- fullTree: fullTree ?? forcedFullTree,
2608
+ fullTree: fullTree || forcedFullTree,
2564
2609
  trackState: true,
2565
2610
  summaryLogger: summaryNumberLogger,
2566
2611
  runGC: this.garbageCollector.shouldRunGC,
@@ -2674,7 +2719,7 @@ export class ContainerRuntime
2674
2719
 
2675
2720
  let clientSequenceNumber: number;
2676
2721
  try {
2677
- clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
2722
+ clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
2678
2723
  } catch (error) {
2679
2724
  return { stage: "upload", ...uploadData, error };
2680
2725
  }
@@ -2691,8 +2736,12 @@ export class ContainerRuntime
2691
2736
  } finally {
2692
2737
  // Cleanup wip summary in case of failure
2693
2738
  this.summarizerNode.clearSummary();
2739
+
2694
2740
  // Restart the delta manager
2695
2741
  this.deltaManager.inbound.resume();
2742
+ if (shouldPauseInboundSignal) {
2743
+ this.deltaManager.inboundSignal.resume();
2744
+ }
2696
2745
  }
2697
2746
  }
2698
2747
 
@@ -2763,10 +2812,11 @@ export class ContainerRuntime
2763
2812
  0x132 /* "sending ops in detached container" */,
2764
2813
  );
2765
2814
 
2766
- const deserializedContent: ContainerRuntimeMessage = { type, contents };
2767
- const serializedContent = JSON.stringify(deserializedContent);
2815
+ const serializedContent = JSON.stringify({ type, contents });
2768
2816
 
2769
- if (this.deltaManager.readOnlyInfo.readonly) {
2817
+ // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2818
+ // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
2819
+ if (this.innerDeltaManager.readOnlyInfo.readonly) {
2770
2820
  this.logger.sendTelemetryEvent({
2771
2821
  eventName: "SubmitOpInReadonly",
2772
2822
  connected: this.connected,
@@ -2775,7 +2825,7 @@ export class ContainerRuntime
2775
2825
 
2776
2826
  const message: BatchMessage = {
2777
2827
  contents: serializedContent,
2778
- deserializedContent,
2828
+ deserializedContent: JSON.parse(serializedContent), // Deep copy in case caller changes reference object
2779
2829
  metadata,
2780
2830
  localOpMetadata,
2781
2831
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -2805,7 +2855,7 @@ export class ContainerRuntime
2805
2855
  if (
2806
2856
  this.currentlyBatching() &&
2807
2857
  type === ContainerMessageType.Attach &&
2808
- this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder") !== true
2858
+ this.disableAttachReorder !== true
2809
2859
  ) {
2810
2860
  this.outbox.submitAttach(message);
2811
2861
  } else {
@@ -2814,17 +2864,8 @@ export class ContainerRuntime
2814
2864
 
2815
2865
  if (!this.currentlyBatching()) {
2816
2866
  this.flush();
2817
- } else if (!this.flushMicroTaskExists) {
2818
- this.flushMicroTaskExists = true;
2819
- // Queue a microtask to detect the end of the turn and force a flush.
2820
- Promise.resolve()
2821
- .then(() => {
2822
- this.flushMicroTaskExists = false;
2823
- this.flush();
2824
- })
2825
- .catch((error) => {
2826
- this.closeFn(error as GenericError);
2827
- });
2867
+ } else {
2868
+ this.scheduleFlush();
2828
2869
  }
2829
2870
  } catch (error) {
2830
2871
  this.closeFn(error as GenericError);
@@ -2836,7 +2877,47 @@ export class ContainerRuntime
2836
2877
  }
2837
2878
  }
2838
2879
 
2839
- private submitSummaryMessage(contents: ISummaryContent) {
2880
+ private scheduleFlush() {
2881
+ if (this.flushTaskExists) {
2882
+ return;
2883
+ }
2884
+
2885
+ this.flushTaskExists = true;
2886
+ const flush = () => {
2887
+ this.flushTaskExists = false;
2888
+ try {
2889
+ this.flush();
2890
+ } catch (error) {
2891
+ this.closeFn(error as GenericError);
2892
+ }
2893
+ };
2894
+
2895
+ switch (this.flushMode) {
2896
+ case FlushMode.TurnBased:
2897
+ // When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
2898
+ // batch at the end of the turn
2899
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
2900
+ Promise.resolve().then(flush);
2901
+ break;
2902
+
2903
+ // FlushModeExperimental is experimental and not exposed directly in the runtime APIs
2904
+ case FlushModeExperimental.Async as unknown as FlushMode:
2905
+ // When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
2906
+ // batch when all micro-tasks are complete.
2907
+ // Compared to TurnBased, this flush mode will capture more ops into the same batch.
2908
+ setTimeout(flush, 0);
2909
+ break;
2910
+
2911
+ default:
2912
+ assert(
2913
+ this._orderSequentiallyCalls > 0,
2914
+ 0x587 /* Unreachable unless running under orderSequentially */,
2915
+ );
2916
+ break;
2917
+ }
2918
+ }
2919
+
2920
+ private submitSummaryMessage(contents: ISummaryContent, referenceSequenceNumber: number) {
2840
2921
  this.verifyNotClosed();
2841
2922
  assert(
2842
2923
  this.connected,
@@ -2848,7 +2929,7 @@ export class ContainerRuntime
2848
2929
 
2849
2930
  // back-compat: ADO #1385: Make this call unconditional in the future
2850
2931
  return this.context.submitSummaryFn !== undefined
2851
- ? this.context.submitSummaryFn(contents)
2932
+ ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
2852
2933
  : this.context.submitFn(MessageType.Summarize, contents, false);
2853
2934
  }
2854
2935
 
@@ -2967,18 +3048,17 @@ export class ContainerRuntime
2967
3048
  // The call to fetch the snapshot is very expensive and not always needed.
2968
3049
  // It should only be done by the summarizerNode, if required.
2969
3050
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
2970
- const snapshotTreeFetcher = async () => {
2971
- const fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2972
- eventName: "RefreshLatestSummaryGetSnapshot",
2973
- ackHandle,
2974
- summaryRefSeq,
2975
- fetchLatest: true,
2976
- });
2977
-
2978
- const latestSnapshotRefSeq = await seqFromTree(
2979
- fetchResult.snapshotTree,
3051
+ const fetchLatestSnapshot: () => Promise<IFetchSnapshotResult> = async () => {
3052
+ let fetchResult = await this.fetchLatestSnapshotFromStorage(
3053
+ summaryLogger,
3054
+ {
3055
+ eventName: "RefreshLatestSummaryAckFetch",
3056
+ ackHandle,
3057
+ targetSequenceNumber: summaryRefSeq,
3058
+ },
2980
3059
  readAndParseBlob,
2981
3060
  );
3061
+
2982
3062
  /**
2983
3063
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2984
3064
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2989,50 +3069,58 @@ export class ContainerRuntime
2989
3069
  * such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
2990
3070
  * state.
2991
3071
  */
2992
- if (latestSnapshotRefSeq < summaryRefSeq) {
2993
- const error = DataProcessingError.create(
2994
- "Fetched snapshot is older than the received ack",
2995
- "RefreshLatestSummaryAck",
2996
- undefined /* sequencedMessage */,
3072
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3073
+ /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
3074
+ fetchResult = await this.fetchSnapshotFromStorage(
3075
+ summaryLogger,
2997
3076
  {
3077
+ eventName: "RefreshLatestSummaryAckFetch",
2998
3078
  ackHandle,
2999
- summaryRefSeq,
3000
- latestSnapshotRefSeq,
3079
+ targetSequenceNumber: summaryRefSeq,
3001
3080
  },
3081
+ readAndParseBlob,
3082
+ ackHandle,
3002
3083
  );
3003
- this.closeFn(error);
3004
- throw error;
3005
- }
3006
3084
 
3007
- summaryLogger.sendTelemetryEvent({
3008
- eventName: "LatestSummaryRetrieved",
3009
- ackHandle,
3010
- lastSequenceNumber: latestSnapshotRefSeq,
3011
- targetSequenceNumber: summaryRefSeq,
3012
- });
3085
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3086
+ const error = DataProcessingError.create(
3087
+ "Fetched snapshot is older than the received ack",
3088
+ "RefreshLatestSummaryAck",
3089
+ undefined /* sequencedMessage */,
3090
+ {
3091
+ ackHandle,
3092
+ summaryRefSeq,
3093
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3094
+ },
3095
+ );
3096
+ this.closeFn(error);
3097
+ throw error;
3098
+ }
3099
+ }
3013
3100
 
3014
3101
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
3015
3102
  // wait for the delta manager to catch up before refreshing the latest Summary.
3016
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
3103
+ await this.waitForDeltaManagerToCatchup(
3104
+ fetchResult.latestSnapshotRefSeq,
3105
+ summaryLogger,
3106
+ );
3017
3107
 
3018
- return fetchResult.snapshotTree;
3108
+ return {
3109
+ snapshotTree: fetchResult.snapshotTree,
3110
+ snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3111
+ };
3019
3112
  };
3020
3113
 
3021
3114
  const result = await this.summarizerNode.refreshLatestSummary(
3022
3115
  proposalHandle,
3023
3116
  summaryRefSeq,
3024
- snapshotTreeFetcher,
3117
+ fetchLatestSnapshot,
3025
3118
  readAndParseBlob,
3026
3119
  summaryLogger,
3027
3120
  );
3028
3121
 
3029
3122
  // Notify the garbage collector so it can update its latest summary state.
3030
- await this.garbageCollector.refreshLatestSummary(
3031
- result,
3032
- proposalHandle,
3033
- summaryRefSeq,
3034
- readAndParseBlob,
3035
- );
3123
+ await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
3036
3124
  }
3037
3125
 
3038
3126
  /**
@@ -3044,30 +3132,31 @@ export class ContainerRuntime
3044
3132
  private async refreshLatestSummaryAckFromServer(
3045
3133
  summaryLogger: ITelemetryLogger,
3046
3134
  ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
3047
- const { snapshotTree, versionId } = await this.fetchLatestSnapshotFromStorage(
3048
- summaryLogger,
3049
- {
3050
- eventName: "RefreshLatestSummaryGetSnapshot",
3051
- fetchLatest: true,
3052
- },
3053
- );
3054
-
3055
3135
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3056
- const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
3057
-
3136
+ const { snapshotTree, versionId, latestSnapshotRefSeq } =
3137
+ await this.fetchLatestSnapshotFromStorage(
3138
+ summaryLogger,
3139
+ {
3140
+ eventName: "RefreshLatestSummaryFromServerFetch",
3141
+ },
3142
+ readAndParseBlob,
3143
+ );
3144
+ const fetchLatestSnapshot: IFetchSnapshotResult = {
3145
+ snapshotTree,
3146
+ snapshotRefSeq: latestSnapshotRefSeq,
3147
+ };
3058
3148
  const result = await this.summarizerNode.refreshLatestSummary(
3059
- undefined,
3149
+ undefined /* proposalHandle */,
3060
3150
  latestSnapshotRefSeq,
3061
- async () => snapshotTree,
3151
+ async () => fetchLatestSnapshot,
3062
3152
  readAndParseBlob,
3063
3153
  summaryLogger,
3064
3154
  );
3065
3155
 
3066
3156
  // Notify the garbage collector so it can update its latest summary state.
3067
3157
  await this.garbageCollector.refreshLatestSummary(
3158
+ undefined /* proposalHandle */,
3068
3159
  result,
3069
- undefined,
3070
- latestSnapshotRefSeq,
3071
3160
  readAndParseBlob,
3072
3161
  );
3073
3162
 
@@ -3077,7 +3166,17 @@ export class ContainerRuntime
3077
3166
  private async fetchLatestSnapshotFromStorage(
3078
3167
  logger: ITelemetryLogger,
3079
3168
  event: ITelemetryGenericEvent,
3080
- ): Promise<{ snapshotTree: ISnapshotTree; versionId: string }> {
3169
+ readAndParseBlob: ReadAndParseBlob,
3170
+ ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3171
+ return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
3172
+ }
3173
+
3174
+ private async fetchSnapshotFromStorage(
3175
+ logger: ITelemetryLogger,
3176
+ event: ITelemetryGenericEvent,
3177
+ readAndParseBlob: ReadAndParseBlob,
3178
+ versionId: string | null,
3179
+ ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3081
3180
  return PerformanceEvent.timedExecAsync(
3082
3181
  logger,
3083
3182
  event,
@@ -3085,16 +3184,23 @@ export class ContainerRuntime
3085
3184
  end: (arg0: {
3086
3185
  getVersionDuration?: number | undefined;
3087
3186
  getSnapshotDuration?: number | undefined;
3187
+ snapshotRefSeq?: number | undefined;
3188
+ snapshotVersion?: string | undefined;
3088
3189
  }) => void;
3089
3190
  }) => {
3090
- const stats: { getVersionDuration?: number; getSnapshotDuration?: number } = {};
3191
+ const stats: {
3192
+ getVersionDuration?: number;
3193
+ getSnapshotDuration?: number;
3194
+ snapshotRefSeq?: number;
3195
+ snapshotVersion?: string;
3196
+ } = {};
3091
3197
  const trace = Trace.start();
3092
3198
 
3093
3199
  const versions = await this.storage.getVersions(
3094
- null,
3200
+ versionId,
3095
3201
  1,
3096
3202
  "refreshLatestSummaryAckFromServer",
3097
- FetchSource.noCache,
3203
+ versionId === null ? FetchSource.noCache : undefined,
3098
3204
  );
3099
3205
  assert(
3100
3206
  !!versions && !!versions[0],
@@ -3105,51 +3211,23 @@ export class ContainerRuntime
3105
3211
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
3106
3212
  assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
3107
3213
  stats.getSnapshotDuration = trace.trace().duration;
3214
+ const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
3215
+ stats.snapshotRefSeq = latestSnapshotRefSeq;
3216
+ stats.snapshotVersion = versions[0].id;
3108
3217
 
3109
3218
  perfEvent.end(stats);
3110
- return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
3219
+ return {
3220
+ snapshotTree: maybeSnapshot,
3221
+ versionId: versions[0].id,
3222
+ latestSnapshotRefSeq,
3223
+ };
3111
3224
  },
3112
3225
  );
3113
3226
  }
3114
3227
 
3115
- public notifyAttaching(snapshot: ISnapshotTreeWithBlobContents) {
3116
- if (
3117
- this.mc.config.getBoolean("enableOfflineLoad") ??
3118
- this.runtimeOptions.enableOfflineLoad
3119
- ) {
3120
- this.baseSnapshotBlobs =
3121
- SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
3122
- }
3123
- }
3124
-
3125
- private async initializeBaseSnapshotBlobs(): Promise<void> {
3126
- if (
3127
- !(
3128
- this.mc.config.getBoolean("enableOfflineLoad") ??
3129
- this.runtimeOptions.enableOfflineLoad
3130
- ) ||
3131
- this.attachState !== AttachState.Attached ||
3132
- this.context.pendingLocalState
3133
- ) {
3134
- return;
3135
- }
3136
- assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
3137
- this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(
3138
- this.context.baseSnapshot,
3139
- this.storage,
3140
- );
3141
- }
3228
+ public notifyAttaching() {} // do nothing (deprecated method)
3142
3229
 
3143
3230
  public getPendingLocalState(): unknown {
3144
- if (
3145
- !(
3146
- this.mc.config.getBoolean("enableOfflineLoad") ??
3147
- this.runtimeOptions.enableOfflineLoad
3148
- )
3149
- ) {
3150
- throw new UsageError("can't get state when offline load disabled");
3151
- }
3152
-
3153
3231
  if (this._orderSequentiallyCalls !== 0) {
3154
3232
  throw new UsageError("can't get state during orderSequentially");
3155
3233
  }
@@ -3158,29 +3236,9 @@ export class ContainerRuntime
3158
3236
  // to close current batch.
3159
3237
  this.flush();
3160
3238
 
3161
- const previousPendingState = this.context.pendingLocalState as
3162
- | IPendingRuntimeState
3163
- | undefined;
3164
- if (previousPendingState) {
3165
- return {
3166
- pending: this.pendingStateManager.getLocalState(),
3167
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
3168
- snapshotBlobs: previousPendingState.snapshotBlobs,
3169
- baseSnapshot: previousPendingState.baseSnapshot,
3170
- savedOps: this.savedOps,
3171
- };
3172
- }
3173
- assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
3174
- assert(
3175
- !!this.baseSnapshotBlobs,
3176
- 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */,
3177
- );
3178
3239
  return {
3179
3240
  pending: this.pendingStateManager.getLocalState(),
3180
3241
  pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
3181
- snapshotBlobs: this.baseSnapshotBlobs,
3182
- baseSnapshot: this.context.baseSnapshot,
3183
- savedOps: this.savedOps,
3184
3242
  };
3185
3243
  }
3186
3244
 
@@ -3243,25 +3301,6 @@ export class ContainerRuntime
3243
3301
  };
3244
3302
  }
3245
3303
 
3246
- private async processSavedOps(state: IPendingRuntimeState) {
3247
- for (const op of state.savedOps) {
3248
- this.process(op, false);
3249
- await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
3250
- }
3251
- // we may not have seen every sequence number (because of system ops) so apply everything once we
3252
- // don't have any more saved ops
3253
- await this.pendingStateManager.applyStashedOpsAt();
3254
-
3255
- // If it's not the case, we should take it into account when calculating dirty state.
3256
- assert(
3257
- this.context.attachState === AttachState.Attached,
3258
- 0x3d5 /* this function is called for attached containers only */,
3259
- );
3260
- if (!this.hasPendingMessages()) {
3261
- this.updateDocumentDirtyState(false);
3262
- }
3263
- }
3264
-
3265
3304
  private validateSummaryHeuristicConfiguration(configuration: ISummaryConfigurationHeuristics) {
3266
3305
  // eslint-disable-next-line no-restricted-syntax
3267
3306
  for (const prop in configuration) {