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

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 (703) 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-lint.json +4 -0
  6. package/api-extractor.json +2 -2
  7. package/api-report/container-runtime.api.md +863 -0
  8. package/dist/{batchTracker.js → batchTracker.cjs} +9 -8
  9. package/dist/batchTracker.cjs.map +1 -0
  10. package/dist/batchTracker.d.ts +6 -5
  11. package/dist/batchTracker.d.ts.map +1 -1
  12. package/dist/blobManager.cjs +704 -0
  13. package/dist/blobManager.cjs.map +1 -0
  14. package/dist/blobManager.d.ts +135 -39
  15. package/dist/blobManager.d.ts.map +1 -1
  16. package/dist/connectionTelemetry.cjs +230 -0
  17. package/dist/connectionTelemetry.cjs.map +1 -0
  18. package/dist/connectionTelemetry.d.ts +2 -2
  19. package/dist/connectionTelemetry.d.ts.map +1 -1
  20. package/dist/container-runtime-alpha.d.ts +1677 -0
  21. package/dist/container-runtime-beta.d.ts +250 -0
  22. package/dist/container-runtime-public.d.ts +250 -0
  23. package/dist/container-runtime-untrimmed.d.ts +1792 -0
  24. package/dist/{containerHandleContext.js → containerHandleContext.cjs} +4 -2
  25. package/dist/containerHandleContext.cjs.map +1 -0
  26. package/dist/containerHandleContext.d.ts.map +1 -1
  27. package/dist/containerRuntime.cjs +2531 -0
  28. package/dist/containerRuntime.cjs.map +1 -0
  29. package/dist/containerRuntime.d.ts +454 -256
  30. package/dist/containerRuntime.d.ts.map +1 -1
  31. package/dist/{dataStore.js → dataStore.cjs} +54 -45
  32. package/dist/dataStore.cjs.map +1 -0
  33. package/dist/dataStore.d.ts +2 -2
  34. package/dist/dataStore.d.ts.map +1 -1
  35. package/dist/{dataStoreContext.js → dataStoreContext.cjs} +343 -247
  36. package/dist/dataStoreContext.cjs.map +1 -0
  37. package/dist/dataStoreContext.d.ts +73 -41
  38. package/dist/dataStoreContext.d.ts.map +1 -1
  39. package/dist/{dataStoreContexts.js → dataStoreContexts.cjs} +19 -15
  40. package/dist/dataStoreContexts.cjs.map +1 -0
  41. package/dist/dataStoreContexts.d.ts +1 -1
  42. package/dist/dataStoreContexts.d.ts.map +1 -1
  43. package/dist/{dataStoreRegistry.js → dataStoreRegistry.cjs} +9 -4
  44. package/dist/dataStoreRegistry.cjs.map +1 -0
  45. package/dist/dataStoreRegistry.d.ts +3 -0
  46. package/dist/dataStoreRegistry.d.ts.map +1 -1
  47. package/dist/{dataStores.js → dataStores.cjs} +273 -124
  48. package/dist/dataStores.cjs.map +1 -0
  49. package/dist/dataStores.d.ts +53 -23
  50. package/dist/dataStores.d.ts.map +1 -1
  51. package/dist/deltaManagerProxyBase.cjs +77 -0
  52. package/dist/deltaManagerProxyBase.cjs.map +1 -0
  53. package/dist/deltaManagerProxyBase.d.ts +35 -0
  54. package/dist/deltaManagerProxyBase.d.ts.map +1 -0
  55. package/dist/deltaManagerSummarizerProxy.cjs +42 -0
  56. package/dist/deltaManagerSummarizerProxy.cjs.map +1 -0
  57. package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
  58. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
  59. package/dist/{deltaScheduler.js → deltaScheduler.cjs} +25 -18
  60. package/dist/deltaScheduler.cjs.map +1 -0
  61. package/dist/deltaScheduler.d.ts +8 -6
  62. package/dist/deltaScheduler.d.ts.map +1 -1
  63. package/dist/error.cjs +21 -0
  64. package/dist/error.cjs.map +1 -0
  65. package/dist/error.d.ts +14 -0
  66. package/dist/error.d.ts.map +1 -0
  67. package/dist/gc/garbageCollection.cjs +861 -0
  68. package/dist/gc/garbageCollection.cjs.map +1 -0
  69. package/dist/gc/garbageCollection.d.ts +224 -0
  70. package/dist/gc/garbageCollection.d.ts.map +1 -0
  71. package/dist/gc/gcConfigs.cjs +153 -0
  72. package/dist/gc/gcConfigs.cjs.map +1 -0
  73. package/dist/gc/gcConfigs.d.ts +23 -0
  74. package/dist/gc/gcConfigs.d.ts.map +1 -0
  75. package/dist/gc/gcDefinitions.cjs +96 -0
  76. package/dist/gc/gcDefinitions.cjs.map +1 -0
  77. package/dist/gc/gcDefinitions.d.ts +437 -0
  78. package/dist/gc/gcDefinitions.d.ts.map +1 -0
  79. package/dist/gc/gcHelpers.cjs +235 -0
  80. package/dist/gc/gcHelpers.cjs.map +1 -0
  81. package/dist/gc/gcHelpers.d.ts +71 -0
  82. package/dist/gc/gcHelpers.d.ts.map +1 -0
  83. package/dist/gc/gcReferenceGraphAlgorithm.cjs +49 -0
  84. package/dist/gc/gcReferenceGraphAlgorithm.cjs.map +1 -0
  85. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
  86. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  87. package/dist/{summarizerTypes.js → gc/gcSummaryDefinitions.cjs} +1 -6
  88. package/dist/gc/gcSummaryDefinitions.cjs.map +1 -0
  89. package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
  90. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
  91. package/dist/gc/gcSummaryStateTracker.cjs +213 -0
  92. package/dist/gc/gcSummaryStateTracker.cjs.map +1 -0
  93. package/dist/gc/gcSummaryStateTracker.d.ts +94 -0
  94. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
  95. package/dist/gc/gcTelemetry.cjs +298 -0
  96. package/dist/gc/gcTelemetry.cjs.map +1 -0
  97. package/dist/gc/gcTelemetry.d.ts +92 -0
  98. package/dist/gc/gcTelemetry.d.ts.map +1 -0
  99. package/dist/gc/gcUnreferencedStateTracker.cjs +118 -0
  100. package/dist/gc/gcUnreferencedStateTracker.cjs.map +1 -0
  101. package/dist/gc/gcUnreferencedStateTracker.d.ts +40 -0
  102. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  103. package/dist/gc/index.cjs +44 -0
  104. package/dist/gc/index.cjs.map +1 -0
  105. package/dist/gc/index.d.ts +13 -0
  106. package/dist/gc/index.d.ts.map +1 -0
  107. package/dist/index.cjs +47 -0
  108. package/dist/index.cjs.map +1 -0
  109. package/dist/index.d.ts +19 -8
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/messageTypes.cjs +37 -0
  112. package/dist/messageTypes.cjs.map +1 -0
  113. package/dist/messageTypes.d.ts +142 -0
  114. package/dist/messageTypes.d.ts.map +1 -0
  115. package/dist/metadata.cjs +7 -0
  116. package/dist/metadata.cjs.map +1 -0
  117. package/dist/metadata.d.ts +24 -0
  118. package/dist/metadata.d.ts.map +1 -0
  119. package/dist/opLifecycle/batchManager.cjs +139 -0
  120. package/dist/opLifecycle/batchManager.cjs.map +1 -0
  121. package/dist/opLifecycle/batchManager.d.ts +48 -0
  122. package/dist/opLifecycle/batchManager.d.ts.map +1 -0
  123. package/dist/opLifecycle/definitions.cjs +7 -0
  124. package/dist/opLifecycle/definitions.cjs.map +1 -0
  125. package/dist/opLifecycle/definitions.d.ts +83 -0
  126. package/dist/opLifecycle/definitions.d.ts.map +1 -0
  127. package/dist/opLifecycle/index.cjs +26 -0
  128. package/dist/opLifecycle/index.cjs.map +1 -0
  129. package/dist/opLifecycle/index.d.ts +13 -0
  130. package/dist/opLifecycle/index.d.ts.map +1 -0
  131. package/dist/opLifecycle/opCompressor.cjs +84 -0
  132. package/dist/opLifecycle/opCompressor.cjs.map +1 -0
  133. package/dist/opLifecycle/opCompressor.d.ts +18 -0
  134. package/dist/opLifecycle/opCompressor.d.ts.map +1 -0
  135. package/dist/opLifecycle/opDecompressor.cjs +132 -0
  136. package/dist/opLifecycle/opDecompressor.cjs.map +1 -0
  137. package/dist/opLifecycle/opDecompressor.d.ts +25 -0
  138. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -0
  139. package/dist/opLifecycle/opGroupingManager.cjs +95 -0
  140. package/dist/opLifecycle/opGroupingManager.cjs.map +1 -0
  141. package/dist/opLifecycle/opGroupingManager.d.ts +22 -0
  142. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
  143. package/dist/opLifecycle/opSplitter.cjs +202 -0
  144. package/dist/opLifecycle/opSplitter.cjs.map +1 -0
  145. package/dist/opLifecycle/opSplitter.d.ts +61 -0
  146. package/dist/opLifecycle/opSplitter.d.ts.map +1 -0
  147. package/dist/opLifecycle/outbox.cjs +323 -0
  148. package/dist/opLifecycle/outbox.cjs.map +1 -0
  149. package/dist/opLifecycle/outbox.d.ts +104 -0
  150. package/dist/opLifecycle/outbox.d.ts.map +1 -0
  151. package/dist/opLifecycle/remoteMessageProcessor.cjs +136 -0
  152. package/dist/opLifecycle/remoteMessageProcessor.cjs.map +1 -0
  153. package/dist/opLifecycle/remoteMessageProcessor.d.ts +47 -0
  154. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
  155. package/dist/opProperties.cjs +17 -0
  156. package/dist/opProperties.cjs.map +1 -0
  157. package/dist/opProperties.d.ts +7 -0
  158. package/dist/opProperties.d.ts.map +1 -0
  159. package/dist/{packageVersion.js → packageVersion.cjs} +2 -2
  160. package/dist/packageVersion.cjs.map +1 -0
  161. package/dist/packageVersion.d.ts +1 -1
  162. package/dist/packageVersion.d.ts.map +1 -1
  163. package/dist/pendingStateManager.cjs +282 -0
  164. package/dist/pendingStateManager.cjs.map +1 -0
  165. package/dist/pendingStateManager.d.ts +32 -69
  166. package/dist/pendingStateManager.d.ts.map +1 -1
  167. package/dist/scheduleManager.cjs +258 -0
  168. package/dist/scheduleManager.cjs.map +1 -0
  169. package/dist/scheduleManager.d.ts +31 -0
  170. package/dist/scheduleManager.d.ts.map +1 -0
  171. package/dist/storageServiceWithAttachBlobs.cjs +32 -0
  172. package/dist/storageServiceWithAttachBlobs.cjs.map +1 -0
  173. package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
  174. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
  175. package/dist/summary/index.cjs +51 -0
  176. package/dist/summary/index.cjs.map +1 -0
  177. package/dist/summary/index.d.ts +17 -0
  178. package/dist/summary/index.d.ts.map +1 -0
  179. package/dist/{orderedClientElection.js → summary/orderedClientElection.cjs} +100 -84
  180. package/dist/summary/orderedClientElection.cjs.map +1 -0
  181. package/{lib → dist/summary}/orderedClientElection.d.ts +41 -18
  182. package/dist/summary/orderedClientElection.d.ts.map +1 -0
  183. package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.cjs} +12 -10
  184. package/dist/summary/runWhileConnectedCoordinator.cjs.map +1 -0
  185. package/{lib → dist/summary}/runWhileConnectedCoordinator.d.ts +8 -2
  186. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  187. package/dist/summary/runningSummarizer.cjs +679 -0
  188. package/dist/summary/runningSummarizer.cjs.map +1 -0
  189. package/dist/summary/runningSummarizer.d.ts +128 -0
  190. package/dist/summary/runningSummarizer.d.ts.map +1 -0
  191. package/dist/summary/summarizer.cjs +263 -0
  192. package/dist/summary/summarizer.cjs.map +1 -0
  193. package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +18 -33
  194. package/dist/summary/summarizer.d.ts.map +1 -0
  195. package/dist/{summarizerClientElection.js → summary/summarizerClientElection.cjs} +15 -46
  196. package/dist/summary/summarizerClientElection.cjs.map +1 -0
  197. package/{lib → dist/summary}/summarizerClientElection.d.ts +4 -4
  198. package/dist/summary/summarizerClientElection.d.ts.map +1 -0
  199. package/dist/summary/summarizerHeuristics.cjs +156 -0
  200. package/dist/summary/summarizerHeuristics.cjs.map +1 -0
  201. package/{lib → dist/summary}/summarizerHeuristics.d.ts +28 -6
  202. package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
  203. package/dist/summary/summarizerNode/index.cjs +12 -0
  204. package/dist/summary/summarizerNode/index.cjs.map +1 -0
  205. package/dist/summary/summarizerNode/index.d.ts +8 -0
  206. package/dist/summary/summarizerNode/index.d.ts.map +1 -0
  207. package/dist/summary/summarizerNode/summarizerNode.cjs +526 -0
  208. package/dist/summary/summarizerNode/summarizerNode.cjs.map +1 -0
  209. package/dist/summary/summarizerNode/summarizerNode.d.ts +167 -0
  210. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  211. package/dist/summary/summarizerNode/summarizerNodeUtils.cjs +130 -0
  212. package/dist/summary/summarizerNode/summarizerNodeUtils.cjs.map +1 -0
  213. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +121 -0
  214. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  215. package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs +375 -0
  216. package/dist/summary/summarizerNode/summarizerNodeWithGc.cjs.map +1 -0
  217. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +153 -0
  218. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  219. package/dist/summary/summarizerTypes.cjs +7 -0
  220. package/dist/summary/summarizerTypes.cjs.map +1 -0
  221. package/{lib → dist/summary}/summarizerTypes.d.ts +233 -83
  222. package/dist/summary/summarizerTypes.d.ts.map +1 -0
  223. package/dist/{summaryCollection.js → summary/summaryCollection.cjs} +80 -49
  224. package/dist/summary/summaryCollection.cjs.map +1 -0
  225. package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +23 -5
  226. package/dist/summary/summaryCollection.d.ts.map +1 -0
  227. package/dist/{summaryFormat.js → summary/summaryFormat.cjs} +29 -26
  228. package/dist/summary/summaryFormat.cjs.map +1 -0
  229. package/{lib → dist/summary}/summaryFormat.d.ts +25 -30
  230. package/dist/summary/summaryFormat.d.ts.map +1 -0
  231. package/dist/{summaryGenerator.js → summary/summaryGenerator.cjs} +162 -74
  232. package/dist/summary/summaryGenerator.cjs.map +1 -0
  233. package/dist/{summaryGenerator.d.ts → summary/summaryGenerator.d.ts} +53 -11
  234. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  235. package/dist/{summaryManager.js → summary/summaryManager.cjs} +98 -55
  236. package/dist/summary/summaryManager.cjs.map +1 -0
  237. package/{lib → dist/summary}/summaryManager.d.ts +13 -11
  238. package/dist/summary/summaryManager.d.ts.map +1 -0
  239. package/dist/{throttler.js → throttler.cjs} +21 -21
  240. package/dist/throttler.cjs.map +1 -0
  241. package/dist/throttler.d.ts +2 -2
  242. package/dist/throttler.d.ts.map +1 -1
  243. package/dist/tsdoc-metadata.json +11 -0
  244. package/lib/{batchTracker.d.ts → batchTracker.d.mts} +6 -5
  245. package/lib/batchTracker.d.mts.map +1 -0
  246. package/lib/{batchTracker.js → batchTracker.mjs} +9 -8
  247. package/lib/batchTracker.mjs.map +1 -0
  248. package/lib/blobManager.d.mts +191 -0
  249. package/lib/blobManager.d.mts.map +1 -0
  250. package/lib/blobManager.mjs +699 -0
  251. package/lib/blobManager.mjs.map +1 -0
  252. package/lib/{connectionTelemetry.d.ts → connectionTelemetry.d.mts} +2 -2
  253. package/lib/connectionTelemetry.d.mts.map +1 -0
  254. package/lib/connectionTelemetry.mjs +226 -0
  255. package/lib/connectionTelemetry.mjs.map +1 -0
  256. package/lib/container-runtime-alpha.d.mts +1677 -0
  257. package/lib/container-runtime-beta.d.mts +250 -0
  258. package/lib/container-runtime-public.d.mts +250 -0
  259. package/lib/container-runtime-untrimmed.d.mts +1792 -0
  260. package/lib/{containerHandleContext.d.ts → containerHandleContext.d.mts} +1 -1
  261. package/lib/containerHandleContext.d.mts.map +1 -0
  262. package/lib/{containerHandleContext.js → containerHandleContext.mjs} +4 -2
  263. package/lib/containerHandleContext.mjs.map +1 -0
  264. package/lib/containerRuntime.d.mts +809 -0
  265. package/lib/containerRuntime.d.mts.map +1 -0
  266. package/lib/containerRuntime.mjs +2526 -0
  267. package/lib/containerRuntime.mjs.map +1 -0
  268. package/lib/{dataStore.d.ts → dataStore.d.mts} +4 -4
  269. package/lib/dataStore.d.mts.map +1 -0
  270. package/lib/{dataStore.js → dataStore.mjs} +52 -43
  271. package/lib/dataStore.mjs.map +1 -0
  272. package/lib/{dataStoreContext.d.ts → dataStoreContext.d.mts} +74 -42
  273. package/lib/dataStoreContext.d.mts.map +1 -0
  274. package/lib/{dataStoreContext.js → dataStoreContext.mjs} +309 -213
  275. package/lib/dataStoreContext.mjs.map +1 -0
  276. package/lib/{dataStoreContexts.d.ts → dataStoreContexts.d.mts} +2 -2
  277. package/lib/dataStoreContexts.d.mts.map +1 -0
  278. package/lib/{dataStoreContexts.js → dataStoreContexts.mjs} +12 -8
  279. package/lib/dataStoreContexts.mjs.map +1 -0
  280. package/lib/{dataStoreRegistry.d.ts → dataStoreRegistry.d.mts} +3 -0
  281. package/lib/dataStoreRegistry.d.mts.map +1 -0
  282. package/lib/{dataStoreRegistry.js → dataStoreRegistry.mjs} +7 -6
  283. package/lib/dataStoreRegistry.mjs.map +1 -0
  284. package/lib/{dataStores.d.ts → dataStores.d.mts} +56 -26
  285. package/lib/dataStores.d.mts.map +1 -0
  286. package/lib/{dataStores.js → dataStores.mjs} +254 -105
  287. package/lib/dataStores.mjs.map +1 -0
  288. package/lib/deltaManagerProxyBase.d.mts +35 -0
  289. package/lib/deltaManagerProxyBase.d.mts.map +1 -0
  290. package/lib/deltaManagerProxyBase.mjs +73 -0
  291. package/lib/deltaManagerProxyBase.mjs.map +1 -0
  292. package/lib/deltaManagerSummarizerProxy.d.mts +19 -0
  293. package/lib/deltaManagerSummarizerProxy.d.mts.map +1 -0
  294. package/lib/deltaManagerSummarizerProxy.mjs +38 -0
  295. package/lib/deltaManagerSummarizerProxy.mjs.map +1 -0
  296. package/lib/{deltaScheduler.d.ts → deltaScheduler.d.mts} +8 -6
  297. package/lib/deltaScheduler.d.mts.map +1 -0
  298. package/lib/{deltaScheduler.js → deltaScheduler.mjs} +22 -15
  299. package/lib/deltaScheduler.mjs.map +1 -0
  300. package/lib/error.d.mts +14 -0
  301. package/lib/error.d.mts.map +1 -0
  302. package/lib/error.mjs +17 -0
  303. package/lib/error.mjs.map +1 -0
  304. package/lib/gc/garbageCollection.d.mts +224 -0
  305. package/lib/gc/garbageCollection.d.mts.map +1 -0
  306. package/lib/gc/garbageCollection.mjs +857 -0
  307. package/lib/gc/garbageCollection.mjs.map +1 -0
  308. package/lib/gc/gcConfigs.d.mts +23 -0
  309. package/lib/gc/gcConfigs.d.mts.map +1 -0
  310. package/lib/gc/gcConfigs.mjs +149 -0
  311. package/lib/gc/gcConfigs.mjs.map +1 -0
  312. package/lib/gc/gcDefinitions.d.mts +437 -0
  313. package/lib/gc/gcDefinitions.d.mts.map +1 -0
  314. package/lib/gc/gcDefinitions.mjs +93 -0
  315. package/lib/gc/gcDefinitions.mjs.map +1 -0
  316. package/lib/gc/gcHelpers.d.mts +71 -0
  317. package/lib/gc/gcHelpers.d.mts.map +1 -0
  318. package/lib/gc/gcHelpers.mjs +222 -0
  319. package/lib/gc/gcHelpers.mjs.map +1 -0
  320. package/lib/gc/gcReferenceGraphAlgorithm.d.mts +16 -0
  321. package/lib/gc/gcReferenceGraphAlgorithm.d.mts.map +1 -0
  322. package/lib/gc/gcReferenceGraphAlgorithm.mjs +45 -0
  323. package/lib/gc/gcReferenceGraphAlgorithm.mjs.map +1 -0
  324. package/lib/gc/gcSummaryDefinitions.d.mts +52 -0
  325. package/lib/gc/gcSummaryDefinitions.d.mts.map +1 -0
  326. package/lib/gc/gcSummaryDefinitions.mjs +6 -0
  327. package/lib/gc/gcSummaryDefinitions.mjs.map +1 -0
  328. package/lib/gc/gcSummaryStateTracker.d.mts +94 -0
  329. package/lib/gc/gcSummaryStateTracker.d.mts.map +1 -0
  330. package/lib/gc/gcSummaryStateTracker.mjs +209 -0
  331. package/lib/gc/gcSummaryStateTracker.mjs.map +1 -0
  332. package/lib/gc/gcTelemetry.d.mts +92 -0
  333. package/lib/gc/gcTelemetry.d.mts.map +1 -0
  334. package/lib/gc/gcTelemetry.mjs +293 -0
  335. package/lib/gc/gcTelemetry.mjs.map +1 -0
  336. package/lib/gc/gcUnreferencedStateTracker.d.mts +40 -0
  337. package/lib/gc/gcUnreferencedStateTracker.d.mts.map +1 -0
  338. package/lib/gc/gcUnreferencedStateTracker.mjs +114 -0
  339. package/lib/gc/gcUnreferencedStateTracker.mjs.map +1 -0
  340. package/lib/gc/index.d.mts +13 -0
  341. package/lib/gc/index.d.mts.map +1 -0
  342. package/lib/gc/index.mjs +12 -0
  343. package/lib/gc/index.mjs.map +1 -0
  344. package/lib/index.d.mts +25 -0
  345. package/lib/index.d.mts.map +1 -0
  346. package/lib/index.mjs +24 -0
  347. package/lib/index.mjs.map +1 -0
  348. package/lib/messageTypes.d.mts +142 -0
  349. package/lib/messageTypes.d.mts.map +1 -0
  350. package/lib/messageTypes.mjs +34 -0
  351. package/lib/messageTypes.mjs.map +1 -0
  352. package/lib/metadata.d.mts +24 -0
  353. package/lib/metadata.d.mts.map +1 -0
  354. package/lib/metadata.mjs +6 -0
  355. package/lib/metadata.mjs.map +1 -0
  356. package/lib/opLifecycle/batchManager.d.mts +48 -0
  357. package/lib/opLifecycle/batchManager.d.mts.map +1 -0
  358. package/lib/opLifecycle/batchManager.mjs +133 -0
  359. package/lib/opLifecycle/batchManager.mjs.map +1 -0
  360. package/lib/opLifecycle/definitions.d.mts +83 -0
  361. package/lib/opLifecycle/definitions.d.mts.map +1 -0
  362. package/lib/opLifecycle/definitions.mjs +6 -0
  363. package/lib/opLifecycle/definitions.mjs.map +1 -0
  364. package/lib/opLifecycle/index.d.mts +13 -0
  365. package/lib/opLifecycle/index.d.mts.map +1 -0
  366. package/lib/opLifecycle/index.mjs +12 -0
  367. package/lib/opLifecycle/index.mjs.map +1 -0
  368. package/lib/opLifecycle/opCompressor.d.mts +18 -0
  369. package/lib/opLifecycle/opCompressor.d.mts.map +1 -0
  370. package/lib/opLifecycle/opCompressor.mjs +80 -0
  371. package/lib/opLifecycle/opCompressor.mjs.map +1 -0
  372. package/lib/opLifecycle/opDecompressor.d.mts +25 -0
  373. package/lib/opLifecycle/opDecompressor.d.mts.map +1 -0
  374. package/lib/opLifecycle/opDecompressor.mjs +128 -0
  375. package/lib/opLifecycle/opDecompressor.mjs.map +1 -0
  376. package/lib/opLifecycle/opGroupingManager.d.mts +22 -0
  377. package/lib/opLifecycle/opGroupingManager.d.mts.map +1 -0
  378. package/lib/opLifecycle/opGroupingManager.mjs +91 -0
  379. package/lib/opLifecycle/opGroupingManager.mjs.map +1 -0
  380. package/lib/opLifecycle/opSplitter.d.mts +61 -0
  381. package/lib/opLifecycle/opSplitter.d.mts.map +1 -0
  382. package/lib/opLifecycle/opSplitter.mjs +197 -0
  383. package/lib/opLifecycle/opSplitter.mjs.map +1 -0
  384. package/lib/opLifecycle/outbox.d.mts +104 -0
  385. package/lib/opLifecycle/outbox.d.mts.map +1 -0
  386. package/lib/opLifecycle/outbox.mjs +318 -0
  387. package/lib/opLifecycle/outbox.mjs.map +1 -0
  388. package/lib/opLifecycle/remoteMessageProcessor.d.mts +47 -0
  389. package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +1 -0
  390. package/lib/opLifecycle/remoteMessageProcessor.mjs +131 -0
  391. package/lib/opLifecycle/remoteMessageProcessor.mjs.map +1 -0
  392. package/lib/opProperties.d.mts +7 -0
  393. package/lib/opProperties.d.mts.map +1 -0
  394. package/lib/opProperties.mjs +13 -0
  395. package/lib/opProperties.mjs.map +1 -0
  396. package/lib/{packageVersion.d.ts → packageVersion.d.mts} +1 -1
  397. package/lib/{packageVersion.d.ts.map → packageVersion.d.mts.map} +1 -1
  398. package/lib/{packageVersion.js → packageVersion.mjs} +2 -2
  399. package/lib/packageVersion.mjs.map +1 -0
  400. package/lib/{pendingStateManager.d.ts → pendingStateManager.d.mts} +32 -69
  401. package/lib/pendingStateManager.d.mts.map +1 -0
  402. package/lib/pendingStateManager.mjs +275 -0
  403. package/lib/pendingStateManager.mjs.map +1 -0
  404. package/lib/scheduleManager.d.mts +27 -0
  405. package/lib/scheduleManager.d.mts.map +1 -0
  406. package/lib/scheduleManager.mjs +254 -0
  407. package/lib/scheduleManager.mjs.map +1 -0
  408. package/lib/storageServiceWithAttachBlobs.d.mts +17 -0
  409. package/lib/storageServiceWithAttachBlobs.d.mts.map +1 -0
  410. package/lib/storageServiceWithAttachBlobs.mjs +28 -0
  411. package/lib/storageServiceWithAttachBlobs.mjs.map +1 -0
  412. package/lib/summary/index.d.mts +17 -0
  413. package/lib/summary/index.d.mts.map +1 -0
  414. package/lib/summary/index.mjs +16 -0
  415. package/lib/summary/index.mjs.map +1 -0
  416. package/{dist/orderedClientElection.d.ts → lib/summary/orderedClientElection.d.mts} +41 -22
  417. package/lib/summary/orderedClientElection.d.mts.map +1 -0
  418. package/lib/{orderedClientElection.js → summary/orderedClientElection.mjs} +95 -79
  419. package/lib/summary/orderedClientElection.mjs.map +1 -0
  420. package/{dist/runWhileConnectedCoordinator.d.ts → lib/summary/runWhileConnectedCoordinator.d.mts} +9 -3
  421. package/lib/summary/runWhileConnectedCoordinator.d.mts.map +1 -0
  422. package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.mjs} +12 -10
  423. package/lib/summary/runWhileConnectedCoordinator.mjs.map +1 -0
  424. package/lib/summary/runningSummarizer.d.mts +128 -0
  425. package/lib/summary/runningSummarizer.d.mts.map +1 -0
  426. package/lib/summary/runningSummarizer.mjs +675 -0
  427. package/lib/summary/runningSummarizer.mjs.map +1 -0
  428. package/lib/{summarizer.d.ts → summary/summarizer.d.mts} +20 -35
  429. package/lib/summary/summarizer.d.mts.map +1 -0
  430. package/lib/summary/summarizer.mjs +257 -0
  431. package/lib/summary/summarizer.mjs.map +1 -0
  432. package/{dist/summarizerClientElection.d.ts → lib/summary/summarizerClientElection.d.mts} +6 -6
  433. package/lib/summary/summarizerClientElection.d.mts.map +1 -0
  434. package/lib/{summarizerClientElection.js → summary/summarizerClientElection.mjs} +14 -45
  435. package/lib/summary/summarizerClientElection.mjs.map +1 -0
  436. package/{dist/summarizerHeuristics.d.ts → lib/summary/summarizerHeuristics.d.mts} +29 -7
  437. package/lib/summary/summarizerHeuristics.d.mts.map +1 -0
  438. package/lib/summary/summarizerHeuristics.mjs +151 -0
  439. package/lib/summary/summarizerHeuristics.mjs.map +1 -0
  440. package/lib/summary/summarizerNode/index.d.mts +8 -0
  441. package/lib/summary/summarizerNode/index.d.mts.map +1 -0
  442. package/lib/summary/summarizerNode/index.mjs +7 -0
  443. package/lib/summary/summarizerNode/index.mjs.map +1 -0
  444. package/lib/summary/summarizerNode/summarizerNode.d.mts +167 -0
  445. package/lib/summary/summarizerNode/summarizerNode.d.mts.map +1 -0
  446. package/lib/summary/summarizerNode/summarizerNode.mjs +521 -0
  447. package/lib/summary/summarizerNode/summarizerNode.mjs.map +1 -0
  448. package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts +121 -0
  449. package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +1 -0
  450. package/lib/summary/summarizerNode/summarizerNodeUtils.mjs +123 -0
  451. package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +1 -0
  452. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts +153 -0
  453. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +1 -0
  454. package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs +370 -0
  455. package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +1 -0
  456. package/{dist/summarizerTypes.d.ts → lib/summary/summarizerTypes.d.mts} +234 -84
  457. package/lib/summary/summarizerTypes.d.mts.map +1 -0
  458. package/lib/summary/summarizerTypes.mjs +6 -0
  459. package/lib/summary/summarizerTypes.mjs.map +1 -0
  460. package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.mts} +23 -5
  461. package/lib/summary/summaryCollection.d.mts.map +1 -0
  462. package/lib/{summaryCollection.js → summary/summaryCollection.mjs} +76 -45
  463. package/lib/summary/summaryCollection.mjs.map +1 -0
  464. package/{dist/summaryFormat.d.ts → lib/summary/summaryFormat.d.mts} +25 -30
  465. package/lib/summary/summaryFormat.d.mts.map +1 -0
  466. package/lib/{summaryFormat.js → summary/summaryFormat.mjs} +30 -26
  467. package/lib/summary/summaryFormat.mjs.map +1 -0
  468. package/lib/summary/summaryGenerator.d.mts +127 -0
  469. package/lib/summary/summaryGenerator.d.mts.map +1 -0
  470. package/lib/{summaryGenerator.js → summary/summaryGenerator.mjs} +153 -67
  471. package/lib/summary/summaryGenerator.mjs.map +1 -0
  472. package/{dist/summaryManager.d.ts → lib/summary/summaryManager.d.mts} +15 -13
  473. package/lib/summary/summaryManager.d.mts.map +1 -0
  474. package/lib/{summaryManager.js → summary/summaryManager.mjs} +94 -51
  475. package/lib/summary/summaryManager.mjs.map +1 -0
  476. package/lib/{throttler.d.ts → throttler.d.mts} +2 -2
  477. package/lib/throttler.d.mts.map +1 -0
  478. package/lib/{throttler.js → throttler.mjs} +21 -21
  479. package/lib/throttler.mjs.map +1 -0
  480. package/package.json +173 -72
  481. package/prettier.config.cjs +8 -0
  482. package/src/batchTracker.ts +59 -54
  483. package/src/blobManager.ts +937 -294
  484. package/src/connectionTelemetry.ts +342 -252
  485. package/src/containerHandleContext.ts +27 -29
  486. package/src/containerRuntime.ts +3879 -3143
  487. package/src/dataStore.ts +170 -140
  488. package/src/dataStoreContext.ts +1166 -986
  489. package/src/dataStoreContexts.ts +176 -163
  490. package/src/dataStoreRegistry.ts +29 -21
  491. package/src/dataStores.ts +921 -678
  492. package/src/deltaManagerProxyBase.ts +111 -0
  493. package/src/deltaManagerSummarizerProxy.ts +49 -0
  494. package/src/deltaScheduler.ts +161 -156
  495. package/src/error.ts +21 -0
  496. package/src/gc/garbageCollection.md +106 -0
  497. package/src/gc/garbageCollection.ts +1153 -0
  498. package/src/gc/gcConfigs.ts +216 -0
  499. package/src/gc/gcDefinitions.ts +502 -0
  500. package/src/gc/gcHelpers.ts +284 -0
  501. package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
  502. package/src/gc/gcSummaryDefinitions.ts +54 -0
  503. package/src/gc/gcSummaryStateTracker.ts +299 -0
  504. package/src/gc/gcTelemetry.ts +423 -0
  505. package/src/gc/gcUnreferencedStateTracker.ts +153 -0
  506. package/src/gc/index.ts +59 -0
  507. package/src/index.ts +101 -74
  508. package/src/messageTypes.ts +238 -0
  509. package/src/metadata.ts +26 -0
  510. package/src/opLifecycle/README.md +321 -0
  511. package/src/opLifecycle/batchManager.ts +179 -0
  512. package/src/opLifecycle/definitions.ts +89 -0
  513. package/src/opLifecycle/index.ts +19 -0
  514. package/src/opLifecycle/opCompressor.ts +99 -0
  515. package/src/opLifecycle/opDecompressor.ts +190 -0
  516. package/src/opLifecycle/opGroupingManager.ts +133 -0
  517. package/src/opLifecycle/opSplitter.ts +279 -0
  518. package/src/opLifecycle/outbox.ts +471 -0
  519. package/src/opLifecycle/remoteMessageProcessor.ts +175 -0
  520. package/src/opProperties.ts +21 -0
  521. package/src/packageVersion.ts +1 -1
  522. package/src/pendingStateManager.ts +396 -465
  523. package/src/scheduleManager.ts +358 -0
  524. package/src/storageServiceWithAttachBlobs.ts +38 -0
  525. package/src/summary/index.ts +109 -0
  526. package/src/summary/orderedClientElection.ts +571 -0
  527. package/src/summary/runWhileConnectedCoordinator.ts +117 -0
  528. package/src/summary/runningSummarizer.ts +920 -0
  529. package/src/summary/summarizer.ts +352 -0
  530. package/src/summary/summarizerClientElection.ts +140 -0
  531. package/src/summary/summarizerHeuristics.ts +227 -0
  532. package/src/summary/summarizerNode/index.ts +12 -0
  533. package/src/summary/summarizerNode/summarizerNode.ts +725 -0
  534. package/src/summary/summarizerNode/summarizerNodeUtils.ts +206 -0
  535. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +571 -0
  536. package/src/summary/summarizerTypes.ts +631 -0
  537. package/src/summary/summaryCollection.ts +474 -0
  538. package/src/summary/summaryFormat.ts +249 -0
  539. package/src/summary/summaryGenerator.ts +539 -0
  540. package/src/summary/summaryManager.ts +452 -0
  541. package/src/throttler.ts +131 -122
  542. package/tsc-multi.test.json +4 -0
  543. package/tsconfig.json +11 -13
  544. package/dist/batchTracker.js.map +0 -1
  545. package/dist/blobManager.js +0 -249
  546. package/dist/blobManager.js.map +0 -1
  547. package/dist/connectionTelemetry.js +0 -178
  548. package/dist/connectionTelemetry.js.map +0 -1
  549. package/dist/containerHandleContext.js.map +0 -1
  550. package/dist/containerRuntime.js +0 -2174
  551. package/dist/containerRuntime.js.map +0 -1
  552. package/dist/dataStore.js.map +0 -1
  553. package/dist/dataStoreContext.js.map +0 -1
  554. package/dist/dataStoreContexts.js.map +0 -1
  555. package/dist/dataStoreRegistry.js.map +0 -1
  556. package/dist/dataStores.js.map +0 -1
  557. package/dist/deltaScheduler.js.map +0 -1
  558. package/dist/garbageCollection.d.ts +0 -319
  559. package/dist/garbageCollection.d.ts.map +0 -1
  560. package/dist/garbageCollection.js +0 -993
  561. package/dist/garbageCollection.js.map +0 -1
  562. package/dist/index.js +0 -33
  563. package/dist/index.js.map +0 -1
  564. package/dist/opTelemetry.d.ts +0 -22
  565. package/dist/opTelemetry.d.ts.map +0 -1
  566. package/dist/opTelemetry.js +0 -60
  567. package/dist/opTelemetry.js.map +0 -1
  568. package/dist/orderedClientElection.d.ts.map +0 -1
  569. package/dist/orderedClientElection.js.map +0 -1
  570. package/dist/packageVersion.js.map +0 -1
  571. package/dist/pendingStateManager.js +0 -346
  572. package/dist/pendingStateManager.js.map +0 -1
  573. package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
  574. package/dist/runWhileConnectedCoordinator.js.map +0 -1
  575. package/dist/runningSummarizer.d.ts +0 -93
  576. package/dist/runningSummarizer.d.ts.map +0 -1
  577. package/dist/runningSummarizer.js +0 -384
  578. package/dist/runningSummarizer.js.map +0 -1
  579. package/dist/serializedSnapshotStorage.d.ts +0 -58
  580. package/dist/serializedSnapshotStorage.d.ts.map +0 -1
  581. package/dist/serializedSnapshotStorage.js +0 -108
  582. package/dist/serializedSnapshotStorage.js.map +0 -1
  583. package/dist/summarizer.d.ts.map +0 -1
  584. package/dist/summarizer.js +0 -348
  585. package/dist/summarizer.js.map +0 -1
  586. package/dist/summarizerClientElection.d.ts.map +0 -1
  587. package/dist/summarizerClientElection.js.map +0 -1
  588. package/dist/summarizerHandle.d.ts +0 -12
  589. package/dist/summarizerHandle.d.ts.map +0 -1
  590. package/dist/summarizerHandle.js +0 -22
  591. package/dist/summarizerHandle.js.map +0 -1
  592. package/dist/summarizerHeuristics.d.ts.map +0 -1
  593. package/dist/summarizerHeuristics.js +0 -84
  594. package/dist/summarizerHeuristics.js.map +0 -1
  595. package/dist/summarizerTypes.d.ts.map +0 -1
  596. package/dist/summarizerTypes.js.map +0 -1
  597. package/dist/summaryCollection.d.ts.map +0 -1
  598. package/dist/summaryCollection.js.map +0 -1
  599. package/dist/summaryFormat.d.ts.map +0 -1
  600. package/dist/summaryFormat.js.map +0 -1
  601. package/dist/summaryGenerator.d.ts.map +0 -1
  602. package/dist/summaryGenerator.js.map +0 -1
  603. package/dist/summaryManager.d.ts.map +0 -1
  604. package/dist/summaryManager.js.map +0 -1
  605. package/dist/throttler.js.map +0 -1
  606. package/garbageCollection.md +0 -41
  607. package/lib/batchTracker.d.ts.map +0 -1
  608. package/lib/batchTracker.js.map +0 -1
  609. package/lib/blobManager.d.ts +0 -95
  610. package/lib/blobManager.d.ts.map +0 -1
  611. package/lib/blobManager.js +0 -244
  612. package/lib/blobManager.js.map +0 -1
  613. package/lib/connectionTelemetry.d.ts.map +0 -1
  614. package/lib/connectionTelemetry.js +0 -174
  615. package/lib/connectionTelemetry.js.map +0 -1
  616. package/lib/containerHandleContext.d.ts.map +0 -1
  617. package/lib/containerHandleContext.js.map +0 -1
  618. package/lib/containerRuntime.d.ts +0 -615
  619. package/lib/containerRuntime.d.ts.map +0 -1
  620. package/lib/containerRuntime.js +0 -2166
  621. package/lib/containerRuntime.js.map +0 -1
  622. package/lib/dataStore.d.ts.map +0 -1
  623. package/lib/dataStore.js.map +0 -1
  624. package/lib/dataStoreContext.d.ts.map +0 -1
  625. package/lib/dataStoreContext.js.map +0 -1
  626. package/lib/dataStoreContexts.d.ts.map +0 -1
  627. package/lib/dataStoreContexts.js.map +0 -1
  628. package/lib/dataStoreRegistry.d.ts.map +0 -1
  629. package/lib/dataStoreRegistry.js.map +0 -1
  630. package/lib/dataStores.d.ts.map +0 -1
  631. package/lib/dataStores.js.map +0 -1
  632. package/lib/deltaScheduler.d.ts.map +0 -1
  633. package/lib/deltaScheduler.js.map +0 -1
  634. package/lib/garbageCollection.d.ts +0 -319
  635. package/lib/garbageCollection.d.ts.map +0 -1
  636. package/lib/garbageCollection.js +0 -989
  637. package/lib/garbageCollection.js.map +0 -1
  638. package/lib/index.d.ts +0 -14
  639. package/lib/index.d.ts.map +0 -1
  640. package/lib/index.js +0 -13
  641. package/lib/index.js.map +0 -1
  642. package/lib/opTelemetry.d.ts +0 -22
  643. package/lib/opTelemetry.d.ts.map +0 -1
  644. package/lib/opTelemetry.js +0 -56
  645. package/lib/opTelemetry.js.map +0 -1
  646. package/lib/orderedClientElection.d.ts.map +0 -1
  647. package/lib/orderedClientElection.js.map +0 -1
  648. package/lib/packageVersion.js.map +0 -1
  649. package/lib/pendingStateManager.d.ts.map +0 -1
  650. package/lib/pendingStateManager.js +0 -339
  651. package/lib/pendingStateManager.js.map +0 -1
  652. package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
  653. package/lib/runWhileConnectedCoordinator.js.map +0 -1
  654. package/lib/runningSummarizer.d.ts +0 -93
  655. package/lib/runningSummarizer.d.ts.map +0 -1
  656. package/lib/runningSummarizer.js +0 -380
  657. package/lib/runningSummarizer.js.map +0 -1
  658. package/lib/serializedSnapshotStorage.d.ts +0 -58
  659. package/lib/serializedSnapshotStorage.d.ts.map +0 -1
  660. package/lib/serializedSnapshotStorage.js +0 -104
  661. package/lib/serializedSnapshotStorage.js.map +0 -1
  662. package/lib/summarizer.d.ts.map +0 -1
  663. package/lib/summarizer.js +0 -342
  664. package/lib/summarizer.js.map +0 -1
  665. package/lib/summarizerClientElection.d.ts.map +0 -1
  666. package/lib/summarizerClientElection.js.map +0 -1
  667. package/lib/summarizerHandle.d.ts +0 -12
  668. package/lib/summarizerHandle.d.ts.map +0 -1
  669. package/lib/summarizerHandle.js +0 -18
  670. package/lib/summarizerHandle.js.map +0 -1
  671. package/lib/summarizerHeuristics.d.ts.map +0 -1
  672. package/lib/summarizerHeuristics.js +0 -79
  673. package/lib/summarizerHeuristics.js.map +0 -1
  674. package/lib/summarizerTypes.d.ts.map +0 -1
  675. package/lib/summarizerTypes.js +0 -9
  676. package/lib/summarizerTypes.js.map +0 -1
  677. package/lib/summaryCollection.d.ts.map +0 -1
  678. package/lib/summaryCollection.js.map +0 -1
  679. package/lib/summaryFormat.d.ts.map +0 -1
  680. package/lib/summaryFormat.js.map +0 -1
  681. package/lib/summaryGenerator.d.ts +0 -85
  682. package/lib/summaryGenerator.d.ts.map +0 -1
  683. package/lib/summaryGenerator.js.map +0 -1
  684. package/lib/summaryManager.d.ts.map +0 -1
  685. package/lib/summaryManager.js.map +0 -1
  686. package/lib/throttler.d.ts.map +0 -1
  687. package/lib/throttler.js.map +0 -1
  688. package/src/garbageCollection.ts +0 -1434
  689. package/src/opTelemetry.ts +0 -71
  690. package/src/orderedClientElection.ts +0 -511
  691. package/src/runWhileConnectedCoordinator.ts +0 -106
  692. package/src/runningSummarizer.ts +0 -550
  693. package/src/serializedSnapshotStorage.ts +0 -146
  694. package/src/summarizer.ts +0 -438
  695. package/src/summarizerClientElection.ts +0 -161
  696. package/src/summarizerHandle.ts +0 -21
  697. package/src/summarizerHeuristics.ts +0 -108
  698. package/src/summarizerTypes.ts +0 -462
  699. package/src/summaryCollection.ts +0 -406
  700. package/src/summaryFormat.ts +0 -239
  701. package/src/summaryGenerator.ts +0 -427
  702. package/src/summaryManager.ts +0 -368
  703. package/tsconfig.esnext.json +0 -7
