@fluidframework/container-runtime 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.225277

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 (705) hide show
  1. package/.eslintrc.js +19 -29
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +427 -0
  4. package/README.md +69 -0
  5. package/api-extractor-esm.json +4 -0
  6. package/api-extractor-lint.json +4 -0
  7. package/api-extractor.json +2 -2
  8. package/api-report/container-runtime.api.md +863 -0
  9. package/dist/{batchTracker.js → batchTracker.cjs} +9 -8
  10. package/dist/batchTracker.cjs.map +1 -0
  11. package/dist/batchTracker.d.ts +6 -5
  12. package/dist/batchTracker.d.ts.map +1 -1
  13. package/dist/blobManager.cjs +709 -0
  14. package/dist/blobManager.cjs.map +1 -0
  15. package/dist/blobManager.d.ts +140 -39
  16. package/dist/blobManager.d.ts.map +1 -1
  17. package/dist/connectionTelemetry.cjs +230 -0
  18. package/dist/connectionTelemetry.cjs.map +1 -0
  19. package/dist/connectionTelemetry.d.ts +2 -2
  20. package/dist/connectionTelemetry.d.ts.map +1 -1
  21. package/dist/container-runtime-alpha.d.ts +1690 -0
  22. package/dist/container-runtime-beta.d.ts +250 -0
  23. package/dist/container-runtime-public.d.ts +250 -0
  24. package/dist/container-runtime-untrimmed.d.ts +1805 -0
  25. package/dist/{containerHandleContext.js → containerHandleContext.cjs} +4 -2
  26. package/dist/containerHandleContext.cjs.map +1 -0
  27. package/dist/containerHandleContext.d.ts.map +1 -1
  28. package/dist/containerRuntime.cjs +2535 -0
  29. package/dist/containerRuntime.cjs.map +1 -0
  30. package/dist/containerRuntime.d.ts +458 -256
  31. package/dist/containerRuntime.d.ts.map +1 -1
  32. package/dist/{dataStore.js → dataStore.cjs} +54 -45
  33. package/dist/dataStore.cjs.map +1 -0
  34. package/dist/dataStore.d.ts +2 -2
  35. package/dist/dataStore.d.ts.map +1 -1
  36. package/dist/{dataStoreContext.js → dataStoreContext.cjs} +343 -247
  37. package/dist/dataStoreContext.cjs.map +1 -0
  38. package/dist/dataStoreContext.d.ts +73 -41
  39. package/dist/dataStoreContext.d.ts.map +1 -1
  40. package/dist/{dataStoreContexts.js → dataStoreContexts.cjs} +19 -15
  41. package/dist/dataStoreContexts.cjs.map +1 -0
  42. package/dist/dataStoreContexts.d.ts +1 -1
  43. package/dist/dataStoreContexts.d.ts.map +1 -1
  44. package/dist/{dataStoreRegistry.js → dataStoreRegistry.cjs} +9 -4
  45. package/dist/dataStoreRegistry.cjs.map +1 -0
  46. package/dist/dataStoreRegistry.d.ts +3 -0
  47. package/dist/dataStoreRegistry.d.ts.map +1 -1
  48. package/dist/{dataStores.js → dataStores.cjs} +276 -124
  49. package/dist/dataStores.cjs.map +1 -0
  50. package/dist/dataStores.d.ts +56 -23
  51. package/dist/dataStores.d.ts.map +1 -1
  52. package/dist/deltaManagerProxyBase.cjs +77 -0
  53. package/dist/deltaManagerProxyBase.cjs.map +1 -0
  54. package/dist/deltaManagerProxyBase.d.ts +35 -0
  55. package/dist/deltaManagerProxyBase.d.ts.map +1 -0
  56. package/dist/deltaManagerSummarizerProxy.cjs +42 -0
  57. package/dist/deltaManagerSummarizerProxy.cjs.map +1 -0
  58. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  59. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  60. package/dist/{deltaScheduler.js → deltaScheduler.cjs} +25 -18
  61. package/dist/deltaScheduler.cjs.map +1 -0
  62. package/dist/deltaScheduler.d.ts +8 -6
  63. package/dist/deltaScheduler.d.ts.map +1 -1
  64. package/dist/error.cjs +21 -0
  65. package/dist/error.cjs.map +1 -0
  66. package/dist/error.d.ts +14 -0
  67. package/dist/error.d.ts.map +1 -0
  68. package/dist/gc/garbageCollection.cjs +865 -0
  69. package/dist/gc/garbageCollection.cjs.map +1 -0
  70. package/dist/gc/garbageCollection.d.ts +224 -0
  71. package/dist/gc/garbageCollection.d.ts.map +1 -0
  72. package/dist/gc/gcConfigs.cjs +160 -0
  73. package/dist/gc/gcConfigs.cjs.map +1 -0
  74. package/dist/gc/gcConfigs.d.ts +23 -0
  75. package/dist/gc/gcConfigs.d.ts.map +1 -0
  76. package/dist/gc/gcDefinitions.cjs +96 -0
  77. package/dist/gc/gcDefinitions.cjs.map +1 -0
  78. package/dist/gc/gcDefinitions.d.ts +458 -0
  79. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  80. package/dist/gc/gcHelpers.cjs +235 -0
  81. package/dist/gc/gcHelpers.cjs.map +1 -0
  82. package/dist/gc/gcHelpers.d.ts +71 -0
  83. package/dist/gc/gcHelpers.d.ts.map +1 -0
  84. package/dist/gc/gcReferenceGraphAlgorithm.cjs +49 -0
  85. package/dist/gc/gcReferenceGraphAlgorithm.cjs.map +1 -0
  86. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  87. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  88. package/dist/{summarizerTypes.js → gc/gcSummaryDefinitions.cjs} +1 -6
  89. package/dist/gc/gcSummaryDefinitions.cjs.map +1 -0
  90. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  91. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  92. package/dist/gc/gcSummaryStateTracker.cjs +213 -0
  93. package/dist/gc/gcSummaryStateTracker.cjs.map +1 -0
  94. package/dist/gc/gcSummaryStateTracker.d.ts +94 -0
  95. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  96. package/dist/gc/gcTelemetry.cjs +307 -0
  97. package/dist/gc/gcTelemetry.cjs.map +1 -0
  98. package/dist/gc/gcTelemetry.d.ts +99 -0
  99. package/dist/gc/gcTelemetry.d.ts.map +1 -0
  100. package/dist/gc/gcUnreferencedStateTracker.cjs +118 -0
  101. package/dist/gc/gcUnreferencedStateTracker.cjs.map +1 -0
  102. package/dist/gc/gcUnreferencedStateTracker.d.ts +40 -0
  103. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  104. package/dist/gc/index.cjs +44 -0
  105. package/dist/gc/index.cjs.map +1 -0
  106. package/dist/gc/index.d.ts +13 -0
  107. package/dist/gc/index.d.ts.map +1 -0
  108. package/dist/index.cjs +47 -0
  109. package/dist/index.cjs.map +1 -0
  110. package/dist/index.d.ts +19 -8
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/messageTypes.cjs +37 -0
  113. package/dist/messageTypes.cjs.map +1 -0
  114. package/dist/messageTypes.d.ts +142 -0
  115. package/dist/messageTypes.d.ts.map +1 -0
  116. package/dist/metadata.cjs +7 -0
  117. package/dist/metadata.cjs.map +1 -0
  118. package/dist/metadata.d.ts +24 -0
  119. package/dist/metadata.d.ts.map +1 -0
  120. package/dist/opLifecycle/batchManager.cjs +139 -0
  121. package/dist/opLifecycle/batchManager.cjs.map +1 -0
  122. package/dist/opLifecycle/batchManager.d.ts +48 -0
  123. package/dist/opLifecycle/batchManager.d.ts.map +1 -0
  124. package/dist/opLifecycle/definitions.cjs +7 -0
  125. package/dist/opLifecycle/definitions.cjs.map +1 -0
  126. package/dist/opLifecycle/definitions.d.ts +83 -0
  127. package/dist/opLifecycle/definitions.d.ts.map +1 -0
  128. package/dist/opLifecycle/index.cjs +26 -0
  129. package/dist/opLifecycle/index.cjs.map +1 -0
  130. package/dist/opLifecycle/index.d.ts +13 -0
  131. package/dist/opLifecycle/index.d.ts.map +1 -0
  132. package/dist/opLifecycle/opCompressor.cjs +84 -0
  133. package/dist/opLifecycle/opCompressor.cjs.map +1 -0
  134. package/dist/opLifecycle/opCompressor.d.ts +18 -0
  135. package/dist/opLifecycle/opCompressor.d.ts.map +1 -0
  136. package/dist/opLifecycle/opDecompressor.cjs +132 -0
  137. package/dist/opLifecycle/opDecompressor.cjs.map +1 -0
  138. package/dist/opLifecycle/opDecompressor.d.ts +25 -0
  139. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -0
  140. package/dist/opLifecycle/opGroupingManager.cjs +95 -0
  141. package/dist/opLifecycle/opGroupingManager.cjs.map +1 -0
  142. package/dist/opLifecycle/opGroupingManager.d.ts +22 -0
  143. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
  144. package/dist/opLifecycle/opSplitter.cjs +202 -0
  145. package/dist/opLifecycle/opSplitter.cjs.map +1 -0
  146. package/dist/opLifecycle/opSplitter.d.ts +61 -0
  147. package/dist/opLifecycle/opSplitter.d.ts.map +1 -0
  148. package/dist/opLifecycle/outbox.cjs +326 -0
  149. package/dist/opLifecycle/outbox.cjs.map +1 -0
  150. package/dist/opLifecycle/outbox.d.ts +104 -0
  151. package/dist/opLifecycle/outbox.d.ts.map +1 -0
  152. package/dist/opLifecycle/remoteMessageProcessor.cjs +136 -0
  153. package/dist/opLifecycle/remoteMessageProcessor.cjs.map +1 -0
  154. package/dist/opLifecycle/remoteMessageProcessor.d.ts +47 -0
  155. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
  156. package/dist/opProperties.cjs +17 -0
  157. package/dist/opProperties.cjs.map +1 -0
  158. package/dist/opProperties.d.ts +7 -0
  159. package/dist/opProperties.d.ts.map +1 -0
  160. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  161. package/dist/packageVersion.cjs.map +1 -0
  162. package/dist/packageVersion.d.ts +1 -1
  163. package/dist/packageVersion.d.ts.map +1 -1
  164. package/dist/pendingStateManager.cjs +282 -0
  165. package/dist/pendingStateManager.cjs.map +1 -0
  166. package/dist/pendingStateManager.d.ts +32 -69
  167. package/dist/pendingStateManager.d.ts.map +1 -1
  168. package/dist/scheduleManager.cjs +258 -0
  169. package/dist/scheduleManager.cjs.map +1 -0
  170. package/dist/scheduleManager.d.ts +31 -0
  171. package/dist/scheduleManager.d.ts.map +1 -0
  172. package/dist/storageServiceWithAttachBlobs.cjs +32 -0
  173. package/dist/storageServiceWithAttachBlobs.cjs.map +1 -0
  174. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  175. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  176. package/dist/summary/index.cjs +51 -0
  177. package/dist/summary/index.cjs.map +1 -0
  178. package/dist/summary/index.d.ts +17 -0
  179. package/dist/summary/index.d.ts.map +1 -0
  180. package/dist/{orderedClientElection.js → summary/orderedClientElection.cjs} +100 -84
  181. package/dist/summary/orderedClientElection.cjs.map +1 -0
  182. package/{lib → dist/summary}/orderedClientElection.d.ts +41 -18
  183. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  184. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.cjs} +12 -10
  185. package/dist/summary/runWhileConnectedCoordinator.cjs.map +1 -0
  186. package/{lib → dist/summary}/runWhileConnectedCoordinator.d.ts +8 -2
  187. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  188. package/dist/summary/runningSummarizer.cjs +679 -0
  189. package/dist/summary/runningSummarizer.cjs.map +1 -0
  190. package/dist/summary/runningSummarizer.d.ts +128 -0
  191. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  192. package/dist/summary/summarizer.cjs +263 -0
  193. package/dist/summary/summarizer.cjs.map +1 -0
  194. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +18 -33
  195. package/dist/summary/summarizer.d.ts.map +1 -0
  196. package/dist/{summarizerClientElection.js → summary/summarizerClientElection.cjs} +15 -46
  197. package/dist/summary/summarizerClientElection.cjs.map +1 -0
  198. package/{lib → dist/summary}/summarizerClientElection.d.ts +4 -4
  199. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  200. package/dist/summary/summarizerHeuristics.cjs +156 -0
  201. package/dist/summary/summarizerHeuristics.cjs.map +1 -0
  202. package/{lib → dist/summary}/summarizerHeuristics.d.ts +28 -6
  203. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  204. package/dist/summary/summarizerNode/index.cjs +12 -0
  205. package/dist/summary/summarizerNode/index.cjs.map +1 -0
  206. package/dist/summary/summarizerNode/index.d.ts +8 -0
  207. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  208. package/dist/summary/summarizerNode/summarizerNode.cjs +526 -0
  209. package/dist/summary/summarizerNode/summarizerNode.cjs.map +1 -0
  210. package/dist/summary/summarizerNode/summarizerNode.d.ts +167 -0
  211. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  212. package/dist/summary/summarizerNode/summarizerNodeUtils.cjs +130 -0
  213. package/dist/summary/summarizerNode/summarizerNodeUtils.cjs.map +1 -0
  214. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +121 -0
  215. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  216. package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs +375 -0
  217. package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs.map +1 -0
  218. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +153 -0
  219. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  220. package/dist/summary/summarizerTypes.cjs +7 -0
  221. package/dist/summary/summarizerTypes.cjs.map +1 -0
  222. package/{lib → dist/summary}/summarizerTypes.d.ts +233 -83
  223. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  224. package/dist/{summaryCollection.js → summary/summaryCollection.cjs} +80 -49
  225. package/dist/summary/summaryCollection.cjs.map +1 -0
  226. package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +23 -5
  227. package/dist/summary/summaryCollection.d.ts.map +1 -0
  228. package/dist/{summaryFormat.js → summary/summaryFormat.cjs} +29 -26
  229. package/dist/summary/summaryFormat.cjs.map +1 -0
  230. package/{lib → dist/summary}/summaryFormat.d.ts +25 -30
  231. package/dist/summary/summaryFormat.d.ts.map +1 -0
  232. package/dist/{summaryGenerator.js → summary/summaryGenerator.cjs} +162 -74
  233. package/dist/summary/summaryGenerator.cjs.map +1 -0
  234. package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +53 -11
  235. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  236. package/dist/{summaryManager.js → summary/summaryManager.cjs} +98 -55
  237. package/dist/summary/summaryManager.cjs.map +1 -0
  238. package/{lib → dist/summary}/summaryManager.d.ts +13 -11
  239. package/dist/summary/summaryManager.d.ts.map +1 -0
  240. package/dist/{throttler.js → throttler.cjs} +21 -21
  241. package/dist/throttler.cjs.map +1 -0
  242. package/dist/throttler.d.ts +2 -2
  243. package/dist/throttler.d.ts.map +1 -1
  244. package/dist/tsdoc-metadata.json +11 -0
  245. package/lib/{batchTracker.d.ts → batchTracker.d.mts} +7 -6
  246. package/lib/batchTracker.d.mts.map +1 -0
  247. package/lib/{batchTracker.js → batchTracker.mjs} +9 -8
  248. package/lib/batchTracker.mjs.map +1 -0
  249. package/lib/blobManager.d.mts +196 -0
  250. package/lib/blobManager.d.mts.map +1 -0
  251. package/lib/blobManager.mjs +704 -0
  252. package/lib/blobManager.mjs.map +1 -0
  253. package/lib/{connectionTelemetry.d.ts → connectionTelemetry.d.mts} +3 -3
  254. package/lib/connectionTelemetry.d.mts.map +1 -0
  255. package/lib/connectionTelemetry.mjs +226 -0
  256. package/lib/connectionTelemetry.mjs.map +1 -0
  257. package/lib/container-runtime-alpha.d.mts +1690 -0
  258. package/lib/container-runtime-beta.d.mts +250 -0
  259. package/lib/container-runtime-public.d.mts +250 -0
  260. package/lib/container-runtime-untrimmed.d.mts +1805 -0
  261. package/lib/{containerHandleContext.d.ts → containerHandleContext.d.mts} +2 -2
  262. package/lib/containerHandleContext.d.mts.map +1 -0
  263. package/lib/{containerHandleContext.js → containerHandleContext.mjs} +4 -2
  264. package/lib/containerHandleContext.mjs.map +1 -0
  265. package/lib/containerRuntime.d.mts +813 -0
  266. package/lib/containerRuntime.d.mts.map +1 -0
  267. package/lib/containerRuntime.mjs +2530 -0
  268. package/lib/containerRuntime.mjs.map +1 -0
  269. package/lib/{dataStore.d.ts → dataStore.d.mts} +5 -5
  270. package/lib/dataStore.d.mts.map +1 -0
  271. package/lib/{dataStore.js → dataStore.mjs} +52 -43
  272. package/lib/dataStore.mjs.map +1 -0
  273. package/lib/{dataStoreContext.d.ts → dataStoreContext.d.mts} +75 -43
  274. package/lib/dataStoreContext.d.mts.map +1 -0
  275. package/lib/{dataStoreContext.js → dataStoreContext.mjs} +309 -213
  276. package/lib/dataStoreContext.mjs.map +1 -0
  277. package/lib/{dataStoreContexts.d.ts → dataStoreContexts.d.mts} +3 -3
  278. package/lib/dataStoreContexts.d.mts.map +1 -0
  279. package/lib/{dataStoreContexts.js → dataStoreContexts.mjs} +12 -8
  280. package/lib/dataStoreContexts.mjs.map +1 -0
  281. package/lib/{dataStoreRegistry.d.ts → dataStoreRegistry.d.mts} +4 -1
  282. package/lib/dataStoreRegistry.d.mts.map +1 -0
  283. package/lib/{dataStoreRegistry.js → dataStoreRegistry.mjs} +7 -6
  284. package/lib/dataStoreRegistry.mjs.map +1 -0
  285. package/lib/{dataStores.d.ts → dataStores.d.mts} +60 -27
  286. package/lib/dataStores.d.mts.map +1 -0
  287. package/lib/{dataStores.js → dataStores.mjs} +257 -105
  288. package/lib/dataStores.mjs.map +1 -0
  289. package/lib/deltaManagerProxyBase.d.mts +35 -0
  290. package/lib/deltaManagerProxyBase.d.mts.map +1 -0
  291. package/lib/deltaManagerProxyBase.mjs +73 -0
  292. package/lib/deltaManagerProxyBase.mjs.map +1 -0
  293. package/lib/deltaManagerSummarizerProxy.d.mts +19 -0
  294. package/lib/deltaManagerSummarizerProxy.d.mts.map +1 -0
  295. package/lib/deltaManagerSummarizerProxy.mjs +38 -0
  296. package/lib/deltaManagerSummarizerProxy.mjs.map +1 -0
  297. package/lib/{deltaScheduler.d.ts → deltaScheduler.d.mts} +9 -7
  298. package/lib/deltaScheduler.d.mts.map +1 -0
  299. package/lib/{deltaScheduler.js → deltaScheduler.mjs} +22 -15
  300. package/lib/deltaScheduler.mjs.map +1 -0
  301. package/lib/error.d.mts +14 -0
  302. package/lib/error.d.mts.map +1 -0
  303. package/lib/error.mjs +17 -0
  304. package/lib/error.mjs.map +1 -0
  305. package/lib/gc/garbageCollection.d.mts +224 -0
  306. package/lib/gc/garbageCollection.d.mts.map +1 -0
  307. package/lib/gc/garbageCollection.mjs +861 -0
  308. package/lib/gc/garbageCollection.mjs.map +1 -0
  309. package/lib/gc/gcConfigs.d.mts +23 -0
  310. package/lib/gc/gcConfigs.d.mts.map +1 -0
  311. package/lib/gc/gcConfigs.mjs +156 -0
  312. package/lib/gc/gcConfigs.mjs.map +1 -0
  313. package/lib/gc/gcDefinitions.d.mts +458 -0
  314. package/lib/gc/gcDefinitions.d.mts.map +1 -0
  315. package/lib/gc/gcDefinitions.mjs +93 -0
  316. package/lib/gc/gcDefinitions.mjs.map +1 -0
  317. package/lib/gc/gcHelpers.d.mts +71 -0
  318. package/lib/gc/gcHelpers.d.mts.map +1 -0
  319. package/lib/gc/gcHelpers.mjs +222 -0
  320. package/lib/gc/gcHelpers.mjs.map +1 -0
  321. package/lib/gc/gcReferenceGraphAlgorithm.d.mts +16 -0
  322. package/lib/gc/gcReferenceGraphAlgorithm.d.mts.map +1 -0
  323. package/lib/gc/gcReferenceGraphAlgorithm.mjs +45 -0
  324. package/lib/gc/gcReferenceGraphAlgorithm.mjs.map +1 -0
  325. package/lib/gc/gcSummaryDefinitions.d.mts +52 -0
  326. package/lib/gc/gcSummaryDefinitions.d.mts.map +1 -0
  327. package/lib/gc/gcSummaryDefinitions.mjs +6 -0
  328. package/lib/gc/gcSummaryDefinitions.mjs.map +1 -0
  329. package/lib/gc/gcSummaryStateTracker.d.mts +94 -0
  330. package/lib/gc/gcSummaryStateTracker.d.mts.map +1 -0
  331. package/lib/gc/gcSummaryStateTracker.mjs +209 -0
  332. package/lib/gc/gcSummaryStateTracker.mjs.map +1 -0
  333. package/lib/gc/gcTelemetry.d.mts +99 -0
  334. package/lib/gc/gcTelemetry.d.mts.map +1 -0
  335. package/lib/gc/gcTelemetry.mjs +302 -0
  336. package/lib/gc/gcTelemetry.mjs.map +1 -0
  337. package/lib/gc/gcUnreferencedStateTracker.d.mts +40 -0
  338. package/lib/gc/gcUnreferencedStateTracker.d.mts.map +1 -0
  339. package/lib/gc/gcUnreferencedStateTracker.mjs +114 -0
  340. package/lib/gc/gcUnreferencedStateTracker.mjs.map +1 -0
  341. package/lib/gc/index.d.mts +13 -0
  342. package/lib/gc/index.d.mts.map +1 -0
  343. package/lib/gc/index.mjs +12 -0
  344. package/lib/gc/index.mjs.map +1 -0
  345. package/lib/index.d.mts +25 -0
  346. package/lib/index.d.mts.map +1 -0
  347. package/lib/index.mjs +24 -0
  348. package/lib/index.mjs.map +1 -0
  349. package/lib/messageTypes.d.mts +142 -0
  350. package/lib/messageTypes.d.mts.map +1 -0
  351. package/lib/messageTypes.mjs +34 -0
  352. package/lib/messageTypes.mjs.map +1 -0
  353. package/lib/metadata.d.mts +24 -0
  354. package/lib/metadata.d.mts.map +1 -0
  355. package/lib/metadata.mjs +6 -0
  356. package/lib/metadata.mjs.map +1 -0
  357. package/lib/opLifecycle/batchManager.d.mts +48 -0
  358. package/lib/opLifecycle/batchManager.d.mts.map +1 -0
  359. package/lib/opLifecycle/batchManager.mjs +133 -0
  360. package/lib/opLifecycle/batchManager.mjs.map +1 -0
  361. package/lib/opLifecycle/definitions.d.mts +83 -0
  362. package/lib/opLifecycle/definitions.d.mts.map +1 -0
  363. package/lib/opLifecycle/definitions.mjs +6 -0
  364. package/lib/opLifecycle/definitions.mjs.map +1 -0
  365. package/lib/opLifecycle/index.d.mts +13 -0
  366. package/lib/opLifecycle/index.d.mts.map +1 -0
  367. package/lib/opLifecycle/index.mjs +12 -0
  368. package/lib/opLifecycle/index.mjs.map +1 -0
  369. package/lib/opLifecycle/opCompressor.d.mts +18 -0
  370. package/lib/opLifecycle/opCompressor.d.mts.map +1 -0
  371. package/lib/opLifecycle/opCompressor.mjs +80 -0
  372. package/lib/opLifecycle/opCompressor.mjs.map +1 -0
  373. package/lib/opLifecycle/opDecompressor.d.mts +25 -0
  374. package/lib/opLifecycle/opDecompressor.d.mts.map +1 -0
  375. package/lib/opLifecycle/opDecompressor.mjs +128 -0
  376. package/lib/opLifecycle/opDecompressor.mjs.map +1 -0
  377. package/lib/opLifecycle/opGroupingManager.d.mts +22 -0
  378. package/lib/opLifecycle/opGroupingManager.d.mts.map +1 -0
  379. package/lib/opLifecycle/opGroupingManager.mjs +91 -0
  380. package/lib/opLifecycle/opGroupingManager.mjs.map +1 -0
  381. package/lib/opLifecycle/opSplitter.d.mts +61 -0
  382. package/lib/opLifecycle/opSplitter.d.mts.map +1 -0
  383. package/lib/opLifecycle/opSplitter.mjs +197 -0
  384. package/lib/opLifecycle/opSplitter.mjs.map +1 -0
  385. package/lib/opLifecycle/outbox.d.mts +104 -0
  386. package/lib/opLifecycle/outbox.d.mts.map +1 -0
  387. package/lib/opLifecycle/outbox.mjs +321 -0
  388. package/lib/opLifecycle/outbox.mjs.map +1 -0
  389. package/lib/opLifecycle/remoteMessageProcessor.d.mts +47 -0
  390. package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +1 -0
  391. package/lib/opLifecycle/remoteMessageProcessor.mjs +131 -0
  392. package/lib/opLifecycle/remoteMessageProcessor.mjs.map +1 -0
  393. package/lib/opProperties.d.mts +7 -0
  394. package/lib/opProperties.d.mts.map +1 -0
  395. package/lib/opProperties.mjs +13 -0
  396. package/lib/opProperties.mjs.map +1 -0
  397. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +2 -2
  398. package/lib/packageVersion.d.mts.map +1 -0
  399. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  400. package/lib/packageVersion.mjs.map +1 -0
  401. package/lib/{pendingStateManager.d.ts → pendingStateManager.d.mts} +33 -70
  402. package/lib/pendingStateManager.d.mts.map +1 -0
  403. package/lib/pendingStateManager.mjs +275 -0
  404. package/lib/pendingStateManager.mjs.map +1 -0
  405. package/lib/scheduleManager.d.mts +27 -0
  406. package/lib/scheduleManager.d.mts.map +1 -0
  407. package/lib/scheduleManager.mjs +254 -0
  408. package/lib/scheduleManager.mjs.map +1 -0
  409. package/lib/storageServiceWithAttachBlobs.d.mts +17 -0
  410. package/lib/storageServiceWithAttachBlobs.d.mts.map +1 -0
  411. package/lib/storageServiceWithAttachBlobs.mjs +28 -0
  412. package/lib/storageServiceWithAttachBlobs.mjs.map +1 -0
  413. package/lib/summary/index.d.mts +17 -0
  414. package/lib/summary/index.d.mts.map +1 -0
  415. package/lib/summary/index.mjs +16 -0
  416. package/lib/summary/index.mjs.map +1 -0
  417. package/{dist/orderedClientElection.d.ts → lib/summary/orderedClientElection.d.mts} +42 -23
  418. package/lib/summary/orderedClientElection.d.mts.map +1 -0
  419. package/lib/{orderedClientElection.js → summary/orderedClientElection.mjs} +95 -79
  420. package/lib/summary/orderedClientElection.mjs.map +1 -0
  421. package/{dist/runWhileConnectedCoordinator.d.ts → lib/summary/runWhileConnectedCoordinator.d.mts} +10 -4
  422. package/lib/summary/runWhileConnectedCoordinator.d.mts.map +1 -0
  423. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.mjs} +12 -10
  424. package/lib/summary/runWhileConnectedCoordinator.mjs.map +1 -0
  425. package/lib/summary/runningSummarizer.d.mts +128 -0
  426. package/lib/summary/runningSummarizer.d.mts.map +1 -0
  427. package/lib/summary/runningSummarizer.mjs +675 -0
  428. package/lib/summary/runningSummarizer.mjs.map +1 -0
  429. package/lib/{summarizer.d.ts → summary/summarizer.d.mts} +21 -36
  430. package/lib/summary/summarizer.d.mts.map +1 -0
  431. package/lib/summary/summarizer.mjs +257 -0
  432. package/lib/summary/summarizer.mjs.map +1 -0
  433. package/{dist/summarizerClientElection.d.ts → lib/summary/summarizerClientElection.d.mts} +7 -7
  434. package/lib/summary/summarizerClientElection.d.mts.map +1 -0
  435. package/lib/{summarizerClientElection.js → summary/summarizerClientElection.mjs} +14 -45
  436. package/lib/summary/summarizerClientElection.mjs.map +1 -0
  437. package/{dist/summarizerHeuristics.d.ts → lib/summary/summarizerHeuristics.d.mts} +30 -8
  438. package/lib/summary/summarizerHeuristics.d.mts.map +1 -0
  439. package/lib/summary/summarizerHeuristics.mjs +151 -0
  440. package/lib/summary/summarizerHeuristics.mjs.map +1 -0
  441. package/lib/summary/summarizerNode/index.d.mts +8 -0
  442. package/lib/summary/summarizerNode/index.d.mts.map +1 -0
  443. package/lib/summary/summarizerNode/index.mjs +7 -0
  444. package/lib/summary/summarizerNode/index.mjs.map +1 -0
  445. package/lib/summary/summarizerNode/summarizerNode.d.mts +167 -0
  446. package/lib/summary/summarizerNode/summarizerNode.d.mts.map +1 -0
  447. package/lib/summary/summarizerNode/summarizerNode.mjs +521 -0
  448. package/lib/summary/summarizerNode/summarizerNode.mjs.map +1 -0
  449. package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts +121 -0
  450. package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +1 -0
  451. package/lib/summary/summarizerNode/summarizerNodeUtils.mjs +123 -0
  452. package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +1 -0
  453. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts +153 -0
  454. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +1 -0
  455. package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs +370 -0
  456. package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +1 -0
  457. package/{dist/summarizerTypes.d.ts → lib/summary/summarizerTypes.d.mts} +235 -85
  458. package/lib/summary/summarizerTypes.d.mts.map +1 -0
  459. package/lib/summary/summarizerTypes.mjs +6 -0
  460. package/lib/summary/summarizerTypes.mjs.map +1 -0
  461. package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.mts} +24 -6
  462. package/lib/summary/summaryCollection.d.mts.map +1 -0
  463. package/lib/{summaryCollection.js → summary/summaryCollection.mjs} +76 -45
  464. package/lib/summary/summaryCollection.mjs.map +1 -0
  465. package/{dist/summaryFormat.d.ts → lib/summary/summaryFormat.d.mts} +26 -31
  466. package/lib/summary/summaryFormat.d.mts.map +1 -0
  467. package/lib/{summaryFormat.js → summary/summaryFormat.mjs} +30 -26
  468. package/lib/summary/summaryFormat.mjs.map +1 -0
  469. package/lib/summary/summaryGenerator.d.mts +127 -0
  470. package/lib/summary/summaryGenerator.d.mts.map +1 -0
  471. package/lib/{summaryGenerator.js → summary/summaryGenerator.mjs} +153 -67
  472. package/lib/summary/summaryGenerator.mjs.map +1 -0
  473. package/{dist/summaryManager.d.ts → lib/summary/summaryManager.d.mts} +16 -14
  474. package/lib/summary/summaryManager.d.mts.map +1 -0
  475. package/lib/{summaryManager.js → summary/summaryManager.mjs} +94 -51
  476. package/lib/summary/summaryManager.mjs.map +1 -0
  477. package/lib/{throttler.d.ts → throttler.d.mts} +3 -3
  478. package/lib/throttler.d.mts.map +1 -0
  479. package/lib/{throttler.js → throttler.mjs} +21 -21
  480. package/lib/throttler.mjs.map +1 -0
  481. package/package.json +199 -71
  482. package/prettier.config.cjs +8 -0
  483. package/src/batchTracker.ts +59 -54
  484. package/src/blobManager.ts +942 -294
  485. package/src/connectionTelemetry.ts +342 -252
  486. package/src/containerHandleContext.ts +27 -29
  487. package/src/containerRuntime.ts +3883 -3143
  488. package/src/dataStore.ts +170 -140
  489. package/src/dataStoreContext.ts +1166 -986
  490. package/src/dataStoreContexts.ts +176 -163
  491. package/src/dataStoreRegistry.ts +29 -21
  492. package/src/dataStores.ts +924 -678
  493. package/src/deltaManagerProxyBase.ts +111 -0
  494. package/src/deltaManagerSummarizerProxy.ts +49 -0
  495. package/src/deltaScheduler.ts +161 -156
  496. package/src/error.ts +21 -0
  497. package/src/gc/garbageCollection.md +106 -0
  498. package/src/gc/garbageCollection.ts +1157 -0
  499. package/src/gc/gcConfigs.ts +224 -0
  500. package/src/gc/gcDefinitions.ts +524 -0
  501. package/src/gc/gcHelpers.ts +284 -0
  502. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  503. package/src/gc/gcSummaryDefinitions.ts +54 -0
  504. package/src/gc/gcSummaryStateTracker.ts +299 -0
  505. package/src/gc/gcTelemetry.ts +433 -0
  506. package/src/gc/gcUnreferencedStateTracker.ts +153 -0
  507. package/src/gc/index.ts +60 -0
  508. package/src/index.ts +101 -74
  509. package/src/messageTypes.ts +238 -0
  510. package/src/metadata.ts +26 -0
  511. package/src/opLifecycle/README.md +321 -0
  512. package/src/opLifecycle/batchManager.ts +179 -0
  513. package/src/opLifecycle/definitions.ts +89 -0
  514. package/src/opLifecycle/index.ts +19 -0
  515. package/src/opLifecycle/opCompressor.ts +99 -0
  516. package/src/opLifecycle/opDecompressor.ts +190 -0
  517. package/src/opLifecycle/opGroupingManager.ts +133 -0
  518. package/src/opLifecycle/opSplitter.ts +279 -0
  519. package/src/opLifecycle/outbox.ts +474 -0
  520. package/src/opLifecycle/remoteMessageProcessor.ts +175 -0
  521. package/src/opProperties.ts +21 -0
  522. package/src/packageVersion.ts +1 -1
  523. package/src/pendingStateManager.ts +396 -465
  524. package/src/scheduleManager.ts +358 -0
  525. package/src/storageServiceWithAttachBlobs.ts +38 -0
  526. package/src/summary/index.ts +109 -0
  527. package/src/summary/orderedClientElection.ts +571 -0
  528. package/src/summary/runWhileConnectedCoordinator.ts +117 -0
  529. package/src/summary/runningSummarizer.ts +920 -0
  530. package/src/summary/summarizer.ts +352 -0
  531. package/src/summary/summarizerClientElection.ts +140 -0
  532. package/src/summary/summarizerHeuristics.ts +227 -0
  533. package/src/summary/summarizerNode/index.ts +12 -0
  534. package/src/summary/summarizerNode/summarizerNode.ts +725 -0
  535. package/src/summary/summarizerNode/summarizerNodeUtils.ts +206 -0
  536. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +571 -0
  537. package/src/summary/summarizerTypes.ts +631 -0
  538. package/src/summary/summaryCollection.ts +474 -0
  539. package/src/summary/summaryFormat.ts +249 -0
  540. package/src/summary/summaryGenerator.ts +539 -0
  541. package/src/summary/summaryManager.ts +452 -0
  542. package/src/throttler.ts +131 -122
  543. package/tsc-multi.test.json +4 -0
  544. package/tsconfig.json +11 -13
  545. package/dist/batchTracker.js.map +0 -1
  546. package/dist/blobManager.js +0 -249
  547. package/dist/blobManager.js.map +0 -1
  548. package/dist/connectionTelemetry.js +0 -178
  549. package/dist/connectionTelemetry.js.map +0 -1
  550. package/dist/containerHandleContext.js.map +0 -1
  551. package/dist/containerRuntime.js +0 -2174
  552. package/dist/containerRuntime.js.map +0 -1
  553. package/dist/dataStore.js.map +0 -1
  554. package/dist/dataStoreContext.js.map +0 -1
  555. package/dist/dataStoreContexts.js.map +0 -1
  556. package/dist/dataStoreRegistry.js.map +0 -1
  557. package/dist/dataStores.js.map +0 -1
  558. package/dist/deltaScheduler.js.map +0 -1
  559. package/dist/garbageCollection.d.ts +0 -319
  560. package/dist/garbageCollection.d.ts.map +0 -1
  561. package/dist/garbageCollection.js +0 -993
  562. package/dist/garbageCollection.js.map +0 -1
  563. package/dist/index.js +0 -33
  564. package/dist/index.js.map +0 -1
  565. package/dist/opTelemetry.d.ts +0 -22
  566. package/dist/opTelemetry.d.ts.map +0 -1
  567. package/dist/opTelemetry.js +0 -60
  568. package/dist/opTelemetry.js.map +0 -1
  569. package/dist/orderedClientElection.d.ts.map +0 -1
  570. package/dist/orderedClientElection.js.map +0 -1
  571. package/dist/packageVersion.js.map +0 -1
  572. package/dist/pendingStateManager.js +0 -346
  573. package/dist/pendingStateManager.js.map +0 -1
  574. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  575. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  576. package/dist/runningSummarizer.d.ts +0 -93
  577. package/dist/runningSummarizer.d.ts.map +0 -1
  578. package/dist/runningSummarizer.js +0 -384
  579. package/dist/runningSummarizer.js.map +0 -1
  580. package/dist/serializedSnapshotStorage.d.ts +0 -58
  581. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  582. package/dist/serializedSnapshotStorage.js +0 -108
  583. package/dist/serializedSnapshotStorage.js.map +0 -1
  584. package/dist/summarizer.d.ts.map +0 -1
  585. package/dist/summarizer.js +0 -348
  586. package/dist/summarizer.js.map +0 -1
  587. package/dist/summarizerClientElection.d.ts.map +0 -1
  588. package/dist/summarizerClientElection.js.map +0 -1
  589. package/dist/summarizerHandle.d.ts +0 -12
  590. package/dist/summarizerHandle.d.ts.map +0 -1
  591. package/dist/summarizerHandle.js +0 -22
  592. package/dist/summarizerHandle.js.map +0 -1
  593. package/dist/summarizerHeuristics.d.ts.map +0 -1
  594. package/dist/summarizerHeuristics.js +0 -84
  595. package/dist/summarizerHeuristics.js.map +0 -1
  596. package/dist/summarizerTypes.d.ts.map +0 -1
  597. package/dist/summarizerTypes.js.map +0 -1
  598. package/dist/summaryCollection.d.ts.map +0 -1
  599. package/dist/summaryCollection.js.map +0 -1
  600. package/dist/summaryFormat.d.ts.map +0 -1
  601. package/dist/summaryFormat.js.map +0 -1
  602. package/dist/summaryGenerator.d.ts.map +0 -1
  603. package/dist/summaryGenerator.js.map +0 -1
  604. package/dist/summaryManager.d.ts.map +0 -1
  605. package/dist/summaryManager.js.map +0 -1
  606. package/dist/throttler.js.map +0 -1
  607. package/garbageCollection.md +0 -41
  608. package/lib/batchTracker.d.ts.map +0 -1
  609. package/lib/batchTracker.js.map +0 -1
  610. package/lib/blobManager.d.ts +0 -95
  611. package/lib/blobManager.d.ts.map +0 -1
  612. package/lib/blobManager.js +0 -244
  613. package/lib/blobManager.js.map +0 -1
  614. package/lib/connectionTelemetry.d.ts.map +0 -1
  615. package/lib/connectionTelemetry.js +0 -174
  616. package/lib/connectionTelemetry.js.map +0 -1
  617. package/lib/containerHandleContext.d.ts.map +0 -1
  618. package/lib/containerHandleContext.js.map +0 -1
  619. package/lib/containerRuntime.d.ts +0 -615
  620. package/lib/containerRuntime.d.ts.map +0 -1
  621. package/lib/containerRuntime.js +0 -2166
  622. package/lib/containerRuntime.js.map +0 -1
  623. package/lib/dataStore.d.ts.map +0 -1
  624. package/lib/dataStore.js.map +0 -1
  625. package/lib/dataStoreContext.d.ts.map +0 -1
  626. package/lib/dataStoreContext.js.map +0 -1
  627. package/lib/dataStoreContexts.d.ts.map +0 -1
  628. package/lib/dataStoreContexts.js.map +0 -1
  629. package/lib/dataStoreRegistry.d.ts.map +0 -1
  630. package/lib/dataStoreRegistry.js.map +0 -1
  631. package/lib/dataStores.d.ts.map +0 -1
  632. package/lib/dataStores.js.map +0 -1
  633. package/lib/deltaScheduler.d.ts.map +0 -1
  634. package/lib/deltaScheduler.js.map +0 -1
  635. package/lib/garbageCollection.d.ts +0 -319
  636. package/lib/garbageCollection.d.ts.map +0 -1
  637. package/lib/garbageCollection.js +0 -989
  638. package/lib/garbageCollection.js.map +0 -1
  639. package/lib/index.d.ts +0 -14
  640. package/lib/index.d.ts.map +0 -1
  641. package/lib/index.js +0 -13
  642. package/lib/index.js.map +0 -1
  643. package/lib/opTelemetry.d.ts +0 -22
  644. package/lib/opTelemetry.d.ts.map +0 -1
  645. package/lib/opTelemetry.js +0 -56
  646. package/lib/opTelemetry.js.map +0 -1
  647. package/lib/orderedClientElection.d.ts.map +0 -1
  648. package/lib/orderedClientElection.js.map +0 -1
  649. package/lib/packageVersion.d.ts.map +0 -1
  650. package/lib/packageVersion.js.map +0 -1
  651. package/lib/pendingStateManager.d.ts.map +0 -1
  652. package/lib/pendingStateManager.js +0 -339
  653. package/lib/pendingStateManager.js.map +0 -1
  654. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  655. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  656. package/lib/runningSummarizer.d.ts +0 -93
  657. package/lib/runningSummarizer.d.ts.map +0 -1
  658. package/lib/runningSummarizer.js +0 -380
  659. package/lib/runningSummarizer.js.map +0 -1
  660. package/lib/serializedSnapshotStorage.d.ts +0 -58
  661. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  662. package/lib/serializedSnapshotStorage.js +0 -104
  663. package/lib/serializedSnapshotStorage.js.map +0 -1
  664. package/lib/summarizer.d.ts.map +0 -1
  665. package/lib/summarizer.js +0 -342
  666. package/lib/summarizer.js.map +0 -1
  667. package/lib/summarizerClientElection.d.ts.map +0 -1
  668. package/lib/summarizerClientElection.js.map +0 -1
  669. package/lib/summarizerHandle.d.ts +0 -12
  670. package/lib/summarizerHandle.d.ts.map +0 -1
  671. package/lib/summarizerHandle.js +0 -18
  672. package/lib/summarizerHandle.js.map +0 -1
  673. package/lib/summarizerHeuristics.d.ts.map +0 -1
  674. package/lib/summarizerHeuristics.js +0 -79
  675. package/lib/summarizerHeuristics.js.map +0 -1
  676. package/lib/summarizerTypes.d.ts.map +0 -1
  677. package/lib/summarizerTypes.js +0 -9
  678. package/lib/summarizerTypes.js.map +0 -1
  679. package/lib/summaryCollection.d.ts.map +0 -1
  680. package/lib/summaryCollection.js.map +0 -1
  681. package/lib/summaryFormat.d.ts.map +0 -1
  682. package/lib/summaryFormat.js.map +0 -1
  683. package/lib/summaryGenerator.d.ts +0 -85
  684. package/lib/summaryGenerator.d.ts.map +0 -1
  685. package/lib/summaryGenerator.js.map +0 -1
  686. package/lib/summaryManager.d.ts.map +0 -1
  687. package/lib/summaryManager.js.map +0 -1
  688. package/lib/throttler.d.ts.map +0 -1
  689. package/lib/throttler.js.map +0 -1
  690. package/src/garbageCollection.ts +0 -1434
  691. package/src/opTelemetry.ts +0 -71
  692. package/src/orderedClientElection.ts +0 -511
  693. package/src/runWhileConnectedCoordinator.ts +0 -106
  694. package/src/runningSummarizer.ts +0 -550
  695. package/src/serializedSnapshotStorage.ts +0 -146
  696. package/src/summarizer.ts +0 -438
  697. package/src/summarizerClientElection.ts +0 -161
  698. package/src/summarizerHandle.ts +0 -21
  699. package/src/summarizerHeuristics.ts +0 -108
  700. package/src/summarizerTypes.ts +0 -462
  701. package/src/summaryCollection.ts +0 -406
  702. package/src/summaryFormat.ts +0 -239
  703. package/src/summaryGenerator.ts +0 -427
  704. package/src/summaryManager.ts +0 -368
  705. package/tsconfig.esnext.json +0 -7
