@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,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
3
+ exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.TombstoneResponseHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
4
4
  const container_definitions_1 = require("@fluidframework/container-definitions");
5
5
  const common_utils_1 = require("@fluidframework/common-utils");
6
6
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
@@ -10,30 +10,22 @@ const container_utils_1 = require("@fluidframework/container-utils");
10
10
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
11
11
  const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
12
12
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
13
- const garbage_collector_1 = require("@fluidframework/garbage-collector");
14
13
  const uuid_1 = require("uuid");
15
14
  const containerHandleContext_1 = require("./containerHandleContext");
16
15
  const dataStoreRegistry_1 = require("./dataStoreRegistry");
17
- const summarizer_1 = require("./summarizer");
18
- const summaryManager_1 = require("./summaryManager");
19
16
  const connectionTelemetry_1 = require("./connectionTelemetry");
20
17
  const pendingStateManager_1 = require("./pendingStateManager");
21
18
  const packageVersion_1 = require("./packageVersion");
22
19
  const blobManager_1 = require("./blobManager");
23
20
  const dataStores_1 = require("./dataStores");
24
- const summaryFormat_1 = require("./summaryFormat");
25
- const summaryCollection_1 = require("./summaryCollection");
26
- const orderedClientElection_1 = require("./orderedClientElection");
27
- const summarizerClientElection_1 = require("./summarizerClientElection");
21
+ const summary_1 = require("./summary");
28
22
  const throttler_1 = require("./throttler");
29
- const runWhileConnectedCoordinator_1 = require("./runWhileConnectedCoordinator");
30
- const garbageCollection_1 = require("./garbageCollection");
31
- const garbageCollectionConstants_1 = require("./garbageCollectionConstants");
23
+ const gc_1 = require("./gc");
32
24
  const dataStore_1 = require("./dataStore");
33
25
  const batchTracker_1 = require("./batchTracker");
34
- const serializedSnapshotStorage_1 = require("./serializedSnapshotStorage");
35
26
  const scheduleManager_1 = require("./scheduleManager");
36
27
  const opLifecycle_1 = require("./opLifecycle");
28
+ const deltaManagerSummarizerProxy_1 = require("./deltaManagerSummarizerProxy");
37
29
  var ContainerMessageType;
38
30
  (function (ContainerMessageType) {
39
31
  // An op to be delivered to store
@@ -59,7 +51,6 @@ exports.DefaultSummaryConfiguration = {
59
51
  maxAckWaitTime: 10 * 60 * 1000,
60
52
  maxOpsSinceLastSummary: 7000,
61
53
  initialSummarizerDelayMs: 5 * 1000,
62
- summarizerClientElection: false,
63
54
  nonRuntimeOpWeight: 0.1,
64
55
  runtimeOpWeight: 1.0,
65
56
  nonRuntimeHeuristicThreshold: 20,
@@ -71,14 +62,19 @@ var RuntimeHeaders;
71
62
  (function (RuntimeHeaders) {
72
63
  /** True to wait for a data store to be created and loaded before returning it. */
73
64
  RuntimeHeaders["wait"] = "wait";
74
- /**
75
- * True if the request is from an external app. Used for GC to handle scenarios where a data store
76
- * is deleted and requested via an external app.
77
- */
78
- RuntimeHeaders["externalRequest"] = "externalRequest";
79
65
  /** True if the request is coming from an IFluidHandle. */
80
66
  RuntimeHeaders["viaHandle"] = "viaHandle";
81
67
  })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
68
+ /** True if a tombstoned object should be returned without erroring */
69
+ exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
70
+ /** Tombstone error responses will have this header set to true */
71
+ exports.TombstoneResponseHeaderKey = "isTombstoned";
72
+ /** Default values for Runtime Headers */
73
+ exports.defaultRuntimeHeaderData = {
74
+ wait: true,
75
+ viaHandle: false,
76
+ allowTombstone: false,
77
+ };
82
78
  /**
83
79
  * Available compression algorithms for op compression.
84
80
  */
@@ -92,7 +88,13 @@ const defaultFlushMode = runtime_definitions_1.FlushMode.TurnBased;
92
88
  // We can't estimate it fully, as we
93
89
  // - do not know what properties relay service will add
94
90
  // - we do not stringify final op, thus we do not know how much escaping will be added.
95
- const defaultMaxBatchSizeInBytes = 950 * 1024;
91
+ const defaultMaxBatchSizeInBytes = 700 * 1024;
92
+ const defaultCompressionConfig = {
93
+ // Batches with content size exceeding this value will be compressed
94
+ minimumBatchSizeInBytes: 614400,
95
+ compressionAlgorithm: CompressionAlgorithms.lz4,
96
+ };
97
+ const defaultChunkSizeInBytes = 204800;
96
98
  /**
97
99
  * @deprecated - use ContainerRuntimeMessage instead
98
100
  */
@@ -129,8 +131,7 @@ function getDeviceSpec() {
129
131
  };
130
132
  }
131
133
  }
132
- catch (_a) {
133
- }
134
+ catch (_a) { }
134
135
  return {};
135
136
  }
136
137
  exports.getDeviceSpec = getDeviceSpec;
@@ -142,8 +143,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
142
143
  /**
143
144
  * @internal
144
145
  */
145
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
146
- var _a, _b, _c, _d, _e, _f;
146
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
147
+ var _a, _b, _c, _d, _e, _f, _g, _h;
147
148
  if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, exports.DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
148
149
  super();
149
150
  this.context = context;
@@ -156,9 +157,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
156
157
  this.summaryConfiguration = summaryConfiguration;
157
158
  this.defaultMaxConsecutiveReconnects = 7;
158
159
  this._orderSequentiallyCalls = 0;
159
- this.flushMicroTaskExists = false;
160
- this.savedOps = [];
160
+ this.flushTaskExists = false;
161
161
  this.consecutiveReconnects = 0;
162
+ this.ensureNoDataModelChangesCalls = 0;
163
+ /**
164
+ * Tracks the number of detected reentrant ops to report,
165
+ * in order to self-throttle the telemetry events.
166
+ *
167
+ * This should be removed as part of ADO:2322
168
+ */
169
+ this.opReentryCallsToReport = 5;
162
170
  this._disposed = false;
163
171
  this.emitDirtyDocumentEvent = true;
164
172
  this.defaultTelemetrySignalSampleCount = 100;
@@ -169,7 +177,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
169
177
  trackingSignalSequenceNumber: undefined,
170
178
  };
171
179
  this.summarizeOnDemand = (...args) => {
172
- if (this.clientDetails.type === summarizerClientElection_1.summarizerClientType) {
180
+ if (this.clientDetails.type === summary_1.summarizerClientType) {
173
181
  return this.summarizer.summarizeOnDemand(...args);
174
182
  }
175
183
  else if (this.summaryManager !== undefined) {
@@ -183,7 +191,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
183
191
  }
184
192
  };
185
193
  this.enqueueSummarize = (...args) => {
186
- if (this.clientDetails.type === summarizerClientElection_1.summarizerClientType) {
194
+ if (this.clientDetails.type === summary_1.summarizerClientType) {
187
195
  return this.summarizer.enqueueSummarize(...args);
188
196
  }
189
197
  else if (this.summaryManager !== undefined) {
@@ -196,6 +204,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
196
204
  throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
197
205
  }
198
206
  };
207
+ this.innerDeltaManager = context.deltaManager;
208
+ this.deltaManager = new deltaManagerSummarizerProxy_1.DeltaManagerSummarizerProxy(context.deltaManager);
199
209
  let loadSummaryNumber;
200
210
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
201
211
  // get the values from the metadata blob.
@@ -218,52 +228,78 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
218
228
  this.nextSummaryNumber = loadSummaryNumber + 1;
219
229
  this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
220
230
  this._connected = this.context.connected;
221
- this.remoteMessageProcessor = new opLifecycle_1.RemoteMessageProcessor(new opLifecycle_1.OpSplitter(chunks), new opLifecycle_1.OpDecompressor());
222
- this.handleContext = new containerHandleContext_1.ContainerFluidHandleContext("", this);
231
+ this.gcTombstoneEnforcementAllowed = (0, gc_1.shouldAllowGcTombstoneEnforcement)((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gc_1.gcTombstoneGenerationOptionName] /* current */);
223
232
  this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(this.logger, "ContainerRuntime"));
233
+ this.mc.logger.sendTelemetryEvent({
234
+ eventName: "GCFeatureMatrix",
235
+ metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
236
+ inputs: JSON.stringify({
237
+ gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gc_1.gcTombstoneGenerationOptionName],
238
+ }),
239
+ });
240
+ this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : (0, uuid_1.v4)();
241
+ this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
242
+ const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
243
+ const opSplitter = new opLifecycle_1.OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
244
+ this.remoteMessageProcessor = new opLifecycle_1.RemoteMessageProcessor(opSplitter, new opLifecycle_1.OpDecompressor(this.mc.logger));
245
+ this.handleContext = new containerHandleContext_1.ContainerFluidHandleContext("", this);
224
246
  if (this.summaryConfiguration.state === "enabled") {
225
247
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
226
248
  }