package/src/dataStores.ts CHANGED
@@ -3,701 +3,944 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryLogger, ITelemetryBaseLogger, IDisposable } from "@fluidframework/common-definitions";
7
- import { DataCorruptionError, extractSafePropertiesFromMessage } from "@fluidframework/container-utils";
8
- import { IFluidHandle } from "@fluidframework/core-interfaces";
9
- import { FluidObjectHandle } from "@fluidframework/datastore";
10
6
  import {
11
- ISequencedDocumentMessage,
12
- ISnapshotTree,
13
- } from "@fluidframework/protocol-definitions";
7
+ ITelemetryBaseLogger,
8
+ IDisposable,
9
+ IFluidHandle,
10
+ IRequest,
11
+ } from "@fluidframework/core-interfaces";
12
+ import { FluidObjectHandle } from "@fluidframework/datastore";
13
+ import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
14
14
  import {
15
- channelsTreeName,
16
- CreateChildSummarizerNodeFn,
17
- CreateChildSummarizerNodeParam,
18
- CreateSummarizerNodeSource,
19
- IAttachMessage,
20
- IEnvelope,
21
- IFluidDataStoreContextDetached,
22
- IGarbageCollectionData,
23
- IGarbageCollectionDetailsBase,
24
- IInboundSignalMessage,
25
- InboundAttachMessage,
26
- ISummarizeResult,
27
- ISummaryTreeWithStats,
28
- ITelemetryContext,
15
+ AliasResult,
16
+ channelsTreeName,
17
+ CreateChildSummarizerNodeFn,
18
+ CreateChildSummarizerNodeParam,
19
+ CreateSummarizerNodeSource,
20
+ IAttachMessage,
21
+ IEnvelope,
22
+ IFluidDataStoreContextDetached,
23
+ IGarbageCollectionData,
24
+ IInboundSignalMessage,
25
+ InboundAttachMessage,
26
+ ISummarizeResult,
27
+ ISummaryTreeWithStats,
28
+ ITelemetryContext,
29
29
  } from "@fluidframework/runtime-definitions";
