@fluidframework/container-runtime 2.0.0-dev.2.3.0.115467 → 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 (563) hide show
  1. package/.eslintrc.js +21 -10
  2. package/.mocharc.js +2 -2
  3. package/api-extractor.json +2 -2
  4. package/dist/batchTracker.d.ts +1 -2
  5. package/dist/batchTracker.d.ts.map +1 -1
  6. package/dist/batchTracker.js +2 -1
  7. package/dist/batchTracker.js.map +1 -1
  8. package/dist/blobManager.d.ts +74 -42
  9. package/dist/blobManager.d.ts.map +1 -1
  10. package/dist/blobManager.js +321 -152
  11. package/dist/blobManager.js.map +1 -1
  12. package/dist/connectionTelemetry.d.ts.map +1 -1
  13. package/dist/connectionTelemetry.js +11 -9
  14. package/dist/connectionTelemetry.js.map +1 -1
  15. package/dist/containerHandleContext.d.ts.map +1 -1
  16. package/dist/containerHandleContext.js +3 -1
  17. package/dist/containerHandleContext.js.map +1 -1
  18. package/dist/containerRuntime.d.ts +148 -114
  19. package/dist/containerRuntime.d.ts.map +1 -1
  20. package/dist/containerRuntime.js +534 -342
  21. package/dist/containerRuntime.js.map +1 -1
  22. package/dist/dataStore.d.ts.map +1 -1
  23. package/dist/dataStore.js +11 -9
  24. package/dist/dataStore.js.map +1 -1
  25. package/dist/dataStoreContext.d.ts +40 -13
  26. package/dist/dataStoreContext.d.ts.map +1 -1
  27. package/dist/dataStoreContext.js +146 -66
  28. package/dist/dataStoreContext.js.map +1 -1
  29. package/dist/dataStoreContexts.d.ts.map +1 -1
  30. package/dist/dataStoreContexts.js +7 -3
  31. package/dist/dataStoreContexts.js.map +1 -1
  32. package/dist/dataStoreRegistry.d.ts.map +1 -1
  33. package/dist/dataStoreRegistry.js +3 -1
  34. package/dist/dataStoreRegistry.js.map +1 -1
  35. package/dist/dataStores.d.ts +39 -12
  36. package/dist/dataStores.d.ts.map +1 -1
  37. package/dist/dataStores.js +164 -76
  38. package/dist/dataStores.js.map +1 -1
  39. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  40. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  41. package/dist/deltaManagerSummarizerProxy.js +40 -0
  42. package/dist/deltaManagerSummarizerProxy.js.map +1 -0
  43. package/dist/deltaScheduler.d.ts.map +1 -1
  44. package/dist/deltaScheduler.js +8 -3
  45. package/dist/deltaScheduler.js.map +1 -1
  46. package/dist/gc/garbageCollection.d.ts +204 -0
  47. package/dist/gc/garbageCollection.d.ts.map +1 -0
  48. package/dist/gc/garbageCollection.js +926 -0
  49. package/dist/gc/garbageCollection.js.map +1 -0
  50. package/dist/gc/gcConfigs.d.ts +22 -0
  51. package/dist/gc/gcConfigs.d.ts.map +1 -0
  52. package/dist/gc/gcConfigs.js +143 -0
  53. package/dist/gc/gcConfigs.js.map +1 -0
  54. package/dist/gc/gcDefinitions.d.ts +320 -0
  55. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  56. package/dist/gc/gcDefinitions.js +81 -0
  57. package/dist/gc/gcDefinitions.js.map +1 -0
  58. package/dist/gc/gcHelpers.d.ts +86 -0
  59. package/dist/gc/gcHelpers.d.ts.map +1 -0
  60. package/dist/gc/gcHelpers.js +268 -0
  61. package/dist/gc/gcHelpers.js.map +1 -0
  62. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  63. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  64. package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
  65. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  66. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  67. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  68. package/dist/gc/gcSummaryDefinitions.js +7 -0
  69. package/dist/gc/gcSummaryDefinitions.js.map +1 -0
  70. package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
  71. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  72. package/dist/gc/gcSummaryStateTracker.js +239 -0
  73. package/dist/gc/gcSummaryStateTracker.js.map +1 -0
  74. package/{lib → dist/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  75. package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  76. package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  77. package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
  78. package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
  79. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  80. package/dist/gc/gcUnreferencedStateTracker.js +94 -0
  81. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
  82. package/dist/gc/index.d.ts +13 -0
  83. package/dist/gc/index.d.ts.map +1 -0
  84. package/dist/gc/index.js +50 -0
  85. package/dist/gc/index.js.map +1 -0
  86. package/dist/index.d.ts +3 -8
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +7 -13
  89. package/dist/index.js.map +1 -1
  90. package/dist/opLifecycle/batchManager.d.ts +10 -0
  91. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  92. package/dist/opLifecycle/batchManager.js +37 -8
  93. package/dist/opLifecycle/batchManager.js.map +1 -1
  94. package/dist/opLifecycle/definitions.d.ts +29 -1
  95. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  96. package/dist/opLifecycle/definitions.js.map +1 -1
  97. package/dist/opLifecycle/index.d.ts +3 -3
  98. package/dist/opLifecycle/index.d.ts.map +1 -1
  99. package/dist/opLifecycle/index.js +3 -1
  100. package/dist/opLifecycle/index.js.map +1 -1
  101. package/dist/opLifecycle/opCompressor.d.ts +1 -1
  102. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  103. package/dist/opLifecycle/opCompressor.js +46 -17
  104. package/dist/opLifecycle/opCompressor.js.map +1 -1
  105. package/dist/opLifecycle/opDecompressor.d.ts +6 -1
  106. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  107. package/dist/opLifecycle/opDecompressor.js +72 -18
  108. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  109. package/dist/opLifecycle/opSplitter.d.ts +46 -2
  110. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  111. package/dist/opLifecycle/opSplitter.js +142 -5
  112. package/dist/opLifecycle/opSplitter.js.map +1 -1
  113. package/dist/opLifecycle/outbox.d.ts +23 -2
  114. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  115. package/dist/opLifecycle/outbox.js +101 -51
  116. package/dist/opLifecycle/outbox.js.map +1 -1
  117. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  118. package/dist/opLifecycle/remoteMessageProcessor.js +17 -2
  119. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  120. package/dist/opProperties.d.ts.map +1 -1
  121. package/dist/opProperties.js +1 -3
  122. package/dist/opProperties.js.map +1 -1
  123. package/dist/packageVersion.d.ts +1 -1
  124. package/dist/packageVersion.js +1 -1
  125. package/dist/packageVersion.js.map +1 -1
  126. package/dist/pendingStateManager.d.ts +6 -15
  127. package/dist/pendingStateManager.d.ts.map +1 -1
  128. package/dist/pendingStateManager.js +137 -165
  129. package/dist/pendingStateManager.js.map +1 -1
  130. package/dist/scheduleManager.d.ts +0 -1
  131. package/dist/scheduleManager.d.ts.map +1 -1
  132. package/dist/scheduleManager.js +11 -21
  133. package/dist/scheduleManager.js.map +1 -1
  134. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  135. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  136. package/dist/storageServiceWithAttachBlobs.js +32 -0
  137. package/dist/storageServiceWithAttachBlobs.js.map +1 -0
  138. package/dist/summary/index.d.ts +17 -0
  139. package/dist/summary/index.d.ts.map +1 -0
  140. package/dist/summary/index.js +46 -0
  141. package/dist/summary/index.js.map +1 -0
  142. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  143. package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  144. package/dist/summary/orderedClientElection.js.map +1 -0
  145. package/{lib → dist/summary}/runWhileConnectedCoordinator.d.ts +3 -2
  146. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  147. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  148. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
  149. package/{lib → dist/summary}/runningSummarizer.d.ts +19 -18
  150. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  151. package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -77
  152. package/dist/summary/runningSummarizer.js.map +1 -0
  153. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +6 -12
  154. package/dist/summary/summarizer.d.ts.map +1 -0
  155. package/dist/{summarizer.js → summary/summarizer.js} +32 -76
  156. package/dist/summary/summarizer.js.map +1 -0
  157. package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +1 -2
  158. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  159. package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +3 -30
  160. package/dist/summary/summarizerClientElection.js.map +1 -0
  161. package/dist/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +1 -1
  162. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  163. package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +9 -12
  164. package/dist/summary/summarizerHeuristics.js.map +1 -0
  165. package/dist/summary/summarizerNode/index.d.ts +8 -0
  166. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  167. package/dist/summary/summarizerNode/index.js +12 -0
  168. package/dist/summary/summarizerNode/index.js.map +1 -0
  169. package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
  170. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  171. package/dist/summary/summarizerNode/summarizerNode.js +531 -0
  172. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
  173. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  174. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  175. package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
  176. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  177. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  178. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  179. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +423 -0
  180. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  181. package/{lib → dist/summary}/summarizerTypes.d.ts +29 -42
  182. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  183. package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
  184. package/dist/summary/summarizerTypes.js.map +1 -0
  185. package/dist/summary/summaryCollection.d.ts.map +1 -0
  186. package/dist/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  187. package/dist/summary/summaryCollection.js.map +1 -0
  188. package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
  189. package/dist/summary/summaryFormat.d.ts.map +1 -0
  190. package/dist/{summaryFormat.js → summary/summaryFormat.js} +19 -21
  191. package/dist/summary/summaryFormat.js.map +1 -0
  192. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  193. package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +34 -16
  194. package/dist/summary/summaryGenerator.js.map +1 -0
  195. package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  196. package/dist/summary/summaryManager.d.ts.map +1 -0
  197. package/dist/{summaryManager.js → summary/summaryManager.js} +21 -9
  198. package/dist/summary/summaryManager.js.map +1 -0
  199. package/dist/throttler.d.ts +2 -2
  200. package/dist/throttler.d.ts.map +1 -1
  201. package/dist/throttler.js +4 -4
  202. package/dist/throttler.js.map +1 -1
  203. package/lib/batchTracker.d.ts +1 -2
  204. package/lib/batchTracker.d.ts.map +1 -1
  205. package/lib/batchTracker.js +2 -1
  206. package/lib/batchTracker.js.map +1 -1
  207. package/lib/blobManager.d.ts +74 -42
  208. package/lib/blobManager.d.ts.map +1 -1
  209. package/lib/blobManager.js +322 -153
  210. package/lib/blobManager.js.map +1 -1
  211. package/lib/connectionTelemetry.d.ts.map +1 -1
  212. package/lib/connectionTelemetry.js +11 -9
  213. package/lib/connectionTelemetry.js.map +1 -1
  214. package/lib/containerHandleContext.d.ts.map +1 -1
  215. package/lib/containerHandleContext.js +3 -1
  216. package/lib/containerHandleContext.js.map +1 -1
  217. package/lib/containerRuntime.d.ts +148 -114
  218. package/lib/containerRuntime.d.ts.map +1 -1
  219. package/lib/containerRuntime.js +506 -314
  220. package/lib/containerRuntime.js.map +1 -1
  221. package/lib/dataStore.d.ts.map +1 -1
  222. package/lib/dataStore.js +11 -9
  223. package/lib/dataStore.js.map +1 -1
  224. package/lib/dataStoreContext.d.ts +40 -13
  225. package/lib/dataStoreContext.d.ts.map +1 -1
  226. package/lib/dataStoreContext.js +136 -56
  227. package/lib/dataStoreContext.js.map +1 -1
  228. package/lib/dataStoreContexts.d.ts.map +1 -1
  229. package/lib/dataStoreContexts.js +7 -3
  230. package/lib/dataStoreContexts.js.map +1 -1
  231. package/lib/dataStoreRegistry.d.ts.map +1 -1
  232. package/lib/dataStoreRegistry.js +3 -1
  233. package/lib/dataStoreRegistry.js.map +1 -1
  234. package/lib/dataStores.d.ts +39 -12
  235. package/lib/dataStores.d.ts.map +1 -1
  236. package/lib/dataStores.js +162 -74
  237. package/lib/dataStores.js.map +1 -1
  238. package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
  239. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  240. package/lib/deltaManagerSummarizerProxy.js +36 -0
  241. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  242. package/lib/deltaScheduler.d.ts.map +1 -1
  243. package/lib/deltaScheduler.js +9 -4
  244. package/lib/deltaScheduler.js.map +1 -1
  245. package/lib/gc/garbageCollection.d.ts +204 -0
  246. package/lib/gc/garbageCollection.d.ts.map +1 -0
  247. package/lib/gc/garbageCollection.js +922 -0
  248. package/lib/gc/garbageCollection.js.map +1 -0
  249. package/lib/gc/gcConfigs.d.ts +22 -0
  250. package/lib/gc/gcConfigs.d.ts.map +1 -0
  251. package/lib/gc/gcConfigs.js +139 -0
  252. package/lib/gc/gcConfigs.js.map +1 -0
  253. package/lib/gc/gcDefinitions.d.ts +320 -0
  254. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  255. package/lib/gc/gcDefinitions.js +78 -0
  256. package/lib/gc/gcDefinitions.js.map +1 -0
  257. package/lib/gc/gcHelpers.d.ts +86 -0
  258. package/lib/gc/gcHelpers.d.ts.map +1 -0
  259. package/lib/gc/gcHelpers.js +254 -0
  260. package/lib/gc/gcHelpers.js.map +1 -0
  261. package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  262. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  263. package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
  264. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  265. package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
  266. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  267. package/lib/gc/gcSummaryDefinitions.js +6 -0
  268. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  269. package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
  270. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  271. package/lib/gc/gcSummaryStateTracker.js +235 -0
  272. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  273. package/{dist → lib/gc}/gcSweepReadyUsageDetection.d.ts +5 -5
  274. package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
  275. package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +15 -11
  276. package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
  277. package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
  278. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  279. package/lib/gc/gcUnreferencedStateTracker.js +90 -0
  280. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  281. package/lib/gc/index.d.ts +13 -0
  282. package/lib/gc/index.d.ts.map +1 -0
  283. package/lib/gc/index.js +12 -0
  284. package/lib/gc/index.js.map +1 -0
  285. package/lib/index.d.ts +3 -8
  286. package/lib/index.d.ts.map +1 -1
  287. package/lib/index.js +2 -6
  288. package/lib/index.js.map +1 -1
  289. package/lib/opLifecycle/batchManager.d.ts +10 -0
  290. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  291. package/lib/opLifecycle/batchManager.js +35 -7
  292. package/lib/opLifecycle/batchManager.js.map +1 -1
  293. package/lib/opLifecycle/definitions.d.ts +29 -1
  294. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  295. package/lib/opLifecycle/definitions.js.map +1 -1
  296. package/lib/opLifecycle/index.d.ts +3 -3
  297. package/lib/opLifecycle/index.d.ts.map +1 -1
  298. package/lib/opLifecycle/index.js +2 -2
  299. package/lib/opLifecycle/index.js.map +1 -1
  300. package/lib/opLifecycle/opCompressor.d.ts +1 -1
  301. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  302. package/lib/opLifecycle/opCompressor.js +47 -18
  303. package/lib/opLifecycle/opCompressor.js.map +1 -1
  304. package/lib/opLifecycle/opDecompressor.d.ts +6 -1
  305. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  306. package/lib/opLifecycle/opDecompressor.js +72 -18
  307. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  308. package/lib/opLifecycle/opSplitter.d.ts +46 -2
  309. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  310. package/lib/opLifecycle/opSplitter.js +141 -5
  311. package/lib/opLifecycle/opSplitter.js.map +1 -1
  312. package/lib/opLifecycle/outbox.d.ts +23 -2
  313. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  314. package/lib/opLifecycle/outbox.js +103 -53
  315. package/lib/opLifecycle/outbox.js.map +1 -1
  316. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  317. package/lib/opLifecycle/remoteMessageProcessor.js +17 -2
  318. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  319. package/lib/opProperties.d.ts.map +1 -1
  320. package/lib/opProperties.js +1 -3
  321. package/lib/opProperties.js.map +1 -1
  322. package/lib/packageVersion.d.ts +1 -1
  323. package/lib/packageVersion.js +1 -1
  324. package/lib/packageVersion.js.map +1 -1
  325. package/lib/pendingStateManager.d.ts +6 -15
  326. package/lib/pendingStateManager.d.ts.map +1 -1
  327. package/lib/pendingStateManager.js +137 -165
  328. package/lib/pendingStateManager.js.map +1 -1
  329. package/lib/scheduleManager.d.ts +0 -1
  330. package/lib/scheduleManager.d.ts.map +1 -1
  331. package/lib/scheduleManager.js +11 -21
  332. package/lib/scheduleManager.js.map +1 -1
  333. package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
  334. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  335. package/lib/storageServiceWithAttachBlobs.js +28 -0
  336. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  337. package/lib/summary/index.d.ts +17 -0
  338. package/lib/summary/index.d.ts.map +1 -0
  339. package/lib/summary/index.js +15 -0
  340. package/lib/summary/index.js.map +1 -0
  341. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  342. package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +10 -4
  343. package/lib/summary/orderedClientElection.js.map +1 -0
  344. package/{dist → lib/summary}/runWhileConnectedCoordinator.d.ts +3 -2
  345. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  346. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
  347. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  348. package/{dist → lib/summary}/runningSummarizer.d.ts +19 -18
  349. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  350. package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +193 -79
  351. package/lib/summary/runningSummarizer.js.map +1 -0
  352. package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +6 -12
  353. package/lib/summary/summarizer.d.ts.map +1 -0
  354. package/lib/{summarizer.js → summary/summarizer.js} +34 -78
  355. package/lib/summary/summarizer.js.map +1 -0
  356. package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +1 -2
  357. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  358. package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +3 -30
  359. package/lib/summary/summarizerClientElection.js.map +1 -0
  360. package/lib/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +1 -1
  361. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  362. package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +9 -12
  363. package/lib/summary/summarizerHeuristics.js.map +1 -0
  364. package/lib/summary/summarizerNode/index.d.ts +8 -0
  365. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  366. package/lib/summary/summarizerNode/index.js +7 -0
  367. package/lib/summary/summarizerNode/index.js.map +1 -0
  368. package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
  369. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  370. package/lib/summary/summarizerNode/summarizerNode.js +526 -0
  371. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  372. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
  373. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  374. package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
  375. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  376. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +22 -0
  377. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  378. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
  379. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  380. package/{dist → lib/summary}/summarizerTypes.d.ts +29 -42
  381. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  382. package/lib/summary/summarizerTypes.js +6 -0
  383. package/lib/summary/summarizerTypes.js.map +1 -0
  384. package/lib/summary/summaryCollection.d.ts.map +1 -0
  385. package/lib/{summaryCollection.js → summary/summaryCollection.js} +18 -8
  386. package/lib/summary/summaryCollection.js.map +1 -0
  387. package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
  388. package/lib/summary/summaryFormat.d.ts.map +1 -0
  389. package/lib/{summaryFormat.js → summary/summaryFormat.js} +20 -21
  390. package/lib/summary/summaryFormat.js.map +1 -0
  391. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  392. package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +34 -16
  393. package/lib/summary/summaryGenerator.js.map +1 -0
  394. package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
  395. package/lib/summary/summaryManager.d.ts.map +1 -0
  396. package/lib/{summaryManager.js → summary/summaryManager.js} +21 -9
  397. package/lib/summary/summaryManager.js.map +1 -0
  398. package/lib/throttler.d.ts +2 -2
  399. package/lib/throttler.d.ts.map +1 -1
  400. package/lib/throttler.js +4 -4
  401. package/lib/throttler.js.map +1 -1
  402. package/package.json +67 -61
  403. package/prettier.config.cjs +1 -1
  404. package/src/batchTracker.ts +55 -50
  405. package/src/blobManager.ts +863 -594
  406. package/src/connectionTelemetry.ts +280 -249
  407. package/src/containerHandleContext.ts +27 -29
  408. package/src/containerRuntime.ts +3174 -2805
  409. package/src/dataStore.ts +172 -159
  410. package/src/dataStoreContext.ts +1141 -993
  411. package/src/dataStoreContexts.ts +178 -161
  412. package/src/dataStoreRegistry.ts +25 -20
  413. package/src/dataStores.ts +887 -716
  414. package/src/deltaManagerSummarizerProxy.ts +46 -0
  415. package/src/deltaScheduler.ts +158 -150
  416. package/{garbageCollection.md → src/gc/garbageCollection.md} +16 -3
  417. package/src/gc/garbageCollection.ts +1250 -0
  418. package/src/gc/gcConfigs.ts +193 -0
  419. package/src/gc/gcDefinitions.ts +387 -0
  420. package/src/gc/gcHelpers.ts +332 -0
  421. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  422. package/src/gc/gcSummaryDefinitions.ts +54 -0
  423. package/src/gc/gcSummaryStateTracker.ts +329 -0
  424. package/src/gc/gcSweepReadyUsageDetection.ts +145 -0
  425. package/src/gc/gcUnreferencedStateTracker.ts +114 -0
  426. package/src/gc/index.ts +65 -0
  427. package/src/index.ts +61 -75
  428. package/src/opLifecycle/README.md +157 -0
  429. package/src/opLifecycle/batchManager.ts +119 -86
  430. package/src/opLifecycle/definitions.ts +49 -19
  431. package/src/opLifecycle/index.ts +7 -6
  432. package/src/opLifecycle/opCompressor.ts +78 -40
  433. package/src/opLifecycle/opDecompressor.ts +148 -64
  434. package/src/opLifecycle/opSplitter.ts +269 -66
  435. package/src/opLifecycle/outbox.ts +268 -184
  436. package/src/opLifecycle/remoteMessageProcessor.ts +63 -47
  437. package/src/opProperties.ts +11 -9
  438. package/src/packageVersion.ts +1 -1
  439. package/src/pendingStateManager.ts +386 -381
  440. package/src/scheduleManager.ts +299 -280
  441. package/src/storageServiceWithAttachBlobs.ts +38 -0
  442. package/src/summary/index.ts +105 -0
  443. package/src/summary/orderedClientElection.ts +564 -0
  444. package/src/summary/runWhileConnectedCoordinator.ts +113 -0
  445. package/src/summary/runningSummarizer.ts +788 -0
  446. package/src/summary/summarizer.ts +372 -0
  447. package/src/summary/summarizerClientElection.ts +139 -0
  448. package/src/summary/summarizerHeuristics.ts +224 -0
  449. package/src/summary/summarizerNode/index.ts +12 -0
  450. package/src/summary/summarizerNode/summarizerNode.ts +766 -0
  451. package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
  452. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
  453. package/src/summary/summarizerTypes.ts +507 -0
  454. package/src/summary/summaryCollection.ts +450 -0
  455. package/src/summary/summaryFormat.ts +228 -0
  456. package/src/summary/summaryGenerator.ts +505 -0
  457. package/src/summary/summaryManager.ts +423 -0
  458. package/src/throttler.ts +131 -122
  459. package/tsconfig.esnext.json +6 -6
  460. package/tsconfig.json +9 -13
  461. package/dist/garbageCollection.d.ts +0 -387
  462. package/dist/garbageCollection.d.ts.map +0 -1
  463. package/dist/garbageCollection.js +0 -1138
  464. package/dist/garbageCollection.js.map +0 -1
  465. package/dist/garbageCollectionConstants.d.ts +0 -19
  466. package/dist/garbageCollectionConstants.d.ts.map +0 -1
  467. package/dist/garbageCollectionConstants.js +0 -34
  468. package/dist/garbageCollectionConstants.js.map +0 -1
  469. package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
  470. package/dist/gcSweepReadyUsageDetection.js.map +0 -1
  471. package/dist/orderedClientElection.d.ts.map +0 -1
  472. package/dist/orderedClientElection.js.map +0 -1
  473. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  474. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  475. package/dist/runningSummarizer.d.ts.map +0 -1
  476. package/dist/runningSummarizer.js.map +0 -1
  477. package/dist/serializedSnapshotStorage.d.ts +0 -58
  478. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  479. package/dist/serializedSnapshotStorage.js +0 -108
  480. package/dist/serializedSnapshotStorage.js.map +0 -1
  481. package/dist/summarizer.d.ts.map +0 -1
  482. package/dist/summarizer.js.map +0 -1
  483. package/dist/summarizerClientElection.d.ts.map +0 -1
  484. package/dist/summarizerClientElection.js.map +0 -1
  485. package/dist/summarizerHandle.d.ts +0 -12
  486. package/dist/summarizerHandle.d.ts.map +0 -1
  487. package/dist/summarizerHandle.js +0 -22
  488. package/dist/summarizerHandle.js.map +0 -1
  489. package/dist/summarizerHeuristics.d.ts.map +0 -1
  490. package/dist/summarizerHeuristics.js.map +0 -1
  491. package/dist/summarizerTypes.d.ts.map +0 -1
  492. package/dist/summarizerTypes.js.map +0 -1
  493. package/dist/summaryCollection.d.ts.map +0 -1
  494. package/dist/summaryCollection.js.map +0 -1
  495. package/dist/summaryFormat.d.ts.map +0 -1
  496. package/dist/summaryFormat.js.map +0 -1
  497. package/dist/summaryGenerator.d.ts.map +0 -1
  498. package/dist/summaryGenerator.js.map +0 -1
  499. package/dist/summaryManager.d.ts.map +0 -1
  500. package/dist/summaryManager.js.map +0 -1
  501. package/lib/garbageCollection.d.ts +0 -387
  502. package/lib/garbageCollection.d.ts.map +0 -1
  503. package/lib/garbageCollection.js +0 -1133
  504. package/lib/garbageCollection.js.map +0 -1
  505. package/lib/garbageCollectionConstants.d.ts +0 -19
  506. package/lib/garbageCollectionConstants.d.ts.map +0 -1
  507. package/lib/garbageCollectionConstants.js +0 -31
  508. package/lib/garbageCollectionConstants.js.map +0 -1
  509. package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
  510. package/lib/gcSweepReadyUsageDetection.js.map +0 -1
  511. package/lib/orderedClientElection.d.ts.map +0 -1
  512. package/lib/orderedClientElection.js.map +0 -1
  513. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  514. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  515. package/lib/runningSummarizer.d.ts.map +0 -1
  516. package/lib/runningSummarizer.js.map +0 -1
  517. package/lib/serializedSnapshotStorage.d.ts +0 -58
  518. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  519. package/lib/serializedSnapshotStorage.js +0 -104
  520. package/lib/serializedSnapshotStorage.js.map +0 -1
  521. package/lib/summarizer.d.ts.map +0 -1
  522. package/lib/summarizer.js.map +0 -1
  523. package/lib/summarizerClientElection.d.ts.map +0 -1
  524. package/lib/summarizerClientElection.js.map +0 -1
  525. package/lib/summarizerHandle.d.ts +0 -12
  526. package/lib/summarizerHandle.d.ts.map +0 -1
  527. package/lib/summarizerHandle.js +0 -18
  528. package/lib/summarizerHandle.js.map +0 -1
  529. package/lib/summarizerHeuristics.d.ts.map +0 -1
  530. package/lib/summarizerHeuristics.js.map +0 -1
  531. package/lib/summarizerTypes.d.ts.map +0 -1
  532. package/lib/summarizerTypes.js +0 -9
  533. package/lib/summarizerTypes.js.map +0 -1
  534. package/lib/summaryCollection.d.ts.map +0 -1
  535. package/lib/summaryCollection.js.map +0 -1
  536. package/lib/summaryFormat.d.ts.map +0 -1
  537. package/lib/summaryFormat.js.map +0 -1
  538. package/lib/summaryGenerator.d.ts.map +0 -1
  539. package/lib/summaryGenerator.js.map +0 -1
  540. package/lib/summaryManager.d.ts.map +0 -1
  541. package/lib/summaryManager.js.map +0 -1
  542. package/src/garbageCollection.ts +0 -1646
  543. package/src/garbageCollectionConstants.ts +0 -35
  544. package/src/gcSweepReadyUsageDetection.ts +0 -139
  545. package/src/orderedClientElection.ts +0 -532
  546. package/src/runWhileConnectedCoordinator.ts +0 -106
  547. package/src/runningSummarizer.ts +0 -611
  548. package/src/serializedSnapshotStorage.ts +0 -146
  549. package/src/summarizer.ts +0 -421
  550. package/src/summarizerClientElection.ts +0 -161
  551. package/src/summarizerHandle.ts +0 -21
  552. package/src/summarizerHeuristics.ts +0 -222
  553. package/src/summarizerTypes.ts +0 -510
  554. package/src/summaryCollection.ts +0 -421
  555. package/src/summaryFormat.ts +0 -235
  556. package/src/summaryGenerator.ts +0 -446
  557. package/src/summaryManager.ts +0 -394
  558. /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  559. /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  560. /package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
  561. /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
  562. /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
  563. /package/lib/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +0 -0
@@ -1,36 +1,28 @@
1
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
- import { assert, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
2
+ import { assert, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
3
3
  import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
4
4
  import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
5
5
  import { readAndParse } from "@fluidframework/driver-utils";
6
6
  import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
7
7
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
8
- import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
- import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
10
- import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
8
+ import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
+ import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
11
10
  import { v4 as uuid } from "uuid";
12
11
  import { ContainerFluidHandleContext } from "./containerHandleContext";
13
12
  import { FluidDataStoreRegistry } from "./dataStoreRegistry";
14
- import { Summarizer } from "./summarizer";
15
- import { SummaryManager } from "./summaryManager";
16
- import { ReportOpPerfTelemetry, } from "./connectionTelemetry";
17
- import { PendingStateManager, } from "./pendingStateManager";
13
+ import { ReportOpPerfTelemetry } from "./connectionTelemetry";
14
+ import { PendingStateManager } from "./pendingStateManager";
18
15
  import { pkgVersion } from "./packageVersion";
19
16
  import { BlobManager } from "./blobManager";
20
17
  import { DataStores, getSummaryForDatastores } from "./dataStores";
21
- import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
22
- import { SummaryCollection } from "./summaryCollection";
23
- import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
24
- import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
18
+ import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
25
19
  import { formExponentialFn, Throttler } from "./throttler";
26
- import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
27
- import { GarbageCollector, GCNodeType, } from "./garbageCollection";
28
- import { gcTreeKey, } from "./garbageCollectionConstants";
29
- import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
20
+ import { GarbageCollector, GCNodeType, gcTombstoneGenerationOptionName, shouldAllowGcTombstoneEnforcement, trimLeadingAndTrailingSlashes, } from "./gc";
21
+ import { channelToDataStore, isDataStoreAliasMessage } from "./dataStore";
30
22
  import { BindBatchTracker } from "./batchTracker";
31
- import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
32
23
  import { ScheduleManager } from "./scheduleManager";
33
24
  import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, } from "./opLifecycle";
25
+ import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
34
26
  export var ContainerMessageType;
35
27
  (function (ContainerMessageType) {
36
28
  // An op to be delivered to store
@@ -56,7 +48,6 @@ export const DefaultSummaryConfiguration = {
56
48
  maxAckWaitTime: 10 * 60 * 1000,
57
49
  maxOpsSinceLastSummary: 7000,
58
50
  initialSummarizerDelayMs: 5 * 1000,
59
- summarizerClientElection: false,
60
51
  nonRuntimeOpWeight: 0.1,
61
52
  runtimeOpWeight: 1.0,
62
53
  nonRuntimeHeuristicThreshold: 20,
@@ -68,14 +59,19 @@ export var RuntimeHeaders;
68
59
  (function (RuntimeHeaders) {
69
60
  /** True to wait for a data store to be created and loaded before returning it. */
70
61
  RuntimeHeaders["wait"] = "wait";
71
- /**
72
- * True if the request is from an external app. Used for GC to handle scenarios where a data store
73
- * is deleted and requested via an external app.
74
- */
75
- RuntimeHeaders["externalRequest"] = "externalRequest";
76
62
  /** True if the request is coming from an IFluidHandle. */
77
63
  RuntimeHeaders["viaHandle"] = "viaHandle";
78
64
  })(RuntimeHeaders || (RuntimeHeaders = {}));
65
+ /** True if a tombstoned object should be returned without erroring */
66
+ export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
67
+ /** Tombstone error responses will have this header set to true */
68
+ export const TombstoneResponseHeaderKey = "isTombstoned";
69
+ /** Default values for Runtime Headers */
70
+ export const defaultRuntimeHeaderData = {
71
+ wait: true,
72
+ viaHandle: false,
73
+ allowTombstone: false,
74
+ };
79
75
  /**
80
76
  * Available compression algorithms for op compression.
81
77
  */
@@ -89,7 +85,13 @@ const defaultFlushMode = FlushMode.TurnBased;
89
85
  // We can't estimate it fully, as we
90
86
  // - do not know what properties relay service will add
91
87
  // - we do not stringify final op, thus we do not know how much escaping will be added.
92
- const defaultMaxBatchSizeInBytes = 950 * 1024;
88
+ const defaultMaxBatchSizeInBytes = 700 * 1024;
89
+ const defaultCompressionConfig = {
90
+ // Batches with content size exceeding this value will be compressed
91
+ minimumBatchSizeInBytes: 614400,
92
+ compressionAlgorithm: CompressionAlgorithms.lz4,
93
+ };
94
+ const defaultChunkSizeInBytes = 204800;
93
95
  /**
94
96
  * @deprecated - use ContainerRuntimeMessage instead
95
97
  */
@@ -125,8 +127,7 @@ export function getDeviceSpec() {
125
127
  };
126
128
  }
127
129
  }
128
- catch (_a) {
129
- }
130
+ catch (_a) { }
130
131
  return {};
131
132
  }
132
133
  /**
@@ -137,8 +138,8 @@ export class ContainerRuntime extends TypedEventEmitter {
137
138
  /**
138
139
  * @internal
139
140
  */
140
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
141
- var _a, _b, _c, _d, _e, _f;
141
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
142
+ var _a, _b, _c, _d, _e, _f, _g, _h;
142
143
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
143
144
  super();
144
145
  this.context = context;
@@ -151,9 +152,16 @@ export class ContainerRuntime extends TypedEventEmitter {
151
152
  this.summaryConfiguration = summaryConfiguration;
152
153
  this.defaultMaxConsecutiveReconnects = 7;
153
154
  this._orderSequentiallyCalls = 0;
154
- this.flushMicroTaskExists = false;
155
- this.savedOps = [];
155
+ this.flushTaskExists = false;
156
156
  this.consecutiveReconnects = 0;
157
+ this.ensureNoDataModelChangesCalls = 0;
158
+ /**
159
+ * Tracks the number of detected reentrant ops to report,
160
+ * in order to self-throttle the telemetry events.
161
+ *
162
+ * This should be removed as part of ADO:2322
163
+ */
164
+ this.opReentryCallsToReport = 5;
157
165
  this._disposed = false;
158
166
  this.emitDirtyDocumentEvent = true;
159
167
  this.defaultTelemetrySignalSampleCount = 100;
@@ -191,6 +199,8 @@ export class ContainerRuntime extends TypedEventEmitter {
191
199
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
192
200
  }
193
201
  };
202
+ this.innerDeltaManager = context.deltaManager;
203
+ this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
194
204
  let loadSummaryNumber;
195
205
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
196
206
  // get the values from the metadata blob.
@@ -213,24 +223,48 @@ export class ContainerRuntime extends TypedEventEmitter {
213
223
  this.nextSummaryNumber = loadSummaryNumber + 1;
214
224
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
215
225
  this._connected = this.context.connected;
216
- this.remoteMessageProcessor = new RemoteMessageProcessor(new OpSplitter(chunks), new OpDecompressor());
217
- this.handleContext = new ContainerFluidHandleContext("", this);
226
+ this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
218
227
  this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
228
+ this.mc.logger.sendTelemetryEvent({
229
+ eventName: "GCFeatureMatrix",
230
+ metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
231
+ inputs: JSON.stringify({
232
+ gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
233
+ }),
234
+ });
235
+ this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : uuid();
236
+ this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
237
+ const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
238
+ const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
239
+ this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger));
240
+ this.handleContext = new ContainerFluidHandleContext("", this);
219
241
  if (this.summaryConfiguration.state === "enabled") {
220
242
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
221
243
  }
244
+ const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
245
+ this.enableOpReentryCheck =
246
+ runtimeOptions.enableOpReentryCheck === true &&
247
+ // Allow for a break-glass config to override the options
248
+ disableOpReentryCheck !== true;
222
249
  this.summariesDisabled = this.isSummariesDisabled();
223
250
  this.heuristicsDisabled = this.isHeuristicsDisabled();
224
- this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
225
251
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
226
252
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
227
253
  this.maxConsecutiveReconnects =
228
- (_c = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _c !== void 0 ? _c : this.defaultMaxConsecutiveReconnects;
229
- this._flushMode = runtimeOptions.flushMode;
254
+ (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
255
+ if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
256
+ ((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
257
+ // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
258
+ this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
259
+ this._flushMode = FlushMode.TurnBased;
260
+ }
261
+ else {
262
+ this._flushMode = runtimeOptions.flushMode;
263
+ }
230
264
  const pendingRuntimeState = context.pendingLocalState;
231
- const baseSnapshot = (_d = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _d !== void 0 ? _d : context.baseSnapshot;
232
- const maxSnapshotCacheDurationMs = (_f = (_e = this._storage) === null || _e === void 0 ? void 0 : _e.policies) === null || _f === void 0 ? void 0 : _f.maximumCacheDurationMs;
233
- if (maxSnapshotCacheDurationMs !== undefined && maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
265
+ const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
266
+ if (maxSnapshotCacheDurationMs !== undefined &&
267
+ maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
234
268
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
235
269
  // which dictates the value is either undefined or exactly 5 days in ms.
236
270
  // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
@@ -239,7 +273,7 @@ export class ContainerRuntime extends TypedEventEmitter {
239
273
  this.garbageCollector = GarbageCollector.create({
240
274
  runtime: this,
241
275
  gcOptions: this.runtimeOptions.gcOptions,
242
- baseSnapshot,
276
+ baseSnapshot: context.baseSnapshot,
243
277
  baseLogger: this.mc.logger,
244
278
  existing,
245
279
  metadata,
@@ -249,7 +283,9 @@ export class ContainerRuntime extends TypedEventEmitter {
249
283
  getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
250
284
  readAndParseBlob: async (id) => readAndParse(this.storage, id),
251
285
  getContainerDiagnosticId: () => this.context.id,
252
- activeConnection: () => this.deltaManager.active,
286
+ // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
287
+ // delta manager would always return false for summarizer client.
288
+ activeConnection: () => this.innerDeltaManager.active,
253
289
  });
254
290
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
255
291
  this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
@@ -258,7 +294,7 @@ export class ContainerRuntime extends TypedEventEmitter {
258
294
  // Latest change sequence number, no changes since summary applied yet
259
295
  loadedFromSequenceNumber,
260
296
  // Summary reference sequence number, undefined if no summary yet
261
- baseSnapshot ? loadedFromSequenceNumber : undefined, {
297
+ context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
262
298
  // Must set to false to prevent sending summary handle which would be pointing to
263
299
  // a summary with an older protocol state.
264
300
  canReuseHandle: false,
@@ -267,43 +303,61 @@ export class ContainerRuntime extends TypedEventEmitter {
267
303
  throwOnFailure: true,
268
304
  // If GC should not run, let the summarizer node know so that it does not track GC state.
269
305
  gcDisabled: !this.garbageCollector.shouldRunGC,
270
- });
271
- if (baseSnapshot) {
272
- this.summarizerNode.updateBaseSummaryState(baseSnapshot);
273
- }
274
- this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap));
275
- this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => {
306
+ },
307
+ // Function to get GC data if needed. This will always be called by the root summarizer node to get GC data.
308
+ async (fullGC) => this.getGCDataInternal(fullGC),
309
+ // Function to get the GC details from the base snapshot we loaded from.
310
+ async () => this.garbageCollector.getBaseGCDetails());
311
+ if (context.baseSnapshot) {
312
+ this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
313
+ }
314
+ this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
315
+ this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
276
316
  if (!this.disposed) {
277
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId });
317
+ this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
318
+ localId,
319
+ blobId,
320
+ });
278
321
  }
279
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
322
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, () => this.getCurrentReferenceTimestampMs());
280
323
  this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
281
324
  this.pendingStateManager = new PendingStateManager({
282
325
  applyStashedOp: this.applyStashedOp.bind(this),
283
326
  clientId: () => this.clientId,
284
327
  close: this.closeFn,
285
328
  connected: () => this.connected,
286
- flush: this.flush.bind(this),
287
329
  reSubmit: this.reSubmit.bind(this),
288
330
  rollback: this.rollback.bind(this),
289
331
  orderSequentially: this.orderSequentially.bind(this),
290
332
  }, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
333
+ const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
334
+ const compressionOptions = disableCompression === true
335
+ ? {
336
+ minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
337
+ compressionAlgorithm: CompressionAlgorithms.lz4,
338
+ }
339
+ : runtimeOptions.compressionOptions;
340
+ const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
291
341
  this.outbox = new Outbox({
292
342
  shouldSend: () => this.canSendOps(),
293
343
  pendingStateManager: this.pendingStateManager,
294
344
  containerContext: this.context,
295
345
  compressor: new OpCompressor(this.mc.logger),
346
+ splitter: opSplitter,
296
347
  config: {
297
- compressionOptions: runtimeOptions.compressionOptions,
348
+ compressionOptions,
298
349
  maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
350
+ disablePartialFlush: disablePartialFlush === true,
299
351
  },
352
+ logger: this.mc.logger,
300
353
  });
301
354
  this.context.quorum.on("removeMember", (clientId) => {
302
355
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
303
356
  });
304
357
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
305
- this.dirtyContainer = this.context.attachState !== AttachState.Attached
306
- || this.pendingStateManager.hasPendingMessages();
358
+ this.dirtyContainer =
359
+ this.context.attachState !== AttachState.Attached ||
360
+ this.pendingStateManager.hasPendingMessages();
307
361
  this.context.updateDirtyContainerState(this.dirtyContainer);
308
362
  if (this.summariesDisabled) {
309
363
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
@@ -312,9 +366,12 @@ export class ContainerRuntime extends TypedEventEmitter {
312
366
  const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
313
367
  const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
314
368
  const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
315
- this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary, this.summarizerClientElectionEnabled);
369
+ this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
316
370
  if (this.context.clientDetails.type === summarizerClientType) {
317
- this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
371
+ this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
372
+ // Summarization runs in summarizer client and needs access to the real (non-proxy) active
373
+ // information. The proxy delta manager would always return false for summarizer client.
374
+ () => this.innerDeltaManager.active));
318
375
  }
319
376
  else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
320
377
  // Only create a SummaryManager and SummarizerClientElection
@@ -349,7 +406,8 @@ export class ContainerRuntime extends TypedEventEmitter {
349
406
  this.deltaManager.on("readonly", (readonly) => {
350
407
  // we accumulate ops while being in read-only state.
351
408
  // once user gets write permissions and we have active connection, flush all pending ops.
352
- assert(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
409
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
410
+ assert(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
353
411
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
354
412
  // when we either never send an op, or attempted to send it but we know for sure it was not
355
413
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -367,13 +425,31 @@ export class ContainerRuntime extends TypedEventEmitter {
367
425
  });
368
426
  // logging hardware telemetry
369
427
  logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
370
- this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
428
+ this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
429
+ disableCompression,
430
+ disableOpReentryCheck,
431
+ disableChunking,
432
+ disableAttachReorder: this.disableAttachReorder,
433
+ disablePartialFlush,
434
+ }), telemetryDocumentId: this.telemetryDocumentId }));
371
435
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
372
436
  BindBatchTracker(this, this.logger);
437
+ this.entryPoint = new LazyPromise(async () => {
438
+ if (this.context.clientDetails.type === summarizerClientType) {
439
+ assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
440
+ return this._summarizer;
441
+ }
442
+ return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
443
+ });
444
+ }
445
+ get IContainerRuntime() {
446
+ return this;
447
+ }
448
+ get IFluidRouter() {
449
+ return this;
373
450
  }