249
+ const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
250
+ this.enableOpReentryCheck =
251
+ runtimeOptions.enableOpReentryCheck === true &&
252
+ // Allow for a break-glass config to override the options
253
+ disableOpReentryCheck !== true;
227
254
  this.summariesDisabled = this.isSummariesDisabled();
228
255
  this.heuristicsDisabled = this.isHeuristicsDisabled();
229
- this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
230
256
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
231
257
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
232
258
  this.maxConsecutiveReconnects =
233
- (_c = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _c !== void 0 ? _c : this.defaultMaxConsecutiveReconnects;
234
- this._flushMode = runtimeOptions.flushMode;
259
+ (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
260
+ if (runtimeOptions.flushMode === runtime_definitions_1.FlushModeExperimental.Async &&
261
+ ((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
262
+ // The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
263
+ this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
264
+ this._flushMode = runtime_definitions_1.FlushMode.TurnBased;
265
+ }
266
+ else {
267
+ this._flushMode = runtimeOptions.flushMode;
268
+ }
235
269
  const pendingRuntimeState = context.pendingLocalState;
236
- const baseSnapshot = (_d = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _d !== void 0 ? _d : context.baseSnapshot;
237
- const maxSnapshotCacheDurationMs = (_f = (_e = this._storage) === null || _e === void 0 ? void 0 : _e.policies) === null || _f === void 0 ? void 0 : _f.maximumCacheDurationMs;
238
- if (maxSnapshotCacheDurationMs !== undefined && maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
270
+ const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
271
+ if (maxSnapshotCacheDurationMs !== undefined &&
272
+ maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
239
273
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
240
274
  // which dictates the value is either undefined or exactly 5 days in ms.
241
275
  // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
242
276
  throw new container_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
243
277
  }
244
- this.garbageCollector = garbageCollection_1.GarbageCollector.create({
278
+ this.garbageCollector = gc_1.GarbageCollector.create({
245
279
  runtime: this,
246
280
  gcOptions: this.runtimeOptions.gcOptions,
247
- baseSnapshot,
281
+ baseSnapshot: context.baseSnapshot,
248
282
  baseLogger: this.mc.logger,
249
283
  existing,
250
284
  metadata,
251
285
  createContainerMetadata: this.createContainerMetadata,
252
- isSummarizerClient: this.context.clientDetails.type === summarizerClientElection_1.summarizerClientType,
286
+ isSummarizerClient: this.context.clientDetails.type === summary_1.summarizerClientType,
253
287
  getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
254
288
  getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
255
289
  readAndParseBlob: async (id) => (0, driver_utils_1.readAndParse)(this.storage, id),
256
290
  getContainerDiagnosticId: () => this.context.id,
257
- activeConnection: () => this.deltaManager.active,
291
+ // GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
292
+ // delta manager would always return false for summarizer client.
293
+ activeConnection: () => this.innerDeltaManager.active,
258
294
  });
259
295
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
260
- this.summarizerNode = (0, runtime_utils_1.createRootSummarizerNodeWithGC)(telemetry_utils_1.ChildLogger.create(this.logger, "SummarizerNode"),
296
+ this.summarizerNode = (0, summary_1.createRootSummarizerNodeWithGC)(telemetry_utils_1.ChildLogger.create(this.logger, "SummarizerNode"),
261
297
  // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
262
298
  async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
263
299
  // Latest change sequence number, no changes since summary applied yet
264
300
  loadedFromSequenceNumber,
265
301
  // Summary reference sequence number, undefined if no summary yet
266
- baseSnapshot ? loadedFromSequenceNumber : undefined, {
302
+ context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
267
303
  // Must set to false to prevent sending summary handle which would be pointing to
268
304
  // a summary with an older protocol state.
269
305
  canReuseHandle: false,
@@ -272,56 +308,77 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
272
308
  throwOnFailure: true,
273
309
  // If GC should not run, let the summarizer node know so that it does not track GC state.
274
310
  gcDisabled: !this.garbageCollector.shouldRunGC,
275
- });
276
- if (baseSnapshot) {
277
- this.summarizerNode.updateBaseSummaryState(baseSnapshot);
278
- }
279
- this.dataStores = new dataStores_1.DataStores((0, dataStores_1.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));
280
- this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => {
311
+ },
312
+ // Function to get GC data if needed. This will always be called by the root summarizer node to get GC data.
313
+ async (fullGC) => this.getGCDataInternal(fullGC),
314
+ // Function to get the GC details from the base snapshot we loaded from.
315
+ async () => this.garbageCollector.getBaseGCDetails());
316
+ if (context.baseSnapshot) {
317
+ this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
318
+ }
319
+ this.dataStores = new dataStores_1.DataStores((0, dataStores_1.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));
320
+ this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
281
321
  if (!this.disposed) {
282
- this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId });
322
+ this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
323
+ localId,
324
+ blobId,
325
+ });
283
326
  }
284
- }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs);
327
+ }, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, () => this.getCurrentReferenceTimestampMs());
285
328
  this.scheduleManager = new scheduleManager_1.ScheduleManager(context.deltaManager, this, () => this.clientId, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
286
329
  this.pendingStateManager = new pendingStateManager_1.PendingStateManager({
287
330
  applyStashedOp: this.applyStashedOp.bind(this),
288
331
  clientId: () => this.clientId,
289
332
  close: this.closeFn,
290
333
  connected: () => this.connected,
291
- flush: this.flush.bind(this),
292
334
  reSubmit: this.reSubmit.bind(this),
293
335
  rollback: this.rollback.bind(this),
294
336
  orderSequentially: this.orderSequentially.bind(this),
295
337
  }, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
338
+ const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
339
+ const compressionOptions = disableCompression === true
340
+ ? {
341
+ minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
342
+ compressionAlgorithm: CompressionAlgorithms.lz4,
343
+ }
344
+ : runtimeOptions.compressionOptions;
345
+ const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
296
346
  this.outbox = new opLifecycle_1.Outbox({
297
347
  shouldSend: () => this.canSendOps(),
298
348
  pendingStateManager: this.pendingStateManager,
299
349
  containerContext: this.context,
300
350
  compressor: new opLifecycle_1.OpCompressor(this.mc.logger),
351
+ splitter: opSplitter,
301
352
  config: {
302
- compressionOptions: runtimeOptions.compressionOptions,
353
+ compressionOptions,
303
354
  maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
355
+ disablePartialFlush: disablePartialFlush === true,
304
356
  },
357
+ logger: this.mc.logger,
305
358
  });
306
359
  this.context.quorum.on("removeMember", (clientId) => {
307
360
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
308
361
  });
309
- this.summaryCollection = new summaryCollection_1.SummaryCollection(this.deltaManager, this.logger);
310
- this.dirtyContainer = this.context.attachState !== container_definitions_1.AttachState.Attached
311
- || this.pendingStateManager.hasPendingMessages();
362
+ this.summaryCollection = new summary_1.SummaryCollection(this.deltaManager, this.logger);
363
+ this.dirtyContainer =
364
+ this.context.attachState !== container_definitions_1.AttachState.Attached ||
365
+ this.pendingStateManager.hasPendingMessages();
312
366
  this.context.updateDirtyContainerState(this.dirtyContainer);
313
367
  if (this.summariesDisabled) {
314
368
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
315
369
  }
316
370
  else {
317
371
  const orderedClientLogger = telemetry_utils_1.ChildLogger.create(this.logger, "OrderedClientElection");
318
- const orderedClientCollection = new orderedClientElection_1.OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
319
- const orderedClientElectionForSummarizer = new orderedClientElection_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, summarizerClientElection_1.SummarizerClientElection.isClientEligible);
320
- this.summarizerClientElection = new summarizerClientElection_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary, this.summarizerClientElectionEnabled);
321
- if (this.context.clientDetails.type === summarizerClientElection_1.summarizerClientType) {
322
- this._summarizer = new summarizer_1.Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => runWhileConnectedCoordinator_1.RunWhileConnectedCoordinator.create(runtime));
372
+ const orderedClientCollection = new summary_1.OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
373
+ const orderedClientElectionForSummarizer = new summary_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, summary_1.SummarizerClientElection.isClientEligible);
374
+ this.summarizerClientElection = new summary_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
375
+ if (this.context.clientDetails.type === summary_1.summarizerClientType) {
376
+ this._summarizer = new summary_1.Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => summary_1.RunWhileConnectedCoordinator.create(runtime,
377
+ // Summarization runs in summarizer client and needs access to the real (non-proxy) active
378
+ // information. The proxy delta manager would always return false for summarizer client.
379
+ () => this.innerDeltaManager.active));
323
380
  }