30
30
  import {
31
- convertSnapshotTreeToSummaryTree,
32
- convertToSummaryTree,
33
- create404Response,
34
- responseToException,
35
- SummaryTreeBuilder,
31
+ convertSnapshotTreeToSummaryTree,
32
+ convertToSummaryTree,
33
+ create404Response,
34
+ createResponseError,
35
+ GCDataBuilder,
36
+ responseToException,
37
+ SummaryTreeBuilder,
38
+ unpackChildNodesUsedRoutes,
36
39
  } from "@fluidframework/runtime-utils";
37
- import { ChildLogger, LoggingError, TelemetryDataTag } from "@fluidframework/telemetry-utils";
40
+ import {
41
+ createChildMonitoringContext,
42
+ DataCorruptionError,
43
+ DataProcessingError,
44
+ extractSafePropertiesFromMessage,
45
+ LoggingError,
46
+ MonitoringContext,
47
+ tagCodeArtifacts,
48
+ } from "@fluidframework/telemetry-utils";
38
49
  import { AttachState } from "@fluidframework/container-definitions";
39
- import { BlobCacheStorageService, buildSnapshotTree } from "@fluidframework/driver-utils";
40
- import { assert, Lazy, LazyPromise } from "@fluidframework/common-utils";
50
+ import { buildSnapshotTree } from "@fluidframework/driver-utils";
51
+ import { assert, Lazy } from "@fluidframework/core-utils";
41
52
  import { v4 as uuid } from "uuid";