374
- get IContainerRuntime() { return this; }
375
- get IFluidRouter() { return this; }
376
451
  /**
452
+ * @deprecated - use loadRuntime instead.
377
453
  * Load the stores from a snapshot and returns the runtime.
378
454
  * @param context - Context of the container.
379
455
  * @param registryEntries - Mapping to the stores.
@@ -384,7 +460,38 @@ export class ContainerRuntime extends TypedEventEmitter {
384
460
  * allows mixin classes to leverage this method to define their own async initializer.
385
461
  */
386
462
  static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
387
- var _a, _b, _c;
463
+ let existingFlag = true;
464
+ if (!existing) {
465
+ existingFlag = false;
466
+ }
467
+ return this.loadRuntime({
468
+ context,
469
+ registryEntries,
470
+ existing: existingFlag,
471
+ requestHandler,
472
+ runtimeOptions,
473
+ containerScope,
474
+ containerRuntimeCtor,
475
+ });
476
+ }
477
+ /**
478
+ * Load the stores from a snapshot and returns the runtime.
479
+ * @param params - An object housing the runtime properties:
480
+ * - context - Context of the container.
481
+ * - registryEntries - Mapping from data store types to their corresponding factories.
482
+ * - existing - Pass 'true' if loading from an existing snapshot.
483
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
484
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
485
+ * - runtimeOptions - Additional options to be passed to the runtime
486
+ * - containerScope - runtime services provided with context
487
+ * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
488
+ * This allows mixin classes to leverage this method to define their own async initializer.
489
+ * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
490
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
491
+ */
492
+ static async loadRuntime(params) {
493
+ var _a, _b, _c, _d;
494
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
388
495
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
389
496
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
390
497
  const backCompatContext = context;
@@ -394,23 +501,16 @@ export class ContainerRuntime extends TypedEventEmitter {
394
501
  runtimeVersion: pkgVersion,
395
502
  },
396
503
  });