324
- else if (summarizerClientElection_1.SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
381
+ else if (summary_1.SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
325
382
  // Only create a SummaryManager and SummarizerClientElection
326
383
  // if summaries are enabled and we are not the summarizer client.
327
384
  const defaultAction = () => {
@@ -341,7 +398,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
341
398
  };
342
399
  this.summaryCollection.on("default", defaultAction);
343
400
  // Create the SummaryManager and mark the initial state
344
- this.summaryManager = new summaryManager_1.SummaryManager(this.summarizerClientElection, this, // IConnectedState
401
+ this.summaryManager = new summary_1.SummaryManager(this.summarizerClientElection, this, // IConnectedState
345
402
  this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new throttler_1.Throttler(60 * 1000, // 60 sec delay window
346
403
  30 * 1000, // 30 sec max delay
347
404
  // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
@@ -354,7 +411,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
354
411
  this.deltaManager.on("readonly", (readonly) => {
355
412
  // we accumulate ops while being in read-only state.
356
413
  // once user gets write permissions and we have active connection, flush all pending ops.
357
- (0, common_utils_1.assert)(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
414
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
415
+ (0, common_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
358
416
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
359
417
  // when we either never send an op, or attempted to send it but we know for sure it was not
360
418
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -372,13 +430,31 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
372
430
  });
373
431
  // logging hardware telemetry
374
432
  logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
375
- 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 }));
433
+ 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({
434
+ disableCompression,
435
+ disableOpReentryCheck,
436
+ disableChunking,
437
+ disableAttachReorder: this.disableAttachReorder,
438
+ disablePartialFlush,
439
+ }), telemetryDocumentId: this.telemetryDocumentId }));
376
440
  (0, connectionTelemetry_1.ReportOpPerfTelemetry)(this.context.clientId, this.deltaManager, this.logger);
377
441
  (0, batchTracker_1.BindBatchTracker)(this, this.logger);
442
+ this.entryPoint = new common_utils_1.LazyPromise(async () => {
443
+ if (this.context.clientDetails.type === summary_1.summarizerClientType) {
444
+ (0, common_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
445
+ return this._summarizer;
446
+ }
447
+ return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
448
+ });
449
+ }
450
+ get IContainerRuntime() {
451
+ return this;
452
+ }
453
+ get IFluidRouter() {
454
+ return this;
378
455
  }
379
- get IContainerRuntime() { return this; }
380
- get IFluidRouter() { return this; }
381
456
  /**
457
+ * @deprecated - use loadRuntime instead.
382
458
  * Load the stores from a snapshot and returns the runtime.
383
459
  * @param context - Context of the container.
384
460
  * @param registryEntries - Mapping to the stores.
@@ -389,7 +465,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
389
465
  * allows mixin classes to leverage this method to define their own async initializer.
390
466
  */
391
467
  static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
392
- var _a, _b, _c;
468
+ let existingFlag = true;
469
+ if (!existing) {
470
+ existingFlag = false;
471
+ }
472
+ return this.loadRuntime({
473
+ context,
474
+ registryEntries,
475
+ existing: existingFlag,
476
+ requestHandler,
477
+ runtimeOptions,
478
+ containerScope,
479
+ containerRuntimeCtor,
480
+ });
481
+ }
482
+ /**
483
+ * Load the stores from a snapshot and returns the runtime.
484
+ * @param params - An object housing the runtime properties:
485
+ * - context - Context of the container.
486
+ * - registryEntries - Mapping from data store types to their corresponding factories.
487
+ * - existing - Pass 'true' if loading from an existing snapshot.
488
+ * - requestHandler - (optional) Request handler for the request() method of the container runtime.
489
+ * Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
490
+ * - runtimeOptions - Additional options to be passed to the runtime
491
+ * - containerScope - runtime services provided with context
492
+ * - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
493
+ * This allows mixin classes to leverage this method to define their own async initializer.
494
+ * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
495
+ * This object should provide all the functionality that the Container is expected to provide to the loader layer.
496
+ */
497
+ static async loadRuntime(params) {
498
+ var _a, _b, _c, _d;
499
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
393
500
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
394
501
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
395
502
  const backCompatContext = context;
@@ -399,46 +506,40 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
399
506
  runtimeVersion: packageVersion_1.pkgVersion,
400
507
  },
401
508
  });
402
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, compressionOptions = {
403
- minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
404
- compressionAlgorithm: CompressionAlgorithms.lz4
405
- }, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, } = runtimeOptions;
406
- const pendingRuntimeState = context.pendingLocalState;
407
- const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
408
- const storage = !pendingRuntimeState ?
409
- context.storage :
410
- new serializedSnapshotStorage_1.SerializedSnapshotStorage(() => { return context.storage; }, pendingRuntimeState.snapshotBlobs);
509
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, } = runtimeOptions;
411
510
  const registry = new dataStoreRegistry_1.FluidDataStoreRegistry(registryEntries);
412
511
  const tryFetchBlob = async (blobName) => {
413
- const blobId = baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.blobs[blobName];
414
- if (baseSnapshot && blobId) {
512
+ var _a;
513
+ const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
514
+ if (context.baseSnapshot && blobId) {
415
515
  // IContainerContext storage api return type still has undefined in 0.39 package version.
416
516
  // So once we release 0.40 container-defn package we can remove this check.
417
- (0, common_utils_1.assert)(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
418
- return (0, driver_utils_1.readAndParse)(storage, blobId);
517
+ (0, common_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
518
+ return (0, driver_utils_1.readAndParse)(context.storage, blobId);
419
519
  }
420
520
  };
421
521
  const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
422
- tryFetchBlob(summaryFormat_1.chunksBlobName),
423
- tryFetchBlob(summaryFormat_1.metadataBlobName),
424
- tryFetchBlob(summaryFormat_1.electedSummarizerBlobName),
425
- tryFetchBlob(summaryFormat_1.aliasBlobName),
522
+ tryFetchBlob(summary_1.chunksBlobName),
523
+ tryFetchBlob(summary_1.metadataBlobName),
524
+ tryFetchBlob(summary_1.electedSummarizerBlobName),
525
+ tryFetchBlob(summary_1.aliasBlobName),
426
526
  ]);
427
527
  const loadExisting = existing === true || context.existing === true;
428
528
  // read snapshot blobs needed for BlobManager to load
429
- const blobManagerSnapshot = await blobManager_1.BlobManager.load(baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[summaryFormat_1.blobsTreeName], async (id) => {
529
+ const blobManagerSnapshot = await blobManager_1.BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[summary_1.blobsTreeName], async (id) => {
430
530
  // IContainerContext storage api return type still has undefined in 0.39 package version.
431
531
  // So once we release 0.40 container-defn package we can remove this check.
432
- (0, common_utils_1.assert)(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
433
- return (0, driver_utils_1.readAndParse)(storage, id);
532
+ (0, common_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
533
+ return (0, driver_utils_1.readAndParse)(context.storage, id);
434
534
  });
435
535
  // Verify summary runtime sequence number matches protocol sequence number.
436
536
  const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
437
537
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
438
- if (!pendingRuntimeState && runtimeSequenceNumber !== undefined) {
538
+ if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
439
539
  const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
440
540
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
441
- if (loadSequenceNumberVerification !== "bypass" && runtimeSequenceNumber !== protocolSequenceNumber) {
541
+ if (loadSequenceNumberVerification !== "bypass" &&
542
+ runtimeSequenceNumber !== protocolSequenceNumber) {
442
543
  // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
443
544
  const error = new container_utils_1.DataCorruptionError(
444
545
  // pre-0.58 error message: SummaryMetadataMismatch
@@ -447,7 +548,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
447
548
  logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
448
549
  }
449
550
  else {
551
+ // Call both close and dispose as closeFn implementation will no longer dispose runtime in future
450
552
  context.closeFn(error);
553
+ (_d = context.disposeFn) === null || _d === void 0 ? void 0 : _d.call(context, error);
451
554
  }
452
555
  }
453
556
  }
@@ -456,15 +559,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
456
559
  gcOptions,
457
560
  loadSequenceNumberVerification,
458
561
  flushMode,
459
- enableOfflineLoad,
460
562
  compressionOptions,
461
563
  maxBatchSizeInBytes,
462
- }, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
463
- if (pendingRuntimeState) {
464
- await runtime.processSavedOps(pendingRuntimeState);
465
- // delete these once runtime has seen them to save space
466
- pendingRuntimeState.savedOps = [];
467
- }
564
+ chunkSizeInBytes,
565
+ enableOpReentryCheck,
566
+ }, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
567
+ initializeEntryPoint);
568
+ // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
569
+ // at 1, so we won't see a replayed saved op with a sequence number of 0.
570
+ await runtime.pendingStateManager.applyStashedOpsAt(0);
468
571
  // Initialize the base state of the runtime before it's returned.
469
572
  await runtime.initializeBaseState();
470
573
  return runtime;
@@ -478,9 +581,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
478
581
  get clientDetails() {
479
582
  return this.context.clientDetails;
480
583
  }
481
- get deltaManager() {
482
- return this.context.deltaManager;
483
- }
484
584
  get storage() {
485
585
  return this._storage;
486
586
  }
@@ -488,8 +588,18 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
488
588
  // eslint-disable-next-line @typescript-eslint/unbound-method
489
589
  return this.reSubmit;
490
590
  }
591
+ get disposeFn() {
592
+ var _a;
593
+ // In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
594
+ return (_a = this.context.disposeFn) !== null && _a !== void 0 ? _a : this.context.closeFn;
595
+ }
491
596
  get closeFn() {
492
- return this.context.closeFn;
597
+ // Also call disposeFn to retain functionality of runtime being disposed on close
598
+ return (error) => {
599
+ var _a, _b;
600
+ this.context.closeFn(error);
601
+ (_b = (_a = this.context).disposeFn) === null || _b === void 0 ? void 0 : _b.call(_a, error);
602
+ };
493
603
  }
494
604
  get flushMode() {
495
605
  return this._flushMode;
@@ -506,6 +616,23 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
506
616
  get IFluidHandleContext() {
507
617
  return this.handleContext;
508
618
  }
619
+ /**
620
+ * Invokes the given callback and expects that no ops are submitted
621
+ * until execution finishes. If an op is submitted, an error will be raised.
622
+ *
623
+ * Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
624
+ *
625
+ * @param callback - the callback to be invoked
626
+ */
627
+ ensureNoDataModelChanges(callback) {
628
+ this.ensureNoDataModelChangesCalls++;
629
+ try {
630
+ return callback();
631
+ }
632
+ finally {
633
+ this.ensureNoDataModelChangesCalls--;
634
+ }
635
+ }
509
636
  get connected() {
510
637
  return this._connected;
511
638
  }
@@ -514,48 +641,20 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
514
641
  var _a;
515
642
  return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
516
643
  }
517
- get disposed() { return this._disposed; }
644
+ get disposed() {
645
+ return this._disposed;
646
+ }
518
647
  get summarizer() {
519
648
  (0, common_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
520
649
  return this._summarizer;
521
650
  }
522
651
  isSummariesDisabled() {
523
- // back-compat: disableSummaries was moved from ISummaryRuntimeOptions
524
- // to ISummaryConfiguration in 0.60.
525
- if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
526
- return true;
527
- }
528
652
  return this.summaryConfiguration.state === "disabled";
529
653
  }
530
654
  isHeuristicsDisabled() {
531
- var _a;
532
- // back-compat: disableHeuristics was moved from ISummarizerOptions
533
- // to ISummaryConfiguration in 0.60.
534
- if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
535
- return true;
536
- }
537
655
  return this.summaryConfiguration.state === "disableHeuristics";
538
656
  }