42
- import { GCDataBuilder, unpackChildNodesUsedRoutes } from "@fluidframework/garbage-collector";
43
53
  import { DataStoreContexts } from "./dataStoreContexts";
44
- import { ContainerRuntime } from "./containerRuntime";
54
+ import { ContainerRuntime, defaultRuntimeHeaderData, RuntimeHeaderData } from "./containerRuntime";
45
55
  import {
46
- FluidDataStoreContext,
47
- RemoteFluidDataStoreContext,
48
- LocalFluidDataStoreContext,
49
- createAttributesBlob,
50
- LocalDetachedFluidDataStoreContext,
56
+ FluidDataStoreContext,
57
+ RemoteFluidDataStoreContext,
58
+ LocalFluidDataStoreContext,
59
+ createAttributesBlob,
60
+ LocalDetachedFluidDataStoreContext,
51
61
  } from "./dataStoreContext";
52
- import { IContainerRuntimeMetadata, nonDataStorePaths, rootHasIsolatedChannels } from "./summaryFormat";
62
+ import { StorageServiceWithAttachBlobs } from "./storageServiceWithAttachBlobs";
53
63
  import { IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
54
- import { GCNodeType } from "./garbageCollection";
64
+ import { GCNodeType, disableDatastoreSweepKey } from "./gc";
65
+ import { IContainerRuntimeMetadata, nonDataStorePaths, rootHasIsolatedChannels } from "./summary";
55
66
 
56
67
  type PendingAliasResolve = (success: boolean) => void;
57
68
 
58
- /**
59
- * This class encapsulates data store handling. Currently it is only used by the container runtime,
60
- * but eventually could be hosted on any channel once we formalize the channel api boundary.
61
- */
69
+ /**
70
+ * This class encapsulates data store handling. Currently it is only used by the container runtime,
71
+ * but eventually could be hosted on any channel once we formalize the channel api boundary.
72
+ */
62
73
  export class DataStores implements IDisposable {
63
- // Stores tracked by the Domain
64
- private readonly pendingAttach = new Map<string, IAttachMessage>();
65
- // 0.24 back-compat attachingBeforeSummary
66
- public readonly attachOpFiredForDataStore = new Set<string>();
67
-
68
- private readonly logger: ITelemetryLogger;
69
-
70
- private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());
71
-
72
- public readonly containerLoadStats: {
73
- // number of dataStores during loadContainer
74
- readonly containerLoadDataStoreCount: number;
75
- // number of unreferenced dataStores during loadContainer
76
- readonly referencedDataStoreCount: number;
77
- };
78
-
79
- // Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
80
- // root data stores that are added.
81
- private dataStoresSinceLastGC: string[] = [];
82
- // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
83
- // the container runtime to other nodes.
84
- private readonly containerRuntimeHandle: IFluidHandle;
85
-
86
- constructor(
87
- private readonly baseSnapshot: ISnapshotTree | undefined,
88
- private readonly runtime: ContainerRuntime,
89
- private readonly submitAttachFn: (attachContent: any) => void,
90
- private readonly getCreateChildSummarizerNodeFn:
91
- (id: string, createParam: CreateChildSummarizerNodeParam) => CreateChildSummarizerNodeFn,
92
- private readonly deleteChildSummarizerNodeFn: (id: string) => void,
93
- baseLogger: ITelemetryBaseLogger,
94
- getBaseGCDetails: () => Promise<Map<string, IGarbageCollectionDetailsBase>>,
95
- private readonly gcNodeUpdated: (
96
- nodePath: string, timestampMs: number, packagePath?: readonly string[]) => void,
97
- private readonly aliasMap: Map<string, string>,
98
- private readonly writeGCDataAtRoot: boolean,
99
- private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),
100
- ) {
101
- this.logger = ChildLogger.create(baseLogger);
102
- this.containerRuntimeHandle = new FluidObjectHandle(this.runtime, "/", this.runtime.IFluidHandleContext);
103
-
104
- const baseGCDetailsP = new LazyPromise(async () => {
105
- return getBaseGCDetails();
106
- });
107
- // Returns the base GC details for the data store with the given id.
108
- const dataStoreBaseGCDetails = async (dataStoreId: string) => {
109
- const baseGCDetails = await baseGCDetailsP;
110
- return baseGCDetails.get(dataStoreId);
111
- };
112
-
113
- // Extract stores stored inside the snapshot
114
- const fluidDataStores = new Map<string, ISnapshotTree>();
115
- if (baseSnapshot) {
116
- for (const [key, value] of Object.entries(baseSnapshot.trees)) {
117
- fluidDataStores.set(key, value);
118
- }
119
- }
120
-
121
- let unreferencedDataStoreCount = 0;
122
- // Create a context for each of them
123
- for (const [key, value] of fluidDataStores) {
124
- let dataStoreContext: FluidDataStoreContext;
125
-
126
- // counting number of unreferenced data stores
127
- if (value.unreferenced) {
128
- unreferencedDataStoreCount++;
129
- }
130
- // If we have a detached container, then create local data store contexts.
131
- if (this.runtime.attachState !== AttachState.Detached) {
132
- dataStoreContext = new RemoteFluidDataStoreContext({
133
- id: key,
134
- snapshotTree: value,
135
- getBaseGCDetails: async () => dataStoreBaseGCDetails(key),
136
- runtime: this.runtime,
137
- storage: this.runtime.storage,
138
- scope: this.runtime.scope,
139
- createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
140
- key,
141
- { type: CreateSummarizerNodeSource.FromSummary },
142
- ),
143
- writeGCDataAtRoot: this.writeGCDataAtRoot,
144
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
145
- });
146
- } else {
147
- if (typeof value !== "object") {
148
- throw new LoggingError("Snapshot should be there to load from!!");
149
- }
150
- const snapshotTree = value;
151
- dataStoreContext = new LocalFluidDataStoreContext({
152
- id: key,
153
- pkg: undefined,
154
- runtime: this.runtime,
155
- storage: this.runtime.storage,
156
- scope: this.runtime.scope,
157
- createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
158
- key,
159
- { type: CreateSummarizerNodeSource.FromSummary },
160
- ),
161
- makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(key),
162
- snapshotTree,
163
- isRootDataStore: undefined,
164
- writeGCDataAtRoot: this.writeGCDataAtRoot,
165
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
166
- });
167
- }
168
- this.contexts.addBoundOrRemoted(dataStoreContext);
169
- }
170
- this.containerLoadStats = {
171
- containerLoadDataStoreCount: fluidDataStores.size,
172
- referencedDataStoreCount: fluidDataStores.size - unreferencedDataStoreCount,
173
- };
174
- }
175
-
176
- public aliases(): ReadonlyMap<string, string> {
177
- return this.aliasMap;
178
- }
179
-
180
- public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
181
- const attachMessage = message.contents as InboundAttachMessage;
182
-
183
- this.dataStoresSinceLastGC.push(attachMessage.id);
184
-
185
- // The local object has already been attached
186
- if (local) {
187
- assert(this.pendingAttach.has(attachMessage.id),
188
- 0x15e /* "Local object does not have matching attach message id" */);
189
- this.contexts.get(attachMessage.id)?.emit("attached");
190
- this.pendingAttach.delete(attachMessage.id);
191
- return;
192
- }
193
-
194
- // If a non-local operation then go and create the object, otherwise mark it as officially attached.
195
- if (this.alreadyProcessed(attachMessage.id)) {
196
- // TODO: dataStoreId may require a different tag from PackageData #7488
197
- const error = new DataCorruptionError(
198
- // pre-0.58 error message: duplicateDataStoreCreatedWithExistingId
199
- "Duplicate DataStore created with existing id",
200
- {
201
- ...extractSafePropertiesFromMessage(message),
202
- dataStoreId: {
203
- value: attachMessage.id,
204
- tag: TelemetryDataTag.PackageData,
205
- },
206
- },
207
- );
208
- throw error;
209
- }
210
-
211
- const flatBlobs = new Map<string, ArrayBufferLike>();
212
- let snapshotTree: ISnapshotTree | undefined;
213
- if (attachMessage.snapshot) {
214
- snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatBlobs);
215
- }
216
-
217
- // Include the type of attach message which is the pkg of the store to be
218
- // used by RemoteFluidDataStoreContext in case it is not in the snapshot.
219
- const pkg = [attachMessage.type];
220
- const remoteFluidDataStoreContext = new RemoteFluidDataStoreContext({
221
- id: attachMessage.id,
222
- snapshotTree,
223
- // New data stores begin with empty GC details since GC hasn't run on them yet.
224
- getBaseGCDetails: async () => { return {}; },
225
- runtime: this.runtime,
226
- storage: new BlobCacheStorageService(this.runtime.storage, flatBlobs),
227
- scope: this.runtime.scope,
228
- createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
229
- attachMessage.id,
230
- {
231
- type: CreateSummarizerNodeSource.FromAttach,
232
- sequenceNumber: message.sequenceNumber,
233
- snapshot: attachMessage.snapshot ?? {
234
- entries: [createAttributesBlob(
235
- pkg,
236
- true /* isRootDataStore */,
237
- this.runtime.disableIsolatedChannels,
238
- )],
239
- },
240
- },
241
- ),
242
- writeGCDataAtRoot: this.writeGCDataAtRoot,
243
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
244
- pkg,
245
- });
246
-
247
- this.contexts.addBoundOrRemoted(remoteFluidDataStoreContext);
248
- }
249
-
250
- public processAliasMessage(
251
- message: ISequencedDocumentMessage,
252
- localOpMetadata: unknown,
253
- local: boolean,
254
- ): void {
255
- const aliasMessage = message.contents as IDataStoreAliasMessage;
256
- if (!isDataStoreAliasMessage(aliasMessage)) {
257
- throw new DataCorruptionError(
258
- "malformedDataStoreAliasMessage",
259
- {
260
- ...extractSafePropertiesFromMessage(message),
261
- },
262
- );
263
- }
264
-
265
- const resolve = localOpMetadata as PendingAliasResolve;
266
- const aliasResult = this.processAliasMessageCore(aliasMessage);
267
- if (local) {
268
- resolve(aliasResult);
269
- }
270
- }
271
-
272
- public processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {
273
- if (this.alreadyProcessed(aliasMessage.alias)) {
274
- return false;
275
- }
276
-
277
- const context = this.contexts.get(aliasMessage.internalId);
278
- if (context === undefined) {
279
- this.logger.sendErrorEvent({
280
- eventName: "AliasFluidDataStoreNotFound",
281
- fluidDataStoreId: aliasMessage.internalId,
282
- });
283
- return false;
284
- }
285
-
286
- const handle = new FluidObjectHandle(
287
- context,
288
- aliasMessage.internalId,
289
- this.runtime.IFluidHandleContext,
290
- );
291
- this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
292
-
293
- this.aliasMap.set(aliasMessage.alias, context.id);
294
- context.setInMemoryRoot();
295
- return true;
296
- }
297
-
298
- private alreadyProcessed(id: string): boolean {
299
- return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
300
- }
301
-
302
- /**
303
- * Make the data stores locally visible in the container graph by moving the data store context from unbound to
304
- * bound list. This data store can now be reached from the root.
305
- * @param id - The id of the data store context to make visible.
306
- */
307
- private makeDataStoreLocallyVisible(id: string): void {
308
- const localContext = this.contexts.getUnbound(id);
309
- assert(!!localContext, 0x15f /* "Could not find unbound context to bind" */);
310
-
311
- /**
312
- * If the container is not detached, it is globally visible to all clients. This data store should also be
313
- * globally visible. Move it to attaching state and send an "attach" op for it.
314
- * If the container is detached, this data store will be part of the summary that makes the container attached.
315
- */
316
- if (this.runtime.attachState !== AttachState.Detached) {
317
- localContext.emit("attaching");
318
- const message = localContext.generateAttachMessage();
319
-
320
- this.pendingAttach.set(id, message);
321
- this.submitAttachFn(message);
322
- this.attachOpFiredForDataStore.add(id);
323
- }
324
-
325
- this.contexts.bind(id);
326
- }
327
-
328
- public createDetachedDataStoreCore(
329
- pkg: Readonly<string[]>,
330
- isRoot: boolean,
331
- id = uuid()): IFluidDataStoreContextDetached {
332
- assert(!id.includes("/"), 0x30c /* Id cannot contain slashes */);
333
-
334
- const context = new LocalDetachedFluidDataStoreContext({
335
- id,
336
- pkg,
337
- runtime: this.runtime,
338
- storage: this.runtime.storage,
339
- scope: this.runtime.scope,
340
- createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
341
- id,
342
- { type: CreateSummarizerNodeSource.Local },
343
- ),
344
- makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
345
- snapshotTree: undefined,
346
- isRootDataStore: isRoot,
347
- writeGCDataAtRoot: this.writeGCDataAtRoot,
348
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
349
- });
350
- this.contexts.addUnbound(context);
351
- return context;
352
- }
353
-
354
- public _createFluidDataStoreContext(pkg: string[], id: string, isRoot: boolean, props?: any) {
355
- assert(!id.includes("/"), 0x30d /* Id cannot contain slashes */);
356
- const context = new LocalFluidDataStoreContext({
357
- id,
358
- pkg,
359
- runtime: this.runtime,
360
- storage: this.runtime.storage,
361
- scope: this.runtime.scope,
362
- createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(
363
- id,
364
- { type: CreateSummarizerNodeSource.Local },
365
- ),
366
- makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
367
- snapshotTree: undefined,
368
- isRootDataStore: isRoot,
369
- writeGCDataAtRoot: this.writeGCDataAtRoot,
370
- disableIsolatedChannels: this.runtime.disableIsolatedChannels,
371
- createProps: props,
372
- });
373
- this.contexts.addUnbound(context);
374
- return context;
375
- }
376
-
377
- public get disposed() { return this.disposeOnce.evaluated; }
378
- public readonly dispose = () => this.disposeOnce.value;
379
-
380
- public resubmitDataStoreOp(content: any, localOpMetadata: unknown) {
381
- const envelope = content as IEnvelope;
382
- const context = this.contexts.get(envelope.address);
383
- assert(!!context, 0x160 /* "There should be a store context for the op" */);
384
- context.reSubmit(envelope.contents, localOpMetadata);
385
- }
386
-
387
- public rollbackDataStoreOp(content: any, localOpMetadata: unknown) {
388
- const envelope = content as IEnvelope;
389
- const context = this.contexts.get(envelope.address);
390
- assert(!!context, 0x2e8 /* "There should be a store context for the op" */);
391
- context.rollback(envelope.contents, localOpMetadata);
392
- }
393
-
394
- public async applyStashedOp(content: any): Promise<unknown> {
395
- const envelope = content as IEnvelope;
396
- const context = this.contexts.get(envelope.address);
397
- assert(!!context, 0x161 /* "There should be a store context for the op" */);
398
- return context.applyStashedOp(envelope.contents);
399
- }
400
-
401
- public async applyStashedAttachOp(message: IAttachMessage) {
402
- this.pendingAttach.set(message.id, message);
403
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
404
- this.processAttachMessage({ contents: message } as ISequencedDocumentMessage, false);
405
- }
406
-
407
- public processFluidDataStoreOp(message: ISequencedDocumentMessage, local: boolean, localMessageMetadata: unknown) {
408
- const envelope = message.contents as IEnvelope;
409
- const transformed = { ...message, contents: envelope.contents };
410
- const context = this.contexts.get(envelope.address);
411
- assert(!!context, 0x162 /* "There should be a store context for the op" */);
412
- context.process(transformed, local, localMessageMetadata);
413
-
414
- // Notify that a GC node for the data store changed. This is used to detect if a deleted data store is
415
- // being used.
416
- this.gcNodeUpdated(
417
- `/${envelope.address}`,
418
- message.timestamp,
419
- context.isLoaded ? context.packagePath : undefined,
420
- );
421
- }
422
-
423
- public async getDataStore(id: string, wait: boolean): Promise<FluidDataStoreContext> {
424
- const context = await this.contexts.getBoundOrRemoted(id, wait);
425
- if (context === undefined) {
426
- // The requested data store does not exits. Throw a 404 response exception.
427
- const request = { url: id };
428
- throw responseToException(create404Response(request), request);
429
- }
430
-
431
- return context;
432
- }
433
-
434
- public processSignal(address: string, message: IInboundSignalMessage, local: boolean) {
435
- const context = this.contexts.get(address);
436
- if (!context) {
437
- // Attach message may not have been processed yet
438
- assert(!local, 0x163 /* "Missing datastore for local signal" */);
439
- this.logger.sendTelemetryEvent({
440
- eventName: "SignalFluidDataStoreNotFound",
441
- fluidDataStoreId: {
442
- value: address,
443
- tag: TelemetryDataTag.PackageData,
444
- },
445
- });
446
- return;
447
- }
448
-
449
- context.processSignal(message, local);
450
- }
451
-
452
- public setConnectionState(connected: boolean, clientId?: string) {
453
- for (const [fluidDataStore, context] of this.contexts) {
454
- try {
455
- context.setConnectionState(connected, clientId);
456
- } catch (error) {
457
- this.logger.sendErrorEvent({
458
- eventName: "SetConnectionStateError",
459
- clientId,
460
- fluidDataStore,
461
- }, error);
462
- }
463
- }
464
- }
465
-
466
- public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
467
- let eventName: "attaching" | "attached";
468
- if (attachState === AttachState.Attaching) {
469
- eventName = "attaching";
470
- } else {
471
- eventName = "attached";
472
- }
473
- for (const [,context] of this.contexts) {
474
- // Fire only for bounded stores.
475
- if (!this.contexts.isNotBound(context.id)) {
476
- context.emit(eventName);
477
- }
478
- }
479
- }
480
-
481
- public get size(): number {
482
- return this.contexts.size;
483
- }
484
-
485
- public async summarize(
486
- fullTree: boolean,
487
- trackState: boolean,
488
- telemetryContext?: ITelemetryContext,
489
- ): Promise<ISummaryTreeWithStats> {
490
- const summaryBuilder = new SummaryTreeBuilder();
491
-
492
- // Iterate over each store and ask it to snapshot
493
- await Promise.all(Array.from(this.contexts)
494
- .filter(([_, context]) => {
495
- // Summarizer works only with clients with no local changes!
496
- assert(context.attachState !== AttachState.Attaching,
497
- 0x165 /* "Summarizer cannot work if client has local changes" */);
498
- return context.attachState === AttachState.Attached;
499
- }).map(async ([contextId, context]) => {
500
- const contextSummary = await context.summarize(fullTree, trackState, telemetryContext);
501
- summaryBuilder.addWithStats(contextId, contextSummary);
502
- }));
503
-
504
- return summaryBuilder.getSummaryTree();
505
- }
506
-
507
- public createSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {
508
- const builder = new SummaryTreeBuilder();
509
- // Attaching graph of some stores can cause other stores to get bound too.
510
- // So keep taking summary until no new stores get bound.
511
- let notBoundContextsLength: number;
512
- do {
513
- const builderTree = builder.summary.tree;
514
- notBoundContextsLength = this.contexts.notBoundLength();
515
- // Iterate over each data store and ask it to snapshot
516
- Array.from(this.contexts)
517
- .filter(([key, _]) =>
518
- // Take summary of bounded data stores only, make sure we haven't summarized them already
519
- // and no attach op has been fired for that data store because for loader versions <= 0.24
520
- // we set attach state as "attaching" before taking createNew summary.
521
- !(this.contexts.isNotBound(key)
522
- || builderTree[key]
523
- || this.attachOpFiredForDataStore.has(key)),
524
- )
525
- .map(([key, value]) => {
526
- let dataStoreSummary: ISummarizeResult;
527
- if (value.isLoaded) {
528
- const snapshot = value.generateAttachMessage().snapshot;
529
- dataStoreSummary = convertToSummaryTree(snapshot, true);
530
- } else {
531
- // If this data store is not yet loaded, then there should be no changes in the snapshot from
532
- // which it was created as it is detached container. So just use the previous snapshot.
533
- assert(!!this.baseSnapshot,
534
- 0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
535
- dataStoreSummary = convertSnapshotTreeToSummaryTree(this.baseSnapshot.trees[key]);
536
- }
537
- builder.addWithStats(key, dataStoreSummary);
538
- });
539
- } while (notBoundContextsLength !== this.contexts.notBoundLength());
540
-
541
- return builder.getSummaryTree();
542
- }
543
-
544
- /**
545
- * Before GC runs, called by the garbage collector to update any pending GC state.
546
- * The garbage collector needs to know all outbound references that are added. Since root data stores are not
547
- * explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
548
- */
549
- public async updateStateBeforeGC(): Promise<void> {
550
- for (const id of this.dataStoresSinceLastGC) {
551
- const context = this.contexts.get(id);
552
- assert(context !== undefined, 0x2b6 /* Missing data store context */);
553
- if (await context.isRoot()) {
554
- // A root data store is basically a reference from the container runtime to the data store.
555
- const handle = new FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);
556
- this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
557
- }
558
- }
559
- this.dataStoresSinceLastGC = [];
560
- }
561
-
562
- /**
563
- * Generates data used for garbage collection. It does the following:
564
- * 1. Calls into each child data store context to get its GC data.
565
- * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be
566
- * identified as belonging to the child.
567
- * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent
568
- * the GC data of this channel.
569
- * @param fullGC - true to bypass optimizations and force full generation of GC data.
570
- */
571
- public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {
572
- const builder = new GCDataBuilder();
573
- // Iterate over each store and get their GC data.
574
- await Promise.all(Array.from(this.contexts)
575
- .filter(([_, context]) => {
576
- // Get GC data only for attached contexts. Detached contexts are not connected in the GC reference
577
- // graph so any references they might have won't be connected as well.
578
- return context.attachState === AttachState.Attached;
579
- }).map(async ([contextId, context]) => {
580
- const contextGCData = await context.getGCData(fullGC);
581
- // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
582
- // This also gradually builds the id of each node to be a path from the root.
583
- builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
584
- }));
585
-
586
- // Get the outbound routes and add a GC node for this channel.
587
- builder.addNode("/", await this.getOutboundRoutes());
588
- return builder.getGCData();
589
- }
590
-
591
- /**
592
- * After GC has run, called to notify this Container's data stores of routes that are used in it.
593
- * @param usedRoutes - The routes that are used in all data stores in this Container.
594
- * @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
595
- * unreferenced as part of this GC run, this should be used to update the time when it happens.
596
- */
597
- public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number) {
598
- // Get a map of data store ids to routes used in it.
599
- const usedDataStoreRoutes = unpackChildNodesUsedRoutes(usedRoutes);
600
-
601
- // Verify that the used routes are correct.
602
- for (const [id] of usedDataStoreRoutes) {
603
- assert(this.contexts.has(id), 0x167 /* "Used route does not belong to any known data store" */);
604
- }
605
-
606
- // Update the used routes in each data store. Used routes is empty for unused data stores.
607
- for (const [contextId, context] of this.contexts) {
608
- context.updateUsedRoutes(usedDataStoreRoutes.get(contextId) ?? [], gcTimestamp);
609
- }
610
- }
611
-
612
- /**
613
- * When running GC in test mode, this is called to delete objects whose routes are unused. This enables testing
614
- * scenarios with accessing deleted content.
615
- * @param unusedRoutes - The routes that are unused in all data stores in this Container.
616
- */
617
- public deleteUnusedRoutes(unusedRoutes: string[]) {
618
- for (const route of unusedRoutes) {
619
- const pathParts = route.split("/");
620
- // Delete data store only if its route (/datastoreId) is in unusedRoutes. We don't want to delete a data
621
- // store based on its DDS being unused.
622
- if (pathParts.length > 2) {
623
- continue;
624
- }
625
- const dataStoreId = pathParts[1];
626
- assert(this.contexts.has(dataStoreId), 0x2d7 /* No data store with specified id */);
627
- // Delete the contexts of unused data stores.
628
- this.contexts.delete(dataStoreId);
629
- // Delete the summarizer node of the unused data stores.
630
- this.deleteChildSummarizerNodeFn(dataStoreId);
631
- }
632
- }
633
-
634
- /**
635
- * Returns the outbound routes of this channel. Only root data stores are considered referenced and their paths are
636
- * part of outbound routes.
637
- */
638
- private async getOutboundRoutes(): Promise<string[]> {
639
- const outboundRoutes: string[] = [];
640
- for (const [contextId, context] of this.contexts) {
641
- const isRootDataStore = await context.isRoot();
642
- if (isRootDataStore) {
643
- outboundRoutes.push(`/${contextId}`);
644
- }
645
- }
646
- return outboundRoutes;
647
- }
648
-
649
- /**
650
- * Called by GC to retrieve the package path of a data store node with the given path.
651
- */
652
- public async getDataStorePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
653
- // If the node belongs to a data store, return its package path. For DDSes, we return the package path of the
654
- // data store that contains it.
655
- const context = this.contexts.get(nodePath.split("/")[1]);
656
- return (await context?.getInitialSnapshotDetails())?.pkg;
657
- }
658
-
659
- /**
660
- * Called by GC to determine if a node is for a data store or for an object within a data store (for e.g. DDS).
661
- * @returns the GC node type if the node belongs to a data store or object within data store, undefined otherwise.
662
- */
663
- public getGCNodeType(nodePath: string): GCNodeType | undefined {
664
- const pathParts = nodePath.split("/");
665
- if (!this.contexts.has(pathParts[1])) {
666
- return undefined;
667
- }
668
-
669
- // Data stores paths are of the format "/dataStoreId".
670
- // Sub data store paths are of the format "/dataStoreId/subPath/...".
671
- if (pathParts.length === 2) {
672
- return GCNodeType.DataStore;
673
- }
674
- return GCNodeType.SubDataStore;
675
- }
74
+ // Stores tracked by the Domain
75
+ private readonly pendingAttach = new Map<string, IAttachMessage>();
76
+ // 0.24 back-compat attachingBeforeSummary
77
+ public readonly attachOpFiredForDataStore = new Set<string>();
78
+
79
+ private readonly mc: MonitoringContext;
80
+
81
+ private readonly disposeOnce = new Lazy<void>(() => this.contexts.dispose());
82
+
83
+ public readonly containerLoadStats: {
84
+ // number of dataStores during loadContainer
85
+ readonly containerLoadDataStoreCount: number;
86
+ // number of unreferenced dataStores during loadContainer
87
+ readonly referencedDataStoreCount: number;
88
+ };
89
+
90
+ // Stores the ids of new data stores between two GC runs. This is used to notify the garbage collector of new
91
+ // root data stores that are added.
92
+ private dataStoresSinceLastGC: string[] = [];
93
+ // The handle to the container runtime. This is used mainly for GC purposes to represent outbound reference from
94
+ // the container runtime to other nodes.
95
+ private readonly containerRuntimeHandle: IFluidHandle;
96
+ private readonly pendingAliasMap: Map<string, Promise<AliasResult>> = new Map<
97
+ string,
98
+ Promise<AliasResult>
99
+ >();
100
+
101
+ constructor(
102
+ private readonly baseSnapshot: ISnapshotTree | undefined,
103
+ private readonly runtime: ContainerRuntime,
104
+ private readonly submitAttachFn: (attachContent: IAttachMessage) => void,
105
+ private readonly getCreateChildSummarizerNodeFn: (
106
+ id: string,
107
+ createParam: CreateChildSummarizerNodeParam,
108
+ ) => CreateChildSummarizerNodeFn,
109
+ private readonly deleteChildSummarizerNodeFn: (id: string) => void,
110
+ baseLogger: ITelemetryBaseLogger,
111
+ private readonly gcNodeUpdated: (
112
+ nodePath: string,
113
+ timestampMs: number,
114
+ packagePath?: readonly string[],
115
+ ) => void,
116
+ private readonly isDataStoreDeleted: (nodePath: string) => boolean,
117
+ private readonly aliasMap: Map<string, string>,
118
+ private readonly contexts: DataStoreContexts = new DataStoreContexts(baseLogger),
119
+ ) {
120
+ this.mc = createChildMonitoringContext({ logger: baseLogger });
121
+ this.containerRuntimeHandle = new FluidObjectHandle(
122
+ this.runtime,
123
+ "/",
124
+ this.runtime.IFluidHandleContext,
125
+ );
126
+
127
+ // Extract stores stored inside the snapshot
128
+ const fluidDataStores = new Map<string, ISnapshotTree>();
129
+ if (baseSnapshot) {
130
+ for (const [key, value] of Object.entries(baseSnapshot.trees)) {
131
+ fluidDataStores.set(key, value);
132
+ }
133
+ }
134
+
135
+ let unreferencedDataStoreCount = 0;
136
+ // Create a context for each of them
137
+ for (const [key, value] of fluidDataStores) {
138
+ let dataStoreContext: FluidDataStoreContext;
139
+
140
+ // counting number of unreferenced data stores
141
+ if (value.unreferenced) {
142
+ unreferencedDataStoreCount++;
143
+ }
144
+ // If we have a detached container, then create local data store contexts.
145
+ if (this.runtime.attachState !== AttachState.Detached) {
146
+ dataStoreContext = new RemoteFluidDataStoreContext({
147
+ id: key,
148
+ snapshotTree: value,
149
+ runtime: this.runtime,
150
+ storage: this.runtime.storage,
151
+ scope: this.runtime.scope,
152
+ createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(key, {
153
+ type: CreateSummarizerNodeSource.FromSummary,
154
+ }),
155
+ });
156
+ } else {
157
+ if (typeof value !== "object") {
158
+ throw new LoggingError("Snapshot should be there to load from!!");
159
+ }
160
+ const snapshotTree = value;
161
+ dataStoreContext = new LocalFluidDataStoreContext({
162
+ id: key,
163
+ pkg: undefined,
164
+ runtime: this.runtime,
165
+ storage: this.runtime.storage,
166
+ scope: this.runtime.scope,
167
+ createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(key, {
168
+ type: CreateSummarizerNodeSource.FromSummary,
169
+ }),
170
+ makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(key),
171
+ snapshotTree,
172
+ isRootDataStore: undefined,
173
+ });
174
+ }
175
+ this.contexts.addBoundOrRemoted(dataStoreContext);
176
+ }
177
+ this.containerLoadStats = {
178
+ containerLoadDataStoreCount: fluidDataStores.size,
179
+ referencedDataStoreCount: fluidDataStores.size - unreferencedDataStoreCount,
180
+ };
181
+ }
182
+
183
+ public get aliases(): ReadonlyMap<string, string> {
184
+ return this.aliasMap;
185
+ }
186
+
187
+ public get pendingAliases(): Map<string, Promise<AliasResult>> {
188
+ return this.pendingAliasMap;
189
+ }
190
+
191
+ public async waitIfPendingAlias(maybeAlias: string): Promise<AliasResult> {
192
+ const pendingAliasPromise = this.pendingAliases.get(maybeAlias);
193
+ return pendingAliasPromise ?? "Success";
194
+ }
195
+
196
+ public processAttachMessage(message: ISequencedDocumentMessage, local: boolean) {
197
+ const attachMessage = message.contents as InboundAttachMessage;
198
+
199
+ this.dataStoresSinceLastGC.push(attachMessage.id);
200
+
201
+ // The local object has already been attached
202
+ if (local) {
203
+ assert(
204
+ this.pendingAttach.has(attachMessage.id),
205
+ 0x15e /* "Local object does not have matching attach message id" */,
206
+ );
207
+ this.contexts.get(attachMessage.id)?.emit("attached");
208
+ this.pendingAttach.delete(attachMessage.id);
209
+ return;
210
+ }
211
+
212
+ // If a non-local operation then go and create the object, otherwise mark it as officially attached.
213
+ if (this.alreadyProcessed(attachMessage.id)) {
214
+ // TODO: dataStoreId may require a different tag from PackageData #7488
215
+ const error = new DataCorruptionError(
216
+ // pre-0.58 error message: duplicateDataStoreCreatedWithExistingId
217
+ "Duplicate DataStore created with existing id",
218
+ {
219
+ ...extractSafePropertiesFromMessage(message),
220
+ ...tagCodeArtifacts({ dataStoreId: attachMessage.id }),
221
+ },
222
+ );
223
+ throw error;
224
+ }
225
+
226
+ const flatAttachBlobs = new Map<string, ArrayBufferLike>();
227
+ let snapshotTree: ISnapshotTree | undefined;
228
+ if (attachMessage.snapshot) {
229
+ snapshotTree = buildSnapshotTree(attachMessage.snapshot.entries, flatAttachBlobs);
230
+ }
231
+
232
+ // Include the type of attach message which is the pkg of the store to be
233
+ // used by RemoteFluidDataStoreContext in case it is not in the snapshot.
234
+ const pkg = [attachMessage.type];
235
+ const remoteFluidDataStoreContext = new RemoteFluidDataStoreContext({
236
+ id: attachMessage.id,
237
+ snapshotTree,
238
+ runtime: this.runtime,
239
+ storage: new StorageServiceWithAttachBlobs(this.runtime.storage, flatAttachBlobs),
240
+ scope: this.runtime.scope,
241
+ createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(attachMessage.id, {
242
+ type: CreateSummarizerNodeSource.FromAttach,
243
+ sequenceNumber: message.sequenceNumber,
244
+ snapshot: attachMessage.snapshot ?? {
245
+ entries: [createAttributesBlob(pkg, true /* isRootDataStore */)],
246
+ },
247
+ }),
248
+ pkg,
249
+ });
250
+
251
+ this.contexts.addBoundOrRemoted(remoteFluidDataStoreContext);
252
+ }
253
+
254
+ public processAliasMessage(
255
+ message: ISequencedDocumentMessage,
256
+ localOpMetadata: unknown,
257
+ local: boolean,
258
+ ): void {
259
+ const aliasMessage = message.contents as IDataStoreAliasMessage;
260
+ if (!isDataStoreAliasMessage(aliasMessage)) {
261
+ throw new DataCorruptionError("malformedDataStoreAliasMessage", {
262
+ ...extractSafePropertiesFromMessage(message),
263
+ });
264
+ }
265
+
266
+ const resolve = localOpMetadata as PendingAliasResolve;
267
+ const aliasResult = this.processAliasMessageCore(aliasMessage);
268
+ if (local) {
269
+ resolve(aliasResult);
270
+ }
271
+ }
272
+
273
+ public processAliasMessageCore(aliasMessage: IDataStoreAliasMessage): boolean {
274
+ if (this.alreadyProcessed(aliasMessage.alias)) {
275
+ return false;
276
+ }
277
+
278
+ const context = this.contexts.get(aliasMessage.internalId);
279
+ // If the data store has been deleted, log an error and ignore this message. This helps prevent document
280
+ // corruption in case a deleted data store accidentally submitted a signal.
281
+ if (
282
+ this.checkAndLogIfDeleted(
283
+ aliasMessage.internalId,
284
+ context,
285
+ "Changed",
286
+ "processAliasMessageCore",
287
+ )
288
+ ) {
289
+ return false;
290
+ }
291
+
292
+ if (context === undefined) {
293
+ this.mc.logger.sendErrorEvent({
294
+ eventName: "AliasFluidDataStoreNotFound",
295
+ fluidDataStoreId: aliasMessage.internalId,
296
+ });
297
+ return false;
298
+ }
299
+
300
+ const handle = new FluidObjectHandle(
301
+ context,
302
+ aliasMessage.internalId,
303
+ this.runtime.IFluidHandleContext,
304
+ );
305
+ this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
306
+
307
+ this.aliasMap.set(aliasMessage.alias, context.id);
308
+ context.setInMemoryRoot();
309
+ return true;
310
+ }
311
+
312
+ private alreadyProcessed(id: string): boolean {
313
+ return this.aliasMap.get(id) !== undefined || this.contexts.get(id) !== undefined;
314
+ }
315
+
316
+ /**
317
+ * Make the data stores locally visible in the container graph by moving the data store context from unbound to
318
+ * bound list. This data store can now be reached from the root.
319
+ * @param id - The id of the data store context to make visible.
320
+ */
321
+ private makeDataStoreLocallyVisible(id: string): void {
322
+ const localContext = this.contexts.getUnbound(id);
323
+ assert(!!localContext, 0x15f /* "Could not find unbound context to bind" */);
324
+
325
+ /**
326
+ * If the container is not detached, it is globally visible to all clients. This data store should also be
327
+ * globally visible. Move it to attaching state and send an "attach" op for it.
328
+ * If the container is detached, this data store will be part of the summary that makes the container attached.
329
+ */
330
+ if (this.runtime.attachState !== AttachState.Detached) {
331
+ localContext.emit("attaching");
332
+ const message = localContext.generateAttachMessage();
333
+
334
+ this.pendingAttach.set(id, message);
335
+ this.submitAttachFn(message);
336
+ this.attachOpFiredForDataStore.add(id);
337
+ }
338
+
339
+ this.contexts.bind(id);
340
+ }
341
+
342
+ public createDetachedDataStoreCore(
343
+ pkg: Readonly<string[]>,
344
+ isRoot: boolean,
345
+ id = uuid(),
346
+ ): IFluidDataStoreContextDetached {
347
+ assert(!id.includes("/"), 0x30c /* Id cannot contain slashes */);
348
+
349
+ const context = new LocalDetachedFluidDataStoreContext({
350
+ id,
351
+ pkg,
352
+ runtime: this.runtime,
353
+ storage: this.runtime.storage,
354
+ scope: this.runtime.scope,
355
+ createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(id, {
356
+ type: CreateSummarizerNodeSource.Local,
357
+ }),
358
+ makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
359
+ snapshotTree: undefined,
360
+ isRootDataStore: isRoot,
361
+ });
362
+ this.contexts.addUnbound(context);
363
+ return context;
364
+ }
365
+
366
+ public _createFluidDataStoreContext(pkg: string[], id: string, props?: any) {
367
+ assert(!id.includes("/"), 0x30d /* Id cannot contain slashes */);
368
+ const context = new LocalFluidDataStoreContext({
369
+ id,
370
+ pkg,
371
+ runtime: this.runtime,
372
+ storage: this.runtime.storage,
373
+ scope: this.runtime.scope,
374
+ createSummarizerNodeFn: this.getCreateChildSummarizerNodeFn(id, {
375
+ type: CreateSummarizerNodeSource.Local,
376
+ }),
377
+ makeLocallyVisibleFn: () => this.makeDataStoreLocallyVisible(id),
378
+ snapshotTree: undefined,
379
+ isRootDataStore: false,
380
+ createProps: props,
381
+ });
382
+ this.contexts.addUnbound(context);
383
+ return context;
384
+ }
385
+
386
+ public get disposed() {
387
+ return this.disposeOnce.evaluated;
388
+ }
389
+ public readonly dispose = () => this.disposeOnce.value;
390
+
391
+ public resubmitDataStoreOp(envelope: IEnvelope, localOpMetadata: unknown) {
392
+ const context = this.contexts.get(envelope.address);
393
+ // If the data store has been deleted, log an error and throw an error. If there are local changes for a
394
+ // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
395
+ if (
396
+ this.checkAndLogIfDeleted(envelope.address, context, "Changed", "resubmitDataStoreOp")
397
+ ) {
398
+ throw new DataCorruptionError("Context is deleted!", {
399
+ callSite: "resubmitDataStoreOp",
400
+ ...tagCodeArtifacts({ id: envelope.address }),
401
+ });
402
+ }
403
+ assert(!!context, 0x160 /* "There should be a store context for the op" */);
404
+ context.reSubmit(envelope.contents, localOpMetadata);
405
+ }
406
+
407
+ public rollbackDataStoreOp(envelope: IEnvelope, localOpMetadata: unknown) {
408
+ const context = this.contexts.get(envelope.address);
409
+ // If the data store has been deleted, log an error and throw an error. If there are local changes for a
410
+ // deleted data store, it can otherwise lead to inconsistent state when compared to other clients.
411
+ if (
412
+ this.checkAndLogIfDeleted(envelope.address, context, "Changed", "rollbackDataStoreOp")
413
+ ) {
414
+ throw new DataCorruptionError("Context is deleted!", {
415
+ callSite: "rollbackDataStoreOp",
416
+ ...tagCodeArtifacts({ id: envelope.address }),
417
+ });
418
+ }
419
+ assert(!!context, 0x2e8 /* "There should be a store context for the op" */);
420
+ context.rollback(envelope.contents, localOpMetadata);
421
+ }
422
+
423
+ public async applyStashedOp(envelope: IEnvelope): Promise<unknown> {
424
+ const context = this.contexts.get(envelope.address);
425
+ // If the data store has been deleted, log an error and ignore this message. This helps prevent document
426
+ // corruption in case the data store that stashed the op is deleted.
427
+ if (this.checkAndLogIfDeleted(envelope.address, context, "Changed", "applyStashedOp")) {
428
+ return undefined;
429
+ }
430
+ assert(!!context, 0x161 /* "There should be a store context for the op" */);
431
+ return context.applyStashedOp(envelope.contents);
432
+ }
433
+
434
+ public async applyStashedAttachOp(message: IAttachMessage) {
435
+ this.pendingAttach.set(message.id, message);
436
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
437
+ this.processAttachMessage({ contents: message } as ISequencedDocumentMessage, false);
438
+ }
439
+
440
+ public processFluidDataStoreOp(
441
+ message: ISequencedDocumentMessage,
442
+ local: boolean,
443
+ localMessageMetadata: unknown,
444
+ ) {
445
+ const envelope = message.contents as IEnvelope;
446
+ const transformed = { ...message, contents: envelope.contents };
447
+ const context = this.contexts.get(envelope.address);
448
+
449
+ // If the data store has been deleted, log an error and ignore this message. This helps prevent document
450
+ // corruption in case a deleted data store accidentally submitted an op.
451
+ if (
452
+ this.checkAndLogIfDeleted(
453
+ envelope.address,
454
+ context,
455
+ "Changed",
456
+ "processFluidDataStoreOp",
457
+ )
458
+ ) {
459
+ return;
460
+ }
461
+
462
+ assert(!!context, 0x162 /* "There should be a store context for the op" */);
463
+ context.process(transformed, local, localMessageMetadata);
464
+
465
+ // Notify that a GC node for the data store changed. This is used to detect if a deleted data store is
466
+ // being used.
467
+ this.gcNodeUpdated(
468
+ `/${envelope.address}`,
469
+ message.timestamp,
470
+ context.isLoaded ? context.packagePath : undefined,
471
+ );
472
+ }
473
+
474
+ public async getDataStore(
475
+ id: string,
476
+ requestHeaderData: RuntimeHeaderData,
477
+ ): Promise<FluidDataStoreContext> {
478
+ const headerData = { ...defaultRuntimeHeaderData, ...requestHeaderData };
479
+ if (
480
+ this.checkAndLogIfDeleted(
481
+ id,
482
+ this.contexts.get(id),
483
+ "Requested",
484
+ "getDataStore",
485
+ requestHeaderData,
486
+ )
487
+ ) {
488
+ // The requested data store has been deleted by gc. Create a 404 response exception.
489
+ const request: IRequest = { url: id };
490
+ throw responseToException(
491
+ createResponseError(404, "DataStore was deleted", request),
492
+ request,
493
+ );
494
+ }
495
+
496
+ const context = await this.contexts.getBoundOrRemoted(id, headerData.wait);
497
+ if (context === undefined) {
498
+ // The requested data store does not exits. Throw a 404 response exception.
499
+ const request: IRequest = { url: id };
500
+ throw responseToException(create404Response(request), request);
501
+ }
502
+ return context;
503
+ }
504
+
505
+ /**
506
+ * Returns the data store requested with the given id if available. Otherwise, returns undefined.
507
+ */
508
+ public async getDataStoreIfAvailable(
509
+ id: string,
510
+ requestHeaderData: RuntimeHeaderData,
511
+ ): Promise<FluidDataStoreContext | undefined> {
512
+ // If the data store has been deleted, log an error and return undefined.
513
+ if (
514
+ this.checkAndLogIfDeleted(
515
+ id,
516
+ this.contexts.get(id),
517
+ "Requested",
518
+ "getDataStoreIfAvailable",
519
+ requestHeaderData,
520
+ )
521
+ ) {
522
+ return undefined;
523
+ }
524
+ const headerData = { ...defaultRuntimeHeaderData, ...requestHeaderData };
525
+ const context = await this.contexts.getBoundOrRemoted(id, headerData.wait);
526
+ if (context === undefined) {
527
+ return undefined;
528
+ }
529
+ return context;
530
+ }
531
+
532
+ /**
533
+ * Checks if the data store has been deleted by GC. If so, log an error.
534
+ * @param id - The data store's id.
535
+ * @param context - The data store context.
536
+ * @param callSite - The function name this is called from.
537
+ * @param requestHeaderData - The request header information to log if the data store is deleted.
538
+ * @returns true if the data store is deleted. Otherwise, returns false.
539
+ */
540
+ private checkAndLogIfDeleted(
541
+ id: string,
542
+ context: FluidDataStoreContext | undefined,
543
+ deletedLogSuffix: string,
544
+ callSite: string,
545
+ requestHeaderData?: RuntimeHeaderData,
546
+ ) {
547
+ const dataStoreNodePath = `/${id}`;
548
+ if (!this.isDataStoreDeleted(dataStoreNodePath)) {
549
+ return false;
550
+ }
551
+
552
+ this.mc.logger.sendErrorEvent({
553
+ eventName: `GC_Deleted_DataStore_${deletedLogSuffix}`,
554
+ ...tagCodeArtifacts({ id }),
555
+ callSite,
556
+ headers: JSON.stringify(requestHeaderData),
557
+ exists: context !== undefined,
558
+ });
559
+ return true;
560
+ }
561
+
562
+ public processSignal(fluidDataStoreId: string, message: IInboundSignalMessage, local: boolean) {
563
+ const context = this.contexts.get(fluidDataStoreId);
564
+ // If the data store has been deleted, log an error and ignore this message. This helps prevent document
565
+ // corruption in case a deleted data store accidentally submitted a signal.
566
+ if (this.checkAndLogIfDeleted(fluidDataStoreId, context, "Changed", "processSignal")) {
567
+ return;
568
+ }
569
+
570
+ if (!context) {
571
+ // Attach message may not have been processed yet
572
+ assert(!local, 0x163 /* "Missing datastore for local signal" */);
573
+ this.mc.logger.sendTelemetryEvent({
574
+ eventName: "SignalFluidDataStoreNotFound",
575
+ ...tagCodeArtifacts({
576
+ fluidDataStoreId,
577
+ }),
578
+ });
579
+ return;
580
+ }
581
+
582
+ context.processSignal(message, local);
583
+ }
584
+
585
+ public setConnectionState(connected: boolean, clientId?: string) {
586
+ for (const [fluidDataStoreId, context] of this.contexts) {
587
+ try {
588
+ context.setConnectionState(connected, clientId);
589
+ } catch (error) {
590
+ this.mc.logger.sendErrorEvent(
591
+ {
592
+ eventName: "SetConnectionStateError",
593
+ clientId,
594
+ ...tagCodeArtifacts({
595
+ fluidDataStoreId,
596
+ }),
597
+ details: JSON.stringify({
598
+ runtimeConnected: this.runtime.connected,
599
+ connected,
600
+ }),
601
+ },
602
+ error,
603
+ );
604
+ }
605
+ }
606
+ }
607
+
608
+ public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
609
+ const eventName = attachState === AttachState.Attaching ? "attaching" : "attached";
610
+ for (const [, context] of this.contexts) {
611
+ // Fire only for bounded stores.
612
+ if (!this.contexts.isNotBound(context.id)) {
613
+ context.emit(eventName);
614
+ }
615
+ }
616
+ }
617
+
618
+ public get size(): number {
619
+ return this.contexts.size;
620
+ }
621
+
622
+ public async summarize(
623
+ fullTree: boolean,
624
+ trackState: boolean,
625
+ telemetryContext?: ITelemetryContext,
626
+ ): Promise<ISummaryTreeWithStats> {
627
+ const summaryBuilder = new SummaryTreeBuilder();
628
+
629
+ // Iterate over each store and ask it to snapshot
630
+ await Promise.all(
631
+ Array.from(this.contexts)
632
+ .filter(([_, context]) => {
633
+ // Summarizer works only with clients with no local changes. A data store in attaching
634
+ // state indicates an op was sent to attach a local data store, and the the attach op
635
+ // had not yet round tripped back to the client.
636
+ if (context.attachState === AttachState.Attaching) {
637
+ // Formerly assert 0x588
638
+ const error = DataProcessingError.create(
639
+ "Local data store detected in attaching state during summarize",
640
+ "summarize",
641
+ );
642
+ throw error;
643
+ }
644
+ return context.attachState === AttachState.Attached;
645
+ })
646
+ .map(async ([contextId, context]) => {
647
+ const contextSummary = await context.summarize(
648
+ fullTree,
649
+ trackState,
650
+ telemetryContext,
651
+ );
652
+ summaryBuilder.addWithStats(contextId, contextSummary);
653
+ }),
654
+ );
655
+
656
+ return summaryBuilder.getSummaryTree();
657
+ }
658
+
659
+ public createSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats {
660
+ const builder = new SummaryTreeBuilder();
661
+ // Attaching graph of some stores can cause other stores to get bound too.
662
+ // So keep taking summary until no new stores get bound.
663
+ let notBoundContextsLength: number;
664
+ do {
665
+ const builderTree = builder.summary.tree;
666
+ notBoundContextsLength = this.contexts.notBoundLength();
667
+ // Iterate over each data store and ask it to snapshot
668
+ Array.from(this.contexts)
669
+ .filter(
670
+ ([key, _]) =>
671
+ // Take summary of bounded data stores only, make sure we haven't summarized them already
672
+ // and no attach op has been fired for that data store because for loader versions <= 0.24
673
+ // we set attach state as "attaching" before taking createNew summary.
674
+ !(
675
+ this.contexts.isNotBound(key) ||
676
+ builderTree[key] ||
677
+ this.attachOpFiredForDataStore.has(key)
678
+ ),
679
+ )
680
+ .map(([key, value]) => {
681
+ let dataStoreSummary: ISummarizeResult;
682
+ if (value.isLoaded) {
683
+ const snapshot = value.generateAttachMessage().snapshot;
684
+ dataStoreSummary = convertToSummaryTree(snapshot, true);
685
+ } else {
686
+ // If this data store is not yet loaded, then there should be no changes in the snapshot from
687
+ // which it was created as it is detached container. So just use the previous snapshot.
688
+ assert(
689
+ !!this.baseSnapshot,
690
+ 0x166 /* "BaseSnapshot should be there as detached container loaded from snapshot" */,
691
+ );
692
+ dataStoreSummary = convertSnapshotTreeToSummaryTree(
693
+ this.baseSnapshot.trees[key],
694
+ );
695
+ }
696
+ builder.addWithStats(key, dataStoreSummary);
697
+ });
698
+ } while (notBoundContextsLength !== this.contexts.notBoundLength());
699
+
700
+ return builder.getSummaryTree();
701
+ }
702
+
703
+ /**
704
+ * Before GC runs, called by the garbage collector to update any pending GC state.
705
+ * The garbage collector needs to know all outbound references that are added. Since root data stores are not
706
+ * explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
707
+ */
708
+ public async updateStateBeforeGC(): Promise<void> {
709
+ for (const id of this.dataStoresSinceLastGC) {
710
+ const context = this.contexts.get(id);
711
+ assert(context !== undefined, 0x2b6 /* Missing data store context */);
712
+ if (await context.isRoot()) {
713
+ // A root data store is basically a reference from the container runtime to the data store.
714
+ const handle = new FluidObjectHandle(context, id, this.runtime.IFluidHandleContext);
715
+ this.runtime.addedGCOutboundReference(this.containerRuntimeHandle, handle);
716
+ }
717
+ }
718
+ this.dataStoresSinceLastGC = [];
719
+ }
720
+
721
+ /**
722
+ * Generates data used for garbage collection. It does the following:
723
+ *
724
+ * 1. Calls into each child data store context to get its GC data.
725
+ *
726
+ * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be
727
+ * identified as belonging to the child.
728
+ *
729
+ * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent
730
+ * the GC data of this channel.
731
+ *
732
+ * @param fullGC - true to bypass optimizations and force full generation of GC data.
733
+ */
734
+ public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {
735
+ const builder = new GCDataBuilder();
736
+ // Iterate over each store and get their GC data.
737
+ await Promise.all(
738
+ Array.from(this.contexts)
739
+ .filter(([_, context]) => {
740
+ // Summarizer client and hence GC works only with clients with no local changes. A data store in
741
+ // attaching state indicates an op was sent to attach a local data store, and the the attach op
742
+ // had not yet round tripped back to the client.
743
+ // Formerly assert 0x589
744
+ if (context.attachState === AttachState.Attaching) {
745
+ const error = DataProcessingError.create(
746
+ "Local data store detected in attaching state while running GC",
747
+ "getGCData",
748
+ );
749
+ throw error;
750
+ }
751
+
752
+ return context.attachState === AttachState.Attached;
753
+ })
754
+ .map(async ([contextId, context]) => {
755
+ const contextGCData = await context.getGCData(fullGC);
756
+ // Prefix the child's id to the ids of its GC nodes so they can be identified as belonging to the child.
757
+ // This also gradually builds the id of each node to be a path from the root.
758
+ builder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
759
+ }),
760
+ );
761
+
762
+ // Get the outbound routes and add a GC node for this channel.
763
+ builder.addNode("/", await this.getOutboundRoutes());
764
+ return builder.getGCData();
765
+ }
766
+
767
+ /**
768
+ * After GC has run, called to notify this Container's data stores of routes that are used in it.
769
+ * @param usedRoutes - The routes that are used in all data stores in this Container.
770
+ */
771
+ public updateUsedRoutes(usedRoutes: readonly string[]) {
772
+ // Get a map of data store ids to routes used in it.
773
+ const usedDataStoreRoutes = unpackChildNodesUsedRoutes(usedRoutes);
774
+
775
+ // Verify that the used routes are correct.
776
+ for (const [id] of usedDataStoreRoutes) {
777
+ assert(
778
+ this.contexts.has(id),
779
+ 0x167 /* "Used route does not belong to any known data store" */,
780
+ );
781
+ }
782
+
783
+ // Update the used routes in each data store. Used routes is empty for unused data stores.
784
+ for (const [contextId, context] of this.contexts) {
785
+ context.updateUsedRoutes(usedDataStoreRoutes.get(contextId) ?? []);
786
+ }
787
+ }
788
+
789
+ /**
790
+ * This is called to update objects whose routes are unused. The unused objects are deleted.
791
+ * @param unusedRoutes - The routes that are unused in all data stores in this Container.
792
+ */
793
+ public updateUnusedRoutes(unusedRoutes: readonly string[]) {
794
+ for (const route of unusedRoutes) {
795
+ const pathParts = route.split("/");
796
+ // Delete data store only if its route (/datastoreId) is in unusedRoutes. We don't want to delete a data
797
+ // store based on its DDS being unused.
798
+ if (pathParts.length > 2) {
799
+ continue;
800
+ }
801
+ const dataStoreId = pathParts[1];
802
+ assert(this.contexts.has(dataStoreId), 0x2d7 /* No data store with specified id */);
803
+ // Delete the contexts of unused data stores.
804
+ this.contexts.delete(dataStoreId);
805
+ // Delete the summarizer node of the unused data stores.
806
+ this.deleteChildSummarizerNodeFn(dataStoreId);
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Delete data stores and its objects that are sweep ready.
812
+ * @param sweepReadyDataStoreRoutes - The routes of data stores and its objects that are sweep ready and should
813
+ * be deleted.
814
+ * @returns The routes of data stores and its objects that were deleted.
815
+ */
816
+ public deleteSweepReadyNodes(sweepReadyDataStoreRoutes: readonly string[]): readonly string[] {
817
+ // If sweep for data stores is not enabled, return empty list indicating nothing is deleted.
818
+ if (this.mc.config.getBoolean(disableDatastoreSweepKey) === true) {
819
+ return [];
820
+ }
821
+ for (const route of sweepReadyDataStoreRoutes) {
822
+ const pathParts = route.split("/");
823
+ const dataStoreId = pathParts[1];
824
+
825
+ // Ignore sub-data store routes because a data store and its sub-routes are deleted together, so, we only
826
+ // need to delete the data store.
827
+ if (pathParts.length > 2) {
828
+ continue;
829
+ }
830
+
831
+ const dataStoreContext = this.contexts.get(dataStoreId);
832
+ if (dataStoreContext === undefined) {
833
+ this.mc.logger.sendErrorEvent({
834
+ eventName: "DeletedDataStoreNotFound",
835
+ ...tagCodeArtifacts({ id: dataStoreId }),
836
+ details: {
837
+ alreadyDeleted: this.isDataStoreDeleted(dataStoreId),
838
+ },
839
+ });
840
+ continue;
841
+ }
842
+
843
+ dataStoreContext.delete();
844
+
845
+ // Delete the contexts of sweep ready data stores.
846
+ this.contexts.delete(dataStoreId);
847
+ // Delete the summarizer node of the sweep ready data stores.
848
+ this.deleteChildSummarizerNodeFn(dataStoreId);
849
+ }
850
+ return Array.from(sweepReadyDataStoreRoutes);
851
+ }
852
+
853
+ /**
854
+ * This is called to update objects whose routes are tombstones. Tombstoned datastore contexts enable testing
855
+ * scenarios with accessing deleted content without actually deleting content from summaries.
856
+ * @param tombstonedRoutes - The routes that are tombstones in all data stores in this Container.
857
+ */
858
+ public updateTombstonedRoutes(tombstonedRoutes: readonly string[]) {
859
+ const tombstonedDataStoresSet: Set<string> = new Set();
860
+ for (const route of tombstonedRoutes) {
861
+ const pathParts = route.split("/");
862
+ // Tombstone data store only if its route (/datastoreId) is directly in tombstoneRoutes.
863
+ if (pathParts.length > 2) {
864
+ continue;
865
+ }
866
+ const dataStoreId = pathParts[1];
867
+ assert(this.contexts.has(dataStoreId), 0x510 /* No data store with specified id */);
868
+ tombstonedDataStoresSet.add(dataStoreId);
869
+ }
870
+
871
+ // Update the used routes in each data store. Used routes is empty for unused data stores.
872
+ for (const [contextId, context] of this.contexts) {
873
+ context.setTombstone(tombstonedDataStoresSet.has(contextId));
874
+ }
875
+ }
876
+
877
+ /**
878
+ * Returns the outbound routes of this channel. Only root data stores are considered referenced and their paths are
879
+ * part of outbound routes.
880
+ */
881
+ private async getOutboundRoutes(): Promise<string[]> {
882
+ const outboundRoutes: string[] = [];
883
+ for (const [contextId, context] of this.contexts) {
884
+ const isRootDataStore = await context.isRoot();
885
+ if (isRootDataStore) {
886
+ outboundRoutes.push(`/${contextId}`);
887
+ }
888
+ }
889
+ return outboundRoutes;
890
+ }
891
+
892
+ /**
893
+ * Called by GC to retrieve the package path of a data store node with the given path.
894
+ */
895
+ public async getDataStorePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
896
+ // If the node belongs to a data store, return its package path. For DDSes, we return the package path of the
897
+ // data store that contains it.
898
+ const context = this.contexts.get(nodePath.split("/")[1]);
899
+ return (await context?.getInitialSnapshotDetails())?.pkg;
900
+ }
901
+
902
+ /**
903
+ * Called by GC to determine if a node is for a data store or for an object within a data store (for e.g. DDS).
904
+ * @returns the GC node type if the node belongs to a data store or object within data store, undefined otherwise.
905
+ */
906
+ public getGCNodeType(nodePath: string): GCNodeType | undefined {
907
+ const pathParts = nodePath.split("/");
908
+ if (!this.contexts.has(pathParts[1])) {
909
+ return undefined;
910
+ }
911
+
912
+ // Data stores paths are of the format "/dataStoreId".
913
+ // Sub data store paths are of the format "/dataStoreId/subPath/...".
914
+ if (pathParts.length === 2) {
915
+ return GCNodeType.DataStore;
916
+ }
917
+ return GCNodeType.SubDataStore;
918
+ }
676
919
  }