397
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, compressionOptions = {
398
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
399
- compressionAlgorithm: CompressionAlgorithms.lz4
400
- }, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, } = runtimeOptions;
401
- const pendingRuntimeState = context.pendingLocalState;
402
- const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
403
- const storage = !pendingRuntimeState ?
404
- context.storage :
405
- new SerializedSnapshotStorage(() => { return context.storage; }, pendingRuntimeState.snapshotBlobs);
504
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, } = runtimeOptions;
406
505
  const registry = new FluidDataStoreRegistry(registryEntries);
407
506
  const tryFetchBlob = async (blobName) => {
408
- const blobId = baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.blobs[blobName];
409
- if (baseSnapshot && blobId) {
507
+ var _a;
508
+ const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
509
+ if (context.baseSnapshot && blobId) {
410
510
  // IContainerContext storage api return type still has undefined in 0.39 package version.
411
511
  // So once we release 0.40 container-defn package we can remove this check.
412
- assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
413
- return readAndParse(storage, blobId);
512
+ assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
513
+ return readAndParse(context.storage, blobId);
414
514
  }
415
515
  };
416
516
  const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
@@ -421,19 +521,20 @@ export class ContainerRuntime extends TypedEventEmitter {
421
521
  ]);
422
522
  const loadExisting = existing === true || context.existing === true;