@@ -1,2166 +0,0 @@
1
- import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
- import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
3
- import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
4
- import { DriverHeader } from "@fluidframework/driver-definitions";
5
- import { readAndParse, isUnpackedRuntimeMessage } from "@fluidframework/driver-utils";
6
- import { DataCorruptionError, DataProcessingError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
7
- import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
8
- import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
9
- import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
10
- import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
11
- import { v4 as uuid } from "uuid";
12
- import { ContainerFluidHandleContext } from "./containerHandleContext";
13
- import { FluidDataStoreRegistry } from "./dataStoreRegistry";
14
- import { Summarizer } from "./summarizer";
15
- import { SummaryManager } from "./summaryManager";
16
- import { DeltaScheduler } from "./deltaScheduler";
17
- import { ReportOpPerfTelemetry, latencyThreshold, } from "./connectionTelemetry";
18
- import { PendingStateManager } from "./pendingStateManager";
19
- import { pkgVersion } from "./packageVersion";
20
- import { BlobManager } from "./blobManager";
21
- import { DataStores, getSummaryForDatastores } from "./dataStores";
22
- import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
23
- import { SummaryCollection } from "./summaryCollection";
24
- import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
25
- import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
26
- import { formExponentialFn, Throttler } from "./throttler";
27
- import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
28
- import { GarbageCollector, GCNodeType, gcTreeKey, } from "./garbageCollection";
29
- import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
30
- import { BindBatchTracker } from "./batchTracker";
31
- import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
32
- import { OpTracker } from "./opTelemetry";
33
- export var ContainerMessageType;
34
- (function (ContainerMessageType) {
35
- // An op to be delivered to store
36
- ContainerMessageType["FluidDataStoreOp"] = "component";
37
- // Creates a new store
38
- ContainerMessageType["Attach"] = "attach";
39
- // Chunked operation.
40
- ContainerMessageType["ChunkedOp"] = "chunkedOp";
41
- // Signifies that a blob has been attached and should not be garbage collected by storage
42
- ContainerMessageType["BlobAttach"] = "blobAttach";
43
- // Ties our new clientId to our old one on reconnect
44
- ContainerMessageType["Rejoin"] = "rejoin";
45
- // Sets the alias of a root data store
46
- ContainerMessageType["Alias"] = "alias";
47
- })(ContainerMessageType || (ContainerMessageType = {}));
48
- export const DefaultSummaryConfiguration = {
49
- state: "enabled",
50
- idleTime: 5000 * 3,
51
- maxTime: 5000 * 12,
52
- maxOps: 100,
53
- minOpsForLastSummaryAttempt: 10,
54
- maxAckWaitTime: 6 * 10 * 1000,
55
- maxOpsSinceLastSummary: 7000,
56
- initialSummarizerDelayMs: 5000,
57
- summarizerClientElection: false,
58
- };
59
- /**
60
- * Accepted header keys for requests coming to the runtime.
61
- */
62
- export var RuntimeHeaders;
63
- (function (RuntimeHeaders) {
64
- /** True to wait for a data store to be created and loaded before returning it. */
65
- RuntimeHeaders["wait"] = "wait";
66
- /**
67
- * True if the request is from an external app. Used for GC to handle scenarios where a data store
68
- * is deleted and requested via an external app.
69
- */
70
- RuntimeHeaders["externalRequest"] = "externalRequest";
71
- /** True if the request is coming from an IFluidHandle. */
72
- RuntimeHeaders["viaHandle"] = "viaHandle";
73
- })(RuntimeHeaders || (RuntimeHeaders = {}));
74
- const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
75
- const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
76
- // Feature gate for the max op size. If the value is negative, chunking is enabled
77
- // and all ops over 16k would be chunked. If the value is positive, all ops with
78
- // a size strictly larger will be rejected and the container closed with an error.
79
- const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
80
- // By default, we should reject any op larger than 768KB,
81
- // in order to account for some extra overhead from serialization
82
- // to not reach the 1MB limits in socket.io and Kafka.
83
- const defaultMaxOpSizeInBytes = 768000;
84
- // By default, the size of the contents for the incoming ops is tracked.
85
- // However, in certain situations, this may incur a performance hit.
86
- // The feature-gate below can be used to disable this feature.
87
- const disableOpTrackingKey = "Fluid.ContainerRuntime.DisableOpTracking";
88
- const defaultFlushMode = FlushMode.TurnBased;
89
- export var RuntimeMessage;
90
- (function (RuntimeMessage) {
91
- RuntimeMessage["FluidDataStoreOp"] = "component";
92
- RuntimeMessage["Attach"] = "attach";
93
- RuntimeMessage["ChunkedOp"] = "chunkedOp";
94
- RuntimeMessage["BlobAttach"] = "blobAttach";
95
- RuntimeMessage["Rejoin"] = "rejoin";
96
- RuntimeMessage["Alias"] = "alias";
97
- RuntimeMessage["Operation"] = "op";
98
- })(RuntimeMessage || (RuntimeMessage = {}));
99
- export function isRuntimeMessage(message) {
100
- if (Object.values(RuntimeMessage).includes(message.type)) {
101
- return true;
102
- }
103
- return false;
104
- }
105
- export function unpackRuntimeMessage(message) {
106
- if (message.type === MessageType.Operation) {
107
- // legacy op format?
108
- if (message.contents.address !== undefined && message.contents.type === undefined) {
109
- message.type = ContainerMessageType.FluidDataStoreOp;
110
- }
111
- else {
112
- // new format
113
- const innerContents = message.contents;
114
- assert(innerContents.type !== undefined, 0x121 /* "Undefined inner contents type!" */);
115
- message.type = innerContents.type;
116
- message.contents = innerContents.contents;
117
- }
118
- assert(isUnpackedRuntimeMessage(message), 0x122 /* "Message to unpack is not proper runtime message" */);
119
- }
120
- else {
121
- // Legacy format, but it's already "unpacked",
122
- // i.e. message.type is actually ContainerMessageType.
123
- // Nothing to do in such case.
124
- }
125
- return message;
126
- }
127
- /**
128
- * This class controls pausing and resuming of inbound queue to ensure that we never
129
- * start processing ops in a batch IF we do not have all ops in the batch.
130
- */
131
- class ScheduleManagerCore {
132
- constructor(deltaManager, logger) {
133
- this.deltaManager = deltaManager;
134
- this.logger = logger;
135
- this.localPaused = false;
136
- this.timePaused = 0;
137
- this.batchCount = 0;
138
- // Listen for delta manager sends and add batch metadata to messages
139
- this.deltaManager.on("prepareSend", (messages) => {
140
- if (messages.length === 0) {
141
- return;
142
- }
143
- // First message will have the batch flag set to true if doing a batched send
144
- const firstMessageMetadata = messages[0].metadata;
145
- if (!(firstMessageMetadata === null || firstMessageMetadata === void 0 ? void 0 : firstMessageMetadata.batch)) {
146
- return;
147
- }
148
- // If the batch contains only a single op, clear the batch flag.
149
- if (messages.length === 1) {
150
- delete firstMessageMetadata.batch;
151
- return;
152
- }
153
- // Set the batch flag to false on the last message to indicate the end of the send batch
154
- const lastMessage = messages[messages.length - 1];
155
- lastMessage.metadata = Object.assign(Object.assign({}, lastMessage.metadata), { batch: false });
156
- });
157
- // Listen for updates and peek at the inbound
158
- this.deltaManager.inbound.on("push", (message) => {
159
- this.trackPending(message);
160
- });
161
- // Start with baseline - empty inbound queue.
162
- assert(!this.localPaused, 0x293 /* "initial state" */);
163
- const allPending = this.deltaManager.inbound.toArray();
164
- for (const pending of allPending) {
165
- this.trackPending(pending);
166
- }
167
- // We are intentionally directly listening to the "op" to inspect system ops as well.
168
- // If we do not observe system ops, we are likely to hit 0x296 assert when system ops
169
- // precedes start of incomplete batch.
170
- this.deltaManager.on("op", (message) => this.afterOpProcessing(message.sequenceNumber));
171
- }
172
- /**
173
- * The only public function in this class - called when we processed an op,
174
- * to make decision if op processing should be paused or not afer that.
175
- */
176
- afterOpProcessing(sequenceNumber) {
177
- assert(!this.localPaused, 0x294 /* "can't have op processing paused if we are processing an op" */);
178
- // If the inbound queue is ever empty, nothing to do!
179
- if (this.deltaManager.inbound.length === 0) {
180
- assert(this.pauseSequenceNumber === undefined, 0x295 /* "there should be no pending batch if we have no ops" */);
181
- return;
182
- }
183
- // The queue is
184
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
185
- // - here (processing ops until reaching start of incomplete batch)
186
- // - in trackPending(), when queue was empty and start of batch showed up.
187
- // 2. resumed when batch end comes in (in trackPending())
188
- // do we have incomplete batch to worry about?
189
- if (this.pauseSequenceNumber !== undefined) {
190
- assert(sequenceNumber < this.pauseSequenceNumber, 0x296 /* "we should never start processing incomplete batch!" */);
191
- // If the next op is the start of incomplete batch, then we can't process it until it's fully in - pause!
192
- if (sequenceNumber + 1 === this.pauseSequenceNumber) {
193
- this.pauseQueue();
194
- }
195
- }
196
- }
197
- pauseQueue() {
198
- assert(!this.localPaused, 0x297 /* "always called from resumed state" */);
199
- this.localPaused = true;
200
- this.timePaused = performance.now();
201
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
202
- this.deltaManager.inbound.pause();
203
- }
204
- resumeQueue(startBatch, messageEndBatch) {
205
- const endBatch = messageEndBatch.sequenceNumber;
206
- const duration = this.localPaused ? (performance.now() - this.timePaused) : undefined;
207
- this.batchCount++;
208
- if (this.batchCount % 1000 === 1) {
209
- this.logger.sendTelemetryEvent({
210
- eventName: "BatchStats",
211
- sequenceNumber: endBatch,
212
- length: endBatch - startBatch + 1,
213
- msnDistance: endBatch - messageEndBatch.minimumSequenceNumber,
214
- duration,
215
- batchCount: this.batchCount,
216
- interrupted: this.localPaused,
217
- });
218
- }
219
- // Return early if no change in value
220
- if (!this.localPaused) {
221
- return;
222
- }
223
- this.localPaused = false;
224
- // Random round number - we want to know when batch waiting paused op processing.
225
- if (duration !== undefined && duration > latencyThreshold) {
226
- this.logger.sendErrorEvent({
227
- eventName: "MaxBatchWaitTimeExceeded",
228
- duration,
229
- sequenceNumber: endBatch,
230
- length: endBatch - startBatch,
231
- });
232
- }
233
- this.deltaManager.inbound.resume();
234
- }
235
- /**
236
- * Called for each incoming op (i.e. inbound "push" notification)
237
- */
238
- trackPending(message) {
239
- assert(this.deltaManager.inbound.length !== 0, 0x298 /* "we have something in the queue that generates this event" */);
240
- assert((this.currentBatchClientId === undefined) === (this.pauseSequenceNumber === undefined), 0x299 /* "non-synchronized state" */);
241
- const metadata = message.metadata;
242
- const batchMetadata = metadata === null || metadata === void 0 ? void 0 : metadata.batch;
243
- // Protocol messages are never part of a runtime batch of messages
244
- if (!isUnpackedRuntimeMessage(message)) {
245
- // Protocol messages should never show up in the middle of the batch!
246
- assert(this.currentBatchClientId === undefined, 0x29a /* "System message in the middle of batch!" */);
247
- assert(batchMetadata === undefined, 0x29b /* "system op in a batch?" */);
248
- assert(!this.localPaused, 0x29c /* "we should be processing ops when there is no active batch" */);
249
- return;
250
- }
251
- if (this.currentBatchClientId === undefined && batchMetadata === undefined) {
252
- assert(!this.localPaused, 0x29d /* "we should be processing ops when there is no active batch" */);
253
- return;
254
- }
255
- // If the client ID changes then we can move the pause point. If it stayed the same then we need to check.
256
- // If batchMetadata is not undefined then if it's true we've begun a new batch - if false we've ended
257
- // the previous one
258
- if (this.currentBatchClientId !== undefined || batchMetadata === false) {
259
- if (this.currentBatchClientId !== message.clientId) {
260
- // "Batch not closed, yet message from another client!"
261
- throw new DataCorruptionError("OpBatchIncomplete", Object.assign({ runtimeVersion: pkgVersion, batchClientId: this.currentBatchClientId }, extractSafePropertiesFromMessage(message)));
262
- }
263
- }
264
- // The queue is
265
- // 1. paused only when the next message to be processed is the beginning of a batch. Done in two places:
266
- // - in afterOpProcessing() - processing ops until reaching start of incomplete batch
267
- // - here (batchMetadata == false below), when queue was empty and start of batch showed up.
268
- // 2. resumed when batch end comes in (batchMetadata === true case below)
269
- if (batchMetadata) {
270
- assert(this.currentBatchClientId === undefined, 0x29e /* "there can't be active batch" */);
271
- assert(!this.localPaused, 0x29f /* "we should be processing ops when there is no active batch" */);
272
- this.pauseSequenceNumber = message.sequenceNumber;
273
- this.currentBatchClientId = message.clientId;
274
- // Start of the batch
275
- // Only pause processing if queue has no other ops!
276
- // If there are any other ops in the queue, processing will be stopped when they are processed!
277
- if (this.deltaManager.inbound.length === 1) {
278
- this.pauseQueue();
279
- }
280
- }
281
- else if (batchMetadata === false) {
282
- assert(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
283
- // Batch is complete, we can process it!
284
- this.resumeQueue(this.pauseSequenceNumber, message);
285
- this.pauseSequenceNumber = undefined;
286
- this.currentBatchClientId = undefined;
287
- }
288
- else {
289
- // Continuation of current batch. Do nothing
290
- assert(this.currentBatchClientId !== undefined, 0x2a1 /* "logic error" */);
291
- }
292
- }
293
- }
294
- /**
295
- * This class has the following responsibilities:
296
- * 1. It tracks batches as we process ops and raises "batchBegin" and "batchEnd" events.
297
- * As part of it, it validates batch correctness (i.e. no system ops in the middle of batch)
298
- * 2. It creates instance of ScheduleManagerCore that ensures we never start processing ops from batch
299
- * unless all ops of the batch are in.
300
- */
301
- export class ScheduleManager {
302
- constructor(deltaManager, emitter, logger) {
303
- this.deltaManager = deltaManager;
304
- this.emitter = emitter;
305
- this.logger = logger;
306
- this.hitError = false;
307
- this.deltaScheduler = new DeltaScheduler(this.deltaManager, ChildLogger.create(this.logger, "DeltaScheduler"));
308
- void new ScheduleManagerCore(deltaManager, logger);
309
- }
310
- beforeOpProcessing(message) {
311
- var _a;
312
- if (this.batchClientId !== message.clientId) {
313
- assert(this.batchClientId === undefined, 0x2a2 /* "Batch is interrupted by other client op. Should be caught by trackPending()" */);
314
- // This could be the beginning of a new batch or an individual message.
315
- this.emitter.emit("batchBegin", message);
316
- this.deltaScheduler.batchBegin(message);
317
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
318
- if (batch) {
319
- this.batchClientId = message.clientId;
320
- }
321
- else {
322
- this.batchClientId = undefined;
323
- }
324
- }
325
- }
326
- afterOpProcessing(error, message) {
327
- var _a;
328
- // If this is no longer true, we need to revisit what we do where we set this.hitError.
329
- assert(!this.hitError, 0x2a3 /* "container should be closed on any error" */);
330
- if (error) {
331
- // We assume here that loader will close container and stop processing all future ops.
332
- // This is implicit dependency. If this flow changes, this code might no longer be correct.
333
- this.hitError = true;
334
- this.batchClientId = undefined;
335
- this.emitter.emit("batchEnd", error, message);
336
- this.deltaScheduler.batchEnd(message);
337
- return;
338
- }
339
- const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
340
- // If no batchClientId has been set then we're in an individual batch. Else, if we get
341
- // batch end metadata, this is end of the current batch.
342
- if (this.batchClientId === undefined || batch === false) {
343
- this.batchClientId = undefined;
344
- this.emitter.emit("batchEnd", undefined, message);
345
- this.deltaScheduler.batchEnd(message);
346
- return;
347
- }
348
- }
349
- }
350
- /**
351
- * Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
352
- * special-case for document dirty state. Ultimately we should have no special-cases from the
353
- * ContainerRuntime's perspective.
354
- */
355
- export const agentSchedulerId = "_scheduler";
356
- // safely check navigator and get the hardware spec value
357
- export function getDeviceSpec() {
358
- try {
359
- if (typeof navigator === "object" && navigator !== null) {
360
- return {
361
- deviceMemory: navigator.deviceMemory,
362
- hardwareConcurrency: navigator.hardwareConcurrency,
363
- };
364
- }
365
- }
366
- catch (_a) {
367
- }
368
- return {};
369
- }
370
- /**
371
- * Represents the runtime of the container. Contains helper functions/state of the container.
372
- * It will define the store level mappings.
373
- */
374
- export class ContainerRuntime extends TypedEventEmitter {
375
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
376
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
377
- if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
378
- super();
379
- this.context = context;
380
- this.registry = registry;
381
- this.runtimeOptions = runtimeOptions;
382
- this.containerScope = containerScope;
383
- this.logger = logger;
384
- this._storage = _storage;
385
- this.requestHandler = requestHandler;
386
- this.summaryConfiguration = summaryConfiguration;
387
- this.defaultMaxConsecutiveReconnects = 15;
388
- this._orderSequentiallyCalls = 0;
389
- this.needsFlush = false;
390
- this.flushTrigger = false;
391
- this.savedOps = [];
392
- this.consecutiveReconnects = 0;
393
- this._disposed = false;
394
- this.emitDirtyDocumentEvent = true;
395
- this.defaultTelemetrySignalSampleCount = 100;
396
- this._perfSignalData = {
397
- signalsLost: 0,
398
- signalSequenceNumber: 0,
399
- signalTimestamp: 0,
400
- trackingSignalSequenceNumber: undefined,
401
- };
402
- this.summarizeOnDemand = (...args) => {
403
- if (this.clientDetails.type === summarizerClientType) {
404
- return this.summarizer.summarizeOnDemand(...args);
405
- }
406
- else if (this.summaryManager !== undefined) {
407
- return this.summaryManager.summarizeOnDemand(...args);
408
- }
409
- else {
410
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
411
- // disableSummaries is turned on. We are throwing instead of returning a failure here,
412
- // because it is a misuse of the API rather than an expected failure.
413
- throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
414
- }
415
- };
416
- this.enqueueSummarize = (...args) => {
417
- if (this.clientDetails.type === summarizerClientType) {
418
- return this.summarizer.enqueueSummarize(...args);
419
- }
420
- else if (this.summaryManager !== undefined) {
421
- return this.summaryManager.enqueueSummarize(...args);
422
- }
423
- else {
424
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
425
- // generateSummaries is turned off. We are throwing instead of returning a failure here,
426
- // because it is a misuse of the API rather than an expected failure.
427
- throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
428
- }
429
- };
430
- this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
431
- // Default to false (enabled).
432
- this.disableIsolatedChannels = (_b = this.runtimeOptions.summaryOptions.disableIsolatedChannels) !== null && _b !== void 0 ? _b : false;
433
- this._connected = this.context.connected;
434
- this.chunkMap = new Map(chunks);
435
- this.handleContext = new ContainerFluidHandleContext("", this);
436
- this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
437
- this.summariesDisabled = this.isSummariesDisabled();
438
- this.heuristicsDisabled = this.isHeuristicsDisabled();
439
- this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
440
- this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
441
- this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
442
- this._aliasingEnabled =
443
- ((_c = this.mc.config.getBoolean(useDataStoreAliasingKey)) !== null && _c !== void 0 ? _c : false) ||
444
- ((_d = runtimeOptions.useDataStoreAliasing) !== null && _d !== void 0 ? _d : false);
445
- this._maxOpSizeInBytes = ((_e = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _e !== void 0 ? _e : defaultMaxOpSizeInBytes);
446
- this.maxConsecutiveReconnects =
447
- (_f = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _f !== void 0 ? _f : this.defaultMaxConsecutiveReconnects;
448
- this._flushMode = runtimeOptions.flushMode;
449
- const pendingRuntimeState = context.pendingLocalState;
450
- const baseSnapshot = (_g = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _g !== void 0 ? _g : context.baseSnapshot;
451
- this.garbageCollector = GarbageCollector.create({
452
- runtime: this,
453
- gcOptions: this.runtimeOptions.gcOptions,
454
- baseSnapshot,
455
- baseLogger: this.mc.logger,
456
- existing,
457
- metadata,
458
- isSummarizerClient: this.context.clientDetails.type === summarizerClientType,
459
- getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
460
- getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
461
- readAndParseBlob: async (id) => readAndParse(this.storage, id),
462
- });
463
- const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
464
- this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
465
- // Summarize function to call when summarize is called. Summarizer node always tracks summary state.
466
- async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
467
- // Latest change sequence number, no changes since summary applied yet
468
- loadedFromSequenceNumber,
469
- // Summary reference sequence number, undefined if no summary yet
470
- baseSnapshot ? loadedFromSequenceNumber : undefined, {
471
- // Must set to false to prevent sending summary handle which would be pointing to
472
- // a summary with an older protocol state.
473
- canReuseHandle: false,
474
- // Must set to true to throw on any data stores failure that was too severe to be handled.
475
- // We also are not decoding the base summaries at the root.
476
- throwOnFailure: true,
477
- // If GC should not run, let the summarizer node know so that it does not track GC state.
478
- gcDisabled: !this.garbageCollector.shouldRunGC,
479
- });
480
- if (baseSnapshot) {
481
- this.summarizerNode.loadBaseSummaryWithoutDifferential(baseSnapshot);
482
- }
483
- this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
484
- this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this, this.logger);
485
- this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
486
- this.deltaSender = this.deltaManager;
487
- this.pendingStateManager = new PendingStateManager({
488
- applyStashedOp: this.applyStashedOp.bind(this),
489
- clientId: () => this.clientId,
490
- close: this.closeFn,
491
- connected: () => this.connected,
492
- flush: this.flush.bind(this),
493
- flushMode: () => this.flushMode,
494
- reSubmit: this.reSubmit.bind(this),
495
- rollback: this.rollback.bind(this),
496
- setFlushMode: (mode) => this.setFlushMode(mode),
497
- }, this._flushMode, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
498
- this.context.quorum.on("removeMember", (clientId) => {
499
- this.clearPartialChunks(clientId);
500
- });
501
- this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
502
- this.dirtyContainer = this.context.attachState !== AttachState.Attached
503
- || this.pendingStateManager.hasPendingMessages();
504
- this.context.updateDirtyContainerState(this.dirtyContainer);
505
- if (this.summariesDisabled) {
506
- this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
507
- }
508
- else {
509
- const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
510
- const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
511
- const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
512
- this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary, this.summarizerClientElectionEnabled);
513
- if (this.context.clientDetails.type === summarizerClientType) {
514
- this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
515
- }
516
- else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
517
- // Only create a SummaryManager and SummarizerClientElection
518
- // if summaries are enabled and we are not the summarizer client.
519
- const defaultAction = () => {
520
- if (this.summaryCollection.opsSinceLastAck > this.maxOpsSinceLastSummary) {
521
- this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
522
- // unregister default to no log on every op after falling behind
523
- // and register summary ack handler to re-register this handler
524
- // after successful summary
525
- this.summaryCollection.once(MessageType.SummaryAck, () => {
526
- this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
527
- // we've caught up, so re-register the default action to monitor for
528
- // falling behind, and unregister ourself
529
- this.summaryCollection.on("default", defaultAction);
530
- });
531
- this.summaryCollection.off("default", defaultAction);
532
- }
533
- };
534
- this.summaryCollection.on("default", defaultAction);
535
- // Create the SummaryManager and mark the initial state
536
- this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
537
- this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new Throttler(60 * 1000, // 60 sec delay window
538
- 30 * 1000, // 30 sec max delay
539
- // throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
540
- formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
541
- initialDelayMs: this.initialSummarizerDelayMs,
542
- }, this.heuristicsDisabled);
543
- this.summaryManager.start();
544
- }
545
- }
546
- this.deltaManager.on("readonly", (readonly) => {
547
- // we accumulate ops while being in read-only state.
548
- // once user gets write permissions and we have active connection, flush all pending ops.
549
- assert(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
550
- // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
551
- // when we either never send an op, or attempted to send it but we know for sure it was not
552
- // sequenced by server and will never be sequenced (i.e. was lost)
553
- // For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
554
- // ops that made it from previous connection, before switching clientId and raising "connected" event
555
- // But with read-only permissions, if we transition between read-only and r/w states while on same
556
- // connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
557
- // being in read-only state.
558
- // For that reason, we support getting to read-only state only when disconnected. This ensures that we
559
- // can rely on same safety mechanism and resend ops only when we establish new connection.
560
- // This is applicable for read-only permissions (event is raised before connection is properly registered),
561
- // but it's an extra requirement for Container.forceReadonly() API
562
- assert(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
563
- this.replayPendingStates();
564
- });
565
- // logging hardware telemetry
566
- logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
567
- let loadSummaryNumber;
568
- // Get the container creation metadata. For new container, we initialize these. For existing containers,
569
- // get the values from the metadata blob.
570
- if (existing) {
571
- this.createContainerMetadata = {
572
- createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
573
- createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
574
- };
575
- // back-compat 0.59.3000 - Older document may either write summaryCount or not write it at all. If it does
576
- // not write it, initialize summaryNumber to 0.
577
- loadSummaryNumber = (_j = (_h = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _h !== void 0 ? _h : metadata === null || metadata === void 0 ? void 0 : metadata.summaryCount) !== null && _j !== void 0 ? _j : 0;
578
- }
579
- else {
580
- this.createContainerMetadata = {
581
- createContainerRuntimeVersion: pkgVersion,
582
- createContainerTimestamp: Date.now(),
583
- };
584
- loadSummaryNumber = 0;
585
- }
586
- this.nextSummaryNumber = loadSummaryNumber + 1;
587
- 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 }));
588
- ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
589
- BindBatchTracker(this, this.logger);
590
- this.opTracker = new OpTracker(this.deltaManager, this.mc.config.getBoolean(disableOpTrackingKey) === true);
591
- }
592
- get IContainerRuntime() { return this; }
593
- get IFluidRouter() { return this; }
594
- /**
595
- * Load the stores from a snapshot and returns the runtime.
596
- * @param context - Context of the container.
597
- * @param registryEntries - Mapping to the stores.
598
- * @param requestHandler - Request handlers for the container runtime
599
- * @param runtimeOptions - Additional options to be passed to the runtime
600
- * @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
601
- */
602
- static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing) {
603
- var _a, _b, _c;
604
- // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
605
- // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
606
- const backCompatContext = context;
607
- const passLogger = (_a = backCompatContext.taggedLogger) !== null && _a !== void 0 ? _a : new TaggedLoggerAdapter(backCompatContext.logger);
608
- const logger = ChildLogger.create(passLogger, undefined, {
609
- all: {
610
- runtimeVersion: pkgVersion,
611
- },
612
- });
613
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, flushMode = defaultFlushMode, enableOfflineLoad = false, } = runtimeOptions;
614
- const pendingRuntimeState = context.pendingLocalState;
615
- const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
616
- const storage = !pendingRuntimeState ?
617
- context.storage :
618
- new SerializedSnapshotStorage(() => { return context.storage; }, pendingRuntimeState.snapshotBlobs);
619
- const registry = new FluidDataStoreRegistry(registryEntries);
620
- const tryFetchBlob = async (blobName) => {
621
- const blobId = baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.blobs[blobName];
622
- if (baseSnapshot && blobId) {
623
- // IContainerContext storage api return type still has undefined in 0.39 package version.
624
- // So once we release 0.40 container-defn package we can remove this check.
625
- assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
626
- return readAndParse(storage, blobId);
627
- }
628
- };
629
- const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
630
- tryFetchBlob(chunksBlobName),
631
- tryFetchBlob(metadataBlobName),
632
- tryFetchBlob(electedSummarizerBlobName),
633
- tryFetchBlob(aliasBlobName),
634
- ]);
635
- const loadExisting = existing === true || context.existing === true;
636
- // read snapshot blobs needed for BlobManager to load
637
- const blobManagerSnapshot = await BlobManager.load(baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[blobsTreeName], async (id) => {
638
- // IContainerContext storage api return type still has undefined in 0.39 package version.
639
- // So once we release 0.40 container-defn package we can remove this check.
640
- assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
641
- return readAndParse(storage, id);
642
- });
643
- // Verify summary runtime sequence number matches protocol sequence number.
644
- const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
645
- // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
646
- if (!pendingRuntimeState && runtimeSequenceNumber !== undefined) {
647
- const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
648
- // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
649
- if (loadSequenceNumberVerification !== "bypass" && runtimeSequenceNumber !== protocolSequenceNumber) {
650
- // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
651
- const error = new DataCorruptionError(
652
- // pre-0.58 error message: SummaryMetadataMismatch
653
- "Summary metadata mismatch", { runtimeVersion: pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
654
- if (loadSequenceNumberVerification === "log") {
655
- logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
656
- }
657
- else {
658
- context.closeFn(error);
659
- }
660
- }
661
- }
662
- const runtime = new ContainerRuntime(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
663
- summaryOptions,
664
- gcOptions,
665
- loadSequenceNumberVerification,
666
- useDataStoreAliasing,
667
- flushMode,
668
- enableOfflineLoad,
669
- }, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
670
- if (pendingRuntimeState) {
671
- await runtime.processSavedOps(pendingRuntimeState);
672
- // delete these once runtime has seen them to save space
673
- pendingRuntimeState.savedOps = [];
674
- }
675
- await runtime.getSnapshotBlobs();
676
- return runtime;
677
- }
678
- get options() {
679
- return this.context.options;
680
- }
681
- get clientId() {
682
- return this.context.clientId;
683
- }
684
- get clientDetails() {
685
- return this.context.clientDetails;
686
- }
687
- get deltaManager() {
688
- return this.context.deltaManager;
689
- }
690
- get storage() {
691
- return this._storage;
692
- }
693
- get reSubmitFn() {
694
- // eslint-disable-next-line @typescript-eslint/unbound-method
695
- return this.reSubmit;
696
- }
697
- get closeFn() {
698
- return this.context.closeFn;
699
- }
700
- get flushMode() {
701
- return this._flushMode;
702
- }
703
- get scope() {
704
- return this.containerScope;
705
- }
706
- get IFluidDataStoreRegistry() {
707
- return this.registry;
708
- }
709
- get attachState() {
710
- return this.context.attachState;
711
- }
712
- get IFluidHandleContext() {
713
- return this.handleContext;
714
- }
715
- get connected() {
716
- return this._connected;
717
- }
718
- /** clientId of parent (non-summarizing) container that owns summarizer container */
719
- get summarizerClientId() {
720
- var _a;
721
- return (_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.electedClientId;
722
- }
723
- get disposed() { return this._disposed; }
724
- get summarizer() {
725
- assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
726
- return this._summarizer;
727
- }
728
- isSummariesDisabled() {
729
- // back-compat: disableSummaries was moved from ISummaryRuntimeOptions
730
- // to ISummaryConfiguration in 0.60.
731
- if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
732
- return true;
733
- }
734
- return this.summaryConfiguration.state === "disabled";
735
- }
736
- isHeuristicsDisabled() {
737
- var _a;
738
- // back-compat: disableHeuristics was moved from ISummarizerOptions
739
- // to ISummaryConfiguration in 0.60.
740
- if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
741
- return true;
742
- }
743
- return this.summaryConfiguration.state === "disableHeuristics";
744
- }
745
- isSummarizerClientElectionEnabled() {
746
- var _a;
747
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
748
- return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
749
- }
750
- // back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
751
- // to ISummaryConfiguration in 0.60.
752
- if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
753
- return true;
754
- }
755
- if (this.summaryConfiguration.state !== "disabled") {
756
- return this.summaryConfiguration.summarizerClientElection === true;
757
- }
758
- else {
759
- return false;
760
- }
761
- }
762
- getMaxOpsSinceLastSummary() {
763
- // back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
764
- // to ISummaryConfiguration in 0.60.
765
- if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
766
- return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
767
- }
768
- if (this.summaryConfiguration.state !== "disabled") {
769
- return this.summaryConfiguration.maxOpsSinceLastSummary;
770
- }
771
- else {
772
- return 0;
773
- }
774
- }
775
- getInitialSummarizerDelayMs() {
776
- // back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
777
- // to ISummaryConfiguration in 0.60.
778
- if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
779
- return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
780
- }
781
- if (this.summaryConfiguration.state !== "disabled") {
782
- return this.summaryConfiguration.initialSummarizerDelayMs;
783
- }
784
- else {
785
- return 0;
786
- }
787
- }
788
- dispose(error) {
789
- var _a;
790
- if (this._disposed) {
791
- return;
792
- }
793
- this._disposed = true;
794
- this.logger.sendTelemetryEvent({
795
- eventName: "ContainerRuntimeDisposed",
796
- isDirty: this.isDirty,
797
- lastSequenceNumber: this.deltaManager.lastSequenceNumber,
798
- attachState: this.attachState,
799
- }, error);
800
- if (this.summaryManager !== undefined) {
801
- this.summaryManager.dispose();
802
- }
803
- this.garbageCollector.dispose();
804
- (_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.dispose();
805
- this.dataStores.dispose();
806
- this.pendingStateManager.dispose();
807
- this.emit("dispose");
808
- this.removeAllListeners();
809
- }
810
- get IFluidTokenProvider() {
811
- var _a;
812
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
813
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
814
- return {
815
- intelligence: this.options.intelligence,
816
- };
817
- }
818
- return undefined;
819
- }
820
- /**
821
- * Notifies this object about the request made to the container.
822
- * @param request - Request made to the handler.
823
- */
824
- async request(request) {
825
- try {
826
- const parser = RequestParser.create(request);
827
- const id = parser.pathParts[0];
828
- if (id === "_summarizer" && parser.pathParts.length === 1) {
829
- if (this._summarizer !== undefined) {
830
- return {
831
- status: 200,
832
- mimeType: "fluid/object",
833
- value: this.summarizer,
834
- };
835
- }
836
- return create404Response(request);
837
- }
838
- if (this.requestHandler !== undefined) {
839
- return this.requestHandler(parser, this);
840
- }
841
- return create404Response(request);
842
- }
843
- catch (error) {
844
- return exceptionToResponse(error);
845
- }
846
- }
847
- /**
848
- * Resolves URI representing handle
849
- * @param request - Request made to the handler.
850
- */
851
- async resolveHandle(request) {
852
- try {
853
- const requestParser = RequestParser.create(request);
854
- const id = requestParser.pathParts[0];
855
- if (id === "_channels") {
856
- return this.resolveHandle(requestParser.createSubRequest(1));
857
- }
858
- if (id === BlobManager.basePath && requestParser.isLeaf(2)) {
859
- const handle = await this.blobManager.getBlob(requestParser.pathParts[1]);
860
- if (handle) {
861
- return {
862
- status: 200,
863
- mimeType: "fluid/object",
864
- value: handle.get(),
865
- };
866
- }
867
- else {
868
- return create404Response(request);
869
- }
870
- }
871
- else if (requestParser.pathParts.length > 0) {
872
- const dataStore = await this.getDataStoreFromRequest(id, request);
873
- const subRequest = requestParser.createSubRequest(1);
874
- // We always expect createSubRequest to include a leading slash, but asserting here to protect against
875
- // unintentionally modifying the url if that changes.
876
- assert(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
877
- return dataStore.IFluidRouter.request(subRequest);
878
- }
879
- return create404Response(request);
880
- }
881
- catch (error) {
882
- return exceptionToResponse(error);
883
- }
884
- }
885
- internalId(maybeAlias) {
886
- var _a;
887
- return (_a = this.dataStores.aliases().get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
888
- }
889
- async getDataStoreFromRequest(id, request) {
890
- var _a, _b, _c;
891
- const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
892
- ? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait]
893
- : true;
894
- const internalId = this.internalId(id);
895
- const dataStoreContext = await this.dataStores.getDataStore(internalId, wait);
896
- /**
897
- * If GC should run and this an external app request with "externalRequest" header, we need to return
898
- * an error if the data store being requested is marked as unreferenced as per the data store's base
899
- * GC data.
900
- *
901
- * This is a workaround to handle scenarios where a data store shared with an external app is deleted
902
- * and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
903
- */
904
- if (((_c = request.headers) === null || _c === void 0 ? void 0 : _c[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
905
- // The data store is referenced if used routes in the base summary has a route to self.
906
- // Older documents may not have used routes in the summary. They are considered referenced.
907
- const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
908
- if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
909
- throw responseToException(create404Response(request), request);
910
- }
911
- }
912
- const dataStoreChannel = await dataStoreContext.realize();
913
- // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
914
- // the same as GC nodes id.
915
- const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
916
- this.garbageCollector.nodeUpdated(`/${urlWithoutQuery}`, "Loaded", undefined /* timestampMs */, dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
917
- return dataStoreChannel;
918
- }
919
- /** Adds the container's metadata to the given summary tree. */
920
- addMetadataToSummary(summaryTree) {
921
- var _a;
922
- const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
923
- // back-compat 0.59.3000: This is renamed to summaryNumber. Can be removed when 0.59.3000 saturates.
924
- summaryCount: this.nextSummaryNumber,
925
- // Increment the summary number for the next summary that will be generated.
926
- summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined }), this.garbageCollector.getMetadata()), {
927
- // The last message processed at the time of summary. If there are no new messages, use the message from the
928
- // last summary.
929
- message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
930
- addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
931
- }
932
- addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
933
- var _a;
934
- this.addMetadataToSummary(summaryTree);
935
- if (this.chunkMap.size > 0) {
936
- const content = JSON.stringify([...this.chunkMap]);
937
- addBlobToSummary(summaryTree, chunksBlobName, content);
938
- }
939
- const dataStoreAliases = this.dataStores.aliases();
940
- if (dataStoreAliases.size > 0) {
941
- addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
942
- }
943
- if (this.summarizerClientElection) {
944
- const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
945
- addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
946
- }
947
- const blobManagerSummary = this.blobManager.summarize();
948
- // Some storage (like git) doesn't allow empty tree, so we can omit it.
949
- // and the blob manager can handle the tree not existing when loading
950
- if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
951
- addTreeToSummary(summaryTree, blobsTreeName, blobManagerSummary);
952
- }
953
- if (this.garbageCollector.writeDataAtRoot) {
954
- const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
955
- if (gcSummary !== undefined) {
956
- addSummarizeResultToSummary(summaryTree, gcTreeKey, gcSummary);
957
- }
958
- }
959
- }
960
- // Track how many times the container tries to reconnect with pending messages.
961
- // This happens when the connection state is changed and we reset the counter
962
- // when we are able to process a local op or when there are no pending messages.
963
- // If this counter reaches a max, it's a good indicator that the container
964
- // is not making progress and it is stuck in a retry loop.
965
- shouldContinueReconnecting() {
966
- if (this.maxConsecutiveReconnects <= 0) {
967
- // Feature disabled, we never stop reconnecting
968
- return true;
969
- }
970
- if (!this.pendingStateManager.hasPendingMessages()) {
971
- // If there are no pending messages, we can always reconnect
972
- this.resetReconnectCount();
973
- return true;
974
- }
975
- if (this.consecutiveReconnects === Math.floor(this.maxConsecutiveReconnects / 2)) {
976
- // If we're halfway through the max reconnects, send an event in order
977
- // to better identify false positives, if any. If the rate of this event
978
- // matches Container Close count below, we can safely cut down
979
- // maxConsecutiveReconnects to half.
980
- this.mc.logger.sendTelemetryEvent({
981
- eventName: "ReconnectsWithNoProgress",
982
- attempts: this.consecutiveReconnects,
983
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
984
- });
985
- }
986
- return this.consecutiveReconnects < this.maxConsecutiveReconnects;
987
- }
988
- resetReconnectCount() {
989
- this.consecutiveReconnects = 0;
990
- }
991
- replayPendingStates() {
992
- // We need to be able to send ops to replay states
993
- if (!this.canSendOps()) {
994
- return;
995
- }
996
- // We need to temporary clear the dirty flags and disable
997
- // dirty state change events to detect whether replaying ops
998
- // has any effect.
999
- // Save the old state, reset to false, disable event emit
1000
- const oldState = this.dirtyContainer;
1001
- this.dirtyContainer = false;
1002
- assert(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1003
- this.emitDirtyDocumentEvent = false;
1004
- let newState;
1005
- try {
1006
- // replay the ops
1007
- this.pendingStateManager.replayPendingStates();
1008
- }
1009
- finally {
1010
- // Save the new start and restore the old state, re-enable event emit
1011
- newState = this.dirtyContainer;
1012
- this.dirtyContainer = oldState;
1013
- this.emitDirtyDocumentEvent = true;
1014
- }
1015
- // Officially transition from the old state to the new state.
1016
- this.updateDocumentDirtyState(newState);
1017
- }
1018
- async applyStashedOp(type, op) {
1019
- switch (type) {
1020
- case ContainerMessageType.FluidDataStoreOp:
1021
- return this.dataStores.applyStashedOp(op);
1022
- case ContainerMessageType.Attach:
1023
- return this.dataStores.applyStashedAttachOp(op);
1024
- case ContainerMessageType.Alias:
1025
- case ContainerMessageType.BlobAttach:
1026
- return;
1027
- case ContainerMessageType.ChunkedOp:
1028
- throw new Error("chunkedOp not expected here");
1029
- case ContainerMessageType.Rejoin:
1030
- throw new Error("rejoin not expected here");
1031
- default:
1032
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
1033
- }
1034
- }
1035
- setConnectionState(connected, clientId) {
1036
- this.verifyNotClosed();
1037
- // There might be no change of state due to Container calling this API after loading runtime.
1038
- const changeOfState = this._connected !== connected;
1039
- const reconnection = changeOfState && connected;
1040
- this._connected = connected;
1041
- if (!connected) {
1042
- this._perfSignalData.signalsLost = 0;
1043
- this._perfSignalData.signalTimestamp = 0;
1044
- this._perfSignalData.trackingSignalSequenceNumber = undefined;
1045
- }
1046
- if (reconnection) {
1047
- this.consecutiveReconnects++;
1048
- if (!this.shouldContinueReconnecting()) {
1049
- this.closeFn(
1050
- // pre-0.58 error message: MaxReconnectsWithNoProgress
1051
- DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops", "setConnectionState", undefined, {
1052
- dataLoss: 1,
1053
- attempts: this.consecutiveReconnects,
1054
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1055
- }));
1056
- return;
1057
- }
1058
- }
1059
- if (changeOfState) {
1060
- this.replayPendingStates();
1061
- }
1062
- this.dataStores.setConnectionState(connected, clientId);
1063
- raiseConnectedEvent(this.mc.logger, this, connected, clientId);
1064
- }
1065
- process(messageArg, local) {
1066
- var _a, _b;
1067
- this.verifyNotClosed();
1068
- // If it's not message for runtime, bail out right away.
1069
- if (!isUnpackedRuntimeMessage(messageArg)) {
1070
- return;
1071
- }
1072
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
1073
- this.savedOps.push(messageArg);
1074
- }
1075
- // Do shallow copy of message, as methods below will modify it.
1076
- // There might be multiple container instances receiving same message
1077
- // We do not need to make deep copy, as each layer will just replace message.content itself,
1078
- // but would not modify contents details
1079
- let message = Object.assign({}, messageArg);
1080
- // Surround the actual processing of the operation with messages to the schedule manager indicating
1081
- // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1082
- // messages once a batch has been fully processed.
1083
- this.scheduleManager.beforeOpProcessing(message);
1084
- try {
1085
- message = unpackRuntimeMessage(message);
1086
- // Chunk processing must come first given that we will transform the message to the unchunked version
1087
- // once all pieces are available
1088
- message = this.processRemoteChunkedMessage(message);
1089
- let localOpMetadata;
1090
- if (local) {
1091
- // Call the PendingStateManager to process local messages.
1092
- // Do not process local chunked ops until all pieces are available.
1093
- if (message.type !== ContainerMessageType.ChunkedOp) {
1094
- localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1095
- }
1096
- }
1097
- // If there are no more pending messages after processing a local message,
1098
- // the document is no longer dirty.
1099
- if (!this.pendingStateManager.hasPendingMessages()) {
1100
- this.updateDocumentDirtyState(false);
1101
- }
1102
- switch (message.type) {
1103
- case ContainerMessageType.Attach:
1104
- this.dataStores.processAttachMessage(message, local);
1105
- break;
1106
- case ContainerMessageType.Alias:
1107
- this.processAliasMessage(message, localOpMetadata, local);
1108
- break;
1109
- case ContainerMessageType.FluidDataStoreOp:
1110
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1111
- break;
1112
- case ContainerMessageType.BlobAttach:
1113
- assert((_b = message === null || message === void 0 ? void 0 : message.metadata) === null || _b === void 0 ? void 0 : _b.blobId, 0x12a /* "Missing blob id on metadata" */);
1114
- this.blobManager.processBlobAttachOp(message.metadata.blobId, local);
1115
- break;
1116
- default:
1117
- }
1118
- this.emit("op", message);
1119
- this.scheduleManager.afterOpProcessing(undefined, message);
1120
- if (local) {
1121
- // If we have processed a local op, this means that the container is
1122
- // making progress and we can reset the counter for how many times
1123
- // we have consecutively replayed the pending states
1124
- this.resetReconnectCount();
1125
- }
1126
- }
1127
- catch (e) {
1128
- this.scheduleManager.afterOpProcessing(e, message);
1129
- throw e;
1130
- }
1131
- }
1132
- processAliasMessage(message, localOpMetadata, local) {
1133
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1134
- }
1135
- /**
1136
- * Emits the Signal event and update the perf signal data.
1137
- * @param clientSignalSequenceNumber - is the client signal sequence number to be uploaded.
1138
- */
1139
- sendSignalTelemetryEvent(clientSignalSequenceNumber) {
1140
- const duration = Date.now() - this._perfSignalData.signalTimestamp;
1141
- this.logger.sendPerformanceEvent({
1142
- eventName: "SignalLatency",
1143
- duration,
1144
- signalsLost: this._perfSignalData.signalsLost,
1145
- });
1146
- this._perfSignalData.signalsLost = 0;
1147
- this._perfSignalData.signalTimestamp = 0;
1148
- }
1149
- processSignal(message, local) {
1150
- const envelope = message.content;
1151
- const transformed = {
1152
- clientId: message.clientId,
1153
- content: envelope.contents.content,
1154
- type: envelope.contents.type,
1155
- };
1156
- // Only collect signal telemetry for messages sent by the current client.
1157
- if (message.clientId === this.clientId && this.connected) {
1158
- // Check to see if the signal was lost.
1159
- if (this._perfSignalData.trackingSignalSequenceNumber !== undefined &&
1160
- envelope.clientSignalSequenceNumber > this._perfSignalData.trackingSignalSequenceNumber) {
1161
- this._perfSignalData.signalsLost++;
1162
- this._perfSignalData.trackingSignalSequenceNumber = undefined;
1163
- this.logger.sendErrorEvent({
1164
- eventName: "SignalLost",
1165
- type: envelope.contents.type,
1166
- signalsLost: this._perfSignalData.signalsLost,
1167
- trackingSequenceNumber: this._perfSignalData.trackingSignalSequenceNumber,
1168
- clientSignalSequenceNumber: envelope.clientSignalSequenceNumber,
1169
- });
1170
- }
1171
- else if (envelope.clientSignalSequenceNumber === this._perfSignalData.trackingSignalSequenceNumber) {
1172
- this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
1173
- this._perfSignalData.trackingSignalSequenceNumber = undefined;
1174
- }
1175
- }
1176
- if (envelope.address === undefined) {
1177
- // No address indicates a container signal message.
1178
- this.emit("signal", transformed, local);
1179
- return;
1180
- }
1181
- this.dataStores.processSignal(envelope.address, transformed, local);
1182
- }
1183
- async getRootDataStore(id, wait = true) {
1184
- const internalId = this.internalId(id);
1185
- const context = await this.dataStores.getDataStore(internalId, wait);
1186
- assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
1187
- return context.realize();
1188
- }
1189
- setFlushMode(mode) {
1190
- if (mode === this._flushMode) {
1191
- return;
1192
- }
1193
- this.mc.logger.sendTelemetryEvent({
1194
- eventName: "FlushMode Updated",
1195
- old: this._flushMode,
1196
- new: mode,
1197
- });
1198
- // Flush any pending batches if switching to immediate
1199
- if (mode === FlushMode.Immediate) {
1200
- this.flush();
1201
- }
1202
- this._flushMode = mode;
1203
- // Let the PendingStateManager know that FlushMode has been updated.
1204
- this.pendingStateManager.onFlushModeUpdated(mode);
1205
- }
1206
- flush() {
1207
- assert(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1208
- if (!this.deltaSender) {
1209
- return;
1210
- }
1211
- // Let the PendingStateManager know that there was an attempt to flush messages.
1212
- // Note that this should happen before the `this.needsFlush` check below because in the scenario where we are
1213
- // not connected, `this.needsFlush` will be false but the PendingStateManager might have pending messages and
1214
- // hence needs to track this.
1215
- this.pendingStateManager.onFlush();
1216
- // If flush has already been called then exit early
1217
- if (!this.needsFlush) {
1218
- return;
1219
- }
1220
- this.needsFlush = false;
1221
- // Did we disconnect in the middle of turn-based batch?
1222
- // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
1223
- if (!this.canSendOps()) {
1224
- return;
1225
- }
1226
- return this.deltaSender.flush();
1227
- }
1228
- orderSequentially(callback) {
1229
- // If flush mode is already TurnBased we are either
1230
- // nested in another orderSequentially, or
1231
- // the app is flushing manually, in which
1232
- // case this invocation doesn't own
1233
- // flushing.
1234
- if (this.flushMode === FlushMode.TurnBased) {
1235
- this.trackOrderSequentiallyCalls(callback);
1236
- return;
1237
- }
1238
- const savedFlushMode = this.flushMode;
1239
- this.setFlushMode(FlushMode.TurnBased);
1240
- try {
1241
- this.trackOrderSequentiallyCalls(callback);
1242
- this.flush();
1243
- }
1244
- finally {
1245
- this.setFlushMode(savedFlushMode);
1246
- }
1247
- }
1248
- trackOrderSequentiallyCalls(callback) {
1249
- let checkpoint;
1250
- if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1251
- checkpoint = this.pendingStateManager.checkpoint();
1252
- }
1253
- try {
1254
- this._orderSequentiallyCalls++;
1255
- callback();
1256
- }
1257
- catch (error) {
1258
- if (checkpoint) {
1259
- // This will throw and close the container if rollback fails
1260
- checkpoint.rollback();
1261
- }
1262
- else {
1263
- // pre-0.58 error message: orderSequentiallyCallbackException
1264
- this.closeFn(new GenericError("orderSequentially callback exception", error));
1265
- }
1266
- throw error; // throw the original error for the consumer of the runtime
1267
- }
1268
- finally {
1269
- this._orderSequentiallyCalls--;
1270
- }
1271
- }
1272
- async createDataStore(pkg) {
1273
- const internalId = uuid();
1274
- return channelToDataStore(await this._createDataStore(pkg, false /* isRoot */, internalId), internalId, this, this.dataStores, this.mc.logger);
1275
- }
1276
- /**
1277
- * Creates a root datastore directly with a user generated id and attaches it to storage.
1278
- * It is vulnerable to name collisions and should not be used.
1279
- *
1280
- * This method will be removed. See #6465.
1281
- */
1282
- async createRootDataStoreLegacy(pkg, rootDataStoreId) {
1283
- const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
1284
- // back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel. For
1285
- // older versions, we still have to call bindToContext.
1286
- if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
1287
- fluidDataStore.makeVisibleAndAttachGraph();
1288
- }
1289
- else {
1290
- fluidDataStore.bindToContext();
1291
- }
1292
- return fluidDataStore;
1293
- }
1294
- /**
1295
- * @deprecated - will be removed in an upcoming release. See #9660.
1296
- */
1297
- async createRootDataStore(pkg, rootDataStoreId) {
1298
- if (rootDataStoreId.includes("/")) {
1299
- throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1300
- }
1301
- return this._aliasingEnabled === true ?
1302
- this.createAndAliasDataStore(pkg, rootDataStoreId) :
1303
- this.createRootDataStoreLegacy(pkg, rootDataStoreId);
1304
- }
1305
- /**
1306
- * Creates a data store then attempts to alias it.
1307
- * If aliasing fails, it will raise an exception.
1308
- *
1309
- * This method will be removed. See #6465.
1310
- *
1311
- * @param pkg - Package name of the data store
1312
- * @param alias - Alias to be assigned to the data store
1313
- * @param props - Properties for the data store
1314
- * @returns - An aliased data store which can can be found / loaded by alias.
1315
- */
1316
- async createAndAliasDataStore(pkg, alias, props) {
1317
- const internalId = uuid();
1318
- const dataStore = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
1319
- const aliasedDataStore = channelToDataStore(dataStore, internalId, this, this.dataStores, this.mc.logger);
1320
- const result = await aliasedDataStore.trySetAlias(alias);
1321
- if (result !== "Success") {
1322
- throw new GenericError("dataStoreAliasFailure", undefined /* error */, {
1323
- alias: {
1324
- value: alias,
1325
- tag: TelemetryDataTag.UserData,
1326
- },
1327
- internalId: {
1328
- value: internalId,
1329
- tag: TelemetryDataTag.PackageData,
1330
- },
1331
- aliasResult: result,
1332
- });
1333
- }
1334
- return aliasedDataStore;
1335
- }
1336
- createDetachedRootDataStore(pkg, rootDataStoreId) {
1337
- if (rootDataStoreId.includes("/")) {
1338
- throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1339
- }
1340
- return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
1341
- }
1342
- createDetachedDataStore(pkg) {
1343
- return this.dataStores.createDetachedDataStoreCore(pkg, false);
1344
- }
1345
- /**
1346
- * Creates a possibly root datastore directly with a possibly user generated id and attaches it to storage.
1347
- * It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
1348
- *
1349
- * This method will be removed. See #6465.
1350
- */
1351
- async _createDataStoreWithPropsLegacy(pkg, props, id = uuid(), isRoot = false) {
1352
- const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
1353
- if (isRoot) {
1354
- // back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel.
1355
- // For older versions, we still have to call bindToContext.
1356
- if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
1357
- fluidDataStore.makeVisibleAndAttachGraph();
1358
- }
1359
- else {
1360
- fluidDataStore.bindToContext();
1361
- }
1362
- this.logger.sendTelemetryEvent({
1363
- eventName: "Root datastore with props",
1364
- hasProps: props !== undefined,
1365
- });
1366
- }
1367
- return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
1368
- }
1369
- async _createDataStoreWithProps(pkg, props, id = uuid(), isRoot = false) {
1370
- return this._aliasingEnabled === true && isRoot ?
1371
- this.createAndAliasDataStore(pkg, id, props) :
1372
- this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
1373
- }
1374
- async _createDataStore(pkg, isRoot, id = uuid(), props) {
1375
- return this.dataStores
1376
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props)
1377
- .realize();
1378
- }
1379
- canSendOps() {
1380
- return this.connected && !this.deltaManager.readOnlyInfo.readonly;
1381
- }
1382
- getQuorum() {
1383
- return this.context.quorum;
1384
- }
1385
- getAudience() {
1386
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1387
- return this.context.audience;
1388
- }
1389
- /**
1390
- * Returns true of container is dirty, i.e. there are some pending local changes that
1391
- * either were not sent out to delta stream or were not yet acknowledged.
1392
- */
1393
- get isDirty() {
1394
- return this.dirtyContainer;
1395
- }
1396
- isContainerMessageDirtyable(type, contents) {
1397
- // For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
1398
- // Ultimately we should have no special-cases from the ContainerRuntime's perspective.
1399
- if (type === ContainerMessageType.Attach) {
1400
- const attachMessage = contents;
1401
- if (attachMessage.id === agentSchedulerId) {
1402
- return false;
1403
- }
1404
- }
1405
- else if (type === ContainerMessageType.FluidDataStoreOp) {
1406
- const envelope = contents;
1407
- if (envelope.address === agentSchedulerId) {
1408
- return false;
1409
- }
1410
- }
1411
- return true;
1412
- }
1413
- createNewSignalEnvelope(address, type, content) {
1414
- const newSequenceNumber = ++this._perfSignalData.signalSequenceNumber;
1415
- const newEnvelope = {
1416
- address,
1417
- clientSignalSequenceNumber: newSequenceNumber,
1418
- contents: { type, content },
1419
- };
1420
- // We should not track any signals in case we already have a tracking number.
1421
- if (newSequenceNumber % this.defaultTelemetrySignalSampleCount === 1 &&
1422
- this._perfSignalData.trackingSignalSequenceNumber === undefined) {
1423
- this._perfSignalData.signalTimestamp = Date.now();
1424
- this._perfSignalData.trackingSignalSequenceNumber = newSequenceNumber;
1425
- }
1426
- return newEnvelope;
1427
- }
1428
- /**
1429
- * Submits the signal to be sent to other clients.
1430
- * @param type - Type of the signal.
1431
- * @param content - Content of the signal.
1432
- */
1433
- submitSignal(type, content) {
1434
- this.verifyNotClosed();
1435
- const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
1436
- return this.context.submitSignalFn(envelope);
1437
- }
1438
- submitDataStoreSignal(address, type, content) {
1439
- const envelope = this.createNewSignalEnvelope(address, type, content);
1440
- return this.context.submitSignalFn(envelope);
1441
- }
1442
- setAttachState(attachState) {
1443
- if (attachState === AttachState.Attaching) {
1444
- assert(this.attachState === AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1445
- }
1446
- else {
1447
- assert(this.attachState === AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1448
- this.emit("attached");
1449
- }
1450
- if (attachState === AttachState.Attached && !this.pendingStateManager.hasPendingMessages()) {
1451
- this.updateDocumentDirtyState(false);
1452
- }
1453
- this.dataStores.setAttachState(attachState);
1454
- }
1455
- /**
1456
- * Create a summary. Used when attaching or serializing a detached container.
1457
- *
1458
- * @param blobRedirectTable - A table passed during the attach process. While detached, blob upload is supported
1459
- * using IDs generated locally. After attach, these IDs cannot be used, so this table maps the old local IDs to the
1460
- * new storage IDs so requests can be redirected.
1461
- * @param telemetryContext - summary data passed through the layers for telemetry purposes
1462
- */
1463
- createSummary(blobRedirectTable, telemetryContext) {
1464
- if (blobRedirectTable) {
1465
- this.blobManager.setRedirectTable(blobRedirectTable);
1466
- }
1467
- const summarizeResult = this.dataStores.createSummary(telemetryContext);
1468
- if (!this.disableIsolatedChannels) {
1469
- // Wrap data store summaries in .channels subtree.
1470
- wrapSummaryInChannelsTree(summarizeResult);
1471
- }
1472
- this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
1473
- return summarizeResult.summary;
1474
- }
1475
- async getAbsoluteUrl(relativeUrl) {
1476
- if (this.context.getAbsoluteUrl === undefined) {
1477
- throw new Error("Driver does not implement getAbsoluteUrl");
1478
- }
1479
- if (this.attachState !== AttachState.Attached) {
1480
- return undefined;
1481
- }
1482
- return this.context.getAbsoluteUrl(relativeUrl);
1483
- }
1484
- async summarizeInternal(fullTree, trackState, telemetryContext) {
1485
- const summarizeResult = await this.dataStores.summarize(fullTree, trackState, telemetryContext);
1486
- let pathPartsForChildren;
1487
- if (!this.disableIsolatedChannels) {
1488
- // Wrap data store summaries in .channels subtree.
1489
- wrapSummaryInChannelsTree(summarizeResult);
1490
- pathPartsForChildren = [channelsTreeName];
1491
- }
1492
- this.addContainerStateToSummary(summarizeResult, fullTree, trackState, telemetryContext);
1493
- return Object.assign(Object.assign({}, summarizeResult), { id: "", pathPartsForChildren });
1494
- }
1495
- /**
1496
- * Returns a summary of the runtime at the current sequence number.
1497
- */
1498
- async summarize(options) {
1499
- this.verifyNotClosed();
1500
- const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
1501
- let gcStats;
1502
- if (runGC) {
1503
- gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
1504
- }
1505
- const telemetryContext = new TelemetryContext();
1506
- const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1507
- this.logger.sendTelemetryEvent({ eventName: "SummarizeTelemetry", details: telemetryContext.serialize() });
1508
- assert(summary.type === SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1509
- return { stats, summary, gcStats };
1510
- }
1511
- /**
1512
- * Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
1513
- * Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
1514
- * the garbage collector of references detected since the last GC run. Most references are notified immediately
1515
- * but there can be some for which async operation is required (such as detecting new root data stores).
1516
- */
1517
- async updateStateBeforeGC() {
1518
- return this.dataStores.updateStateBeforeGC();
1519
- }
1520
- /**
1521
- * Implementation of IGarbageCollectionRuntime::getGCData.
1522
- * Generates and returns the GC data for this container.
1523
- * @param fullGC - true to bypass optimizations and force full generation of GC data.
1524
- */
1525
- async getGCData(fullGC) {
1526
- const builder = new GCDataBuilder();
1527
- const dsGCData = await this.dataStores.getGCData(fullGC);
1528
- builder.addNodes(dsGCData.gcNodes);
1529
- const blobsGCData = this.blobManager.getGCData(fullGC);
1530
- builder.addNodes(blobsGCData.gcNodes);
1531
- return builder.getGCData();
1532
- }
1533
- /**
1534
- * Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
1535
- * After GC has run, called to notify this container's nodes of routes that are used in it.
1536
- * @param usedRoutes - The routes that are used in all nodes in this Container.
1537
- * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
1538
- * unreferenced as part of this GC run, this should be used to update the time when it happens.
1539
- */
1540
- updateUsedRoutes(usedRoutes, gcTimestamp) {
1541
- // Update our summarizer node's used routes. Updating used routes in summarizer node before
1542
- // summarizing is required and asserted by the the summarizer node. We are the root and are
1543
- // always referenced, so the used routes is only self-route (empty string).
1544
- this.summarizerNode.updateUsedRoutes([""]);
1545
- const dataStoreUsedRoutes = [];
1546
- for (const route of usedRoutes) {
1547
- if (route.split("/")[1] !== BlobManager.basePath) {
1548
- dataStoreUsedRoutes.push(route);
1549
- }
1550
- }
1551
- return this.dataStores.updateUsedRoutes(dataStoreUsedRoutes, gcTimestamp);
1552
- }
1553
- /**
1554
- * When running GC in test mode, this is called to delete objects whose routes are unused. This enables testing
1555
- * scenarios with accessing deleted content.
1556
- * @param unusedRoutes - The routes that are unused in all data stores in this Container.
1557
- */
1558
- deleteUnusedRoutes(unusedRoutes) {
1559
- const blobManagerUnusedRoutes = [];
1560
- const dataStoreUnusedRoutes = [];
1561
- for (const route of unusedRoutes) {
1562
- if (this.isBlobPath(route)) {
1563
- blobManagerUnusedRoutes.push(route);
1564
- }
1565
- else {
1566
- dataStoreUnusedRoutes.push(route);
1567
- }
1568
- }
1569
- this.blobManager.deleteUnusedRoutes(blobManagerUnusedRoutes);
1570
- this.dataStores.deleteUnusedRoutes(dataStoreUnusedRoutes);
1571
- }
1572
- /**
1573
- * Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
1574
- */
1575
- getCurrentReferenceTimestampMs() {
1576
- var _a, _b, _c;
1577
- // Use the timestamp of the last message seen by this client as that is server generated. If no messages have
1578
- // been processed, use the timestamp of the message from the last summary.
1579
- return (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = this.messageAtLastSummary) === null || _c === void 0 ? void 0 : _c.timestamp;
1580
- }
1581
- /**
1582
- * Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
1583
- * blob manager.
1584
- */
1585
- getNodeType(nodePath) {
1586
- var _a;
1587
- if (this.isBlobPath(nodePath)) {
1588
- return GCNodeType.Blob;
1589
- }
1590
- return (_a = this.dataStores.getGCNodeType(nodePath)) !== null && _a !== void 0 ? _a : GCNodeType.Other;
1591
- }
1592
- /**
1593
- * Called by GC to retrieve the package path of the node with the given path. The node should belong to a
1594
- * data store or an attachment blob.
1595
- */
1596
- async getGCNodePackagePath(nodePath) {
1597
- switch (this.getNodeType(nodePath)) {
1598
- case GCNodeType.Blob:
1599
- return ["_blobs"];
1600
- case GCNodeType.DataStore:
1601
- case GCNodeType.SubDataStore:
1602
- return this.dataStores.getDataStorePackagePath(nodePath);
1603
- default:
1604
- assert(false, 0x2de /* "Package path requested for unsupported node type." */);
1605
- }
1606
- }
1607
- /**
1608
- * Returns whether a given path is for attachment blobs that are in the format - "/BlobManager.basePath/...".
1609
- */
1610
- isBlobPath(path) {
1611
- const pathParts = path.split("/");
1612
- if (pathParts.length < 2 || pathParts[1] !== BlobManager.basePath) {
1613
- return false;
1614
- }
1615
- return true;
1616
- }
1617
- /**
1618
- * Runs garbage collection and updates the reference / used state of the nodes in the container.
1619
- * @returns the statistics of the garbage collection run.
1620
- */
1621
- async collectGarbage(options) {
1622
- return this.garbageCollector.collectGarbage(options);
1623
- }
1624
- /**
1625
- * Called when a new outbound reference is added to another node. This is used by garbage collection to identify
1626
- * all references added in the system.
1627
- * @param srcHandle - The handle of the node that added the reference.
1628
- * @param outboundHandle - The handle of the outbound node that is referenced.
1629
- */
1630
- addedGCOutboundReference(srcHandle, outboundHandle) {
1631
- this.garbageCollector.addedOutboundReference(srcHandle.absolutePath, outboundHandle.absolutePath);
1632
- }
1633
- /**
1634
- * Generates the summary tree, uploads it to storage, and then submits the summarize op.
1635
- * This is intended to be called by the summarizer, since it is the implementation of
1636
- * ISummarizerInternalsProvider.submitSummary.
1637
- * It takes care of state management at the container level, including pausing inbound
1638
- * op processing, updating SummarizerNode state tracking, and garbage collection.
1639
- * @param options - options controlling how the summary is generated or submitted
1640
- */
1641
- async submitSummary(options) {
1642
- var _a, _b, _c;
1643
- const { fullTree, refreshLatestAck, summaryLogger } = options;
1644
- // The summary number for this summary. This will be updated during the summary process, so get it now and
1645
- // use it for all events logged during this summary.
1646
- const summaryNumber = this.nextSummaryNumber;
1647
- const summaryNumberLogger = ChildLogger.create(summaryLogger, undefined, {
1648
- all: { summaryNumber },
1649
- });
1650
- let latestSnapshotVersionId;
1651
- if (refreshLatestAck) {
1652
- const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
1653
- const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
1654
- latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
1655
- if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
1656
- // We need to catch up to the latest summary's reference sequence number before pausing.
1657
- await PerformanceEvent.timedExecAsync(summaryNumberLogger, {
1658
- eventName: "WaitingForSeq",
1659
- lastSequenceNumber: this.deltaManager.lastSequenceNumber,
1660
- targetSequenceNumber: latestSnapshotRefSeq,
1661
- lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
1662
- }, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
1663
- }
1664
- }
1665
- try {
1666
- await this.deltaManager.inbound.pause();
1667
- const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
1668
- const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
1669
- const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
1670
- // We should be here is we haven't processed be here. If we are of if the last message's sequence number
1671
- // doesn't match the last processed sequence number, log an error.
1672
- if (summaryRefSeqNum !== ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber)) {
1673
- summaryNumberLogger.sendErrorEvent({
1674
- eventName: "LastSequenceMismatch",
1675
- error: message,
1676
- });
1677
- }
1678
- this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
1679
- // Helper function to check whether we should still continue between each async step.
1680
- const checkContinue = () => {
1681
- // Do not check for loss of connectivity directly! Instead leave it up to
1682
- // RunWhileConnectedCoordinator to control policy in a single place.
1683
- // This will allow easier change of design if we chose to. For example, we may chose to allow
1684
- // summarizer to reconnect in the future.
1685
- // Also checking for cancellation is a must as summary process may be abandoned for other reasons,
1686
- // like loss of connectivity for main (interactive) client.
1687
- if (options.cancellationToken.cancelled) {
1688
- return { continue: false, error: "disconnected" };
1689
- }
1690
- // That said, we rely on submitSystemMessage() that today only works in connected state.
1691
- // So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
1692
- // OR that design changed and we need to remove this check and fix submitSystemMessage.
1693
- assert(this.connected, 0x258 /* "connected" */);
1694
- // Ensure that lastSequenceNumber has not changed after pausing.
1695
- // We need the summary op's reference sequence number to match our summary sequence number,
1696
- // otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
1697
- if (this.deltaManager.lastSequenceNumber !== summaryRefSeqNum) {
1698
- return {
1699
- continue: false,
1700
- // eslint-disable-next-line max-len
1701
- error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1702
- };
1703
- }
1704
- return { continue: true };
1705
- };
1706
- let continueResult = checkContinue();
1707
- if (!continueResult.continue) {
1708
- return {
1709
- stage: "base",
1710
- referenceSequenceNumber: summaryRefSeqNum,
1711
- minimumSequenceNumber,
1712
- error: continueResult.error,
1713
- };
1714
- }
1715
- const trace = Trace.start();
1716
- let summarizeResult;
1717
- // If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
1718
- // state of all the nodes.
1719
- const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
1720
- try {
1721
- summarizeResult = await this.summarize({
1722
- fullTree: fullTree || forcedFullTree,
1723
- trackState: true,
1724
- summaryLogger: summaryNumberLogger,
1725
- runGC: this.garbageCollector.shouldRunGC,
1726
- });
1727
- }
1728
- catch (error) {
1729
- return {
1730
- stage: "base",
1731
- referenceSequenceNumber: summaryRefSeqNum,
1732
- minimumSequenceNumber,
1733
- error,
1734
- };
1735
- }
1736
- const { summary: summaryTree, stats: partialStats } = summarizeResult;
1737
- // Now that we have generated the summary, update the message at last summary to the last message processed.
1738
- this.messageAtLastSummary = this.deltaManager.lastMessage;
1739
- // Counting dataStores and handles
1740
- // Because handles are unchanged dataStores in the current logic,
1741
- // summarized dataStore count is total dataStore count minus handle count
1742
- const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[channelsTreeName];
1743
- assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1744
- const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === SummaryType.Handle).length;
1745
- const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
1746
- ? calculateStats(summaryTree.tree[gcTreeKey])
1747
- : undefined;
1748
- const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_b = summarizeResult.gcStats) === null || _b === void 0 ? void 0 : _b.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, opsSizesSinceLastSummary: this.opTracker.opsSizeAccumulator, nonSystemOpsSinceLastSummary: this.opTracker.nonSystemOpCount, summaryNumber }, partialStats);
1749
- const generateSummaryData = {
1750
- referenceSequenceNumber: summaryRefSeqNum,
1751
- minimumSequenceNumber,
1752
- summaryTree,
1753
- summaryStats,
1754
- generateDuration: trace.trace().duration,
1755
- forcedFullTree,
1756
- };
1757
- continueResult = checkContinue();
1758
- if (!continueResult.continue) {
1759
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
1760
- }
1761
- // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
1762
- // summary. So if the previous summarizer closes just after submitting the summary and before
1763
- // submitting the summaryOp then we can't rely on summaryAck. So in case we have
1764
- // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
1765
- // the one fetched from storage as parent as that is the latest.
1766
- const lastAck = this.summaryCollection.latestAck;
1767
- let summaryContext;
1768
- if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
1769
- && latestSnapshotVersionId !== undefined) {
1770
- summaryContext = {
1771
- proposalHandle: undefined,
1772
- ackHandle: latestSnapshotVersionId,
1773
- referenceSequenceNumber: summaryRefSeqNum,
1774
- };
1775
- }
1776
- else if (lastAck === undefined) {
1777
- summaryContext = {
1778
- proposalHandle: undefined,
1779
- ackHandle: (_c = this.context.getLoadedFromVersion()) === null || _c === void 0 ? void 0 : _c.id,
1780
- referenceSequenceNumber: summaryRefSeqNum,
1781
- };
1782
- }
1783
- else {
1784
- summaryContext = {
1785
- proposalHandle: lastAck.summaryOp.contents.handle,
1786
- ackHandle: lastAck.summaryAck.contents.handle,
1787
- referenceSequenceNumber: summaryRefSeqNum,
1788
- };
1789
- }
1790
- let handle;
1791
- try {
1792
- handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
1793
- }
1794
- catch (error) {
1795
- return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error });
1796
- }
1797
- const parent = summaryContext.ackHandle;
1798
- const summaryMessage = {
1799
- handle,
1800
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1801
- head: parent,
1802
- message,
1803
- parents: parent ? [parent] : [],
1804
- };
1805
- const uploadData = Object.assign(Object.assign({}, generateSummaryData), { handle, uploadDuration: trace.trace().duration });
1806
- continueResult = checkContinue();
1807
- if (!continueResult.continue) {
1808
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error: continueResult.error });
1809
- }
1810
- let clientSequenceNumber;
1811
- try {
1812
- clientSequenceNumber = this.submitSystemMessage(MessageType.Summarize, summaryMessage);
1813
- }
1814
- catch (error) {
1815
- return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
1816
- }
1817
- const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
1818
- this.summarizerNode.completeSummary(handle);
1819
- this.opTracker.reset();
1820
- return submitData;
1821
- }
1822
- finally {
1823
- // Cleanup wip summary in case of failure
1824
- this.summarizerNode.clearSummary();
1825
- // Restart the delta manager
1826
- this.deltaManager.inbound.resume();
1827
- }
1828
- }
1829
- processRemoteChunkedMessage(message) {
1830
- if (message.type !== ContainerMessageType.ChunkedOp) {
1831
- return message;
1832
- }
1833
- const clientId = message.clientId;
1834
- const chunkedContent = message.contents;
1835
- this.addChunk(clientId, chunkedContent);
1836
- if (chunkedContent.chunkId === chunkedContent.totalChunks) {
1837
- const newMessage = Object.assign({}, message);
1838
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1839
- const serializedContent = this.chunkMap.get(clientId).join("");
1840
- newMessage.contents = JSON.parse(serializedContent);
1841
- newMessage.type = chunkedContent.originalType;
1842
- this.clearPartialChunks(clientId);
1843
- return newMessage;
1844
- }
1845
- return message;
1846
- }
1847
- addChunk(clientId, chunkedContent) {
1848
- let map = this.chunkMap.get(clientId);
1849
- if (map === undefined) {
1850
- map = [];
1851
- this.chunkMap.set(clientId, map);
1852
- }
1853
- assert(chunkedContent.chunkId === map.length + 1, 0x131 /* "Mismatch between new chunkId and expected chunkMap" */); // 1-based indexing
1854
- map.push(chunkedContent.contents);
1855
- }
1856
- clearPartialChunks(clientId) {
1857
- if (this.chunkMap.has(clientId)) {
1858
- this.chunkMap.delete(clientId);
1859
- }
1860
- }
1861
- updateDocumentDirtyState(dirty) {
1862
- if (this.dirtyContainer === dirty) {
1863
- return;
1864
- }
1865
- this.dirtyContainer = dirty;
1866
- if (this.emitDirtyDocumentEvent) {
1867
- this.emit(dirty ? "dirty" : "saved");
1868
- this.context.updateDirtyContainerState(dirty);
1869
- }
1870
- }
1871
- submitDataStoreOp(id, contents, localOpMetadata = undefined) {
1872
- const envelope = {
1873
- address: id,
1874
- contents,
1875
- };
1876
- this.submit(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
1877
- }
1878
- submitDataStoreAliasOp(contents, localOpMetadata) {
1879
- const aliasMessage = contents;
1880
- if (!isDataStoreAliasMessage(aliasMessage)) {
1881
- throw new UsageError("malformedDataStoreAliasMessage");
1882
- }
1883
- this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
1884
- }
1885
- async uploadBlob(blob) {
1886
- this.verifyNotClosed();
1887
- return this.blobManager.createBlob(blob);
1888
- }
1889
- submit(type, content, localOpMetadata = undefined, opMetadata = undefined) {
1890
- this.verifyNotClosed();
1891
- // There should be no ops in detached container state!
1892
- assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
1893
- let clientSequenceNumber = -1;
1894
- let opMetadataInternal = opMetadata;
1895
- if (this.canSendOps()) {
1896
- const serializedContent = JSON.stringify(content);
1897
- const maxOpSize = this.context.deltaManager.maxMessageSize;
1898
- // If in TurnBased flush mode we will trigger a flush at the next turn break
1899
- if (this.flushMode === FlushMode.TurnBased && !this.needsFlush) {
1900
- opMetadataInternal = Object.assign(Object.assign({}, opMetadata), { batch: true });
1901
- this.needsFlush = true;
1902
- // Use Promise.resolve().then() to queue a microtask to detect the end of the turn and force a flush.
1903
- if (!this.flushTrigger) {
1904
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1905
- Promise.resolve().then(() => {
1906
- this.flushTrigger = false;
1907
- this.flush();
1908
- });
1909
- }
1910
- }
1911
- clientSequenceNumber = this.submitMaybeChunkedMessages(type, content, serializedContent, maxOpSize, this._flushMode === FlushMode.TurnBased, opMetadataInternal);
1912
- }
1913
- // Let the PendingStateManager know that a message was submitted.
1914
- this.pendingStateManager.onSubmitMessage(type, clientSequenceNumber, this.deltaManager.lastSequenceNumber, content, localOpMetadata, opMetadataInternal);
1915
- if (this.isContainerMessageDirtyable(type, content)) {
1916
- this.updateDocumentDirtyState(true);
1917
- }
1918
- }
1919
- submitMaybeChunkedMessages(type, content, serializedContent, serverMaxOpSize, batch, opMetadataInternal = undefined) {
1920
- if (this._maxOpSizeInBytes >= 0) {
1921
- // Chunking disabled
1922
- if (!serializedContent || serializedContent.length <= this._maxOpSizeInBytes) {
1923
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1924
- }
1925
- // When chunking is disabled, we ignore the server max message size
1926
- // and if the content length is larger than the client configured message size
1927
- // instead of splitting the content, we will fail by explicitly close the container
1928
- this.closeFn(new GenericError("OpTooLarge",
1929
- /* error */ undefined, {
1930
- length: {
1931
- value: serializedContent.length,
1932
- tag: TelemetryDataTag.PackageData,
1933
- },
1934
- limit: {
1935
- value: this._maxOpSizeInBytes,
1936
- tag: TelemetryDataTag.PackageData,
1937
- },
1938
- }));
1939
- return -1;
1940
- }
1941
- // Chunking enabled, fallback on the server's max message size
1942
- // and split the content accordingly
1943
- if (!serializedContent || serializedContent.length <= serverMaxOpSize) {
1944
- return this.submitRuntimeMessage(type, content, batch, opMetadataInternal);
1945
- }
1946
- return this.submitChunkedMessage(type, serializedContent, serverMaxOpSize);
1947
- }
1948
- submitChunkedMessage(type, content, maxOpSize) {
1949
- const contentLength = content.length;
1950
- const chunkN = Math.floor((contentLength - 1) / maxOpSize) + 1;
1951
- let offset = 0;
1952
- let clientSequenceNumber = 0;
1953
- for (let i = 1; i <= chunkN; i = i + 1) {
1954
- const chunkedOp = {
1955
- chunkId: i,
1956
- contents: content.substr(offset, maxOpSize),
1957
- originalType: type,
1958
- totalChunks: chunkN,
1959
- };
1960
- offset += maxOpSize;
1961
- clientSequenceNumber = this.submitRuntimeMessage(ContainerMessageType.ChunkedOp, chunkedOp, false);
1962
- }
1963
- return clientSequenceNumber;
1964
- }
1965
- submitSystemMessage(type, contents) {
1966
- this.verifyNotClosed();
1967
- assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
1968
- // System message should not be sent in the middle of the batch.
1969
- // That said, we can preserve existing behavior by not flushing existing buffer.
1970
- // That might be not what caller hopes to get, but we can look deeper if telemetry tells us it's a problem.
1971
- const middleOfBatch = this.flushMode === FlushMode.TurnBased && this.needsFlush;
1972
- if (middleOfBatch) {
1973
- this.mc.logger.sendErrorEvent({ eventName: "submitSystemMessageError", type });
1974
- }
1975
- return this.context.submitFn(type, contents, middleOfBatch);
1976
- }
1977
- submitRuntimeMessage(type, contents, batch, appData) {
1978
- this.verifyNotClosed();
1979
- assert(this.connected, 0x259 /* "Container disconnected when trying to submit system message" */);
1980
- const payload = { type, contents };
1981
- return this.context.submitFn(MessageType.Operation, payload, batch, appData);
1982
- }
1983
- /**
1984
- * Throw an error if the runtime is closed. Methods that are expected to potentially
1985
- * be called after dispose due to asynchrony should not call this.
1986
- */
1987
- verifyNotClosed() {
1988
- if (this._disposed) {
1989
- throw new Error("Runtime is closed");
1990
- }
1991
- }
1992
- /**
1993
- * Finds the right store and asks it to resubmit the message. This typically happens when we
1994
- * reconnect and there are pending messages.
1995
- * @param content - The content of the original message.
1996
- * @param localOpMetadata - The local metadata associated with the original message.
1997
- */
1998
- reSubmit(type, content, localOpMetadata, opMetadata) {
1999
- switch (type) {
2000
- case ContainerMessageType.FluidDataStoreOp:
2001
- // For Operations, call resubmitDataStoreOp which will find the right store
2002
- // and trigger resubmission on it.
2003
- this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
2004
- break;
2005
- case ContainerMessageType.Attach:
2006
- case ContainerMessageType.Alias:
2007
- this.submit(type, content, localOpMetadata);
2008
- break;
2009
- case ContainerMessageType.ChunkedOp:
2010
- throw new Error(`chunkedOp not expected here`);
2011
- case ContainerMessageType.BlobAttach:
2012
- this.submit(type, content, localOpMetadata, opMetadata);
2013
- break;
2014
- case ContainerMessageType.Rejoin:
2015
- this.submit(type, content);
2016
- break;
2017
- default:
2018
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
2019
- }
2020
- }
2021
- rollback(type, content, localOpMetadata) {
2022
- switch (type) {
2023
- case ContainerMessageType.FluidDataStoreOp:
2024
- // For operations, call rollbackDataStoreOp which will find the right store
2025
- // and trigger rollback on it.
2026
- this.dataStores.rollbackDataStoreOp(content, localOpMetadata);
2027
- break;
2028
- default:
2029
- throw new Error(`Can't rollback ${type}`);
2030
- }
2031
- }
2032
- /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2033
- async refreshLatestSummaryAck(proposalHandle, ackHandle, summaryRefSeq, summaryLogger) {
2034
- const readAndParseBlob = async (id) => readAndParse(this.storage, id);
2035
- const { snapshotTree } = await this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
2036
- eventName: "RefreshLatestSummaryGetSnapshot",
2037
- ackHandle,
2038
- summaryRefSeq,
2039
- fetchLatest: false,
2040
- });
2041
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
2042
- // Notify the garbage collector so it can update its latest summary state.
2043
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
2044
- }
2045
- /**
2046
- * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
2047
- * internal state as it should be considered the latest summary ack.
2048
- * @param summaryLogger - logger to use when fetching snapshot from storage
2049
- * @returns downloaded snapshot's reference sequence number
2050
- */
2051
- async refreshLatestSummaryAckFromServer(summaryLogger) {
2052
- const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
2053
- eventName: "RefreshLatestSummaryGetSnapshot",
2054
- fetchLatest: true,
2055
- });
2056
- const readAndParseBlob = async (id) => readAndParse(this.storage, id);
2057
- const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
2058
- const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
2059
- // Notify the garbage collector so it can update its latest summary state.
2060
- await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
2061
- return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2062
- }
2063
- async fetchSnapshotFromStorage(versionId, logger, event) {
2064
- return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2065
- const stats = {};
2066
- const trace = Trace.start();
2067
- const versions = await this.storage.getVersions(versionId, 1);
2068
- assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2069
- stats.getVersionDuration = trace.trace().duration;
2070
- const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
2071
- assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2072
- stats.getSnapshotDuration = trace.trace().duration;
2073
- perfEvent.end(stats);
2074
- return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
2075
- });
2076
- }
2077
- notifyAttaching(snapshot) {
2078
- var _a;
2079
- if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
2080
- this.baseSnapshotBlobs = SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
2081
- }
2082
- }
2083
- async getSnapshotBlobs() {
2084
- var _a;
2085
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
2086
- this.attachState !== AttachState.Attached || this.context.pendingLocalState) {
2087
- return;
2088
- }
2089
- assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
2090
- this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
2091
- }
2092
- getPendingLocalState() {
2093
- var _a;
2094
- if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
2095
- throw new UsageError("can't get state when offline load disabled");
2096
- }
2097
- const previousPendingState = this.context.pendingLocalState;
2098
- if (previousPendingState) {
2099
- return {
2100
- pending: this.pendingStateManager.getLocalState(),
2101
- snapshotBlobs: previousPendingState.snapshotBlobs,
2102
- baseSnapshot: previousPendingState.baseSnapshot,
2103
- savedOps: this.savedOps,
2104
- };
2105
- }
2106
- assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
2107
- assert(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
2108
- return {
2109
- pending: this.pendingStateManager.getLocalState(),
2110
- snapshotBlobs: this.baseSnapshotBlobs,
2111
- baseSnapshot: this.context.baseSnapshot,
2112
- savedOps: this.savedOps,
2113
- };
2114
- }
2115
- /**
2116
- * * Forms a function that will request a Summarizer.
2117
- * @param loaderRouter - the loader acting as an IFluidRouter
2118
- * */
2119
- formRequestSummarizerFn(loaderRouter) {
2120
- return async () => {
2121
- const request = {
2122
- headers: {
2123
- [LoaderHeader.cache]: false,
2124
- [LoaderHeader.clientDetails]: {
2125
- capabilities: { interactive: false },
2126
- type: summarizerClientType,
2127
- },
2128
- [DriverHeader.summarizingClient]: true,
2129
- [LoaderHeader.reconnect]: false,
2130
- },
2131
- url: "/_summarizer",
2132
- };
2133
- const fluidObject = await requestFluidObject(loaderRouter, request);
2134
- const summarizer = fluidObject.ISummarizer;
2135
- if (!summarizer) {
2136
- throw new UsageError("Fluid object does not implement ISummarizer");
2137
- }
2138
- return summarizer;
2139
- };
2140
- }
2141
- async processSavedOps(state) {
2142
- for (const op of state.savedOps) {
2143
- this.process(op, false);
2144
- await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
2145
- }
2146
- // we may not have seen every sequence number (because of system ops) so apply everything once we
2147
- // don't have any more saved ops
2148
- await this.pendingStateManager.applyStashedOpsAt();
2149
- }
2150
- }
2151
- /**
2152
- * Wait for a specific sequence number. Promise should resolve when we reach that number,
2153
- * or reject if closed.
2154
- */
2155
- const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
2156
- // TODO: remove cast to any when actual event is determined
2157
- deltaManager.on("closed", reject);
2158
- const handleOp = (message) => {
2159
- if (message.sequenceNumber >= targetSeq) {
2160
- resolve();
2161
- deltaManager.off("op", handleOp);
2162
- }
2163
- };
2164
- deltaManager.on("op", handleOp);
2165
- });
2166
- //# sourceMappingURL=containerRuntime.js.map