677
920
 
678
921
  export function getSummaryForDatastores(
679
- snapshot: ISnapshotTree | undefined,
680
- metadata?: IContainerRuntimeMetadata,
922
+ snapshot: ISnapshotTree | undefined,
923
+ metadata?: IContainerRuntimeMetadata,
681
924
  ): ISnapshotTree | undefined {
682
- if (!snapshot) {
683
- return undefined;
684
- }
685
-
686
- if (rootHasIsolatedChannels(metadata)) {
687
- const datastoresSnapshot = snapshot.trees[channelsTreeName];
688
- assert(!!datastoresSnapshot, 0x168 /* Expected tree in snapshot not found */);
689
- return datastoresSnapshot;
690
- } else {
691
- // back-compat: strip out all non-datastore paths before giving to DataStores object.
692
- const datastoresTrees: ISnapshotTree["trees"] = {};
693
- for (const [key, value] of Object.entries(snapshot.trees)) {
694
- if (!nonDataStorePaths.includes(key)) {
695
- datastoresTrees[key] = value;
696
- }
697
- }
698
- return {
699
- ...snapshot,
700
- trees: datastoresTrees,
701
- };
702
- }
925
+ if (!snapshot) {
926
+ return undefined;
927
+ }
928
+
929
+ if (rootHasIsolatedChannels(metadata)) {
930
+ const datastoresSnapshot = snapshot.trees[channelsTreeName];
931
+ assert(!!datastoresSnapshot, 0x168 /* Expected tree in snapshot not found */);
932
+ return datastoresSnapshot;
933
+ } else {
934
+ // back-compat: strip out all non-datastore paths before giving to DataStores object.
935
+ const datastoresTrees: ISnapshotTree["trees"] = {};
936
+ for (const [key, value] of Object.entries(snapshot.trees)) {
937
+ if (!nonDataStorePaths.includes(key)) {
938
+ datastoresTrees[key] = value;
939
+ }
940
+ }
941
+ return {
942
+ ...snapshot,
943
+ trees: datastoresTrees,
944
+ };
945
+ }
703
946
  }