423
523
  // read snapshot blobs needed for BlobManager to load
424
- const blobManagerSnapshot = await BlobManager.load(baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[blobsTreeName], async (id) => {
524
+ const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
425
525
  // IContainerContext storage api return type still has undefined in 0.39 package version.
426
526
  // So once we release 0.40 container-defn package we can remove this check.
427
- assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
428
- return readAndParse(storage, id);
527
+ assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
528
+ return readAndParse(context.storage, id);
429
529
  });
430
530
  // Verify summary runtime sequence number matches protocol sequence number.
431
531
  const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
432
532
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
433
- if (!pendingRuntimeState && runtimeSequenceNumber !== undefined) {
533
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
434
534
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
435
535
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
436
- if (loadSequenceNumberVerification !== "bypass" && runtimeSequenceNumber !== protocolSequenceNumber) {
536
+ if (loadSequenceNumberVerification !== "bypass" &&
537
+ runtimeSequenceNumber !== protocolSequenceNumber) {
437
538
  // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
438
539
  const error = new DataCorruptionError(
439
540
  // pre-0.58 error message: SummaryMetadataMismatch
@@ -442,7 +543,9 @@ export class ContainerRuntime extends TypedEventEmitter {
442
543
  logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
443
544
  }
444
545
  else {
546
+ // Call both close and dispose as closeFn implementation will no longer dispose runtime in future
445
547
  context.closeFn(error);
548
+ (_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
446
549
  }
447
550
  }
448
551
  }
@@ -451,15 +554,15 @@ export class ContainerRuntime extends TypedEventEmitter {
451
554
  gcOptions,
452
555
  loadSequenceNumberVerification,
453
556
  flushMode,
454
- enableOfflineLoad,
455
557
  compressionOptions,
456
558
  maxBatchSizeInBytes,
457
- }, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
458
- if (pendingRuntimeState) {
459
- await runtime.processSavedOps(pendingRuntimeState);
460
- // delete these once runtime has seen them to save space
461
- pendingRuntimeState.savedOps = [];
462
- }
559
+ chunkSizeInBytes,
560
+ enableOpReentryCheck,
561
+ }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
562
+ initializeEntryPoint);
563
+ // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
564
+ // at 1, so we won't see a replayed saved op with a sequence number of 0.
565
+ await runtime.pendingStateManager.applyStashedOpsAt(0);
463
566
  // Initialize the base state of the runtime before it's returned.
464
567
  await runtime.initializeBaseState();
465
568
  return runtime;
@@ -473,9 +576,6 @@ export class ContainerRuntime extends TypedEventEmitter {
473
576
  get clientDetails() {
474
577
  return this.context.clientDetails;
475
578
  }
476
- get deltaManager() {
477
- return this.context.deltaManager;
478
- }
479
579
  get storage() {
480
580
  return this._storage;
481
581
  }
@@ -483,8 +583,18 @@ export class ContainerRuntime extends TypedEventEmitter {
483
583
  // eslint-disable-next-line @typescript-eslint/unbound-method
484
584
  return this.reSubmit;
485
585
  }
586
+ get disposeFn() {
587
+ var _a;
588
+ // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
589
+ return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
590
+ }
486
591
  get closeFn() {
487
- return this.context.closeFn;
592
+ // Also call disposeFn to retain functionality of runtime being disposed on close
593
+ return (error) => {
594
+ var _a, _b;
595
+ this.context.closeFn(error);
596
+ (_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
597
+ };
488
598
  }
489
599
  get flushMode() {
490
600
  return this._flushMode;
@@ -501,6 +611,23 @@ export class ContainerRuntime extends TypedEventEmitter {
501
611
  get IFluidHandleContext() {
502
612
  return this.handleContext;
503
613
  }
614
+ /**
615
+ * Invokes the given callback and expects that no ops are submitted
616
+ * until execution finishes. If an op is submitted, an error will be raised.
617
+ *
618
+ * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
619
+ *
620
+ * @param callback - the callback to be invoked
621
+ */
622
+ ensureNoDataModelChanges(callback) {
623
+ this.ensureNoDataModelChangesCalls++;
624
+ try {
625
+ return callback();
626
+ }
627
+ finally {
628
+ this.ensureNoDataModelChangesCalls--;
629
+ }
630
+ }
504
631
  get connected() {
505
632
  return this._connected;
506
633
  }
@@ -509,48 +636,20 @@ export class ContainerRuntime extends TypedEventEmitter {
509
636
  var _a;
510
637
  return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
511
638
  }
512
- get disposed() { return this._disposed; }
639
+ get disposed() {
640
+ return this._disposed;
641
+ }
513
642
  get summarizer() {
514
643
  assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
515
644
  return this._summarizer;
516
645
  }
517
646
  isSummariesDisabled() {
518
- // back-compat: disableSummaries was moved from ISummaryRuntimeOptions
519
- // to ISummaryConfiguration in 0.60.
520
- if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
521
- return true;
522
- }
523
647
  return this.summaryConfiguration.state === "disabled";
524
648
  }
525
649
  isHeuristicsDisabled() {
526
- var _a;
527
- // back-compat: disableHeuristics was moved from ISummarizerOptions
528
- // to ISummaryConfiguration in 0.60.
529
- if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
530
- return true;
531
- }
532
650
  return this.summaryConfiguration.state === "disableHeuristics";
533
651
  }
534
- isSummarizerClientElectionEnabled() {
535
- var _a;
536
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
537
- return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
538
- }
539
- // back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
540
- // to ISummaryConfiguration in 0.60.
541
- if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
542
- return true;
543
- }
544
- return this.summaryConfiguration.state !== "disabled"
545
- ? this.summaryConfiguration.summarizerClientElection === true
546
- : false;
547
- }
548
652
  getMaxOpsSinceLastSummary() {
549
- // back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
550
- // to ISummaryConfiguration in 0.60.
551
- if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
552
- return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
553
- }
554
653
  return this.summaryConfiguration.state !== "disabled"
555
654
  ? this.summaryConfiguration.maxOpsSinceLastSummary
556
655
  : 0;
@@ -569,7 +668,6 @@ export class ContainerRuntime extends TypedEventEmitter {
569
668
  * Initializes the state from the base snapshot this container runtime loaded from.
570
669
  */
571
670
  async initializeBaseState() {
572
- await this.initializeBaseSnapshotBlobs();
573
671
  await this.garbageCollector.initializeBaseState();
574
672
  }
575
673
  dispose(error) {
@@ -594,16 +692,6 @@ export class ContainerRuntime extends TypedEventEmitter {
594
692
  this.emit("dispose");
595
693
  this.removeAllListeners();
596
694
  }
597
- get IFluidTokenProvider() {
598
- var _a;
599
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
600
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
601
- return {
602
- intelligence: this.options.intelligence,
603
- };
604
- }
605
- return undefined;
606
- }
607
695
  /**
608
696
  * Notifies this object about the request made to the container.
609
697
  * @param request - Request made to the handler.
@@ -649,7 +737,8 @@ export class ContainerRuntime extends TypedEventEmitter {
649
737
  status: 200,
650
738
  mimeType: "fluid/object",
651
739
  value: blob,
652
- } : create404Response(request);
740
+ }
741
+ : create404Response(request);
653
742
  }
654
743
  else if (requestParser.pathParts.length > 0) {
655
744
  const dataStore = await this.getDataStoreFromRequest(id, request);
@@ -665,37 +754,31 @@ export class ContainerRuntime extends TypedEventEmitter {
665
754
  return exceptionToResponse(error);
666
755
  }
667
756
  }
757
+ /**
758
+ * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
759
+ */
760
+ async getEntryPoint() {
761
+ return this.entryPoint;
762
+ }
668
763
  internalId(maybeAlias) {
669
764
  var _a;
670
765
  return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
671
766
  }
672
767
  async getDataStoreFromRequest(id, request) {
673
- var _a, _b, _c, _d, _e;
674
- const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
675
- ? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait]
676
- : true;
677
- const viaHandle = typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[RuntimeHeaders.viaHandle]) === "boolean"
678
- ? (_d = request.headers) === null || _d === void 0 ? void 0 : _d[RuntimeHeaders.viaHandle]
679
- : false;
768
+ var _a, _b, _c;
769
+ const headerData = {};
770
+ if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
771
+ headerData.wait = request.headers[RuntimeHeaders.wait];
772
+ }
773
+ if (typeof ((_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.viaHandle]) === "boolean") {
774
+ headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
775
+ }
776
+ if (typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[AllowTombstoneRequestHeaderKey]) === "boolean") {
777
+ headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
778
+ }
680
779
  await this.dataStores.waitIfPendingAlias(id);