539
- isSummarizerClientElectionEnabled() {
540
- var _a;
541
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
542
- return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
543
- }
544
- // back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
545
- // to ISummaryConfiguration in 0.60.
546
- if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
547
- return true;
548
- }
549
- return this.summaryConfiguration.state !== "disabled"
550
- ? this.summaryConfiguration.summarizerClientElection === true
551
- : false;
552
- }
553
657
  getMaxOpsSinceLastSummary() {
554
- // back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
555
- // to ISummaryConfiguration in 0.60.
556
- if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
557
- return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
558
- }
559
658
  return this.summaryConfiguration.state !== "disabled"
560
659
  ? this.summaryConfiguration.maxOpsSinceLastSummary
561
660
  : 0;
@@ -574,7 +673,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
574
673
  * Initializes the state from the base snapshot this container runtime loaded from.
575
674
  */
576
675
  async initializeBaseState() {
577
- await this.initializeBaseSnapshotBlobs();
578
676
  await this.garbageCollector.initializeBaseState();
579
677
  }
580
678
  dispose(error) {
@@ -599,16 +697,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
599
697
  this.emit("dispose");
600
698
  this.removeAllListeners();
601
699
  }
602
- get IFluidTokenProvider() {
603
- var _a;
604
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
605
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
606
- return {
607
- intelligence: this.options.intelligence,
608
- };
609
- }
610
- return undefined;
611
- }
612
700
  /**
613
701
  * Notifies this object about the request made to the container.
614
702
  * @param request - Request made to the handler.
@@ -654,7 +742,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
654
742
  status: 200,
655
743
  mimeType: "fluid/object",
656
744
  value: blob,
657
- } : (0, runtime_utils_1.create404Response)(request);
745
+ }
746
+ : (0, runtime_utils_1.create404Response)(request);
658
747
  }
659
748
  else if (requestParser.pathParts.length > 0) {
660
749
  const dataStore = await this.getDataStoreFromRequest(id, request);
@@ -670,41 +759,35 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
670
759
  return (0, runtime_utils_1.exceptionToResponse)(error);
671
760
  }
672
761
  }
762
+ /**
763
+ * {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
764
+ */
765
+ async getEntryPoint() {
766
+ return this.entryPoint;
767
+ }
673
768
  internalId(maybeAlias) {
674
769
  var _a;
675
770
  return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
676
771
  }
677
772
  async getDataStoreFromRequest(id, request) {
678
- var _a, _b, _c, _d, _e;
679
- const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
680
- ? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait]
681
- : true;
682
- const viaHandle = typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[RuntimeHeaders.viaHandle]) === "boolean"
683
- ? (_d = request.headers) === null || _d === void 0 ? void 0 : _d[RuntimeHeaders.viaHandle]
684
- : false;
773
+ var _a, _b, _c;
774
+ const headerData = {};
775
+ if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
776
+ headerData.wait = request.headers[RuntimeHeaders.wait];
777
+ }
778
+ if (typeof ((_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.viaHandle]) === "boolean") {
779
+ headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
780
+ }
781
+ if (typeof ((_c = request.headers) === null || _c === void 0 ? void 0 : _c[exports.AllowTombstoneRequestHeaderKey]) === "boolean") {
782
+ headerData.allowTombstone = request.headers[exports.AllowTombstoneRequestHeaderKey];
783
+ }
685
784
  await this.dataStores.waitIfPendingAlias(id);
686
785
  const internalId = this.internalId(id);
687
- const dataStoreContext = await this.dataStores.getDataStore(internalId, wait, viaHandle);
688
- /**
689
- * If GC should run and this an external app request with "externalRequest" header, we need to return
690
- * an error if the data store being requested is marked as unreferenced as per the data store's base
691
- * GC data.
692
- *
693
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
694
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
695
- */
696
- if (((_e = request.headers) === null || _e === void 0 ? void 0 : _e[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
697
- // The data store is referenced if used routes in the base summary has a route to self.
698
- // Older documents may not have used routes in the summary. They are considered referenced.
699
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
700
- if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
701
- throw (0, runtime_utils_1.responseToException)((0, runtime_utils_1.create404Response)(request), request);
702
- }
703
- }
786
+ const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
704
787
  const dataStoreChannel = await dataStoreContext.realize();
705
788
  // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
706
789
  // the same as GC nodes id.
707
- const urlWithoutQuery = (0, garbage_collector_1.trimLeadingAndTrailingSlashes)(request.url.split("?")[0]);
790
+ const urlWithoutQuery = (0, gc_1.trimLeadingAndTrailingSlashes)(request.url.split("?")[0]);
708
791
  this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
709
792
  return dataStoreChannel;
710
793
  }
@@ -716,33 +799,33 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
716
799
  summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
717
800
  // The last message processed at the time of summary. If there are no new messages, use the message from the
718
801
  // last summary.