681
780
  const internalId = this.internalId(id);
682
- const dataStoreContext = await this.dataStores.getDataStore(internalId, wait, viaHandle);
683
- /**
684
- * If GC should run and this an external app request with "externalRequest" header, we need to return
685
- * an error if the data store being requested is marked as unreferenced as per the data store's base
686
- * GC data.
687
- *
688
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
689
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
690
- */
691
- if (((_e = request.headers) === null || _e === void 0 ? void 0 : _e[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
692
- // The data store is referenced if used routes in the base summary has a route to self.
693
- // Older documents may not have used routes in the summary. They are considered referenced.
694
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
695
- if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
696
- throw responseToException(create404Response(request), request);
697
- }
698
- }
781
+ const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
699
782
  const dataStoreChannel = await dataStoreContext.realize();
700
783
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
701
784
  // the same as GC nodes id.
@@ -711,7 +794,7 @@ export class ContainerRuntime extends TypedEventEmitter {
711
794
  summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
712
795
  // The last message processed at the time of summary. If there are no new messages, use the message from the
713
796
  // last summary.
714
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
797
+ message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
715
798
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
716
799
  }
717
800
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
@@ -827,7 +910,8 @@ export class ContainerRuntime extends TypedEventEmitter {
827
910
  // If attachment blobs were added while disconnected, we need to delay
828
911
  // propagation of the "connected" event until we have uploaded them to
829
912
  // ensure we don't submit ops referencing a blob that has not been uploaded
830
- const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
913
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
914
+ const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
831
915
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
832
916
  assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
833
917
  assert(!!clientId, 0x393 /* Must have clientId when connecting */);
@@ -862,9 +946,7 @@ export class ContainerRuntime extends TypedEventEmitter {
862
946
  if (reconnection) {
863
947
  this.consecutiveReconnects++;
864
948
  if (!this.shouldContinueReconnecting()) {
865
- this.closeFn(DataProcessingError.create(
866
- // eslint-disable-next-line max-len
867
- "Runtime detected too many reconnects with no progress syncing local ops. Batch of ops is likely too large (over 1Mb)", "setConnectionState", undefined, {
949
+ this.closeFn(DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
868
950
  dataLoss: 1,
869
951
  attempts: this.consecutiveReconnects,
870
952
  pendingMessages: this.pendingStateManager.pendingMessagesCount,
@@ -879,12 +961,12 @@ export class ContainerRuntime extends TypedEventEmitter {
879
961
  this.garbageCollector.setConnectionState(connected, clientId);
880
962
  raiseConnectedEvent(this.mc.logger, this, connected, clientId);
881
963
  }
964
+ async notifyOpReplay(message) {
965
+ await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
966
+ }
882
967
  process(messageArg, local) {
883
968
  var _a;
884
969
  this.verifyNotClosed();
885
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
886
- this.savedOps.push(messageArg);
887
- }
888
970
  // Whether or not the message is actually a runtime message.
889
971
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
890
972
  // or something different, like a system message.
@@ -898,7 +980,7 @@ export class ContainerRuntime extends TypedEventEmitter {
898
980
  this.scheduleManager.beforeOpProcessing(message);
899
981
  try {
900
982
  let localOpMetadata;
901
- if (local && runtimeMessage) {
983
+ if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
902
984
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
903
985
  }
904
986
  // If there are no more pending messages after processing a local message,
@@ -924,7 +1006,19 @@ export class ContainerRuntime extends TypedEventEmitter {
924
1006
  case ContainerMessageType.Rejoin:
925
1007
  break;
926
1008
  default:
927
- assert(!runtimeMessage, 0x3ce /* Runtime message of unknown type */);
1009
+ if (runtimeMessage) {
1010
+ const error = DataProcessingError.create(
1011
+ // Former assert 0x3ce
1012
+ "Runtime message of unknown type", "OpProcessing", message, {
1013
+ local,
1014
+ type: message.type,
1015
+ contentType: typeof message.contents,
1016
+ batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
1017
+ compression: message.compression,
1018
+ });
1019
+ this.closeFn(error);
1020
+ throw error;
1021
+ }
928
1022
  }
929
1023
  // For back-compat, notify only about runtime messages for now.
930
1024
  if (runtimeMessage) {
@@ -971,7 +1065,8 @@ export class ContainerRuntime extends TypedEventEmitter {
971
1065
  if (message.clientId === this.clientId && this.connected) {
972
1066
  // Check to see if the signal was lost.
973
1067
  if (this._perfSignalData.trackingSignalSequenceNumber !== undefined &&
974
- envelope.clientSignalSequenceNumber > this._perfSignalData.trackingSignalSequenceNumber) {
1068
+ envelope.clientSignalSequenceNumber >
1069
+ this._perfSignalData.trackingSignalSequenceNumber) {
975
1070
  this._perfSignalData.signalsLost++;
976
1071
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
977
1072
  this.logger.sendErrorEvent({
@@ -982,8 +1077,12 @@ export class ContainerRuntime extends TypedEventEmitter {
982
1077
  clientSignalSequenceNumber: envelope.clientSignalSequenceNumber,
983
1078
  });
984
1079
  }
985
- else if (envelope.clientSignalSequenceNumber === this._perfSignalData.trackingSignalSequenceNumber) {
986
- this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1080
+ else if (envelope.clientSignalSequenceNumber ===
1081
+ this._perfSignalData.trackingSignalSequenceNumber) {
1082
+ // only logging for the first connection and the trackingSignalSequenceNUmber.
1083
+ if (this.consecutiveReconnects === 0) {
1084
+ this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1085
+ }
987
1086
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
988
1087
  }
989
1088
  }
@@ -1000,7 +1099,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1000
1099
  async getRootDataStoreChannel(id, wait = true) {
1001
1100
  await this.dataStores.waitIfPendingAlias(id);
1002
1101
  const internalId = this.internalId(id);
1003
- const context = await this.dataStores.getDataStore(internalId, wait, false /* viaHandle */);
1102
+ const context = await this.dataStores.getDataStore(internalId, { wait });
1004
1103
  assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
1005
1104
  return context.realize();
1006
1105
  }
@@ -1049,7 +1148,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1049
1148
  finally {
1050
1149
  this._orderSequentiallyCalls--;
1051
1150
  }
1052
- if (this.flushMode === FlushMode.Immediate && this._orderSequentiallyCalls === 0) {
1151
+ // We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
1152
+ if (this.flushMode !== FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
1053
1153
  this.flush();
1054
1154
  }
1055
1155
  return result;
@@ -1068,7 +1168,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1068
1168
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1069
1169
  }
1070
1170
  async _createDataStoreWithProps(pkg, props, id = uuid()) {
1071
- const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props).realize();
1171
+ const fluidDataStore = await this.dataStores
1172
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1173
+ .realize();
1072
1174
  return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1073
1175
  }
1074
1176
  async _createDataStore(pkg, id = uuid(), props) {
@@ -1077,13 +1179,15 @@ export class ContainerRuntime extends TypedEventEmitter {
1077
1179
  .realize();
1078
1180
  }
1079
1181
  canSendOps() {
1080
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
1182
+ // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
1183
+ // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
1184
+ return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1081
1185
  }
1082
1186
  /**
1083
1187
  * Are we in the middle of batching ops together?
1084
1188
  */
1085
1189
  currentlyBatching() {
1086
- return this.flushMode === FlushMode.TurnBased || this._orderSequentiallyCalls !== 0;
1190
+ return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
1087
1191
  }
1088
1192
  getQuorum() {
1089
1193
  return this.context.quorum;
@@ -1199,81 +1303,98 @@ export class ContainerRuntime extends TypedEventEmitter {
1199
1303
  async summarize(options) {
1200
1304
  this.verifyNotClosed();
1201
1305
  const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
1306
+ const telemetryContext = new TelemetryContext();
1307
+ // Add the options that are used to generate this summary to the telemetry context.
1308
+ telemetryContext.setMultiple("fluid_Summarize", "Options", {
1309
+ fullTree,
1310
+ trackState,
1311
+ runGC,
1312
+ fullGC,
1313
+ runSweep,
1314
+ });
1202
1315
  let gcStats;
1203
1316
  if (runGC) {
1204
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1317
+ gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1205
1318
  }
1206
- const telemetryContext = new TelemetryContext();
1207
1319
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1208
- this.logger.sendTelemetryEvent({ eventName: "SummarizeTelemetry", details: telemetryContext.serialize() });
1320
+ this.logger.sendTelemetryEvent({
1321
+ eventName: "SummarizeTelemetry",
1322
+ details: telemetryContext.serialize(),
1323
+ });
1209
1324
  assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1210
1325
  return { stats, summary, gcStats };
1211
1326
  }
1212
1327
  /**
1213
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
1214
1328
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
1215
1329
  * the garbage collector of references detected since the last GC run. Most references are notified immediately
1216
1330
  * but there can be some for which async operation is required (such as detecting new root data stores).
1331
+ * @see IGarbageCollectionRuntime.updateStateBeforeGC
1217
1332
  */
1218
1333
  async updateStateBeforeGC() {
1219
1334
  return this.dataStores.updateStateBeforeGC();
1220
1335
  }
1336
+ async getGCDataInternal(fullGC) {
1337
+ return this.dataStores.getGCData(fullGC);
1338
+ }
1221
1339
  /**
1222
- * Implementation of IGarbageCollectionRuntime::getGCData.
1223
1340
  * Generates and returns the GC data for this container.
1224
1341
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
1342
+ * @see IGarbageCollectionRuntime.getGCData
1225
1343
  */
1226
1344
  async getGCData(fullGC) {
1227
1345
  const builder = new GCDataBuilder();
1228
- const dsGCData = await this.dataStores.getGCData(fullGC);
1346
+ const dsGCData = await this.summarizerNode.getGCData(fullGC);
1229
1347
  builder.addNodes(dsGCData.gcNodes);
1230
1348
  const blobsGCData = this.blobManager.getGCData(fullGC);
1231
1349
  builder.addNodes(blobsGCData.gcNodes);
1232
1350
  return builder.getGCData();
1233
1351
  }
1234
1352
  /**
1235
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
1236
1353
  * After GC has run, called to notify this container's nodes of routes that are used in it.
1237
1354
  * @param usedRoutes - The routes that are used in all nodes in this Container.
1355
+ * @see IGarbageCollectionRuntime.updateUsedRoutes
1238
1356
  */
1239
1357
  updateUsedRoutes(usedRoutes) {
1240
1358
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
1241
1359
  // summarizing is required and asserted by the the summarizer node. We are the root and are
1242
1360
  // always referenced, so the used routes is only self-route (empty string).
1243
1361
  this.summarizerNode.updateUsedRoutes([""]);
1244
- const blobManagerUsedRoutes = [];
1245
- const dataStoreUsedRoutes = [];
1246
- for (const route of usedRoutes) {
1247
- if (this.isBlobPath(route)) {
1248
- blobManagerUsedRoutes.push(route);
1249
- }
1250
- else {
1251
- dataStoreUsedRoutes.push(route);
1252
- }
1253
- }
1254
- this.blobManager.updateUsedRoutes(blobManagerUsedRoutes);
1255
- this.dataStores.updateUsedRoutes(dataStoreUsedRoutes);
1362
+ const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
1363
+ this.dataStores.updateUsedRoutes(dataStoreRoutes);
1256
1364
  }
1257
1365
  /**
1258
- * This is called to update objects whose routes are unused. The unused objects are either deleted or marked as
1259
- * tombstones.
1260
- * @param unusedRoutes - The routes that are unused in all data stores and attachment blobs in this Container.
1261
- * @param tombstone - if true, the objects corresponding to unused routes are marked tombstones. Otherwise, they
1262
- * are deleted.
1366
+ * This is called to update objects whose routes are unused.
1367
+ * @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
1263
1368
  */
1264
- updateUnusedRoutes(unusedRoutes, tombstone) {
1265
- const blobManagerUnusedRoutes = [];
1266
- const dataStoreUnusedRoutes = [];
1267
- for (const route of unusedRoutes) {
1268
- if (this.isBlobPath(route)) {
1269
- blobManagerUnusedRoutes.push(route);
1270
- }
1271
- else {
1272
- dataStoreUnusedRoutes.push(route);
1273
- }
1274
- }
1275
- this.blobManager.updateUnusedRoutes(blobManagerUnusedRoutes, tombstone);
1276
- this.dataStores.updateUnusedRoutes(dataStoreUnusedRoutes, tombstone);
1369
+ updateUnusedRoutes(unusedRoutes) {
1370
+ const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
1371
+ this.blobManager.updateUnusedRoutes(blobManagerRoutes);
1372
+ this.dataStores.updateUnusedRoutes(dataStoreRoutes);
1373
+ }
1374
+ /**
1375
+ * @deprecated - Replaced by deleteSweepReadyNodes.
1376
+ */
1377
+ deleteUnusedNodes(unusedRoutes) {
1378
+ throw new Error("deleteUnusedRoutes should not be called");
1379
+ }
1380
+ /**
1381
+ * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
1382
+ * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
1383
+ * @returns - The routes of nodes that were deleted.
1384
+ */
1385
+ deleteSweepReadyNodes(sweepReadyRoutes) {
1386
+ const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
1387
+ const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
1388
+ return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
1389
+ }
1390
+ /**
1391
+ * This is called to update objects that are tombstones.
1392
+ * @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
1393
+ */
1394
+ updateTombstonedRoutes(tombstonedRoutes) {
1395
+ const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
1396
+ this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
1397
+ this.dataStores.updateTombstonedRoutes(dataStoreRoutes);
1277
1398
  }
1278
1399
  /**
1279
1400
  * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
@@ -1302,7 +1423,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1302
1423
  async getGCNodePackagePath(nodePath) {
1303
1424
  switch (this.getNodeType(nodePath)) {
1304
1425
  case GCNodeType.Blob:
1305
- return ["_blobs"];
1426
+ return [BlobManager.basePath];
1306
1427
  case GCNodeType.DataStore:
1307
1428
  case GCNodeType.SubDataStore:
1308
1429
  return this.dataStores.getDataStorePackagePath(nodePath);
@@ -1320,12 +1441,31 @@ export class ContainerRuntime extends TypedEventEmitter {
1320
1441
  }
1321
1442
  return true;
1322
1443
  }
1444
+ /**
1445
+ * From a given list of routes, separate and return routes that belong to blob manager and data stores.
1446
+ * @param routes - A list of routes that can belong to data stores or blob manager.
1447
+ * @returns - Two route lists - One that contains routes for blob manager and another one that contains routes
1448
+ * for data stores.
1449
+ */
1450
+ getDataStoreAndBlobManagerRoutes(routes) {
1451
+ const blobManagerRoutes = [];
1452
+ const dataStoreRoutes = [];
1453
+ for (const route of routes) {
1454
+ if (this.isBlobPath(route)) {
1455
+ blobManagerRoutes.push(route);
1456
+ }
1457
+ else {
1458
+ dataStoreRoutes.push(route);
1459
+ }
1460
+ }
1461
+ return { blobManagerRoutes, dataStoreRoutes };
1462
+ }
1323
1463
  /**
1324
1464
  * Runs garbage collection and updates the reference / used state of the nodes in the container.
1325
1465
  * @returns the statistics of the garbage collection run; undefined if GC did not run.
1326
1466
  */
1327
- async collectGarbage(options) {
1328
- return this.garbageCollector.collectGarbage(options);
1467
+ async collectGarbage(options, telemetryContext) {
1468
+ return this.garbageCollector.collectGarbage(options, telemetryContext);
1329
1469
  }
1330
1470
  /**
1331
1471
  * Called when a new outbound reference is added to another node. This is used by garbage collection to identify
@@ -1346,7 +1486,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1346
1486
  */
1347
1487
  async submitSummary(options) {
1348
1488
  var _a, _b;
1349
- const { fullTree, refreshLatestAck, summaryLogger } = options;
1489
+ const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1350
1490
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1351
1491
  // use it for all events logged during this summary.
1352
1492
  const summaryNumber = this.nextSummaryNumber;
@@ -1362,8 +1502,12 @@ export class ContainerRuntime extends TypedEventEmitter {
1362
1502
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1363
1503
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1364
1504
  }
1505
+ const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1365
1506
  try {
1366
1507
  await this.deltaManager.inbound.pause();
1508
+ if (shouldPauseInboundSignal) {
1509
+ await this.deltaManager.inboundSignal.pause();
1510
+ }
1367
1511
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1368
1512
  const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1369
1513
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
@@ -1391,7 +1535,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1391
1535
  if (this.deltaManager.lastSequenceNumber !== summaryRefSeqNum) {
1392
1536
  return {
1393
1537
  continue: false,
1394
- // eslint-disable-next-line max-len
1395
1538
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1396
1539
  };
1397
1540
  }
@@ -1399,7 +1542,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1399
1542
  if (lastAck !== this.summaryCollection.latestAck) {
1400
1543
  return {
1401
1544
  continue: false,
1402
- // eslint-disable-next-line max-len
1403
1545
  error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
1404
1546
  };
1405
1547
  }
@@ -1421,7 +1563,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1421
1563
  const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
1422
1564
  try {
1423
1565
  summarizeResult = await this.summarize({
1424
- fullTree: fullTree !== null && fullTree !== void 0 ? fullTree : forcedFullTree,
1566
+ fullTree: fullTree || forcedFullTree,
1425
1567
  trackState: true,
1426
1568
  summaryLogger: summaryNumberLogger,
1427
1569
  runGC: this.garbageCollector.shouldRunGC,
@@ -1466,8 +1608,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1466
1608
  // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1467
1609
  // the one fetched from storage as parent as that is the latest.
1468
1610
  let summaryContext;
1469
- if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
1470
- && latestSnapshotVersionId !== undefined) {
1611
+ if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId &&
1612
+ latestSnapshotVersionId !== undefined) {
1471
1613
  summaryContext = {
1472
1614
  proposalHandle: undefined,
1473
1615
  ackHandle: latestSnapshotVersionId,
@@ -1510,7 +1652,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1510
1652
  }
1511
1653
  let clientSequenceNumber;
1512
1654
  try {
1513
- clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
1655
+ clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
1514
1656
  }
1515
1657
  catch (error) {
1516
1658
  return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
@@ -1524,6 +1666,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1524
1666
  this.summarizerNode.clearSummary();
1525
1667
  // Restart the delta manager
1526
1668
  this.deltaManager.inbound.resume();
1669
+ if (shouldPauseInboundSignal) {
1670
+ this.deltaManager.inboundSignal.resume();
1671
+ }
1527
1672
  }
1528
1673
  }
1529
1674
  hasPendingMessages() {
@@ -1566,16 +1711,21 @@ export class ContainerRuntime extends TypedEventEmitter {
1566
1711
  }
1567
1712
  submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
1568
1713
  this.verifyNotClosed();
1714
+ this.verifyCanSubmitOps();
1569
1715
  // There should be no ops in detached container state!
1570
1716
  assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1571
- const deserializedContent = { type, contents };
1572
- const serializedContent = JSON.stringify(deserializedContent);
1573
- if (this.deltaManager.readOnlyInfo.readonly) {
1574
- this.logger.sendTelemetryEvent({ eventName: "SubmitOpInReadonly", connected: this.connected });
1717
+ const serializedContent = JSON.stringify({ type, contents });
1718
+ // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
1719
+ // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
1720
+ if (this.innerDeltaManager.readOnlyInfo.readonly) {
1721
+ this.logger.sendTelemetryEvent({
1722
+ eventName: "SubmitOpInReadonly",
1723
+ connected: this.connected,
1724
+ });
1575
1725
  }
1576
1726
  const message = {
1577
1727
  contents: serializedContent,
1578
- deserializedContent,
1728
+ deserializedContent: JSON.parse(serializedContent),
1579
1729
  metadata,
1580
1730
  localOpMetadata,
1581
1731
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -1601,8 +1751,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1601
1751
  // issue than sending.
1602
1752
  // Please note that this does not change file format, so it can be disabled in the future if this
1603
1753
  // optimization no longer makes sense (for example, batch compression may make it less appealing).
1604
- if (this.currentlyBatching() && type === ContainerMessageType.Attach &&
1605
- this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder") !== true) {
1754
+ if (this.currentlyBatching() &&
1755
+ type === ContainerMessageType.Attach &&
1756
+ this.disableAttachReorder !== true) {
1606
1757
  this.outbox.submitAttach(message);
1607
1758
  }
1608
1759
  else {
@@ -1611,14 +1762,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1611
1762
  if (!this.currentlyBatching()) {
1612
1763
  this.flush();
1613
1764
  }
1614
- else if (!this.flushMicroTaskExists) {
1615
- this.flushMicroTaskExists = true;
1616
- // Queue a microtask to detect the end of the turn and force a flush.
1617
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1618
- Promise.resolve().then(() => {
1619
- this.flushMicroTaskExists = false;
1620
- this.flush();
1621
- }).catch((error) => { this.closeFn(error); });
1765
+ else {
1766
+ this.scheduleFlush();
1622
1767
  }
1623
1768
  }
1624
1769
  catch (error) {
@@ -1629,14 +1774,47 @@ export class ContainerRuntime extends TypedEventEmitter {
1629
1774
  this.updateDocumentDirtyState(true);
1630
1775
  }
1631
1776
  }
1632
- submitSummaryMessage(contents) {
1777
+ scheduleFlush() {
1778
+ if (this.flushTaskExists) {
1779
+ return;
1780
+ }
1781
+ this.flushTaskExists = true;
1782
+ const flush = () => {
1783
+ this.flushTaskExists = false;
1784
+ try {
1785
+ this.flush();
1786
+ }
1787
+ catch (error) {
1788
+ this.closeFn(error);
1789
+ }
1790
+ };
1791
+ switch (this.flushMode) {
1792
+ case FlushMode.TurnBased:
1793
+ // When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
1794
+ // batch at the end of the turn
1795
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1796
+ Promise.resolve().then(flush);
1797
+ break;
1798
+ // FlushModeExperimental is experimental and not exposed directly in the runtime APIs
1799
+ case FlushModeExperimental.Async:
1800
+ // When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
1801
+ // batch when all micro-tasks are complete.
1802
+ // Compared to TurnBased, this flush mode will capture more ops into the same batch.
1803
+ setTimeout(flush, 0);
1804
+ break;
1805
+ default:
1806
+ assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
1807
+ break;
1808
+ }
1809
+ }
1810
+ submitSummaryMessage(contents, referenceSequenceNumber) {
1633
1811
  this.verifyNotClosed();
1634
1812
  assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
1635
1813
  // System message should not be sent in the middle of the batch.
1636
1814
  assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
1637
1815
  // back-compat: ADO #1385: Make this call unconditional in the future
1638
1816
  return this.context.submitSummaryFn !== undefined
1639
- ? this.context.submitSummaryFn(contents)
1817
+ ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
1640
1818
  : this.context.submitFn(MessageType.Summarize, contents, false);
1641
1819
  }
1642
1820
  /**
@@ -1648,6 +1826,32 @@ export class ContainerRuntime extends TypedEventEmitter {
1648
1826
  throw new Error("Runtime is closed");
1649
1827
  }
1650
1828
  }
1829
+ verifyCanSubmitOps() {
1830
+ if (this.ensureNoDataModelChangesCalls > 0) {
1831
+ const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
1832
+ if (this.opReentryCallsToReport > 0) {
1833
+ this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
1834
+ // We need to capture the call stack in order to inspect the source of this usage pattern
1835
+ new UsageError(errorMessage));
1836
+ this.opReentryCallsToReport--;
1837
+ }
1838
+ // Creating ops while processing ops can lead
1839
+ // to undefined behavior and events observed in the wrong order.
1840
+ // For example, we have two callbacks registered for a DDS, A and B.
1841
+ // Then if on change #1 callback A creates change #2, the invocation flow will be:
1842
+ //
1843
+ // A because of #1
1844
+ // A because of #2
1845
+ // B because of #2
1846
+ // B because of #1
1847
+ //
1848
+ // The runtime must enforce op coherence by not allowing ops to be submitted
1849
+ // while ops are being processed.
1850
+ if (this.enableOpReentryCheck) {
1851
+ throw new UsageError(errorMessage);
1852
+ }
1853
+ }
1854
+ }
1651
1855
  /**
1652
1856
  * Finds the right store and asks it to resubmit the message. This typically happens when we
1653
1857
  * reconnect and there are pending messages.
@@ -1706,28 +1910,50 @@ export class ContainerRuntime extends TypedEventEmitter {
1706
1910
  // The call to fetch the snapshot is very expensive and not always needed.
1707
1911
  // It should only be done by the summarizerNode, if required.
1708
1912
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
1709
- const snapshotTreeFetcher = async () => {
1710
- const fetchResult = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1711
- eventName: "RefreshLatestSummaryGetSnapshot",
1913
+ const fetchLatestSnapshot = async () => {
1914
+ let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1915
+ eventName: "RefreshLatestSummaryAckFetch",
1712
1916
  ackHandle,
1713
- summaryRefSeq,
1714
- fetchLatest: true,
1715
- });
1716
- const latestSnapshotRefSeq = await seqFromTree(fetchResult.snapshotTree, readAndParseBlob);
1717
- summaryLogger.sendTelemetryEvent({
1718
- eventName: "LatestSummaryRetrieved",
1719
- ackHandle,
1720
- lastSequenceNumber: latestSnapshotRefSeq,
1721
1917
  targetSequenceNumber: summaryRefSeq,
1722
- });
1918
+ }, readAndParseBlob);
1919
+ /**
1920
+ * If the fetched snapshot is older than the one for which the ack was received, close the container.
1921
+ * This should never happen because an ack should be sent after the latest summary is updated in the server.
1922
+ * However, there are couple of scenarios where it's possible:
1923
+ * 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
1924
+ * the document being unusable and we should not proceed.
1925
+ * 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
1926
+ * such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
1927
+ * state.
1928
+ */
1929
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1930
+ /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
1931
+ fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
1932
+ eventName: "RefreshLatestSummaryAckFetch",
1933
+ ackHandle,
1934
+ targetSequenceNumber: summaryRefSeq,
1935
+ }, readAndParseBlob, ackHandle);
1936
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1937
+ const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1938
+ ackHandle,
1939
+ summaryRefSeq,
1940
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1941
+ });
1942
+ this.closeFn(error);
1943
+ throw error;
1944
+ }
1945
+ }
1723
1946
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
1724
1947
  // wait for the delta manager to catch up before refreshing the latest Summary.
1725
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
1726
- return fetchResult.snapshotTree;
1948
+ await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
1949
+ return {
1950
+ snapshotTree: fetchResult.snapshotTree,
1951
+ snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1952
+ };
1727
1953
  };
1728
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, snapshotTreeFetcher, readAndParseBlob, summaryLogger);
1954
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1729
1955
  // Notify the garbage collector so it can update its latest summary state.
1730
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1956
+ await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
1731
1957
  }
1732
1958
  /**
1733
1959
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -1736,76 +1962,55 @@ export class ContainerRuntime extends TypedEventEmitter {
1736
1962
  * @returns downloaded snapshot's reference sequence number
1737
1963
  */
1738
1964
  async refreshLatestSummaryAckFromServer(summaryLogger) {
1739
- const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1740
- eventName: "RefreshLatestSummaryGetSnapshot",
1741
- fetchLatest: true,
1742
- }, FetchSource.noCache);
1743
1965
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
1744
- const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
1745
- const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
1966
+ const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1967
+ eventName: "RefreshLatestSummaryFromServerFetch",
1968
+ }, readAndParseBlob);
1969
+ const fetchLatestSnapshot = {
1970
+ snapshotTree,
1971
+ snapshotRefSeq: latestSnapshotRefSeq,
1972
+ };
1973
+ const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1746
1974
  // Notify the garbage collector so it can update its latest summary state.
1747
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1975
+ await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
1748
1976
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
1749
1977
  }
1750
- async fetchSnapshotFromStorage(versionId, logger, event, fetchSource) {
1978
+ async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
1979
+ return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
1980
+ }
1981
+ async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
1751
1982
  return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
1752
1983
  const stats = {};
1753
1984
  const trace = Trace.start();
1754
- const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", fetchSource);
1985
+ const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
1755
1986
  assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
1756
1987
  stats.getVersionDuration = trace.trace().duration;
1757
1988
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
1758
1989
  assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
1759
1990
  stats.getSnapshotDuration = trace.trace().duration;
1991
+ const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
1992
+ stats.snapshotRefSeq = latestSnapshotRefSeq;
1993
+ stats.snapshotVersion = versions[0].id;
1760
1994
  perfEvent.end(stats);
1761
- return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
1995
+ return {
1996
+ snapshotTree: maybeSnapshot,
1997
+ versionId: versions[0].id,
1998
+ latestSnapshotRefSeq,
1999
+ };
1762
2000
  });
1763
2001
  }
1764
- notifyAttaching(snapshot) {
1765
- var _a;
1766
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
1767
- this.baseSnapshotBlobs = SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
1768
- }
1769
- }
1770
- async initializeBaseSnapshotBlobs() {
1771
- var _a;
1772
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
1773
- this.attachState !== AttachState.Attached || this.context.pendingLocalState) {
1774
- return;
1775
- }
1776
- assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
1777
- this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
1778
- }
2002
+ notifyAttaching() { } // do nothing (deprecated method)
1779
2003
  getPendingLocalState() {
1780
- var _a;
1781
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
1782
- throw new UsageError("can't get state when offline load disabled");
2004
+ if (this._orderSequentiallyCalls !== 0) {
2005
+ throw new UsageError("can't get state during orderSequentially");
1783
2006
  }
1784
2007
  // Flush pending batch.
1785
2008
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
1786
2009
  // to close current batch.
1787
2010
  this.flush();
1788
- if (this._orderSequentiallyCalls !== 0) {
1789
- throw new UsageError("can't get state during orderSequentially");
1790
- }
1791
- const previousPendingState = this.context.pendingLocalState;
1792
- if (previousPendingState) {
1793
- return {
1794
- pending: this.pendingStateManager.getLocalState(),
1795
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1796
- snapshotBlobs: previousPendingState.snapshotBlobs,
1797
- baseSnapshot: previousPendingState.baseSnapshot,
1798
- savedOps: this.savedOps,
1799
- };
1800
- }
1801
- assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
1802
- assert(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
1803
2011
  return {
1804
2012
  pending: this.pendingStateManager.getLocalState(),
1805
2013
  pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1806
- snapshotBlobs: this.baseSnapshotBlobs,
1807
- baseSnapshot: this.context.baseSnapshot,
1808
- savedOps: this.savedOps,
1809
2014
  };
1810
2015
  }
1811
2016
  /**
@@ -1834,20 +2039,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1834
2039
  return summarizer;
1835
2040
  };
1836
2041
  }
1837
- async processSavedOps(state) {
1838
- for (const op of state.savedOps) {
1839
- this.process(op, false);
1840
- await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
1841
- }
1842
- // we may not have seen every sequence number (because of system ops) so apply everything once we
1843
- // don't have any more saved ops
1844
- await this.pendingStateManager.applyStashedOpsAt();
1845
- // If it's not the case, we should take it into account when calculating dirty state.
1846
- assert(this.context.attachState === AttachState.Attached, 0x3d5 /* this function is called for attached containers only */);
1847
- if (!this.hasPendingMessages()) {
1848
- this.updateDocumentDirtyState(false);
1849
- }
1850
- }
1851
2042
  validateSummaryHeuristicConfiguration(configuration) {
1852
2043
  // eslint-disable-next-line no-restricted-syntax
1853
2044
  for (const prop in configuration) {
@@ -1867,6 +2058,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1867
2058
  const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
1868
2059
  // TODO: remove cast to any when actual event is determined
1869
2060
  deltaManager.on("closed", reject);
2061
+ deltaManager.on("disposed", reject);
1870
2062
  // If we already reached target sequence number, simply resolve the promise.
1871
2063
  if (deltaManager.lastSequenceNumber >= targetSeq) {
1872
2064
  resolve();