719
- message: (_a = (0, summaryFormat_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
720
- (0, runtime_utils_1.addBlobToSummary)(summaryTree, summaryFormat_1.metadataBlobName, JSON.stringify(metadata));
802
+ message: (_a = (0, summary_1.extractSummaryMetadataMessage)(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
803
+ (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.metadataBlobName, JSON.stringify(metadata));
721
804
  }
722
805
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
723
806
  var _a;
724
807
  this.addMetadataToSummary(summaryTree);
725
808
  if (this.remoteMessageProcessor.partialMessages.size > 0) {
726
809
  const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
727
- (0, runtime_utils_1.addBlobToSummary)(summaryTree, summaryFormat_1.chunksBlobName, content);
810
+ (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.chunksBlobName, content);
728
811
  }
729
812
  const dataStoreAliases = this.dataStores.aliases;
730
813
  if (dataStoreAliases.size > 0) {
731
- (0, runtime_utils_1.addBlobToSummary)(summaryTree, summaryFormat_1.aliasBlobName, JSON.stringify([...dataStoreAliases]));
814
+ (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.aliasBlobName, JSON.stringify([...dataStoreAliases]));
732
815
  }
733
816
  if (this.summarizerClientElection) {
734
817
  const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
735
- (0, runtime_utils_1.addBlobToSummary)(summaryTree, summaryFormat_1.electedSummarizerBlobName, electedSummarizerContent);
818
+ (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.electedSummarizerBlobName, electedSummarizerContent);
736
819
  }
737
820
  const blobManagerSummary = this.blobManager.summarize();
738
821
  // Some storage (like git) doesn't allow empty tree, so we can omit it.
739
822
  // and the blob manager can handle the tree not existing when loading
740
823
  if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
741
- (0, runtime_utils_1.addTreeToSummary)(summaryTree, summaryFormat_1.blobsTreeName, blobManagerSummary);
824
+ (0, runtime_utils_1.addTreeToSummary)(summaryTree, summary_1.blobsTreeName, blobManagerSummary);
742
825
  }
743
826
  const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
744
827
  if (gcSummary !== undefined) {
745
- (0, runtime_utils_1.addSummarizeResultToSummary)(summaryTree, garbageCollectionConstants_1.gcTreeKey, gcSummary);
828
+ (0, runtime_utils_1.addSummarizeResultToSummary)(summaryTree, runtime_definitions_1.gcTreeKey, gcSummary);
746
829
  }
747
830
  }
748
831
  // Track how many times the container tries to reconnect with pending messages.
@@ -832,7 +915,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
832
915
  // If attachment blobs were added while disconnected, we need to delay
833
916
  // propagation of the "connected" event until we have uploaded them to
834
917
  // ensure we don't submit ops referencing a blob that has not been uploaded
835
- const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
918
+ // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
919
+ const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
836
920
  if (connecting && this.blobManager.hasPendingOfflineUploads) {
837
921
  (0, common_utils_1.assert)(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
838
922
  (0, common_utils_1.assert)(!!clientId, 0x393 /* Must have clientId when connecting */);
@@ -867,9 +951,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
867
951
  if (reconnection) {
868
952
  this.consecutiveReconnects++;
869
953
  if (!this.shouldContinueReconnecting()) {
870
- this.closeFn(container_utils_1.DataProcessingError.create(
871
- // eslint-disable-next-line max-len
872
- "Runtime detected too many reconnects with no progress syncing local ops. Batch of ops is likely too large (over 1Mb)", "setConnectionState", undefined, {
954
+ this.closeFn(container_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
873
955
  dataLoss: 1,
874
956
  attempts: this.consecutiveReconnects,
875
957
  pendingMessages: this.pendingStateManager.pendingMessagesCount,
@@ -884,12 +966,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
884
966
  this.garbageCollector.setConnectionState(connected, clientId);
885
967
  (0, telemetry_utils_1.raiseConnectedEvent)(this.mc.logger, this, connected, clientId);
886
968
  }
969
+ async notifyOpReplay(message) {
970
+ await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
971
+ }
887
972
  process(messageArg, local) {
888
973
  var _a;
889
974
  this.verifyNotClosed();
890
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
891
- this.savedOps.push(messageArg);
892
- }
893
975
  // Whether or not the message is actually a runtime message.
894
976
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
895
977
  // or something different, like a system message.
@@ -903,7 +985,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
903
985
  this.scheduleManager.beforeOpProcessing(message);
904
986
  try {
905
987
  let localOpMetadata;
906
- if (local && runtimeMessage) {
988
+ if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
907
989
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
908
990
  }
909
991
  // If there are no more pending messages after processing a local message,
@@ -929,7 +1011,19 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
929
1011
  case ContainerMessageType.Rejoin:
930
1012
  break;
931
1013
  default:
932
- (0, common_utils_1.assert)(!runtimeMessage, 0x3ce /* Runtime message of unknown type */);
1014
+ if (runtimeMessage) {
1015
+ const error = container_utils_1.DataProcessingError.create(
1016
+ // Former assert 0x3ce
1017
+ "Runtime message of unknown type", "OpProcessing", message, {
1018
+ local,
1019
+ type: message.type,
1020
+ contentType: typeof message.contents,
1021
+ batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
1022
+ compression: message.compression,
1023
+ });
1024
+ this.closeFn(error);
1025
+ throw error;
1026
+ }
933
1027
  }
934
1028
  // For back-compat, notify only about runtime messages for now.
935
1029
  if (runtimeMessage) {
@@ -976,7 +1070,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
976
1070
  if (message.clientId === this.clientId && this.connected) {
977
1071
  // Check to see if the signal was lost.
978
1072
  if (this._perfSignalData.trackingSignalSequenceNumber !== undefined &&
979
- envelope.clientSignalSequenceNumber > this._perfSignalData.trackingSignalSequenceNumber) {
1073
+ envelope.clientSignalSequenceNumber >
1074
+ this._perfSignalData.trackingSignalSequenceNumber) {
980
1075
  this._perfSignalData.signalsLost++;
981
1076
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
982
1077
  this.logger.sendErrorEvent({
@@ -987,8 +1082,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
987
1082
  clientSignalSequenceNumber: envelope.clientSignalSequenceNumber,
988
1083
  });
989
1084
  }
990
- else if (envelope.clientSignalSequenceNumber === this._perfSignalData.trackingSignalSequenceNumber) {
991
- this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1085
+ else if (envelope.clientSignalSequenceNumber ===
1086
+ this._perfSignalData.trackingSignalSequenceNumber) {
1087
+ // only logging for the first connection and the trackingSignalSequenceNUmber.
1088
+ if (this.consecutiveReconnects === 0) {
1089
+ this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1090
+ }
992
1091
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
993
1092
  }
994
1093
  }
@@ -1005,7 +1104,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1005
1104
  async getRootDataStoreChannel(id, wait = true) {
1006
1105
  await this.dataStores.waitIfPendingAlias(id);
1007
1106
  const internalId = this.internalId(id);
1008
- const context = await this.dataStores.getDataStore(internalId, wait, false /* viaHandle */);
1107
+ const context = await this.dataStores.getDataStore(internalId, { wait });
1009
1108
  (0, common_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1010
1109
  return context.realize();
1011
1110
  }
@@ -1054,7 +1153,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1054
1153
  finally {
1055
1154
  this._orderSequentiallyCalls--;
1056
1155
  }
1057
- if (this.flushMode === runtime_definitions_1.FlushMode.Immediate && this._orderSequentiallyCalls === 0) {
1156
+ // We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
1157
+ if (this.flushMode !== runtime_definitions_1.FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
1058
1158
  this.flush();
1059
1159
  }
1060
1160
  return result;
@@ -1073,7 +1173,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1073
1173
  return this.dataStores.createDetachedDataStoreCore(pkg, false);
1074
1174
  }
1075
1175
  async _createDataStoreWithProps(pkg, props, id = (0, uuid_1.v4)()) {
1076
- const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props).realize();
1176
+ const fluidDataStore = await this.dataStores
1177
+ ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
1178
+ .realize();
1077
1179
  return (0, dataStore_1.channelToDataStore)(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1078
1180
  }
1079
1181
  async _createDataStore(pkg, id = (0, uuid_1.v4)(), props) {
@@ -1082,13 +1184,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1082
1184
  .realize();
1083
1185
  }
1084
1186
  canSendOps() {
1085
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
1187
+ // Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
1188
+ // container runtime's ability to send ops depend on the actual readonly state of the delta manager.
1189
+ return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1086
1190
  }
1087
1191
  /**
1088
1192
  * Are we in the middle of batching ops together?
1089
1193
  */
1090
1194
  currentlyBatching() {
1091
- return this.flushMode === runtime_definitions_1.FlushMode.TurnBased || this._orderSequentiallyCalls !== 0;
1195
+ return this.flushMode !== runtime_definitions_1.FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
1092
1196
  }
1093
1197
  getQuorum() {
1094
1198
  return this.context.quorum;
@@ -1177,7 +1281,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1177
1281
  }
1178
1282
  const summarizeResult = this.dataStores.createSummary(telemetryContext);
1179
1283
  // Wrap data store summaries in .channels subtree.
1180
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1284
+ (0, summary_1.wrapSummaryInChannelsTree)(summarizeResult);
1181
1285
  this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1182
1286
  return summarizeResult.summary;
1183
1287
  }
@@ -1193,7 +1297,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1193
1297
  async summarizeInternal(fullTree, trackState, telemetryContext) {
1194
1298
  const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1195
1299
  // Wrap data store summaries in .channels subtree.
1196
- (0, summaryFormat_1.wrapSummaryInChannelsTree)(summarizeResult);
1300
+ (0, summary_1.wrapSummaryInChannelsTree)(summarizeResult);
1197
1301
  const pathPartsForChildren = [runtime_definitions_1.channelsTreeName];
1198
1302
  this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1199
1303
  return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
@@ -1204,81 +1308,98 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1204
1308
  async summarize(options) {
1205
1309
  this.verifyNotClosed();
1206
1310
  const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
1311
+ const telemetryContext = new runtime_utils_1.TelemetryContext();
1312
+ // Add the options that are used to generate this summary to the telemetry context.
1313
+ telemetryContext.setMultiple("fluid_Summarize", "Options", {
1314
+ fullTree,
1315
+ trackState,
1316
+ runGC,
1317
+ fullGC,
1318
+ runSweep,
1319
+ });
1207
1320
  let gcStats;
1208
1321
  if (runGC) {
1209
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1322
+ gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1210
1323
  }
1211
- const telemetryContext = new runtime_utils_1.TelemetryContext();
1212
1324
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1213
- this.logger.sendTelemetryEvent({ eventName: "SummarizeTelemetry", details: telemetryContext.serialize() });
1325
+ this.logger.sendTelemetryEvent({
1326
+ eventName: "SummarizeTelemetry",
1327
+ details: telemetryContext.serialize(),
1328
+ });
1214
1329
  (0, common_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1215
1330
  return { stats, summary, gcStats };
1216
1331
  }
1217
1332
  /**
1218
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
1219
1333
  * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
1220
1334
  * the garbage collector of references detected since the last GC run. Most references are notified immediately
1221
1335
  * but there can be some for which async operation is required (such as detecting new root data stores).
1336
+ * @see IGarbageCollectionRuntime.updateStateBeforeGC
1222
1337
  */
1223
1338
  async updateStateBeforeGC() {
1224
1339
  return this.dataStores.updateStateBeforeGC();
1225
1340
  }
1341
+ async getGCDataInternal(fullGC) {
1342
+ return this.dataStores.getGCData(fullGC);
1343
+ }
1226
1344
  /**
1227
- * Implementation of IGarbageCollectionRuntime::getGCData.
1228
1345
  * Generates and returns the GC data for this container.
1229
1346
  * @param fullGC - true to bypass optimizations and force full generation of GC data.
1347
+ * @see IGarbageCollectionRuntime.getGCData
1230
1348
  */
1231
1349
  async getGCData(fullGC) {
1232
- const builder = new garbage_collector_1.GCDataBuilder();
1233
- const dsGCData = await this.dataStores.getGCData(fullGC);
1350
+ const builder = new runtime_utils_1.GCDataBuilder();
1351
+ const dsGCData = await this.summarizerNode.getGCData(fullGC);
1234
1352
  builder.addNodes(dsGCData.gcNodes);
1235
1353
  const blobsGCData = this.blobManager.getGCData(fullGC);
1236
1354
  builder.addNodes(blobsGCData.gcNodes);
1237
1355
  return builder.getGCData();
1238
1356
  }
1239
1357
  /**
1240
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
1241
1358
  * After GC has run, called to notify this container's nodes of routes that are used in it.
1242
1359
  * @param usedRoutes - The routes that are used in all nodes in this Container.
1360
+ * @see IGarbageCollectionRuntime.updateUsedRoutes
1243
1361
  */
1244
1362
  updateUsedRoutes(usedRoutes) {
1245
1363
  // Update our summarizer node's used routes. Updating used routes in summarizer node before
1246
1364
  // summarizing is required and asserted by the the summarizer node. We are the root and are
1247
1365
  // always referenced, so the used routes is only self-route (empty string).
1248
1366
  this.summarizerNode.updateUsedRoutes([""]);
1249
- const blobManagerUsedRoutes = [];
1250
- const dataStoreUsedRoutes = [];
1251
- for (const route of usedRoutes) {
1252
- if (this.isBlobPath(route)) {
1253
- blobManagerUsedRoutes.push(route);
1254
- }
1255
- else {
1256
- dataStoreUsedRoutes.push(route);
1257
- }
1258
- }
1259
- this.blobManager.updateUsedRoutes(blobManagerUsedRoutes);
1260
- this.dataStores.updateUsedRoutes(dataStoreUsedRoutes);
1367
+ const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
1368
+ this.dataStores.updateUsedRoutes(dataStoreRoutes);
1261
1369
  }
1262
1370
  /**
1263
- * This is called to update objects whose routes are unused. The unused objects are either deleted or marked as
1264
- * tombstones.
1265
- * @param unusedRoutes - The routes that are unused in all data stores and attachment blobs in this Container.
1266
- * @param tombstone - if true, the objects corresponding to unused routes are marked tombstones. Otherwise, they
1267
- * are deleted.
1371
+ * This is called to update objects whose routes are unused.
1372
+ * @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
1268
1373
  */
1269
- updateUnusedRoutes(unusedRoutes, tombstone) {
1270
- const blobManagerUnusedRoutes = [];
1271
- const dataStoreUnusedRoutes = [];
1272
- for (const route of unusedRoutes) {
1273
- if (this.isBlobPath(route)) {
1274
- blobManagerUnusedRoutes.push(route);
1275
- }
1276
- else {
1277
- dataStoreUnusedRoutes.push(route);
1278
- }
1279
- }
1280
- this.blobManager.updateUnusedRoutes(blobManagerUnusedRoutes, tombstone);
1281
- this.dataStores.updateUnusedRoutes(dataStoreUnusedRoutes, tombstone);
1374
+ updateUnusedRoutes(unusedRoutes) {
1375
+ const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
1376
+ this.blobManager.updateUnusedRoutes(blobManagerRoutes);
1377
+ this.dataStores.updateUnusedRoutes(dataStoreRoutes);
1378
+ }
1379
+ /**
1380
+ * @deprecated - Replaced by deleteSweepReadyNodes.
1381
+ */
1382
+ deleteUnusedNodes(unusedRoutes) {
1383
+ throw new Error("deleteUnusedRoutes should not be called");
1384
+ }
1385
+ /**
1386
+ * After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
1387
+ * @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
1388
+ * @returns - The routes of nodes that were deleted.
1389
+ */
1390
+ deleteSweepReadyNodes(sweepReadyRoutes) {
1391
+ const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
1392
+ const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
1393
+ return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
1394
+ }
1395
+ /**
1396
+ * This is called to update objects that are tombstones.
1397
+ * @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
1398
+ */
1399
+ updateTombstonedRoutes(tombstonedRoutes) {
1400
+ const { blobManagerRoutes, dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
1401
+ this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
1402
+ this.dataStores.updateTombstonedRoutes(dataStoreRoutes);
1282
1403
  }
1283
1404
  /**
1284
1405
  * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
@@ -1296,9 +1417,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1296
1417
  getNodeType(nodePath) {
1297
1418
  var _a;
1298
1419
  if (this.isBlobPath(nodePath)) {
1299
- return garbageCollection_1.GCNodeType.Blob;
1420
+ return gc_1.GCNodeType.Blob;
1300
1421
  }
1301
- return (_a = this.dataStores.getGCNodeType(nodePath)) !== null && _a !== void 0 ? _a : garbageCollection_1.GCNodeType.Other;
1422
+ return (_a = this.dataStores.getGCNodeType(nodePath)) !== null && _a !== void 0 ? _a : gc_1.GCNodeType.Other;
1302
1423
  }
1303
1424
  /**
1304
1425
  * Called by GC to retrieve the package path of the node with the given path. The node should belong to a
@@ -1306,10 +1427,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1306
1427
  */
1307
1428
  async getGCNodePackagePath(nodePath) {
1308
1429
  switch (this.getNodeType(nodePath)) {
1309
- case garbageCollection_1.GCNodeType.Blob:
1310
- return ["_blobs"];
1311
- case garbageCollection_1.GCNodeType.DataStore:
1312
- case garbageCollection_1.GCNodeType.SubDataStore:
1430
+ case gc_1.GCNodeType.Blob:
1431
+ return [blobManager_1.BlobManager.basePath];
1432
+ case gc_1.GCNodeType.DataStore:
1433
+ case gc_1.GCNodeType.SubDataStore:
1313
1434
  return this.dataStores.getDataStorePackagePath(nodePath);
1314
1435
  default:
1315
1436
  (0, common_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
@@ -1325,12 +1446,31 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1325
1446
  }
1326
1447
  return true;
1327
1448
  }
1449
+ /**
1450
+ * From a given list of routes, separate and return routes that belong to blob manager and data stores.
1451
+ * @param routes - A list of routes that can belong to data stores or blob manager.
1452
+ * @returns - Two route lists - One that contains routes for blob manager and another one that contains routes
1453
+ * for data stores.
1454
+ */
1455
+ getDataStoreAndBlobManagerRoutes(routes) {
1456
+ const blobManagerRoutes = [];
1457
+ const dataStoreRoutes = [];
1458
+ for (const route of routes) {
1459
+ if (this.isBlobPath(route)) {
1460
+ blobManagerRoutes.push(route);
1461
+ }
1462
+ else {
1463
+ dataStoreRoutes.push(route);
1464
+ }
1465
+ }
1466
+ return { blobManagerRoutes, dataStoreRoutes };
1467
+ }
1328
1468
  /**
1329
1469
  * Runs garbage collection and updates the reference / used state of the nodes in the container.
1330
1470
  * @returns the statistics of the garbage collection run; undefined if GC did not run.
1331
1471
  */
1332
- async collectGarbage(options) {
1333
- return this.garbageCollector.collectGarbage(options);
1472
+ async collectGarbage(options, telemetryContext) {
1473
+ return this.garbageCollector.collectGarbage(options, telemetryContext);
1334
1474
  }
1335
1475
  /**
1336
1476
  * Called when a new outbound reference is added to another node. This is used by garbage collection to identify
@@ -1351,7 +1491,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1351
1491
  */
1352
1492
  async submitSummary(options) {
1353
1493
  var _a, _b;
1354
- const { fullTree, refreshLatestAck, summaryLogger } = options;
1494
+ const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1355
1495
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1356
1496
  // use it for all events logged during this summary.
1357
1497
  const summaryNumber = this.nextSummaryNumber;
@@ -1367,8 +1507,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1367
1507
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1368
1508
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1369
1509
  }
1510
+ const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1370
1511
  try {
1371
1512
  await this.deltaManager.inbound.pause();
1513
+ if (shouldPauseInboundSignal) {
1514
+ await this.deltaManager.inboundSignal.pause();
1515
+ }
1372
1516
  const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1373
1517
  const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1374
1518
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
@@ -1396,7 +1540,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1396
1540
  if (this.deltaManager.lastSequenceNumber !== summaryRefSeqNum) {
1397
1541
  return {
1398
1542
  continue: false,
1399
- // eslint-disable-next-line max-len
1400
1543
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1401
1544
  };
1402
1545
  }
@@ -1404,7 +1547,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1404
1547
  if (lastAck !== this.summaryCollection.latestAck) {
1405
1548
  return {
1406
1549
  continue: false,
1407
- // eslint-disable-next-line max-len
1408
1550
  error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
1409
1551
  };
1410
1552
  }
@@ -1426,7 +1568,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1426
1568
  const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
1427
1569
  try {
1428
1570
  summarizeResult = await this.summarize({
1429
- fullTree: fullTree !== null && fullTree !== void 0 ? fullTree : forcedFullTree,
1571
+ fullTree: fullTree || forcedFullTree,
1430
1572
  trackState: true,
1431
1573
  summaryLogger: summaryNumberLogger,
1432
1574
  runGC: this.garbageCollector.shouldRunGC,
@@ -1449,8 +1591,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1449
1591
  const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1450
1592
  (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1451
1593
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1452
- const gcSummaryTreeStats = summaryTree.tree[garbageCollectionConstants_1.gcTreeKey]
1453
- ? (0, runtime_utils_1.calculateStats)(summaryTree.tree[garbageCollectionConstants_1.gcTreeKey])
1594
+ const gcSummaryTreeStats = summaryTree.tree[runtime_definitions_1.gcTreeKey]
1595
+ ? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
1454
1596
  : undefined;
1455
1597
  const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_a = summarizeResult.gcStats) === null || _a === void 0 ? void 0 : _a.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, summaryNumber }, partialStats);
1456
1598
  const generateSummaryData = {
@@ -1471,8 +1613,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1471
1613
  // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1472
1614
  // the one fetched from storage as parent as that is the latest.
1473
1615
  let summaryContext;
1474
- if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
1475
- && latestSnapshotVersionId !== undefined) {
1616
+ if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId &&
1617
+ latestSnapshotVersionId !== undefined) {
1476
1618
  summaryContext = {
1477
1619
  proposalHandle: undefined,
1478
1620
  ackHandle: latestSnapshotVersionId,
@@ -1515,7 +1657,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1515
1657
  }
1516
1658
  let clientSequenceNumber;
1517
1659
  try {
1518
- clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
1660
+ clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
1519
1661
  }
1520
1662
  catch (error) {
1521
1663
  return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
@@ -1529,6 +1671,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1529
1671
  this.summarizerNode.clearSummary();
1530
1672
  // Restart the delta manager
1531
1673
  this.deltaManager.inbound.resume();
1674
+ if (shouldPauseInboundSignal) {
1675
+ this.deltaManager.inboundSignal.resume();
1676
+ }
1532
1677
  }
1533
1678
  }
1534
1679
  hasPendingMessages() {
@@ -1571,16 +1716,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1571
1716
  }
1572
1717
  submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
1573
1718
  this.verifyNotClosed();
1719
+ this.verifyCanSubmitOps();
1574
1720
  // There should be no ops in detached container state!
1575
1721
  (0, common_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1576
- const deserializedContent = { type, contents };
1577
- const serializedContent = JSON.stringify(deserializedContent);
1578
- if (this.deltaManager.readOnlyInfo.readonly) {
1579
- this.logger.sendTelemetryEvent({ eventName: "SubmitOpInReadonly", connected: this.connected });
1722
+ const serializedContent = JSON.stringify({ type, contents });
1723
+ // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
1724
+ // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
1725
+ if (this.innerDeltaManager.readOnlyInfo.readonly) {
1726
+ this.logger.sendTelemetryEvent({
1727
+ eventName: "SubmitOpInReadonly",
1728
+ connected: this.connected,
1729
+ });
1580
1730
  }
1581
1731
  const message = {
1582
1732
  contents: serializedContent,
1583
- deserializedContent,
1733
+ deserializedContent: JSON.parse(serializedContent),
1584
1734
  metadata,
1585
1735
  localOpMetadata,
1586
1736
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
@@ -1606,8 +1756,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1606
1756
  // issue than sending.
1607
1757
  // Please note that this does not change file format, so it can be disabled in the future if this
1608
1758
  // optimization no longer makes sense (for example, batch compression may make it less appealing).
1609
- if (this.currentlyBatching() && type === ContainerMessageType.Attach &&
1610
- this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder") !== true) {
1759
+ if (this.currentlyBatching() &&
1760
+ type === ContainerMessageType.Attach &&
1761
+ this.disableAttachReorder !== true) {
1611
1762
  this.outbox.submitAttach(message);
1612
1763
  }
1613
1764
  else {
@@ -1616,14 +1767,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1616
1767
  if (!this.currentlyBatching()) {
1617
1768
  this.flush();
1618
1769
  }
1619
- else if (!this.flushMicroTaskExists) {
1620
- this.flushMicroTaskExists = true;
1621
- // Queue a microtask to detect the end of the turn and force a flush.
1622
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1623
- Promise.resolve().then(() => {
1624
- this.flushMicroTaskExists = false;
1625
- this.flush();
1626
- }).catch((error) => { this.closeFn(error); });
1770
+ else {
1771
+ this.scheduleFlush();
1627
1772
  }
1628
1773
  }
1629
1774
  catch (error) {
@@ -1634,14 +1779,47 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1634
1779
  this.updateDocumentDirtyState(true);
1635
1780
  }
1636
1781
  }
1637
- submitSummaryMessage(contents) {
1782
+ scheduleFlush() {
1783
+ if (this.flushTaskExists) {
1784
+ return;
1785
+ }
1786
+ this.flushTaskExists = true;
1787
+ const flush = () => {
1788
+ this.flushTaskExists = false;
1789
+ try {
1790
+ this.flush();
1791
+ }
1792
+ catch (error) {
1793
+ this.closeFn(error);
1794
+ }
1795
+ };
1796
+ switch (this.flushMode) {
1797
+ case runtime_definitions_1.FlushMode.TurnBased:
1798
+ // When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
1799
+ // batch at the end of the turn
1800
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1801
+ Promise.resolve().then(flush);
1802
+ break;
1803
+ // FlushModeExperimental is experimental and not exposed directly in the runtime APIs
1804
+ case runtime_definitions_1.FlushModeExperimental.Async:
1805
+ // When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
1806
+ // batch when all micro-tasks are complete.
1807
+ // Compared to TurnBased, this flush mode will capture more ops into the same batch.
1808
+ setTimeout(flush, 0);
1809
+ break;
1810
+ default:
1811
+ (0, common_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
1812
+ break;
1813
+ }
1814
+ }
1815
+ submitSummaryMessage(contents, referenceSequenceNumber) {
1638
1816
  this.verifyNotClosed();
1639
1817
  (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
1640
1818
  // System message should not be sent in the middle of the batch.
1641
1819
  (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
1642
1820
  // back-compat: ADO #1385: Make this call unconditional in the future
1643
1821
  return this.context.submitSummaryFn !== undefined
1644
- ? this.context.submitSummaryFn(contents)
1822
+ ? this.context.submitSummaryFn(contents, referenceSequenceNumber)
1645
1823
  : this.context.submitFn(protocol_definitions_1.MessageType.Summarize, contents, false);
1646
1824
  }
1647
1825
  /**
@@ -1653,6 +1831,32 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1653
1831
  throw new Error("Runtime is closed");
1654
1832
  }
1655
1833
  }
1834
+ verifyCanSubmitOps() {
1835
+ if (this.ensureNoDataModelChangesCalls > 0) {
1836
+ const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
1837
+ if (this.opReentryCallsToReport > 0) {
1838
+ this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
1839
+ // We need to capture the call stack in order to inspect the source of this usage pattern
1840
+ new container_utils_1.UsageError(errorMessage));
1841
+ this.opReentryCallsToReport--;
1842
+ }
1843
+ // Creating ops while processing ops can lead
1844
+ // to undefined behavior and events observed in the wrong order.
1845
+ // For example, we have two callbacks registered for a DDS, A and B.
1846
+ // Then if on change #1 callback A creates change #2, the invocation flow will be:
1847
+ //
1848
+ // A because of #1
1849
+ // A because of #2
1850
+ // B because of #2
1851
+ // B because of #1
1852
+ //
1853
+ // The runtime must enforce op coherence by not allowing ops to be submitted
1854
+ // while ops are being processed.
1855
+ if (this.enableOpReentryCheck) {
1856
+ throw new container_utils_1.UsageError(errorMessage);
1857
+ }
1858
+ }
1859
+ }
1656
1860
  /**
1657
1861
  * Finds the right store and asks it to resubmit the message. This typically happens when we
1658
1862
  * reconnect and there are pending messages.
@@ -1711,28 +1915,50 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1711
1915
  // The call to fetch the snapshot is very expensive and not always needed.
1712
1916
  // It should only be done by the summarizerNode, if required.
1713
1917
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
1714
- const snapshotTreeFetcher = async () => {
1715
- const fetchResult = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1716
- eventName: "RefreshLatestSummaryGetSnapshot",
1717
- ackHandle,
1718
- summaryRefSeq,
1719
- fetchLatest: true,
1720
- });
1721
- const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(fetchResult.snapshotTree, readAndParseBlob);
1722
- summaryLogger.sendTelemetryEvent({
1723
- eventName: "LatestSummaryRetrieved",
1918
+ const fetchLatestSnapshot = async () => {
1919
+ let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1920
+ eventName: "RefreshLatestSummaryAckFetch",
1724
1921
  ackHandle,
1725
- lastSequenceNumber: latestSnapshotRefSeq,
1726
1922
  targetSequenceNumber: summaryRefSeq,
1727
- });
1923
+ }, readAndParseBlob);
1924
+ /**
1925
+ * If the fetched snapshot is older than the one for which the ack was received, close the container.
1926
+ * This should never happen because an ack should be sent after the latest summary is updated in the server.
1927
+ * However, there are couple of scenarios where it's possible:
1928
+ * 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
1929
+ * the document being unusable and we should not proceed.
1930
+ * 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
1931
+ * such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
1932
+ * state.
1933
+ */
1934
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1935
+ /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
1936
+ fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
1937
+ eventName: "RefreshLatestSummaryAckFetch",
1938
+ ackHandle,
1939
+ targetSequenceNumber: summaryRefSeq,
1940
+ }, readAndParseBlob, ackHandle);
1941
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
1942
+ const error = container_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
1943
+ ackHandle,
1944
+ summaryRefSeq,
1945
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1946
+ });
1947
+ this.closeFn(error);
1948
+ throw error;
1949
+ }
1950
+ }
1728
1951
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
1729
1952
  // wait for the delta manager to catch up before refreshing the latest Summary.
1730
- await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
1731
- return fetchResult.snapshotTree;
1953
+ await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
1954
+ return {
1955
+ snapshotTree: fetchResult.snapshotTree,
1956
+ snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
1957
+ };
1732
1958
  };
1733
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, snapshotTreeFetcher, readAndParseBlob, summaryLogger);
1959
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1734
1960
  // Notify the garbage collector so it can update its latest summary state.
1735
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1961
+ await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
1736
1962
  }
1737
1963
  /**
1738
1964
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -1741,76 +1967,55 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1741
1967
  * @returns downloaded snapshot's reference sequence number
1742
1968
  */
1743
1969
  async refreshLatestSummaryAckFromServer(summaryLogger) {
1744
- const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
1745
- eventName: "RefreshLatestSummaryGetSnapshot",
1746
- fetchLatest: true,
1747
- }, driver_definitions_1.FetchSource.noCache);
1748
1970
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
1749
- const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(snapshotTree, readAndParseBlob);
1750
- const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
1971
+ const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
1972
+ eventName: "RefreshLatestSummaryFromServerFetch",
1973
+ }, readAndParseBlob);
1974
+ const fetchLatestSnapshot = {
1975
+ snapshotTree,
1976
+ snapshotRefSeq: latestSnapshotRefSeq,
1977
+ };
1978
+ const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
1751
1979
  // Notify the garbage collector so it can update its latest summary state.
1752
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
1980
+ await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
1753
1981
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
1754
1982
  }
1755
- async fetchSnapshotFromStorage(versionId, logger, event, fetchSource) {
1983
+ async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
1984
+ return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
1985
+ }
1986
+ async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
1756
1987
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
1757
1988
  const stats = {};
1758
1989
  const trace = common_utils_1.Trace.start();
1759
- const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", fetchSource);
1990
+ const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
1760
1991
  (0, common_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
1761
1992
  stats.getVersionDuration = trace.trace().duration;
1762
1993
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
1763
1994
  (0, common_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
1764
1995
  stats.getSnapshotDuration = trace.trace().duration;
1996
+ const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(maybeSnapshot, readAndParseBlob);
1997
+ stats.snapshotRefSeq = latestSnapshotRefSeq;
1998
+ stats.snapshotVersion = versions[0].id;
1765
1999
  perfEvent.end(stats);
1766
- return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
2000
+ return {
2001
+ snapshotTree: maybeSnapshot,
2002
+ versionId: versions[0].id,
2003
+ latestSnapshotRefSeq,
2004
+ };
1767
2005
  });
1768
2006
  }
1769
- notifyAttaching(snapshot) {
1770
- var _a;
1771
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
1772
- this.baseSnapshotBlobs = serializedSnapshotStorage_1.SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
1773
- }
1774
- }
1775
- async initializeBaseSnapshotBlobs() {
1776
- var _a;
1777
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
1778
- this.attachState !== container_definitions_1.AttachState.Attached || this.context.pendingLocalState) {
1779
- return;
1780
- }
1781
- (0, common_utils_1.assert)(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
1782
- this.baseSnapshotBlobs = await serializedSnapshotStorage_1.SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
1783
- }
2007
+ notifyAttaching() { } // do nothing (deprecated method)
1784
2008
  getPendingLocalState() {
1785
- var _a;
1786
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
1787
- throw new container_utils_1.UsageError("can't get state when offline load disabled");
2009
+ if (this._orderSequentiallyCalls !== 0) {
2010
+ throw new container_utils_1.UsageError("can't get state during orderSequentially");
1788
2011
  }
1789
2012
  // Flush pending batch.
1790
2013
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
1791
2014
  // to close current batch.
1792
2015
  this.flush();
1793
- if (this._orderSequentiallyCalls !== 0) {
1794
- throw new container_utils_1.UsageError("can't get state during orderSequentially");
1795
- }
1796
- const previousPendingState = this.context.pendingLocalState;
1797
- if (previousPendingState) {
1798
- return {
1799
- pending: this.pendingStateManager.getLocalState(),
1800
- pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1801
- snapshotBlobs: previousPendingState.snapshotBlobs,
1802
- baseSnapshot: previousPendingState.baseSnapshot,
1803
- savedOps: this.savedOps,
1804
- };
1805
- }
1806
- (0, common_utils_1.assert)(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
1807
- (0, common_utils_1.assert)(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
1808
2016
  return {
1809
2017
  pending: this.pendingStateManager.getLocalState(),
1810
2018
  pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
1811
- snapshotBlobs: this.baseSnapshotBlobs,
1812
- baseSnapshot: this.context.baseSnapshot,
1813
- savedOps: this.savedOps,
1814
2019
  };
1815
2020
  }
1816
2021
  /**
@@ -1824,7 +2029,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1824
2029
  [container_definitions_1.LoaderHeader.cache]: false,
1825
2030
  [container_definitions_1.LoaderHeader.clientDetails]: {
1826
2031
  capabilities: { interactive: false },
1827
- type: summarizerClientElection_1.summarizerClientType,
2032
+ type: summary_1.summarizerClientType,
1828
2033
  },
1829
2034
  [driver_definitions_1.DriverHeader.summarizingClient]: true,
1830
2035
  [container_definitions_1.LoaderHeader.reconnect]: false,
@@ -1839,20 +2044,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1839
2044
  return summarizer;
1840
2045
  };
1841
2046
  }
1842
- async processSavedOps(state) {
1843
- for (const op of state.savedOps) {
1844
- this.process(op, false);
1845
- await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
1846
- }
1847
- // we may not have seen every sequence number (because of system ops) so apply everything once we
1848
- // don't have any more saved ops
1849
- await this.pendingStateManager.applyStashedOpsAt();
1850
- // If it's not the case, we should take it into account when calculating dirty state.
1851
- (0, common_utils_1.assert)(this.context.attachState === container_definitions_1.AttachState.Attached, 0x3d5 /* this function is called for attached containers only */);
1852
- if (!this.hasPendingMessages()) {
1853
- this.updateDocumentDirtyState(false);
1854
- }
1855
- }
1856
2047
  validateSummaryHeuristicConfiguration(configuration) {
1857
2048
  // eslint-disable-next-line no-restricted-syntax
1858
2049
  for (const prop in configuration) {
@@ -1873,6 +2064,7 @@ exports.ContainerRuntime = ContainerRuntime;
1873
2064
  const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
1874
2065
  // TODO: remove cast to any when actual event is determined
1875
2066
  deltaManager.on("closed", reject);
2067
+ deltaManager.on("disposed", reject);
1876
2068
  // If we already reached target sequence number, simply resolve the promise.
1877
2069
  if (deltaManager.lastSequenceNumber >= targetSeq) {
1878
2070
  resolve();