@fluidframework/container-runtime 2.0.0-dev-rc.1.0.0.228517 → 2.0.0-dev-rc.2.0.0.245554

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 (695) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +5 -5
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +54 -0
  4. package/README.md +46 -1
  5. package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
  6. package/api-extractor-lint.json +1 -1
  7. package/api-extractor.json +1 -1
  8. package/api-report/container-runtime.api.md +435 -33
  9. package/dist/batchTracker.d.ts +1 -2
  10. package/dist/batchTracker.d.ts.map +1 -1
  11. package/dist/batchTracker.js.map +1 -1
  12. package/dist/blobManager.d.ts +0 -5
  13. package/dist/blobManager.d.ts.map +1 -1
  14. package/dist/blobManager.js +0 -12
  15. package/dist/blobManager.js.map +1 -1
  16. package/dist/channelCollection.d.ts +225 -0
  17. package/dist/channelCollection.d.ts.map +1 -0
  18. package/dist/{dataStores.js → channelCollection.js} +449 -143
  19. package/dist/channelCollection.js.map +1 -0
  20. package/dist/connectionTelemetry.d.ts +11 -1
  21. package/dist/connectionTelemetry.d.ts.map +1 -1
  22. package/dist/connectionTelemetry.js +42 -4
  23. package/dist/connectionTelemetry.js.map +1 -1
  24. package/dist/container-runtime-alpha.d.ts +138 -49
  25. package/dist/container-runtime-beta.d.ts +75 -9
  26. package/dist/container-runtime-public.d.ts +75 -9
  27. package/dist/container-runtime-untrimmed.d.ts +717 -49
  28. package/dist/containerHandleContext.d.ts +1 -1
  29. package/dist/containerHandleContext.d.ts.map +1 -1
  30. package/dist/containerHandleContext.js.map +1 -1
  31. package/dist/containerRuntime.d.ts +84 -64
  32. package/dist/containerRuntime.d.ts.map +1 -1
  33. package/dist/containerRuntime.js +550 -427
  34. package/dist/containerRuntime.js.map +1 -1
  35. package/dist/dataStore.d.ts +2 -3
  36. package/dist/dataStore.d.ts.map +1 -1
  37. package/dist/dataStore.js +12 -11
  38. package/dist/dataStore.js.map +1 -1
  39. package/dist/dataStoreContext.d.ts +118 -38
  40. package/dist/dataStoreContext.d.ts.map +1 -1
  41. package/dist/dataStoreContext.js +249 -161
  42. package/dist/dataStoreContext.js.map +1 -1
  43. package/dist/dataStoreContexts.d.ts +2 -1
  44. package/dist/dataStoreContexts.d.ts.map +1 -1
  45. package/dist/dataStoreContexts.js +1 -0
  46. package/dist/dataStoreContexts.js.map +1 -1
  47. package/dist/deltaManagerSummarizerProxy.d.ts +29 -4
  48. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  49. package/dist/deltaManagerSummarizerProxy.js +91 -5
  50. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  51. package/dist/gc/garbageCollection.d.ts +29 -7
  52. package/dist/gc/garbageCollection.d.ts.map +1 -1
  53. package/dist/gc/garbageCollection.js +179 -98
  54. package/dist/gc/garbageCollection.js.map +1 -1
  55. package/dist/gc/gcConfigs.d.ts +2 -2
  56. package/dist/gc/gcConfigs.d.ts.map +1 -1
  57. package/dist/gc/gcConfigs.js +30 -23
  58. package/dist/gc/gcConfigs.js.map +1 -1
  59. package/dist/gc/gcDefinitions.d.ts +40 -15
  60. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  61. package/dist/gc/gcDefinitions.js +11 -4
  62. package/dist/gc/gcDefinitions.js.map +1 -1
  63. package/dist/gc/gcHelpers.d.ts +2 -2
  64. package/dist/gc/gcHelpers.d.ts.map +1 -1
  65. package/dist/gc/gcHelpers.js.map +1 -1
  66. package/dist/gc/gcReferenceGraphAlgorithm.d.ts +1 -1
  67. package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -1
  68. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
  69. package/dist/gc/gcSummaryStateTracker.d.ts +12 -5
  70. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  71. package/dist/gc/gcSummaryStateTracker.js +18 -6
  72. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  73. package/dist/gc/gcTelemetry.d.ts +7 -7
  74. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  75. package/dist/gc/gcTelemetry.js +20 -20
  76. package/dist/gc/gcTelemetry.js.map +1 -1
  77. package/dist/gc/gcUnreferencedStateTracker.d.ts +6 -1
  78. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  79. package/dist/gc/gcUnreferencedStateTracker.js +22 -11
  80. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  81. package/dist/gc/index.d.ts +8 -8
  82. package/dist/gc/index.d.ts.map +1 -1
  83. package/dist/gc/index.js +40 -38
  84. package/dist/gc/index.js.map +1 -1
  85. package/dist/index.d.ts +11 -20
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +36 -40
  88. package/dist/index.js.map +1 -1
  89. package/dist/messageTypes.d.ts +4 -4
  90. package/dist/messageTypes.d.ts.map +1 -1
  91. package/dist/messageTypes.js.map +1 -1
  92. package/dist/opLifecycle/batchManager.d.ts +2 -2
  93. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  94. package/dist/opLifecycle/batchManager.js.map +1 -1
  95. package/dist/opLifecycle/definitions.d.ts +2 -2
  96. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  97. package/dist/opLifecycle/definitions.js.map +1 -1
  98. package/dist/opLifecycle/index.d.ts +8 -8
  99. package/dist/opLifecycle/index.d.ts.map +1 -1
  100. package/dist/opLifecycle/index.js +18 -18
  101. package/dist/opLifecycle/index.js.map +1 -1
  102. package/dist/opLifecycle/opCompressor.d.ts +1 -1
  103. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  104. package/dist/opLifecycle/opCompressor.js +4 -4
  105. package/dist/opLifecycle/opCompressor.js.map +1 -1
  106. package/dist/opLifecycle/opDecompressor.d.ts +1 -1
  107. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  108. package/dist/opLifecycle/opDecompressor.js +3 -3
  109. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  110. package/dist/opLifecycle/opGroupingManager.d.ts +1 -1
  111. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  112. package/dist/opLifecycle/opGroupingManager.js +1 -10
  113. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  114. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  115. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  116. package/dist/opLifecycle/opSplitter.js +5 -5
  117. package/dist/opLifecycle/opSplitter.js.map +1 -1
  118. package/dist/opLifecycle/outbox.d.ts +7 -7
  119. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  120. package/dist/opLifecycle/outbox.js +20 -12
  121. package/dist/opLifecycle/outbox.js.map +1 -1
  122. package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -4
  123. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  124. package/dist/opLifecycle/remoteMessageProcessor.js +2 -2
  125. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  126. package/dist/package.json +3 -0
  127. package/dist/packageVersion.d.ts +1 -1
  128. package/dist/packageVersion.js +1 -1
  129. package/dist/packageVersion.js.map +1 -1
  130. package/dist/pendingStateManager.d.ts +2 -1
  131. package/dist/pendingStateManager.d.ts.map +1 -1
  132. package/dist/pendingStateManager.js +18 -10
  133. package/dist/pendingStateManager.js.map +1 -1
  134. package/dist/scheduleManager.d.ts +1 -2
  135. package/dist/scheduleManager.d.ts.map +1 -1
  136. package/dist/scheduleManager.js +5 -5
  137. package/dist/scheduleManager.js.map +1 -1
  138. package/dist/summary/index.d.ts +12 -12
  139. package/dist/summary/index.d.ts.map +1 -1
  140. package/dist/summary/index.js +43 -43
  141. package/dist/summary/index.js.map +1 -1
  142. package/dist/summary/orderedClientElection.js +8 -8
  143. package/dist/summary/orderedClientElection.js.map +1 -1
  144. package/dist/summary/runWhileConnectedCoordinator.d.ts +1 -1
  145. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  146. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  147. package/dist/summary/runningSummarizer.d.ts +11 -10
  148. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  149. package/dist/summary/runningSummarizer.js +114 -81
  150. package/dist/summary/runningSummarizer.js.map +1 -1
  151. package/dist/summary/summarizer.d.ts +4 -4
  152. package/dist/summary/summarizer.d.ts.map +1 -1
  153. package/dist/summary/summarizer.js +6 -6
  154. package/dist/summary/summarizer.js.map +1 -1
  155. package/dist/summary/summarizerClientElection.d.ts +2 -2
  156. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  157. package/dist/summary/summarizerClientElection.js.map +1 -1
  158. package/dist/summary/summarizerHeuristics.d.ts +3 -3
  159. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  160. package/dist/summary/summarizerHeuristics.js.map +1 -1
  161. package/dist/summary/summarizerNode/index.d.ts +3 -3
  162. package/dist/summary/summarizerNode/index.d.ts.map +1 -1
  163. package/dist/summary/summarizerNode/index.js +4 -4
  164. package/dist/summary/summarizerNode/index.js.map +1 -1
  165. package/dist/summary/summarizerNode/summarizerNode.d.ts +17 -7
  166. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  167. package/dist/summary/summarizerNode/summarizerNode.js +45 -57
  168. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  169. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +10 -19
  170. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  171. package/dist/summary/summarizerNode/summarizerNodeUtils.js +1 -21
  172. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  173. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +5 -6
  174. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  175. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +16 -16
  176. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  177. package/dist/summary/summarizerTypes.d.ts +10 -21
  178. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  179. package/dist/summary/summarizerTypes.js.map +1 -1
  180. package/dist/summary/summaryFormat.d.ts +15 -2
  181. package/dist/summary/summaryFormat.d.ts.map +1 -1
  182. package/dist/summary/summaryFormat.js.map +1 -1
  183. package/dist/summary/summaryGenerator.d.ts +6 -5
  184. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  185. package/dist/summary/summaryGenerator.js +10 -1
  186. package/dist/summary/summaryGenerator.js.map +1 -1
  187. package/dist/summary/summaryManager.d.ts +5 -6
  188. package/dist/summary/summaryManager.d.ts.map +1 -1
  189. package/dist/summary/summaryManager.js +4 -5
  190. package/dist/summary/summaryManager.js.map +1 -1
  191. package/dist/tsdoc-metadata.json +1 -1
  192. package/lib/{batchTracker.d.mts → batchTracker.d.ts} +2 -3
  193. package/lib/batchTracker.d.ts.map +1 -0
  194. package/lib/{batchTracker.mjs → batchTracker.js} +1 -1
  195. package/lib/batchTracker.js.map +1 -0
  196. package/lib/{blobManager.d.mts → blobManager.d.ts} +1 -6
  197. package/lib/blobManager.d.ts.map +1 -0
  198. package/lib/{blobManager.mjs → blobManager.js} +1 -13
  199. package/lib/blobManager.js.map +1 -0
  200. package/lib/channelCollection.d.ts +225 -0
  201. package/lib/channelCollection.d.ts.map +1 -0
  202. package/lib/{dataStores.mjs → channelCollection.js} +436 -133
  203. package/lib/channelCollection.js.map +1 -0
  204. package/lib/{connectionTelemetry.d.mts → connectionTelemetry.d.ts} +12 -2
  205. package/lib/connectionTelemetry.d.ts.map +1 -0
  206. package/lib/{connectionTelemetry.mjs → connectionTelemetry.js} +43 -5
  207. package/lib/connectionTelemetry.js.map +1 -0
  208. package/lib/{container-runtime-alpha.d.mts → container-runtime-alpha.d.ts} +138 -49
  209. package/lib/{container-runtime-beta.d.mts → container-runtime-beta.d.ts} +75 -9
  210. package/lib/{container-runtime-public.d.mts → container-runtime-public.d.ts} +75 -9
  211. package/lib/{container-runtime-untrimmed.d.mts → container-runtime-untrimmed.d.ts} +717 -49
  212. package/lib/{containerHandleContext.d.mts → containerHandleContext.d.ts} +2 -2
  213. package/lib/containerHandleContext.d.ts.map +1 -0
  214. package/lib/{containerHandleContext.mjs → containerHandleContext.js} +1 -1
  215. package/lib/containerHandleContext.js.map +1 -0
  216. package/lib/{containerRuntime.d.mts → containerRuntime.d.ts} +89 -65
  217. package/lib/containerRuntime.d.ts.map +1 -0
  218. package/lib/{containerRuntime.mjs → containerRuntime.js} +469 -348
  219. package/lib/containerRuntime.js.map +1 -0
  220. package/lib/{dataStore.d.mts → dataStore.d.ts} +3 -4
  221. package/lib/dataStore.d.ts.map +1 -0
  222. package/lib/{dataStore.mjs → dataStore.js} +13 -12
  223. package/lib/dataStore.js.map +1 -0
  224. package/lib/{dataStoreContext.d.mts → dataStoreContext.d.ts} +119 -39
  225. package/lib/dataStoreContext.d.ts.map +1 -0
  226. package/lib/{dataStoreContext.mjs → dataStoreContext.js} +241 -153
  227. package/lib/dataStoreContext.js.map +1 -0
  228. package/lib/{dataStoreContexts.d.mts → dataStoreContexts.d.ts} +3 -2
  229. package/lib/dataStoreContexts.d.ts.map +1 -0
  230. package/lib/{dataStoreContexts.mjs → dataStoreContexts.js} +2 -1
  231. package/lib/dataStoreContexts.js.map +1 -0
  232. package/lib/{dataStoreRegistry.d.mts → dataStoreRegistry.d.ts} +1 -1
  233. package/lib/dataStoreRegistry.d.ts.map +1 -0
  234. package/lib/{dataStoreRegistry.mjs → dataStoreRegistry.js} +5 -1
  235. package/lib/dataStoreRegistry.js.map +1 -0
  236. package/{dist/deltaManagerProxyBase.d.ts → lib/deltaManagerSummarizerProxy.d.ts} +16 -7
  237. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
  238. package/lib/deltaManagerSummarizerProxy.js +124 -0
  239. package/lib/deltaManagerSummarizerProxy.js.map +1 -0
  240. package/lib/{deltaScheduler.d.mts → deltaScheduler.d.ts} +1 -1
  241. package/lib/deltaScheduler.d.ts.map +1 -0
  242. package/lib/{deltaScheduler.mjs → deltaScheduler.js} +1 -1
  243. package/lib/deltaScheduler.js.map +1 -0
  244. package/lib/{error.d.mts → error.d.ts} +1 -1
  245. package/lib/error.d.ts.map +1 -0
  246. package/lib/{error.mjs → error.js} +1 -1
  247. package/lib/error.js.map +1 -0
  248. package/lib/gc/{garbageCollection.d.mts → garbageCollection.d.ts} +30 -8
  249. package/lib/gc/garbageCollection.d.ts.map +1 -0
  250. package/lib/gc/{garbageCollection.mjs → garbageCollection.js} +149 -68
  251. package/lib/gc/garbageCollection.js.map +1 -0
  252. package/lib/gc/{gcConfigs.d.mts → gcConfigs.d.ts} +3 -3
  253. package/lib/gc/gcConfigs.d.ts.map +1 -0
  254. package/lib/gc/{gcConfigs.mjs → gcConfigs.js} +14 -7
  255. package/lib/gc/gcConfigs.js.map +1 -0
  256. package/lib/gc/{gcDefinitions.d.mts → gcDefinitions.d.ts} +41 -16
  257. package/lib/gc/gcDefinitions.d.ts.map +1 -0
  258. package/lib/gc/{gcDefinitions.mjs → gcDefinitions.js} +11 -4
  259. package/lib/gc/gcDefinitions.js.map +1 -0
  260. package/lib/gc/{gcHelpers.d.mts → gcHelpers.d.ts} +3 -3
  261. package/lib/gc/{gcHelpers.d.mts.map → gcHelpers.d.ts.map} +1 -1
  262. package/lib/gc/{gcHelpers.mjs → gcHelpers.js} +1 -1
  263. package/lib/gc/gcHelpers.js.map +1 -0
  264. package/lib/gc/{gcReferenceGraphAlgorithm.d.mts → gcReferenceGraphAlgorithm.d.ts} +2 -2
  265. package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
  266. package/lib/gc/{gcReferenceGraphAlgorithm.mjs → gcReferenceGraphAlgorithm.js} +1 -1
  267. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
  268. package/lib/gc/{gcSummaryDefinitions.d.mts → gcSummaryDefinitions.d.ts} +1 -1
  269. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
  270. package/lib/gc/{gcSummaryDefinitions.mjs → gcSummaryDefinitions.js} +1 -1
  271. package/lib/gc/gcSummaryDefinitions.js.map +1 -0
  272. package/lib/gc/{gcSummaryStateTracker.d.mts → gcSummaryStateTracker.d.ts} +13 -6
  273. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
  274. package/lib/gc/{gcSummaryStateTracker.mjs → gcSummaryStateTracker.js} +17 -5
  275. package/lib/gc/gcSummaryStateTracker.js.map +1 -0
  276. package/lib/gc/{gcTelemetry.d.mts → gcTelemetry.d.ts} +8 -8
  277. package/lib/gc/gcTelemetry.d.ts.map +1 -0
  278. package/lib/gc/{gcTelemetry.mjs → gcTelemetry.js} +5 -5
  279. package/lib/gc/gcTelemetry.js.map +1 -0
  280. package/lib/gc/{gcUnreferencedStateTracker.d.mts → gcUnreferencedStateTracker.d.ts} +7 -2
  281. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
  282. package/lib/gc/{gcUnreferencedStateTracker.mjs → gcUnreferencedStateTracker.js} +12 -2
  283. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
  284. package/lib/gc/index.d.ts +13 -0
  285. package/lib/gc/index.d.ts.map +1 -0
  286. package/lib/gc/{index.mjs → index.js} +8 -8
  287. package/lib/gc/index.js.map +1 -0
  288. package/lib/{index.d.mts → index.d.ts} +12 -21
  289. package/lib/index.d.ts.map +1 -0
  290. package/lib/index.js +15 -0
  291. package/lib/index.js.map +1 -0
  292. package/lib/{messageTypes.d.mts → messageTypes.d.ts} +5 -5
  293. package/lib/messageTypes.d.ts.map +1 -0
  294. package/lib/{messageTypes.mjs → messageTypes.js} +1 -1
  295. package/lib/messageTypes.js.map +1 -0
  296. package/lib/{metadata.d.mts → metadata.d.ts} +1 -1
  297. package/lib/metadata.d.ts.map +1 -0
  298. package/lib/{metadata.mjs → metadata.js} +1 -1
  299. package/lib/metadata.js.map +1 -0
  300. package/lib/opLifecycle/{batchManager.d.mts → batchManager.d.ts} +3 -3
  301. package/lib/opLifecycle/batchManager.d.ts.map +1 -0
  302. package/lib/opLifecycle/{batchManager.mjs → batchManager.js} +1 -1
  303. package/lib/opLifecycle/batchManager.js.map +1 -0
  304. package/lib/opLifecycle/{definitions.d.mts → definitions.d.ts} +3 -3
  305. package/lib/opLifecycle/definitions.d.ts.map +1 -0
  306. package/lib/opLifecycle/{definitions.mjs → definitions.js} +1 -1
  307. package/lib/opLifecycle/definitions.js.map +1 -0
  308. package/lib/opLifecycle/index.d.ts +13 -0
  309. package/lib/opLifecycle/index.d.ts.map +1 -0
  310. package/lib/opLifecycle/index.js +12 -0
  311. package/lib/opLifecycle/index.js.map +1 -0
  312. package/lib/opLifecycle/{opCompressor.d.mts → opCompressor.d.ts} +2 -2
  313. package/lib/opLifecycle/opCompressor.d.ts.map +1 -0
  314. package/lib/opLifecycle/{opCompressor.mjs → opCompressor.js} +3 -3
  315. package/lib/opLifecycle/opCompressor.js.map +1 -0
  316. package/lib/opLifecycle/{opDecompressor.d.mts → opDecompressor.d.ts} +2 -2
  317. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -0
  318. package/lib/opLifecycle/{opDecompressor.mjs → opDecompressor.js} +2 -2
  319. package/lib/opLifecycle/opDecompressor.js.map +1 -0
  320. package/lib/opLifecycle/{opGroupingManager.d.mts → opGroupingManager.d.ts} +2 -2
  321. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
  322. package/lib/opLifecycle/{opGroupingManager.mjs → opGroupingManager.js} +2 -11
  323. package/lib/opLifecycle/opGroupingManager.js.map +1 -0
  324. package/lib/opLifecycle/{opSplitter.d.mts → opSplitter.d.ts} +2 -2
  325. package/lib/opLifecycle/opSplitter.d.ts.map +1 -0
  326. package/lib/opLifecycle/{opSplitter.mjs → opSplitter.js} +3 -3
  327. package/lib/opLifecycle/opSplitter.js.map +1 -0
  328. package/lib/opLifecycle/{outbox.d.mts → outbox.d.ts} +8 -8
  329. package/lib/opLifecycle/outbox.d.ts.map +1 -0
  330. package/lib/opLifecycle/{outbox.mjs → outbox.js} +12 -4
  331. package/lib/opLifecycle/outbox.js.map +1 -0
  332. package/lib/opLifecycle/{remoteMessageProcessor.d.mts → remoteMessageProcessor.d.ts} +5 -5
  333. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -0
  334. package/lib/opLifecycle/{remoteMessageProcessor.mjs → remoteMessageProcessor.js} +2 -2
  335. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -0
  336. package/lib/{opProperties.d.mts → opProperties.d.ts} +1 -1
  337. package/lib/opProperties.d.ts.map +1 -0
  338. package/lib/{opProperties.mjs → opProperties.js} +1 -1
  339. package/lib/opProperties.js.map +1 -0
  340. package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
  341. package/lib/packageVersion.d.ts.map +1 -0
  342. package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
  343. package/lib/packageVersion.js.map +1 -0
  344. package/lib/{pendingStateManager.d.mts → pendingStateManager.d.ts} +3 -2
  345. package/lib/pendingStateManager.d.ts.map +1 -0
  346. package/lib/{pendingStateManager.mjs → pendingStateManager.js} +18 -10
  347. package/lib/pendingStateManager.js.map +1 -0
  348. package/lib/{scheduleManager.d.mts → scheduleManager.d.ts} +6 -3
  349. package/lib/scheduleManager.d.ts.map +1 -0
  350. package/lib/{scheduleManager.mjs → scheduleManager.js} +3 -3
  351. package/lib/scheduleManager.js.map +1 -0
  352. package/lib/{storageServiceWithAttachBlobs.d.mts → storageServiceWithAttachBlobs.d.ts} +1 -1
  353. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
  354. package/lib/{storageServiceWithAttachBlobs.mjs → storageServiceWithAttachBlobs.js} +1 -1
  355. package/lib/storageServiceWithAttachBlobs.js.map +1 -0
  356. package/lib/summary/{index.d.mts → index.d.ts} +13 -13
  357. package/lib/summary/index.d.ts.map +1 -0
  358. package/lib/summary/{index.mjs → index.js} +12 -12
  359. package/lib/summary/index.js.map +1 -0
  360. package/lib/summary/{orderedClientElection.d.mts → orderedClientElection.d.ts} +5 -1
  361. package/lib/summary/orderedClientElection.d.ts.map +1 -0
  362. package/lib/summary/{orderedClientElection.mjs → orderedClientElection.js} +2 -2
  363. package/lib/summary/orderedClientElection.js.map +1 -0
  364. package/lib/summary/{runWhileConnectedCoordinator.d.mts → runWhileConnectedCoordinator.d.ts} +2 -2
  365. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
  366. package/lib/summary/{runWhileConnectedCoordinator.mjs → runWhileConnectedCoordinator.js} +1 -1
  367. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
  368. package/lib/summary/{runningSummarizer.d.mts → runningSummarizer.d.ts} +12 -11
  369. package/lib/summary/runningSummarizer.d.ts.map +1 -0
  370. package/lib/summary/{runningSummarizer.mjs → runningSummarizer.js} +108 -75
  371. package/lib/summary/runningSummarizer.js.map +1 -0
  372. package/lib/summary/{summarizer.d.mts → summarizer.d.ts} +5 -5
  373. package/lib/summary/summarizer.d.ts.map +1 -0
  374. package/lib/summary/{summarizer.mjs → summarizer.js} +4 -4
  375. package/lib/summary/summarizer.js.map +1 -0
  376. package/lib/summary/{summarizerClientElection.d.mts → summarizerClientElection.d.ts} +3 -3
  377. package/lib/summary/summarizerClientElection.d.ts.map +1 -0
  378. package/lib/summary/{summarizerClientElection.mjs → summarizerClientElection.js} +1 -1
  379. package/lib/summary/summarizerClientElection.js.map +1 -0
  380. package/lib/summary/{summarizerHeuristics.d.mts → summarizerHeuristics.d.ts} +4 -4
  381. package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
  382. package/lib/summary/{summarizerHeuristics.mjs → summarizerHeuristics.js} +1 -1
  383. package/lib/summary/summarizerHeuristics.js.map +1 -0
  384. package/lib/summary/summarizerNode/{index.d.mts → index.d.ts} +4 -4
  385. package/lib/summary/summarizerNode/index.d.ts.map +1 -0
  386. package/lib/summary/summarizerNode/index.js +7 -0
  387. package/lib/summary/summarizerNode/index.js.map +1 -0
  388. package/lib/summary/summarizerNode/{summarizerNode.d.mts → summarizerNode.d.ts} +18 -8
  389. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
  390. package/lib/summary/summarizerNode/{summarizerNode.mjs → summarizerNode.js} +41 -53
  391. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
  392. package/lib/summary/summarizerNode/{summarizerNodeUtils.d.mts → summarizerNodeUtils.d.ts} +11 -20
  393. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
  394. package/lib/summary/summarizerNode/{summarizerNodeUtils.mjs → summarizerNodeUtils.js} +1 -20
  395. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
  396. package/lib/summary/summarizerNode/{summarizerNodeWithGc.d.mts → summarizerNodeWithGc.d.ts} +6 -7
  397. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
  398. package/lib/summary/summarizerNode/{summarizerNodeWithGc.mjs → summarizerNodeWithGc.js} +12 -12
  399. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
  400. package/lib/summary/{summarizerTypes.d.mts → summarizerTypes.d.ts} +11 -22
  401. package/lib/summary/summarizerTypes.d.ts.map +1 -0
  402. package/lib/summary/{summarizerTypes.mjs → summarizerTypes.js} +1 -1
  403. package/lib/summary/summarizerTypes.js.map +1 -0
  404. package/lib/summary/{summaryCollection.d.mts → summaryCollection.d.ts} +1 -1
  405. package/lib/summary/summaryCollection.d.ts.map +1 -0
  406. package/lib/summary/{summaryCollection.mjs → summaryCollection.js} +1 -1
  407. package/lib/summary/summaryCollection.js.map +1 -0
  408. package/lib/summary/{summaryFormat.d.mts → summaryFormat.d.ts} +16 -3
  409. package/lib/summary/summaryFormat.d.ts.map +1 -0
  410. package/lib/summary/{summaryFormat.mjs → summaryFormat.js} +1 -1
  411. package/lib/summary/summaryFormat.js.map +1 -0
  412. package/lib/summary/{summaryGenerator.d.mts → summaryGenerator.d.ts} +7 -6
  413. package/lib/summary/summaryGenerator.d.ts.map +1 -0
  414. package/lib/summary/{summaryGenerator.mjs → summaryGenerator.js} +11 -2
  415. package/lib/summary/summaryGenerator.js.map +1 -0
  416. package/lib/summary/{summaryManager.d.mts → summaryManager.d.ts} +6 -7
  417. package/lib/summary/summaryManager.d.ts.map +1 -0
  418. package/lib/summary/{summaryManager.mjs → summaryManager.js} +4 -5
  419. package/lib/summary/summaryManager.js.map +1 -0
  420. package/lib/test/batchTracker.spec.js +88 -0
  421. package/lib/test/batchTracker.spec.js.map +1 -0
  422. package/lib/test/blobManager.spec.js +835 -0
  423. package/lib/test/blobManager.spec.js.map +1 -0
  424. package/lib/test/channelCollection.spec.js +138 -0
  425. package/lib/test/channelCollection.spec.js.map +1 -0
  426. package/lib/test/containerRuntime.spec.js +1748 -0
  427. package/lib/test/containerRuntime.spec.js.map +1 -0
  428. package/lib/test/dataStoreContext.spec.js +771 -0
  429. package/lib/test/dataStoreContext.spec.js.map +1 -0
  430. package/lib/test/dataStoreCreation.spec.js +303 -0
  431. package/lib/test/dataStoreCreation.spec.js.map +1 -0
  432. package/lib/test/dataStoreRegistry.spec.js +26 -0
  433. package/lib/test/dataStoreRegistry.spec.js.map +1 -0
  434. package/lib/test/fuzz/fuzzUtils.js +66 -0
  435. package/lib/test/fuzz/fuzzUtils.js.map +1 -0
  436. package/lib/test/fuzz/summarizer.fuzz.spec.js +31 -0
  437. package/lib/test/fuzz/summarizer.fuzz.spec.js.map +1 -0
  438. package/lib/test/fuzz/summarizerFuzzMocks.js +162 -0
  439. package/lib/test/fuzz/summarizerFuzzMocks.js.map +1 -0
  440. package/lib/test/fuzz/summarizerFuzzSuite.js +106 -0
  441. package/lib/test/fuzz/summarizerFuzzSuite.js.map +1 -0
  442. package/lib/test/gc/garbageCollection.spec.js +1464 -0
  443. package/lib/test/gc/garbageCollection.spec.js.map +1 -0
  444. package/lib/test/gc/gcConfigs.spec.js +689 -0
  445. package/lib/test/gc/gcConfigs.spec.js.map +1 -0
  446. package/lib/test/gc/gcHelpers.spec.js +110 -0
  447. package/lib/test/gc/gcHelpers.spec.js.map +1 -0
  448. package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js +68 -0
  449. package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js.map +1 -0
  450. package/lib/test/gc/gcStats.spec.js +390 -0
  451. package/lib/test/gc/gcStats.spec.js.map +1 -0
  452. package/lib/test/gc/gcSummaryStateTracker.spec.js +228 -0
  453. package/lib/test/gc/gcSummaryStateTracker.spec.js.map +1 -0
  454. package/lib/test/gc/gcTelemetry.spec.js +530 -0
  455. package/lib/test/gc/gcTelemetry.spec.js.map +1 -0
  456. package/lib/test/gc/gcUnitTestHelpers.js +29 -0
  457. package/lib/test/gc/gcUnitTestHelpers.js.map +1 -0
  458. package/lib/test/gc/gcUnreferencedStateTracker.spec.js +192 -0
  459. package/lib/test/gc/gcUnreferencedStateTracker.spec.js.map +1 -0
  460. package/lib/test/getPendingBlobs.spec.js +193 -0
  461. package/lib/test/getPendingBlobs.spec.js.map +1 -0
  462. package/lib/test/hardwareStats.spec.js +93 -0
  463. package/lib/test/hardwareStats.spec.js.map +1 -0
  464. package/lib/test/index.js +6 -0
  465. package/lib/test/index.js.map +1 -0
  466. package/lib/test/opLifecycle/OpGroupingManager.spec.js +225 -0
  467. package/lib/test/opLifecycle/OpGroupingManager.spec.js.map +1 -0
  468. package/lib/test/opLifecycle/batchManager.spec.js +189 -0
  469. package/lib/test/opLifecycle/batchManager.spec.js.map +1 -0
  470. package/lib/test/opLifecycle/opCompressor.spec.js +74 -0
  471. package/lib/test/opLifecycle/opCompressor.spec.js.map +1 -0
  472. package/lib/test/opLifecycle/opDecompressor.spec.js +218 -0
  473. package/lib/test/opLifecycle/opDecompressor.spec.js.map +1 -0
  474. package/lib/test/opLifecycle/opSplitter.spec.js +272 -0
  475. package/lib/test/opLifecycle/opSplitter.spec.js.map +1 -0
  476. package/lib/test/opLifecycle/outbox.spec.js +675 -0
  477. package/lib/test/opLifecycle/outbox.spec.js.map +1 -0
  478. package/lib/test/opLifecycle/remoteMessageProcessor.spec.js +196 -0
  479. package/lib/test/opLifecycle/remoteMessageProcessor.spec.js.map +1 -0
  480. package/lib/test/pendingStateManager.spec.js +329 -0
  481. package/lib/test/pendingStateManager.spec.js.map +1 -0
  482. package/lib/test/scheduleManager.spec.js +270 -0
  483. package/lib/test/scheduleManager.spec.js.map +1 -0
  484. package/lib/test/summarizerNode.spec.js +326 -0
  485. package/lib/test/summarizerNode.spec.js.map +1 -0
  486. package/lib/test/summarizerNodeWithGc.spec.js +318 -0
  487. package/lib/test/summarizerNodeWithGc.spec.js.map +1 -0
  488. package/lib/test/summary/orderedClientElection.spec.js +535 -0
  489. package/lib/test/summary/orderedClientElection.spec.js.map +1 -0
  490. package/lib/test/summary/runningSummarizer.spec.js +1349 -0
  491. package/lib/test/summary/runningSummarizer.spec.js.map +1 -0
  492. package/lib/test/summary/summarizer.spec.js +29 -0
  493. package/lib/test/summary/summarizer.spec.js.map +1 -0
  494. package/lib/test/summary/summarizerClientElection.spec.js +436 -0
  495. package/lib/test/summary/summarizerClientElection.spec.js.map +1 -0
  496. package/lib/test/summary/summarizerHeuristics.spec.js +289 -0
  497. package/lib/test/summary/summarizerHeuristics.spec.js.map +1 -0
  498. package/lib/test/summary/summaryCollection.spec.js +200 -0
  499. package/lib/test/summary/summaryCollection.spec.js.map +1 -0
  500. package/lib/test/summary/summaryManager.spec.js +430 -0
  501. package/lib/test/summary/summaryManager.spec.js.map +1 -0
  502. package/lib/test/summary/testQuorumClients.js +34 -0
  503. package/lib/test/summary/testQuorumClients.js.map +1 -0
  504. package/lib/test/throttler.spec.js +175 -0
  505. package/lib/test/throttler.spec.js.map +1 -0
  506. package/lib/test/types/validateContainerRuntimePrevious.generated.js +180 -0
  507. package/lib/test/types/validateContainerRuntimePrevious.generated.js.map +1 -0
  508. package/lib/{throttler.d.mts → throttler.d.ts} +1 -1
  509. package/lib/throttler.d.ts.map +1 -0
  510. package/lib/{throttler.mjs → throttler.js} +1 -1
  511. package/lib/throttler.js.map +1 -0
  512. package/package.json +106 -87
  513. package/src/batchTracker.ts +1 -1
  514. package/src/blobManager.ts +1 -15
  515. package/src/{dataStores.ts → channelCollection.ts} +622 -170
  516. package/src/connectionTelemetry.ts +42 -3
  517. package/src/containerHandleContext.ts +1 -1
  518. package/src/containerRuntime.ts +683 -483
  519. package/src/dataStore.ts +16 -15
  520. package/src/dataStoreContext.ts +378 -216
  521. package/src/dataStoreContexts.ts +2 -1
  522. package/src/deltaManagerSummarizerProxy.ts +132 -7
  523. package/src/gc/garbageCollection.ts +167 -71
  524. package/src/gc/gcConfigs.ts +17 -7
  525. package/src/gc/gcDefinitions.ts +42 -16
  526. package/src/gc/gcHelpers.ts +2 -2
  527. package/src/gc/gcReferenceGraphAlgorithm.ts +1 -1
  528. package/src/gc/gcSummaryStateTracker.ts +19 -7
  529. package/src/gc/gcTelemetry.ts +10 -9
  530. package/src/gc/gcUnreferencedStateTracker.ts +12 -1
  531. package/src/gc/index.ts +11 -9
  532. package/src/index.ts +29 -26
  533. package/src/messageTypes.ts +4 -4
  534. package/src/opLifecycle/README.md +2 -4
  535. package/src/opLifecycle/batchManager.ts +2 -2
  536. package/src/opLifecycle/definitions.ts +2 -2
  537. package/src/opLifecycle/index.ts +8 -8
  538. package/src/opLifecycle/opCompressor.ts +3 -3
  539. package/src/opLifecycle/opDecompressor.ts +3 -3
  540. package/src/opLifecycle/opGroupingManager.ts +3 -12
  541. package/src/opLifecycle/opSplitter.ts +3 -3
  542. package/src/opLifecycle/outbox.ts +29 -9
  543. package/src/opLifecycle/remoteMessageProcessor.ts +4 -4
  544. package/src/packageVersion.ts +1 -1
  545. package/src/pendingStateManager.ts +19 -13
  546. package/src/scheduleManager.ts +4 -4
  547. package/src/summary/index.ts +13 -12
  548. package/src/summary/orderedClientElection.ts +1 -1
  549. package/src/summary/runWhileConnectedCoordinator.ts +1 -1
  550. package/src/summary/runningSummarizer.ts +141 -93
  551. package/src/summary/summarizer.ts +7 -7
  552. package/src/summary/summarizerClientElection.ts +2 -2
  553. package/src/summary/summarizerHeuristics.ts +3 -3
  554. package/src/summary/summarizerNode/index.ts +6 -3
  555. package/src/summary/summarizerNode/summarizerNode.ts +54 -69
  556. package/src/summary/summarizerNode/summarizerNodeUtils.ts +16 -34
  557. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +11 -17
  558. package/src/summary/summarizerTypes.ts +12 -24
  559. package/src/summary/summaryFormat.ts +16 -2
  560. package/src/summary/summaryGenerator.ts +16 -4
  561. package/src/summary/summaryManager.ts +6 -7
  562. package/tsconfig.cjs.json +7 -0
  563. package/tsconfig.json +2 -5
  564. package/dist/dataStores.d.ts +0 -149
  565. package/dist/dataStores.d.ts.map +0 -1
  566. package/dist/dataStores.js.map +0 -1
  567. package/dist/deltaManagerProxyBase.d.ts.map +0 -1
  568. package/dist/deltaManagerProxyBase.js +0 -77
  569. package/dist/deltaManagerProxyBase.js.map +0 -1
  570. package/lib/batchTracker.d.mts.map +0 -1
  571. package/lib/batchTracker.mjs.map +0 -1
  572. package/lib/blobManager.d.mts.map +0 -1
  573. package/lib/blobManager.mjs.map +0 -1
  574. package/lib/connectionTelemetry.d.mts.map +0 -1
  575. package/lib/connectionTelemetry.mjs.map +0 -1
  576. package/lib/containerHandleContext.d.mts.map +0 -1
  577. package/lib/containerHandleContext.mjs.map +0 -1
  578. package/lib/containerRuntime.d.mts.map +0 -1
  579. package/lib/containerRuntime.mjs.map +0 -1
  580. package/lib/dataStore.d.mts.map +0 -1
  581. package/lib/dataStore.mjs.map +0 -1
  582. package/lib/dataStoreContext.d.mts.map +0 -1
  583. package/lib/dataStoreContext.mjs.map +0 -1
  584. package/lib/dataStoreContexts.d.mts.map +0 -1
  585. package/lib/dataStoreContexts.mjs.map +0 -1
  586. package/lib/dataStoreRegistry.d.mts.map +0 -1
  587. package/lib/dataStoreRegistry.mjs.map +0 -1
  588. package/lib/dataStores.d.mts +0 -149
  589. package/lib/dataStores.d.mts.map +0 -1
  590. package/lib/dataStores.mjs.map +0 -1
  591. package/lib/deltaManagerProxyBase.d.mts +0 -35
  592. package/lib/deltaManagerProxyBase.d.mts.map +0 -1
  593. package/lib/deltaManagerProxyBase.mjs +0 -73
  594. package/lib/deltaManagerProxyBase.mjs.map +0 -1
  595. package/lib/deltaManagerSummarizerProxy.d.mts +0 -19
  596. package/lib/deltaManagerSummarizerProxy.d.mts.map +0 -1
  597. package/lib/deltaManagerSummarizerProxy.mjs +0 -38
  598. package/lib/deltaManagerSummarizerProxy.mjs.map +0 -1
  599. package/lib/deltaScheduler.d.mts.map +0 -1
  600. package/lib/deltaScheduler.mjs.map +0 -1
  601. package/lib/error.d.mts.map +0 -1
  602. package/lib/error.mjs.map +0 -1
  603. package/lib/gc/garbageCollection.d.mts.map +0 -1
  604. package/lib/gc/garbageCollection.mjs.map +0 -1
  605. package/lib/gc/gcConfigs.d.mts.map +0 -1
  606. package/lib/gc/gcConfigs.mjs.map +0 -1
  607. package/lib/gc/gcDefinitions.d.mts.map +0 -1
  608. package/lib/gc/gcDefinitions.mjs.map +0 -1
  609. package/lib/gc/gcHelpers.mjs.map +0 -1
  610. package/lib/gc/gcReferenceGraphAlgorithm.d.mts.map +0 -1
  611. package/lib/gc/gcReferenceGraphAlgorithm.mjs.map +0 -1
  612. package/lib/gc/gcSummaryDefinitions.d.mts.map +0 -1
  613. package/lib/gc/gcSummaryDefinitions.mjs.map +0 -1
  614. package/lib/gc/gcSummaryStateTracker.d.mts.map +0 -1
  615. package/lib/gc/gcSummaryStateTracker.mjs.map +0 -1
  616. package/lib/gc/gcTelemetry.d.mts.map +0 -1
  617. package/lib/gc/gcTelemetry.mjs.map +0 -1
  618. package/lib/gc/gcUnreferencedStateTracker.d.mts.map +0 -1
  619. package/lib/gc/gcUnreferencedStateTracker.mjs.map +0 -1
  620. package/lib/gc/index.d.mts +0 -13
  621. package/lib/gc/index.d.mts.map +0 -1
  622. package/lib/gc/index.mjs.map +0 -1
  623. package/lib/index.d.mts.map +0 -1
  624. package/lib/index.mjs +0 -24
  625. package/lib/index.mjs.map +0 -1
  626. package/lib/messageTypes.d.mts.map +0 -1
  627. package/lib/messageTypes.mjs.map +0 -1
  628. package/lib/metadata.d.mts.map +0 -1
  629. package/lib/metadata.mjs.map +0 -1
  630. package/lib/opLifecycle/batchManager.d.mts.map +0 -1
  631. package/lib/opLifecycle/batchManager.mjs.map +0 -1
  632. package/lib/opLifecycle/definitions.d.mts.map +0 -1
  633. package/lib/opLifecycle/definitions.mjs.map +0 -1
  634. package/lib/opLifecycle/index.d.mts +0 -13
  635. package/lib/opLifecycle/index.d.mts.map +0 -1
  636. package/lib/opLifecycle/index.mjs +0 -12
  637. package/lib/opLifecycle/index.mjs.map +0 -1
  638. package/lib/opLifecycle/opCompressor.d.mts.map +0 -1
  639. package/lib/opLifecycle/opCompressor.mjs.map +0 -1
  640. package/lib/opLifecycle/opDecompressor.d.mts.map +0 -1
  641. package/lib/opLifecycle/opDecompressor.mjs.map +0 -1
  642. package/lib/opLifecycle/opGroupingManager.d.mts.map +0 -1
  643. package/lib/opLifecycle/opGroupingManager.mjs.map +0 -1
  644. package/lib/opLifecycle/opSplitter.d.mts.map +0 -1
  645. package/lib/opLifecycle/opSplitter.mjs.map +0 -1
  646. package/lib/opLifecycle/outbox.d.mts.map +0 -1
  647. package/lib/opLifecycle/outbox.mjs.map +0 -1
  648. package/lib/opLifecycle/remoteMessageProcessor.d.mts.map +0 -1
  649. package/lib/opLifecycle/remoteMessageProcessor.mjs.map +0 -1
  650. package/lib/opProperties.d.mts.map +0 -1
  651. package/lib/opProperties.mjs.map +0 -1
  652. package/lib/packageVersion.d.mts.map +0 -1
  653. package/lib/packageVersion.mjs.map +0 -1
  654. package/lib/pendingStateManager.d.mts.map +0 -1
  655. package/lib/pendingStateManager.mjs.map +0 -1
  656. package/lib/scheduleManager.d.mts.map +0 -1
  657. package/lib/scheduleManager.mjs.map +0 -1
  658. package/lib/storageServiceWithAttachBlobs.d.mts.map +0 -1
  659. package/lib/storageServiceWithAttachBlobs.mjs.map +0 -1
  660. package/lib/summary/index.d.mts.map +0 -1
  661. package/lib/summary/index.mjs.map +0 -1
  662. package/lib/summary/orderedClientElection.d.mts.map +0 -1
  663. package/lib/summary/orderedClientElection.mjs.map +0 -1
  664. package/lib/summary/runWhileConnectedCoordinator.d.mts.map +0 -1
  665. package/lib/summary/runWhileConnectedCoordinator.mjs.map +0 -1
  666. package/lib/summary/runningSummarizer.d.mts.map +0 -1
  667. package/lib/summary/runningSummarizer.mjs.map +0 -1
  668. package/lib/summary/summarizer.d.mts.map +0 -1
  669. package/lib/summary/summarizer.mjs.map +0 -1
  670. package/lib/summary/summarizerClientElection.d.mts.map +0 -1
  671. package/lib/summary/summarizerClientElection.mjs.map +0 -1
  672. package/lib/summary/summarizerHeuristics.d.mts.map +0 -1
  673. package/lib/summary/summarizerHeuristics.mjs.map +0 -1
  674. package/lib/summary/summarizerNode/index.d.mts.map +0 -1
  675. package/lib/summary/summarizerNode/index.mjs +0 -7
  676. package/lib/summary/summarizerNode/index.mjs.map +0 -1
  677. package/lib/summary/summarizerNode/summarizerNode.d.mts.map +0 -1
  678. package/lib/summary/summarizerNode/summarizerNode.mjs.map +0 -1
  679. package/lib/summary/summarizerNode/summarizerNodeUtils.d.mts.map +0 -1
  680. package/lib/summary/summarizerNode/summarizerNodeUtils.mjs.map +0 -1
  681. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.mts.map +0 -1
  682. package/lib/summary/summarizerNode/summarizerNodeWithGc.mjs.map +0 -1
  683. package/lib/summary/summarizerTypes.d.mts.map +0 -1
  684. package/lib/summary/summarizerTypes.mjs.map +0 -1
  685. package/lib/summary/summaryCollection.d.mts.map +0 -1
  686. package/lib/summary/summaryCollection.mjs.map +0 -1
  687. package/lib/summary/summaryFormat.d.mts.map +0 -1
  688. package/lib/summary/summaryFormat.mjs.map +0 -1
  689. package/lib/summary/summaryGenerator.d.mts.map +0 -1
  690. package/lib/summary/summaryGenerator.mjs.map +0 -1
  691. package/lib/summary/summaryManager.d.mts.map +0 -1
  692. package/lib/summary/summaryManager.mjs.map +0 -1
  693. package/lib/throttler.d.mts.map +0 -1
  694. package/lib/throttler.mjs.map +0 -1
  695. package/src/deltaManagerProxyBase.ts +0 -111
@@ -4,13 +4,13 @@
4
4
  */
5
5
  import {
6
6
  ITelemetryBaseLogger,
7
- ITelemetryGenericEvent,
8
7
  FluidObject,
9
8
  IFluidHandle,
10
9
  IFluidHandleContext,
11
10
  IRequest,
12
11
  IResponse,
13
12
  IProvideFluidHandleContext,
13
+ ISignalEnvelope,
14
14
  } from "@fluidframework/core-interfaces";
15
15
  import {
16
16
  IAudience,
@@ -20,7 +20,6 @@ import {
20
20
  IRuntime,
21
21
  ICriticalContainerError,
22
22
  AttachState,
23
- ILoaderOptions,
24
23
  ILoader,
25
24
  LoaderHeader,
26
25
  IGetPendingLocalStateProps,
@@ -29,7 +28,7 @@ import {
29
28
  IContainerRuntime,
30
29
  IContainerRuntimeEvents,
31
30
  } from "@fluidframework/container-runtime-definitions";
32
- import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
31
+ import { assert, Deferred, delay, LazyPromise, PromiseCache } from "@fluidframework/core-utils";
33
32
  import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
34
33
  import {
35
34
  createChildLogger,
@@ -39,19 +38,22 @@ import {
39
38
  GenericError,
40
39
  raiseConnectedEvent,
41
40
  PerformanceEvent,
42
- // eslint-disable-next-line import/no-deprecated
43
41
  TaggedLoggerAdapter,
44
42
  MonitoringContext,
45
43
  wrapError,
46
44
  ITelemetryLoggerExt,
47
45
  UsageError,
48
46
  LoggingError,
47
+ createSampledLogger,
48
+ IEventSampler,
49
+ type ITelemetryGenericEventExt,
50
+ loggerToMonitoringContext,
49
51
  } from "@fluidframework/telemetry-utils";
50
52
  import {
51
53
  DriverHeader,
52
54
  FetchSource,
53
55
  IDocumentStorageService,
54
- ISummaryContext,
56
+ type ISnapshot,
55
57
  } from "@fluidframework/driver-definitions";
56
58
  import { readAndParse } from "@fluidframework/driver-utils";
57
59
  import {
@@ -73,11 +75,8 @@ import {
73
75
  InboundAttachMessage,
74
76
  IFluidDataStoreContextDetached,
75
77
  IFluidDataStoreRegistry,
76
- IFluidDataStoreChannel,
77
78
  IGarbageCollectionData,
78
- IEnvelope,
79
79
  IInboundSignalMessage,
80
- ISignalEnvelope,
81
80
  NamedFluidDataStoreRegistryEntries,
82
81
  ISummaryTreeWithStats,
83
82
  ISummarizeInternalResult,
@@ -86,18 +85,18 @@ import {
86
85
  channelsTreeName,
87
86
  IDataStore,
88
87
  ITelemetryContext,
88
+ IEnvelope,
89
89
  } from "@fluidframework/runtime-definitions";
90
90
  import type {
91
91
  SerializedIdCompressorWithNoSession,
92
92
  IIdCompressor,
93
93
  IIdCompressorCore,
94
- IdCreationRange,
95
94
  SerializedIdCompressorWithOngoingSession,
95
+ IdCreationRange,
96
96
  } from "@fluidframework/id-compressor";
97
97
  import {
98
98
  addBlobToSummary,
99
99
  addSummarizeResultToSummary,
100
- addTreeToSummary,
101
100
  RequestParser,
102
101
  create404Response,
103
102
  exceptionToResponse,
@@ -109,17 +108,17 @@ import {
109
108
  responseToException,
110
109
  } from "@fluidframework/runtime-utils";
111
110
  import { v4 as uuid } from "uuid";
112
- import { ContainerFluidHandleContext } from "./containerHandleContext";
113
- import { FluidDataStoreRegistry } from "./dataStoreRegistry";
114
- import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
111
+ import { ContainerFluidHandleContext } from "./containerHandleContext.js";
112
+ import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
113
+ import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry.js";
115
114
  import {
116
115
  IPendingBatchMessage,
117
116
  IPendingLocalState,
118
117
  PendingStateManager,
119
- } from "./pendingStateManager";
120
- import { pkgVersion } from "./packageVersion";
121
- import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager";
122
- import { DataStores, getSummaryForDatastores } from "./dataStores";
118
+ } from "./pendingStateManager.js";
119
+ import { pkgVersion } from "./packageVersion.js";
120
+ import { BlobManager, IBlobManagerLoadInfo, IPendingBlobs } from "./blobManager.js";
121
+ import { ChannelCollection, getSummaryForDatastores, wrapContext } from "./channelCollection.js";
123
122
  import {
124
123
  aliasBlobName,
125
124
  blobsTreeName,
@@ -159,8 +158,10 @@ import {
159
158
  ISummarizerEvents,
160
159
  IBaseSummarizeResult,
161
160
  ISummarizer,
162
- } from "./summary";
163
- import { formExponentialFn, Throttler } from "./throttler";
161
+ rootHasIsolatedChannels,
162
+ IdCompressorMode,
163
+ } from "./summary/index.js";
164
+ import { formExponentialFn, Throttler } from "./throttler.js";
164
165
  import {
165
166
  GarbageCollector,
166
167
  GCNodeType,
@@ -168,11 +169,10 @@ import {
168
169
  IGarbageCollector,
169
170
  IGCRuntimeOptions,
170
171
  IGCStats,
171
- trimLeadingAndTrailingSlashes,
172
- } from "./gc";
173
- import { channelToDataStore, IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
174
- import { BindBatchTracker } from "./batchTracker";
175
- import { ScheduleManager } from "./scheduleManager";
172
+ } from "./gc/index.js";
173
+ import { channelToDataStore } from "./dataStore.js";
174
+ import { BindBatchTracker } from "./batchTracker.js";
175
+ import { ScheduleManager } from "./scheduleManager.js";
176
176
  import {
177
177
  BatchMessage,
178
178
  IBatch,
@@ -184,9 +184,9 @@ import {
184
184
  RemoteMessageProcessor,
185
185
  OpGroupingManager,
186
186
  getLongStack,
187
- } from "./opLifecycle";
188
- import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
189
- import { IBatchMetadata, IIdAllocationMetadata } from "./metadata";
187
+ } from "./opLifecycle/index.js";
188
+ import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
189
+ import { IBatchMetadata, IIdAllocationMetadata } from "./metadata.js";
190
190
  import {
191
191
  ContainerMessageType,
192
192
  type InboundSequencedContainerRuntimeMessage,
@@ -196,7 +196,7 @@ import {
196
196
  type OutboundContainerRuntimeMessage,
197
197
  type UnknownContainerRuntimeMessage,
198
198
  ContainerRuntimeGCMessage,
199
- } from "./messageTypes";
199
+ } from "./messageTypes.js";
200
200
 
201
201
  /**
202
202
  * Utility to implement compat behaviors given an unknown message type
@@ -441,7 +441,7 @@ export interface IContainerRuntimeOptions {
441
441
  * Enable the IdCompressor in the runtime.
442
442
  * @experimental Not ready for use.
443
443
  */
444
- readonly enableRuntimeIdCompressor?: boolean;
444
+ readonly enableRuntimeIdCompressor?: IdCompressorMode;
445
445
 
446
446
  /**
447
447
  * If enabled, the runtime will block all attempts to send an op inside the
@@ -466,27 +466,6 @@ export interface IContainerRuntimeOptions {
466
466
  readonly enableGroupedBatching?: boolean;
467
467
  }
468
468
 
469
- /**
470
- * Accepted header keys for requests coming to the runtime.
471
- * @internal
472
- */
473
- export enum RuntimeHeaders {
474
- /** True to wait for a data store to be created and loaded before returning it. */
475
- wait = "wait",
476
- /** True if the request is coming from an IFluidHandle. */
477
- viaHandle = "viaHandle",
478
- }
479
-
480
- /** True if a tombstoned object should be returned without erroring
481
- * @alpha
482
- */
483
- export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
484
- /**
485
- * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
486
- * @internal
487
- */
488
- export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
489
-
490
469
  /**
491
470
  * Tombstone error responses will have this header set to true
492
471
  * @alpha
@@ -500,6 +479,7 @@ export const InactiveResponseHeaderKey = "isInactive";
500
479
 
501
480
  /**
502
481
  * The full set of parsed header data that may be found on Runtime requests
482
+ * @internal
503
483
  */
504
484
  export interface RuntimeHeaderData {
505
485
  wait?: boolean;
@@ -553,6 +533,11 @@ export interface IPendingRuntimeState {
553
533
  * Pending idCompressor state
554
534
  */
555
535
  pendingIdCompressorState?: SerializedIdCompressorWithOngoingSession;
536
+
537
+ /**
538
+ * Time at which session expiry timer started.
539
+ */
540
+ sessionExpiryTimerStarted?: number | undefined;
556
541
  }
557
542
 
558
543
  const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
@@ -767,7 +752,6 @@ export class ContainerRuntime
767
752
  const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
768
753
  const passLogger =
769
754
  backCompatContext.taggedLogger ??
770
- // eslint-disable-next-line import/no-deprecated
771
755
  new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
772
756
  const logger = createChildLogger({
773
757
  logger: passLogger,
@@ -778,6 +762,8 @@ export class ContainerRuntime
778
762
  },
779
763
  });
780
764
 
765
+ const mc = loggerToMonitoringContext(logger);
766
+
781
767
  const {
782
768
  summaryOptions = {},
783
769
  gcOptions = {},
@@ -785,7 +771,7 @@ export class ContainerRuntime
785
771
  flushMode = defaultFlushMode,
786
772
  compressionOptions = defaultCompressionConfig,
787
773
  maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
788
- enableRuntimeIdCompressor = false,
774
+ enableRuntimeIdCompressor = "off",
789
775
  chunkSizeInBytes = defaultChunkSizeInBytes,
790
776
  enableOpReentryCheck = false,
791
777
  enableGroupedBatching = false,
@@ -854,24 +840,72 @@ export class ContainerRuntime
854
840
  }
855
841
  }
856
842
 
857
- const idCompressorEnabled =
858
- metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
859
- let idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
860
- if (idCompressorEnabled) {
843
+ // Enabling the IdCompressor is a one-way operation and we only want to
844
+ // allow new containers to turn it on
845
+ let idCompressorMode: IdCompressorMode;
846
+ if (existing) {
847
+ // This setting has to be sticky for correctness:
848
+ // 1) if compressior is OFF, it can't be enabled, as already running clients (in given document session) do not know
849
+ // how to process compressor ops
850
+ // 2) if it's ON, then all sessions should load compressor right away
851
+ // 3) Same logic applies for "delayed" mode
852
+ // Maybe in the future we will need to enabled (and figure how to do it safely) "delayed" -> "on" change.
853
+ // We could do "off" -> "on" transtition too, if all clients start loading compressor (but not using it initially) and do so for a while -
854
+ // this will allow clients to eventually to disregard "off" setting (when it's safe so) and start using compressor in future sessions.
855
+ // Everyting is possible, but it needs to be designed and executed carefully, when such need arises.
856
+ idCompressorMode = metadata?.idCompressorMode ?? "off";
857
+ } else {
858
+ // FG overwrite
859
+ const enabled = mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled");
860
+ switch (enabled) {
861
+ case true:
862
+ idCompressorMode = "on";
863
+ break;
864
+ case false:
865
+ idCompressorMode = "off";
866
+ break;
867
+ default:
868
+ idCompressorMode = enableRuntimeIdCompressor;
869
+ break;
870
+ }
871
+ }
872
+
873
+ const createIdCompressorFn = async () => {
861
874
  const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import(
862
875
  "@fluidframework/id-compressor"
863
876
  );
864
877
 
878
+ /**
879
+ * Because the IdCompressor emits so much telemetry, this function is used to sample
880
+ * approximately 5% of all clients. Only the given percentage of sessions will emit telemetry.
881
+ */
882
+ const idCompressorEventSampler: IEventSampler = (() => {
883
+ const isIdCompressorTelemetryEnabled = Math.random() < 0.05;
884
+ return {
885
+ sample: () => {
886
+ return isIdCompressorTelemetryEnabled;
887
+ },
888
+ };
889
+ })();
890
+
891
+ const compressorLogger = createSampledLogger(logger, idCompressorEventSampler);
865
892
  const pendingLocalState = context.pendingLocalState as IPendingRuntimeState;
866
893
 
867
894
  if (pendingLocalState?.pendingIdCompressorState !== undefined) {
868
- idCompressor = deserializeIdCompressor(pendingLocalState.pendingIdCompressorState);
895
+ return deserializeIdCompressor(
896
+ pendingLocalState.pendingIdCompressorState,
897
+ compressorLogger,
898
+ );
869
899
  } else if (serializedIdCompressor !== undefined) {
870
- idCompressor = deserializeIdCompressor(serializedIdCompressor, createSessionId());
900
+ return deserializeIdCompressor(
901
+ serializedIdCompressor,
902
+ createSessionId(),
903
+ compressorLogger,
904
+ );
871
905
  } else {
872
- idCompressor = createIdCompressor(logger);
906
+ return createIdCompressor(compressorLogger);
873
907
  }
874
- }
908
+ };
875
909
 
876
910
  const runtime = new containerRuntimeCtor(
877
911
  context,
@@ -897,7 +931,8 @@ export class ContainerRuntime
897
931
  existing,
898
932
  blobManagerSnapshot,
899
933
  context.storage,
900
- idCompressor,
934
+ createIdCompressorFn,
935
+ idCompressorMode,
901
936
  provideEntryPoint,
902
937
  requestHandler,
903
938
  undefined, // summaryConfiguration
@@ -913,7 +948,7 @@ export class ContainerRuntime
913
948
  return runtime;
914
949
  }
915
950
 
916
- public readonly options: ILoaderOptions;
951
+ public readonly options: Record<string | number, any>;
917
952
  private imminentClosure: boolean = false;
918
953
 
919
954
  private readonly _getClientId: () => string | undefined;
@@ -927,6 +962,10 @@ export class ContainerRuntime
927
962
  return this._storage;
928
963
  }
929
964
 
965
+ public get containerRuntime() {
966
+ return this;
967
+ }
968
+
930
969
  private readonly submitFn: (
931
970
  type: MessageType,
932
971
  contents: any,
@@ -964,7 +1003,47 @@ export class ContainerRuntime
964
1003
  return this._getAttachState();
965
1004
  }
966
1005
 
967
- public idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
1006
+ private _idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
1007
+
1008
+ // We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
1009
+ // Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
1010
+ private pendingIdCompressorOps: IdCreationRange[] = [];
1011
+
1012
+ // Id Compressor serializes final state (see getPendingLocalState()). As result, it needs to skip all ops that preceeded that state
1013
+ // (such ops will be marked by Loader layer as savedOp === true)
1014
+ // That said, in "delayed" mode it's possible that Id Compressor was never initialized before getPendingLocalState() is called.
1015
+ // In such case we have to process all ops, including those marked with saveOp === true.
1016
+ private readonly skipSavedCompressorOps: boolean;
1017
+
1018
+ /**
1019
+ * See IContainerRuntimeBase.idCompressor() for details.
1020
+ */
1021
+ public get idCompressor() {
1022
+ // Expose ID Compressor only if it's On from the start.
1023
+ // If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
1024
+ // That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
1025
+ // to reason over such things as session ID space.
1026
+ if (this.idCompressorMode === "on") {
1027
+ assert(
1028
+ this._idCompressor !== undefined,
1029
+ 0x8ea /* compressor should have been loaded */,
1030
+ );
1031
+ return this._idCompressor;
1032
+ }
1033
+ }
1034
+
1035
+ /**
1036
+ * True if we have ID compressor loading in-flight (async operation). Useful only for
1037
+ * this.idCompressorMode === "delayed" mode
1038
+ */
1039
+ protected compressorLoadInitiated = false;
1040
+
1041
+ /**
1042
+ * See IContainerRuntimeBase.generateDocumentUniqueId() for details.
1043
+ */
1044
+ public generateDocumentUniqueId() {
1045
+ return this._idCompressor?.generateDocumentUniqueId() ?? uuid();
1046
+ }
968
1047
 
969
1048
  public get IFluidHandleContext(): IFluidHandleContext {
970
1049
  return this.handleContext;
@@ -1088,7 +1167,7 @@ export class ContainerRuntime
1088
1167
  private readonly outbox: Outbox;
1089
1168
  private readonly garbageCollector: IGarbageCollector;
1090
1169
 
1091
- private readonly dataStores: DataStores;
1170
+ private readonly channelCollection: ChannelCollection;
1092
1171
  private readonly remoteMessageProcessor: RemoteMessageProcessor;
1093
1172
 
1094
1173
  /** The last message processed at the time of the last summary. */
@@ -1104,11 +1183,6 @@ export class ContainerRuntime
1104
1183
  return this.summaryConfiguration.state === "disabled";
1105
1184
  }
1106
1185
 
1107
- private readonly heuristicsDisabled: boolean;
1108
- private isHeuristicsDisabled(): boolean {
1109
- return this.summaryConfiguration.state === "disableHeuristics";
1110
- }
1111
-
1112
1186
  private readonly maxOpsSinceLastSummary: number;
1113
1187
  private getMaxOpsSinceLastSummary(): number {
1114
1188
  return this.summaryConfiguration.state !== "disabled"
@@ -1151,11 +1225,6 @@ export class ContainerRuntime
1151
1225
  */
1152
1226
  private readonly telemetryDocumentId: string;
1153
1227
 
1154
- /**
1155
- * If true, the runtime has access to an IdCompressor
1156
- */
1157
- private readonly idCompressorEnabled: boolean;
1158
-
1159
1228
  /**
1160
1229
  * Whether this client is the summarizer client itself (type is summarizerClientType)
1161
1230
  */
@@ -1166,11 +1235,19 @@ export class ContainerRuntime
1166
1235
  */
1167
1236
  private readonly loadedFromVersionId: string | undefined;
1168
1237
 
1238
+ /**
1239
+ * It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
1240
+ * Starting with 1 min and based on recorded usage we can tweak it later on.
1241
+ */
1242
+ private readonly snapshotCacheForLoadingGroupIds = new PromiseCache<string, ISnapshot>({
1243
+ expiry: { policy: "absolute", durationMs: 60000 },
1244
+ });
1245
+
1169
1246
  /***/
1170
1247
  protected constructor(
1171
1248
  context: IContainerContext,
1172
1249
  private readonly registry: IFluidDataStoreRegistry,
1173
- metadata: IContainerRuntimeMetadata | undefined,
1250
+ private readonly metadata: IContainerRuntimeMetadata | undefined,
1174
1251
  electedSummarizerData: ISerializedElection | undefined,
1175
1252
  chunks: [string, string[]][],
1176
1253
  dataStoreAliasMap: [string, string][],
@@ -1180,7 +1257,8 @@ export class ContainerRuntime
1180
1257
  existing: boolean,
1181
1258
  blobManagerSnapshot: IBlobManagerLoadInfo,
1182
1259
  private readonly _storage: IDocumentStorageService,
1183
- idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
1260
+ private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
1261
+ private readonly idCompressorMode: IdCompressorMode,
1184
1262
  provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
1185
1263
  private readonly requestHandler?: (
1186
1264
  request: IRequest,
@@ -1224,7 +1302,9 @@ export class ContainerRuntime
1224
1302
  this.submitSummaryFn = submitSummaryFn;
1225
1303
  this.submitSignalFn = submitSignalFn;
1226
1304
 
1227
- this.options = options;
1305
+ // TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
1306
+ // Values are generally expected to be set from the runtime side.
1307
+ this.options = options ?? {};
1228
1308
  this.clientDetails = clientDetails;
1229
1309
  this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
1230
1310
  this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
@@ -1265,20 +1345,12 @@ export class ContainerRuntime
1265
1345
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
1266
1346
  // the count is reset to 0.
1267
1347
  loadSummaryNumber = metadata?.summaryNumber ?? 0;
1268
-
1269
- // Enabling the IdCompressor is a one-way operation and we only want to
1270
- // allow new containers to turn it on
1271
- this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
1272
1348
  } else {
1273
1349
  this.createContainerMetadata = {
1274
1350
  createContainerRuntimeVersion: pkgVersion,
1275
1351
  createContainerTimestamp: Date.now(),
1276
1352
  };
1277
1353
  loadSummaryNumber = 0;
1278
-
1279
- this.idCompressorEnabled =
1280
- this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
1281
- idCompressor !== undefined;
1282
1354
  }
1283
1355
  this.nextSummaryNumber = loadSummaryNumber + 1;
1284
1356
 
@@ -1346,14 +1418,9 @@ export class ContainerRuntime
1346
1418
  disableOpReentryCheck !== true;
1347
1419
 
1348
1420
  this.summariesDisabled = this.isSummariesDisabled();
1349
- this.heuristicsDisabled = this.isHeuristicsDisabled();
1350
1421
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
1351
1422
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
1352
1423
 
1353
- if (this.idCompressorEnabled) {
1354
- this.idCompressor = idCompressor;
1355
- }
1356
-
1357
1424
  this.maxConsecutiveReconnects =
1358
1425
  this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
1359
1426
  this.defaultMaxConsecutiveReconnects;
@@ -1371,15 +1438,17 @@ export class ContainerRuntime
1371
1438
 
1372
1439
  const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
1373
1440
 
1374
- const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
1375
- if (
1376
- maxSnapshotCacheDurationMs !== undefined &&
1377
- maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000
1378
- ) {
1379
- // This is a runtime enforcement of what's already explicit in the policy's type itself,
1380
- // which dictates the value is either undefined or exactly 5 days in ms.
1381
- // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
1382
- throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
1441
+ if (context.attachState === AttachState.Attached) {
1442
+ const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
1443
+ if (
1444
+ maxSnapshotCacheDurationMs !== undefined &&
1445
+ maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000
1446
+ ) {
1447
+ // This is a runtime enforcement of what's already explicit in the policy's type itself,
1448
+ // which dictates the value is either undefined or exactly 5 days in ms.
1449
+ // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
1450
+ throw new UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
1451
+ }
1383
1452
  }
1384
1453
 
1385
1454
  this.garbageCollector = GarbageCollector.create({
@@ -1395,6 +1464,7 @@ export class ContainerRuntime
1395
1464
  getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
1396
1465
  readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
1397
1466
  submitMessage: (message: ContainerRuntimeGCMessage) => this.submit(message),
1467
+ sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
1398
1468
  });
1399
1469
 
1400
1470
  const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
@@ -1411,9 +1481,6 @@ export class ContainerRuntime
1411
1481
  // Must set to false to prevent sending summary handle which would be pointing to
1412
1482
  // a summary with an older protocol state.
1413
1483
  canReuseHandle: false,
1414
- // Must set to true to throw on any data stores failure that was too severe to be handled.
1415
- // We also are not decoding the base summaries at the root.
1416
- throwOnFailure: true,
1417
1484
  // If GC should not run, let the summarizer node know so that it does not track GC state.
1418
1485
  gcDisabled: !this.garbageCollector.shouldRunGC,
1419
1486
  },
@@ -1427,28 +1494,44 @@ export class ContainerRuntime
1427
1494
  this.summarizerNode.updateBaseSummaryState(baseSnapshot);
1428
1495
  }
1429
1496
 
1430
- this.dataStores = new DataStores(
1497
+ const parentContext = wrapContext(this);
1498
+
1499
+ // Due to a mismatch between different layers in terms of
1500
+ // what is the interface of passing signals, we need the
1501
+ // downstream stores to wrap the signal.
1502
+ parentContext.submitSignal = (type: string, content: any, targetClientId?: string) => {
1503
+ const envelope1 = content as IEnvelope;
1504
+ const envelope2 = this.createNewSignalEnvelope(
1505
+ envelope1.address,
1506
+ type,
1507
+ envelope1.contents,
1508
+ );
1509
+ return this.submitSignalFn(envelope2, targetClientId);
1510
+ };
1511
+
1512
+ this.channelCollection = new ChannelCollection(
1431
1513
  getSummaryForDatastores(baseSnapshot, metadata),
1432
- this,
1433
- (attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }),
1434
- (id: string, createParam: CreateChildSummarizerNodeParam) =>
1435
- (
1436
- summarizeInternal: SummarizeInternalFn,
1437
- getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
1438
- ) =>
1439
- this.summarizerNode.createChild(
1440
- summarizeInternal,
1441
- id,
1442
- createParam,
1443
- undefined,
1444
- getGCDataFn,
1445
- ),
1446
- (id: string) => this.summarizerNode.deleteChild(id),
1514
+ parentContext,
1447
1515
  this.mc.logger,
1448
- (path: string, timestampMs: number, packagePath?: readonly string[]) =>
1449
- this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath),
1516
+ (
1517
+ path: string,
1518
+ reason: "Loaded" | "Changed",
1519
+ timestampMs?: number,
1520
+ packagePath?: readonly string[],
1521
+ request?: IRequest,
1522
+ headerData?: RuntimeHeaderData,
1523
+ ) =>
1524
+ this.garbageCollector.nodeUpdated(
1525
+ path,
1526
+ reason,
1527
+ timestampMs,
1528
+ packagePath,
1529
+ request,
1530
+ headerData,
1531
+ ),
1450
1532
  (path: string) => this.garbageCollector.isNodeDeleted(path),
1451
1533
  new Map<string, string>(dataStoreAliasMap),
1534
+ async (runtime: ChannelCollection) => provideEntryPoint,
1452
1535
  );
1453
1536
 
1454
1537
  this.blobManager = new BlobManager(
@@ -1490,6 +1573,7 @@ export class ContainerRuntime
1490
1573
  reSubmit: this.reSubmit.bind(this),
1491
1574
  reSubmitBatch: this.reSubmitBatch.bind(this),
1492
1575
  isActiveConnection: () => this.innerDeltaManager.active,
1576
+ isAttached: () => this.attachState !== AttachState.Detached,
1493
1577
  },
1494
1578
  pendingRuntimeState?.pending,
1495
1579
  this.logger,
@@ -1636,7 +1720,6 @@ export class ContainerRuntime
1636
1720
  {
1637
1721
  initialDelayMs: this.initialSummarizerDelayMs,
1638
1722
  },
1639
- this.heuristicsDisabled,
1640
1723
  );
1641
1724
  this.summaryManager.on("summarize", (eventProps) => {
1642
1725
  this.emit("summarize", eventProps);
@@ -1654,26 +1737,27 @@ export class ContainerRuntime
1654
1737
  this.mc.logger.sendTelemetryEvent({
1655
1738
  eventName: "ContainerLoadStats",
1656
1739
  ...this.createContainerMetadata,
1657
- ...this.dataStores.containerLoadStats,
1740
+ ...this.channelCollection.containerLoadStats,
1658
1741
  summaryNumber: loadSummaryNumber,
1659
1742
  summaryFormatVersion: metadata?.summaryFormatVersion,
1660
1743
  disableIsolatedChannels: metadata?.disableIsolatedChannels,
1661
1744
  gcVersion: metadata?.gcFeature,
1662
1745
  options: JSON.stringify(runtimeOptions),
1746
+ idCompressorModeMetadata: metadata?.idCompressorMode,
1747
+ idCompressorMode: this.idCompressorMode,
1663
1748
  featureGates: JSON.stringify({
1664
1749
  disableCompression,
1665
1750
  disableOpReentryCheck,
1666
1751
  disableChunking,
1667
1752
  disableAttachReorder: this.disableAttachReorder,
1668
1753
  disablePartialFlush,
1669
- idCompressorEnabled: this.idCompressorEnabled,
1670
1754
  closeSummarizerDelayOverride,
1671
1755
  }),
1672
1756
  telemetryDocumentId: this.telemetryDocumentId,
1673
1757
  groupedBatchingEnabled: this.groupedBatchingEnabled,
1674
1758
  });
1675
1759
 
1676
- ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
1760
+ ReportOpPerfTelemetry(this.clientId, this.deltaManager, this, this.logger);
1677
1761
  BindBatchTracker(this, this.logger);
1678
1762
 
1679
1763
  this.entryPoint = new LazyPromise(async () => {
@@ -1686,12 +1770,52 @@ export class ContainerRuntime
1686
1770
  }
1687
1771
  return provideEntryPoint(this);
1688
1772
  });
1773
+
1774
+ // If we loaded from pending state, then we need to skip any ops that are already accounted in such
1775
+ // saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
1776
+ this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
1777
+ }
1778
+
1779
+ public getCreateChildSummarizerNodeFn(id: string, createParam: CreateChildSummarizerNodeParam) {
1780
+ return (
1781
+ summarizeInternal: SummarizeInternalFn,
1782
+ getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
1783
+ ) =>
1784
+ this.summarizerNode.createChild(
1785
+ summarizeInternal,
1786
+ id,
1787
+ createParam,
1788
+ undefined,
1789
+ getGCDataFn,
1790
+ );
1791
+ }
1792
+
1793
+ public deleteChildSummarizerNode(id: string) {
1794
+ return this.summarizerNode.deleteChild(id);
1795
+ }
1796
+
1797
+ /* IFluidParentContext APIs that should not be called on Root */
1798
+ public makeLocallyVisible() {
1799
+ assert(false, 0x8eb /* should not be called */);
1800
+ }
1801
+
1802
+ public setChannelDirty(address: string) {
1803
+ assert(false, "should not be called");
1689
1804
  }
1690
1805
 
1691
1806
  /**
1692
1807
  * Initializes the state from the base snapshot this container runtime loaded from.
1693
1808
  */
1694
1809
  private async initializeBaseState(): Promise<void> {
1810
+ if (
1811
+ this.idCompressorMode === "on" ||
1812
+ (this.idCompressorMode === "delayed" && this.connected)
1813
+ ) {
1814
+ // This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
1815
+ assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
1816
+ this._idCompressor = await this.createIdCompressor();
1817
+ }
1818
+
1695
1819
  await this.garbageCollector.initializeBaseState();
1696
1820
  }
1697
1821
 
@@ -1716,12 +1840,145 @@ export class ContainerRuntime
1716
1840
  }
1717
1841
  this.garbageCollector.dispose();
1718
1842
  this._summarizer?.dispose();
1719
- this.dataStores.dispose();
1843
+ this.channelCollection.dispose();
1720
1844
  this.pendingStateManager.dispose();
1721
1845
  this.emit("dispose");
1722
1846
  this.removeAllListeners();
1723
1847
  }
1724
1848
 
1849
+ /**
1850
+ * Api to fetch the snapshot from the service for a loadingGroupIds.
1851
+ * @param loadingGroupIds - LoadingGroupId for which the snapshot is asked for.
1852
+ * @param pathParts - Parts of the path, which we want to extract from the snapshot tree.
1853
+ * @returns - snapshotTree and the sequence number of the snapshot.
1854
+ */
1855
+ public async getSnapshotForLoadingGroupId(
1856
+ loadingGroupIds: string[],
1857
+ pathParts: string[],
1858
+ ): Promise<{ snapshotTree: ISnapshotTree; sequenceNumber: number }> {
1859
+ const sortedLoadingGroupIds = loadingGroupIds.sort();
1860
+ assert(
1861
+ this.storage.getSnapshot !== undefined,
1862
+ 0x8ed /* getSnapshot api should be defined if used */,
1863
+ );
1864
+ let loadedFromCache = true;
1865
+ // Lookup up in the cache, if not present then make the network call as multiple datastores could
1866
+ // be in same loading group. So, once we have fetched the snapshot for that loading group on
1867
+ // any request, then cache that as same group could be requested in future too.
1868
+ const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(
1869
+ sortedLoadingGroupIds.join(),
1870
+ async () => {
1871
+ assert(
1872
+ this.storage.getSnapshot !== undefined,
1873
+ 0x8ee /* getSnapshot api should be defined if used */,
1874
+ );
1875
+ loadedFromCache = false;
1876
+ return this.storage.getSnapshot({
1877
+ cacheSnapshot: false,
1878
+ scenarioName: "snapshotForLoadingGroupId",
1879
+ loadingGroupIds: sortedLoadingGroupIds,
1880
+ });
1881
+ },
1882
+ );
1883
+
1884
+ this.logger.sendTelemetryEvent({
1885
+ eventName: "GroupIdSnapshotFetched",
1886
+ details: JSON.stringify({
1887
+ fromCache: loadedFromCache,
1888
+ loadingGroupIds: loadingGroupIds.join(","),
1889
+ }),
1890
+ });
1891
+ // Find the snapshotTree inside the returned snapshot based on the path as given in the request.
1892
+ const hasIsolatedChannels = rootHasIsolatedChannels(this.metadata);
1893
+ const snapshotTreeForPath = this.getSnapshotTreeForPath(
1894
+ snapshot.snapshotTree,
1895
+ pathParts,
1896
+ hasIsolatedChannels,
1897
+ );
1898
+ assert(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
1899
+ const snapshotSeqNumber = snapshot.sequenceNumber;
1900
+ assert(snapshotSeqNumber !== undefined, 0x8f0 /* snapshotSeqNumber should be present */);
1901
+
1902
+ // This assert fires if we get a snapshot older than the snapshot we loaded from. This is a service issue.
1903
+ // Snapshots should only move forward. If we observe an older snapshot than the one we loaded from, then likely
1904
+ // the file has been overwritten or service lost data.
1905
+ if (snapshotSeqNumber < this.deltaManager.initialSequenceNumber) {
1906
+ throw DataProcessingError.create(
1907
+ "Downloaded snapshot older than snapshot we loaded from",
1908
+ "getSnapshotForLoadingGroupId",
1909
+ undefined,
1910
+ {
1911
+ loadingGroupIds: sortedLoadingGroupIds.join(","),
1912
+ snapshotSeqNumber,
1913
+ initialSequenceNumber: this.deltaManager.initialSequenceNumber,
1914
+ },
1915
+ );
1916
+ }
1917
+
1918
+ // If the snapshot is ahead of the last seq number of the delta manager, then catch up before
1919
+ // returning the snapshot.
1920
+ if (snapshotSeqNumber > this.deltaManager.lastSequenceNumber) {
1921
+ // If this is a summarizer client, which is trying to load a group and it finds that there is
1922
+ // another snapshot from which the summarizer loaded and it is behind, then just give up as
1923
+ // the summarizer state is not up to date.
1924
+ // This should be a recoverable scenario and shouldn't happen as we should process the ack first.
1925
+ if (this.isSummarizerClient) {
1926
+ throw new Error(
1927
+ "Summarizer client behind, loaded newer snapshot with loadingGroupId",
1928
+ );
1929
+ }
1930
+
1931
+ // We want to catchup from sequenceNumber to targetSequenceNumber
1932
+ const props: ITelemetryGenericEventExt = {
1933
+ eventName: "GroupIdSnapshotCatchup",
1934
+ loadingGroupIds: sortedLoadingGroupIds.join(","),
1935
+ targetSequenceNumber: snapshotSeqNumber, // This is so we reuse some columns in telemetry
1936
+ sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
1937
+ };
1938
+
1939
+ const event = PerformanceEvent.start(this.mc.logger, {
1940
+ ...props,
1941
+ });
1942
+ // If the inbound deltas queue is paused or disconnected, we expect a reconnect and unpause
1943
+ // as long as it's not a summarizer client.
1944
+ if (this.deltaManager.inbound.paused) {
1945
+ props.inboundPaused = this.deltaManager.inbound.paused; // reusing telemetry
1946
+ }
1947
+ const defP = new Deferred<boolean>();
1948
+ this.deltaManager.on("op", (message: ISequencedDocumentMessage) => {
1949
+ if (message.sequenceNumber >= snapshotSeqNumber) {
1950
+ defP.resolve(true);
1951
+ }
1952
+ });
1953
+ await defP.promise;
1954
+ event.end(props);
1955
+ }
1956
+ return { snapshotTree: snapshotTreeForPath, sequenceNumber: snapshotSeqNumber };
1957
+ }
1958
+
1959
+ /**
1960
+ * Api to find a snapshot tree inside a bigger snapshot tree based on the path in the pathParts array.
1961
+ * @param snapshotTree - snapshot tree to look into.
1962
+ * @param pathParts - Part of the path, which we want to extract from the snapshot tree.
1963
+ * @param hasIsolatedChannels - whether the channels are present inside ".channels" subtree. Older
1964
+ * snapshots will not have trees inside ".channels", so check that.
1965
+ * @returns - requested snapshot tree based on the path parts.
1966
+ */
1967
+ private getSnapshotTreeForPath(
1968
+ snapshotTree: ISnapshotTree,
1969
+ pathParts: string[],
1970
+ hasIsolatedChannels: boolean,
1971
+ ): ISnapshotTree | undefined {
1972
+ let childTree = snapshotTree;
1973
+ for (const part of pathParts) {
1974
+ if (hasIsolatedChannels) {
1975
+ childTree = childTree?.trees[channelsTreeName];
1976
+ }
1977
+ childTree = childTree?.trees[part];
1978
+ }
1979
+ return childTree;
1980
+ }
1981
+
1725
1982
  /**
1726
1983
  * Notifies this object about the request made to the container.
1727
1984
  * @param request - Request made to the handler.
@@ -1778,19 +2035,7 @@ export class ContainerRuntime
1778
2035
  }
1779
2036
  : create404Response(request);
1780
2037
  } else if (requestParser.pathParts.length > 0) {
1781
- // Differentiate between requesting the dataStore directly, or one of its children
1782
- const requestForChild = !requestParser.isLeaf(1);
1783
- const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
1784
-
1785
- const subRequest = requestParser.createSubRequest(1);
1786
- // We always expect createSubRequest to include a leading slash, but asserting here to protect against
1787
- // unintentionally modifying the url if that changes.
1788
- assert(
1789
- subRequest.url.startsWith("/"),
1790
- 0x126 /* "Expected createSubRequest url to include a leading slash" */,
1791
- );
1792
- // eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
1793
- return dataStore.request(subRequest);
2038
+ return await this.channelCollection.request(request);
1794
2039
  }
1795
2040
 
1796
2041
  return create404Response(request);
@@ -1808,54 +2053,7 @@ export class ContainerRuntime
1808
2053
  private readonly entryPoint: LazyPromise<FluidObject>;
1809
2054
 
1810
2055
  private internalId(maybeAlias: string): string {
1811
- return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
1812
- }
1813
-
1814
- private async getDataStoreFromRequest(
1815
- id: string,
1816
- request: IRequest,
1817
- requestForChild: boolean,
1818
- ): Promise<IFluidDataStoreChannel> {
1819
- const headerData: RuntimeHeaderData = {};
1820
- if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
1821
- headerData.wait = request.headers[RuntimeHeaders.wait];
1822
- }
1823
- if (typeof request.headers?.[RuntimeHeaders.viaHandle] === "boolean") {
1824
- headerData.viaHandle = request.headers[RuntimeHeaders.viaHandle];
1825
- }
1826
- if (typeof request.headers?.[AllowTombstoneRequestHeaderKey] === "boolean") {
1827
- headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
1828
- }
1829
- if (typeof request.headers?.[AllowInactiveRequestHeaderKey] === "boolean") {
1830
- headerData.allowInactive = request.headers[AllowInactiveRequestHeaderKey];
1831
- }
1832
-
1833
- // We allow Tombstone requests for sub-DataStore objects
1834
- if (requestForChild) {
1835
- headerData.allowTombstone = true;
1836
- }
1837
-
1838
- await this.dataStores.waitIfPendingAlias(id);
1839
- const internalId = this.internalId(id);
1840
- const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
1841
-
1842
- // Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
1843
- // the same as GC nodes id.
1844
- const urlWithoutQuery = trimLeadingAndTrailingSlashes(request.url.split("?")[0]);
1845
- // Get the initial snapshot details which contain the data store package path.
1846
- const details = await dataStoreContext.getInitialSnapshotDetails();
1847
-
1848
- // Note that this will throw if the data store is inactive or tombstoned and throwing on incorrect usage
1849
- // is configured.
1850
- this.garbageCollector.nodeUpdated(
1851
- `/${urlWithoutQuery}`,
1852
- "Loaded",
1853
- undefined /* timestampMs */,
1854
- details.pkg,
1855
- request,
1856
- headerData,
1857
- );
1858
- return dataStoreContext.realize();
2056
+ return this.channelCollection.internalId(maybeAlias);
1859
2057
  }
1860
2058
 
1861
2059
  /** Adds the container's metadata to the given summary tree. */
@@ -1872,7 +2070,7 @@ export class ContainerRuntime
1872
2070
  extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
1873
2071
  this.messageAtLastSummary,
1874
2072
  telemetryDocumentId: this.telemetryDocumentId,
1875
- idCompressorEnabled: this.idCompressorEnabled ? true : undefined,
2073
+ idCompressorMode: this.idCompressorMode,
1876
2074
  };
1877
2075
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
1878
2076
  }
@@ -1885,12 +2083,8 @@ export class ContainerRuntime
1885
2083
  ) {
1886
2084
  this.addMetadataToSummary(summaryTree);
1887
2085
 
1888
- if (this.idCompressorEnabled) {
1889
- assert(
1890
- this.idCompressor !== undefined,
1891
- 0x67a /* IdCompressor should be defined if enabled */,
1892
- );
1893
- const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
2086
+ if (this._idCompressor) {
2087
+ const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
1894
2088
  addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
1895
2089
  }
1896
2090
 
@@ -1899,7 +2093,7 @@ export class ContainerRuntime
1899
2093
  addBlobToSummary(summaryTree, chunksBlobName, content);
1900
2094
  }
1901
2095
 
1902
- const dataStoreAliases = this.dataStores.aliases;
2096
+ const dataStoreAliases = this.channelCollection.aliases;
1903
2097
  if (dataStoreAliases.size > 0) {
1904
2098
  addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
1905
2099
  }
@@ -1915,7 +2109,7 @@ export class ContainerRuntime
1915
2109
  // Some storage (like git) doesn't allow empty tree, so we can omit it.
1916
2110
  // and the blob manager can handle the tree not existing when loading
1917
2111
  if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
1918
- addTreeToSummary(summaryTree, blobsTreeName, blobManagerSummary);
2112
+ addSummarizeResultToSummary(summaryTree, blobsTreeName, blobManagerSummary);
1919
2113
  }
1920
2114
 
1921
2115
  const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
@@ -2015,16 +2209,12 @@ export class ContainerRuntime
2015
2209
  const opContents = this.parseLocalOpContent(serializedOpContent);
2016
2210
  switch (opContents.type) {
2017
2211
  case ContainerMessageType.FluidDataStoreOp:
2018
- return this.dataStores.applyStashedOp(opContents.contents);
2019
2212
  case ContainerMessageType.Attach:
2020
- return this.dataStores.applyStashedAttachOp(opContents.contents);
2213
+ case ContainerMessageType.Alias:
2214
+ return this.channelCollection.applyStashedOp(opContents);
2021
2215
  case ContainerMessageType.IdAllocation:
2022
- assert(
2023
- this.idCompressor !== undefined,
2024
- 0x67b /* IdCompressor should be defined if enabled */,
2025
- );
2216
+ assert(this.idCompressorMode !== "off", 0x8f1 /* ID compressor should be in use */);
2026
2217
  return;
2027
- case ContainerMessageType.Alias:
2028
2218
  case ContainerMessageType.BlobAttach:
2029
2219
  return;
2030
2220
  case ContainerMessageType.ChunkedOp:
@@ -2054,11 +2244,27 @@ export class ContainerRuntime
2054
2244
  this.closeFn(error);
2055
2245
  throw error;
2056
2246
  }
2247
+ // Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
2248
+ // All we can do is ignore it (similar to on process).
2057
2249
  }
2058
2250
  }
2059
2251
  }
2060
2252
 
2061
2253
  public setConnectionState(connected: boolean, clientId?: string) {
2254
+ if (connected && this.idCompressorMode === "delayed" && !this.compressorLoadInitiated) {
2255
+ this.compressorLoadInitiated = true;
2256
+ this.createIdCompressor()
2257
+ .then((compressor) => {
2258
+ this._idCompressor = compressor;
2259
+ for (const range of this.pendingIdCompressorOps) {
2260
+ this._idCompressor.finalizeCreationRange(range);
2261
+ }
2262
+ this.pendingIdCompressorOps = [];
2263
+ })
2264
+ .catch((error) => {
2265
+ this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
2266
+ });
2267
+ }
2062
2268
  if (connected === false && this.delayConnectClientId !== undefined) {
2063
2269
  this.delayConnectClientId = undefined;
2064
2270
  this.mc.logger.sendTelemetryEvent({
@@ -2151,7 +2357,7 @@ export class ContainerRuntime
2151
2357
  this.replayPendingStates();
2152
2358
  }
2153
2359
 
2154
- this.dataStores.setConnectionState(connected, clientId);
2360
+ this.channelCollection.setConnectionState(connected, clientId);
2155
2361
  this.garbageCollector.setConnectionState(connected, clientId);
2156
2362
 
2157
2363
  raiseConnectedEvent(this.mc.logger, this, connected, clientId);
@@ -2254,17 +2460,9 @@ export class ContainerRuntime
2254
2460
  const { local } = messageWithContext;
2255
2461
  switch (messageWithContext.message.type) {
2256
2462
  case ContainerMessageType.Attach:
2257
- this.dataStores.processAttachMessage(messageWithContext.message, local);
2258
- break;
2259
2463
  case ContainerMessageType.Alias:
2260
- this.dataStores.processAliasMessage(
2261
- messageWithContext.message,
2262
- localOpMetadata,
2263
- local,
2264
- );
2265
- break;
2266
2464
  case ContainerMessageType.FluidDataStoreOp:
2267
- this.dataStores.processFluidDataStoreOp(
2465
+ this.channelCollection.process(
2268
2466
  messageWithContext.message,
2269
2467
  local,
2270
2468
  localOpMetadata,
@@ -2275,17 +2473,23 @@ export class ContainerRuntime
2275
2473
  this.blobManager.processBlobAttachOp(messageWithContext.message, local);
2276
2474
  break;
2277
2475
  case ContainerMessageType.IdAllocation:
2278
- assert(
2279
- this.idCompressor !== undefined,
2280
- 0x67c /* IdCompressor should be defined if enabled */,
2281
- );
2282
-
2283
2476
  // Don't re-finalize the range if we're processing a "savedOp" in
2284
2477
  // stashed ops flow. The compressor is stashed with these ops already processed.
2478
+ // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
2479
+ // thus we need to process all the ops.
2285
2480
  if (
2286
- (messageWithContext.message.metadata as IIdAllocationMetadata)?.savedOp !== true
2481
+ !(
2482
+ this.skipSavedCompressorOps &&
2483
+ (messageWithContext.message.metadata as IIdAllocationMetadata)?.savedOp ===
2484
+ true
2485
+ )
2287
2486
  ) {
2288
- this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
2487
+ const range = messageWithContext.message.contents;
2488
+ if (this._idCompressor === undefined) {
2489
+ this.pendingIdCompressorOps.push(range);
2490
+ } else {
2491
+ this._idCompressor.finalizeCreationRange(range);
2492
+ }
2289
2493
  }
2290
2494
  break;
2291
2495
  case ContainerMessageType.GC:
@@ -2391,7 +2595,16 @@ export class ContainerRuntime
2391
2595
  return;
2392
2596
  }
2393
2597
 
2394
- this.dataStores.processSignal(envelope.address, transformed, local);
2598
+ // Due to a mismatch between different layers in terms of
2599
+ // what is the interface of passing signals, we need to adjust
2600
+ // the signal envelope before sending it to the datastores to be processed
2601
+ const envelope2: IEnvelope = {
2602
+ address: envelope.address,
2603
+ contents: transformed.content,
2604
+ };
2605
+ transformed.content = envelope2;
2606
+
2607
+ this.channelCollection.processSignal(transformed, local);
2395
2608
  }
2396
2609
 
2397
2610
  /**
@@ -2408,6 +2621,9 @@ export class ContainerRuntime
2408
2621
  assert(this.outbox.isEmpty, 0x3cf /* reentrancy */);
2409
2622
  }
2410
2623
 
2624
+ /**
2625
+ * {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.orderSequentially}
2626
+ */
2411
2627
  public orderSequentially<T>(callback: () => T): T {
2412
2628
  let checkpoint: IBatchCheckpoint | undefined;
2413
2629
  let result: T;
@@ -2439,9 +2655,21 @@ export class ContainerRuntime
2439
2655
  throw error2;
2440
2656
  }
2441
2657
  } else {
2442
- // pre-0.58 error message: orderSequentiallyCallbackException
2443
- this.closeFn(new GenericError("orderSequentially callback exception", error));
2658
+ this.closeFn(
2659
+ wrapError(
2660
+ error,
2661
+ (errorMessage) =>
2662
+ new GenericError(
2663
+ `orderSequentially callback exception: ${errorMessage}`,
2664
+ error,
2665
+ {
2666
+ orderSequentiallyCalls: this._orderSequentiallyCalls,
2667
+ },
2668
+ ),
2669
+ ),
2670
+ );
2444
2671
  }
2672
+
2445
2673
  throw error; // throw the original error for the consumer of the runtime
2446
2674
  } finally {
2447
2675
  this._orderSequentiallyCalls--;
@@ -2463,9 +2691,17 @@ export class ContainerRuntime
2463
2691
  public async getAliasedDataStoreEntryPoint(
2464
2692
  alias: string,
2465
2693
  ): Promise<IFluidHandle<FluidObject> | undefined> {
2466
- await this.dataStores.waitIfPendingAlias(alias);
2694
+ // Back-comapatibility:
2695
+ // There are old files that were created without using data store aliasing feature, but
2696
+ // used createRoot*DataStore*() (already removed) API. Such data stores will have isRoot = true,
2697
+ // and internalID provided by user. The expectation is that such files behave as new files, where
2698
+ // same data store instances created using aliasing feature.
2699
+ // Please also see note on name collisions in DataStores.createDataStoreId()
2700
+ await this.channelCollection.waitIfPendingAlias(alias);
2467
2701
  const internalId = this.internalId(alias);
2468
- const context = await this.dataStores.getDataStoreIfAvailable(internalId, { wait: false });
2702
+ const context = await this.channelCollection.getDataStoreIfAvailable(internalId, {
2703
+ wait: false,
2704
+ });
2469
2705
  // If the data store is not available or not an alias, return undefined.
2470
2706
  if (context === undefined || !(await context.isRoot())) {
2471
2707
  return undefined;
@@ -2486,29 +2722,26 @@ export class ContainerRuntime
2486
2722
  return channel.entryPoint;
2487
2723
  }
2488
2724
 
2489
- public createDetachedRootDataStore(
2725
+ public createDetachedDataStore(
2490
2726
  pkg: Readonly<string[]>,
2491
- rootDataStoreId: string,
2727
+ loadingGroupId?: string,
2492
2728
  ): IFluidDataStoreContextDetached {
2493
- if (rootDataStoreId.includes("/")) {
2494
- throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
2495
- }
2496
- return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
2729
+ return this.channelCollection.createDetachedDataStore(pkg, loadingGroupId);
2497
2730
  }
2498
2731
 
2499
- public createDetachedDataStore(pkg: Readonly<string[]>): IFluidDataStoreContextDetached {
2500
- return this.dataStores.createDetachedDataStoreCore(pkg, false);
2501
- }
2502
-
2503
- public async createDataStore(pkg: string | string[]): Promise<IDataStore> {
2504
- const id = uuid();
2732
+ public async createDataStore(
2733
+ pkg: Readonly<string | string[]>,
2734
+ loadingGroupId?: string,
2735
+ ): Promise<IDataStore> {
2736
+ const context = this.channelCollection.createDataStoreContext(
2737
+ Array.isArray(pkg) ? pkg : [pkg],
2738
+ undefined, // props
2739
+ loadingGroupId,
2740
+ );
2505
2741
  return channelToDataStore(
2506
- await this.dataStores
2507
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
2508
- .realize(),
2509
- id,
2510
- this,
2511
- this.dataStores,
2742
+ await context.realize(),
2743
+ context.id,
2744
+ this.channelCollection,
2512
2745
  this.mc.logger,
2513
2746
  );
2514
2747
  }
@@ -2517,17 +2750,17 @@ export class ContainerRuntime
2517
2750
  * @deprecated 0.16 Issue #1537, #3631
2518
2751
  */
2519
2752
  public async _createDataStoreWithProps(
2520
- pkg: string | string[],
2753
+ pkg: Readonly<string | string[]>,
2521
2754
  props?: any,
2522
- id = uuid(),
2523
2755
  ): Promise<IDataStore> {
2756
+ const context = this.channelCollection.createDataStoreContext(
2757
+ Array.isArray(pkg) ? pkg : [pkg],
2758
+ props,
2759
+ );
2524
2760
  return channelToDataStore(
2525
- await this.dataStores
2526
- ._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
2527
- .realize(),
2528
- id,
2529
- this,
2530
- this.dataStores,
2761
+ await context.realize(),
2762
+ context.id,
2763
+ this.channelCollection,
2531
2764
  this.mc.logger,
2532
2765
  );
2533
2766
  }
@@ -2628,22 +2861,6 @@ export class ContainerRuntime
2628
2861
  return this.submitSignalFn(envelope, targetClientId);
2629
2862
  }
2630
2863
 
2631
- /**
2632
- * Submits the signal to be sent to other clients.
2633
- * @param type - Type of the signal.
2634
- * @param content - Content of the signal.
2635
- * @param targetClientId - When specified, the signal is only sent to the provided client id.
2636
- */
2637
- public submitDataStoreSignal(
2638
- address: string,
2639
- type: string,
2640
- content: any,
2641
- targetClientId?: string,
2642
- ) {
2643
- const envelope = this.createNewSignalEnvelope(address, type, content);
2644
- return this.submitSignalFn(envelope, targetClientId);
2645
- }
2646
-
2647
2864
  public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
2648
2865
  if (attachState === AttachState.Attaching) {
2649
2866
  assert(
@@ -2661,7 +2878,7 @@ export class ContainerRuntime
2661
2878
  if (attachState === AttachState.Attached && !this.hasPendingMessages()) {
2662
2879
  this.updateDocumentDirtyState(false);
2663
2880
  }
2664
- this.dataStores.setAttachState(attachState);
2881
+ this.channelCollection.setAttachState(attachState);
2665
2882
  }
2666
2883
 
2667
2884
  /**
@@ -2681,12 +2898,12 @@ export class ContainerRuntime
2681
2898
  }
2682
2899
 
2683
2900
  // We can finalize any allocated IDs since we're the only client
2684
- const idRange = this.idCompressor?.takeNextCreationRange();
2901
+ const idRange = this._idCompressor?.takeNextCreationRange();
2685
2902
  if (idRange !== undefined) {
2686
- this.idCompressor?.finalizeCreationRange(idRange);
2903
+ this._idCompressor?.finalizeCreationRange(idRange);
2687
2904
  }
2688
2905
 
2689
- const summarizeResult = this.dataStores.createSummary(telemetryContext);
2906
+ const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
2690
2907
  // Wrap data store summaries in .channels subtree.
2691
2908
  wrapSummaryInChannelsTree(summarizeResult);
2692
2909
 
@@ -2706,7 +2923,7 @@ export class ContainerRuntime
2706
2923
  trackState: boolean,
2707
2924
  telemetryContext?: ITelemetryContext,
2708
2925
  ): Promise<ISummarizeInternalResult> {
2709
- const summarizeResult = await this.dataStores.summarize(
2926
+ const summarizeResult = await this.channelCollection.summarize(
2710
2927
  fullTree,
2711
2928
  trackState,
2712
2929
  telemetryContext,
@@ -2797,11 +3014,11 @@ export class ContainerRuntime
2797
3014
  * @see IGarbageCollectionRuntime.updateStateBeforeGC
2798
3015
  */
2799
3016
  public async updateStateBeforeGC() {
2800
- return this.dataStores.updateStateBeforeGC();
3017
+ return this.channelCollection.updateStateBeforeGC();
2801
3018
  }
2802
3019
 
2803
3020
  private async getGCDataInternal(fullGC?: boolean): Promise<IGarbageCollectionData> {
2804
- return this.dataStores.getGCData(fullGC);
3021
+ return this.channelCollection.getGCData(fullGC);
2805
3022
  }
2806
3023
 
2807
3024
  /**
@@ -2831,25 +3048,7 @@ export class ContainerRuntime
2831
3048
  this.summarizerNode.updateUsedRoutes([""]);
2832
3049
 
2833
3050
  const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(usedRoutes);
2834
- this.dataStores.updateUsedRoutes(dataStoreRoutes);
2835
- }
2836
-
2837
- /**
2838
- * This is called to update objects whose routes are unused.
2839
- * @param unusedRoutes - Data store and attachment blob routes that are unused in this Container.
2840
- */
2841
- public updateUnusedRoutes(unusedRoutes: readonly string[]) {
2842
- const { blobManagerRoutes, dataStoreRoutes } =
2843
- this.getDataStoreAndBlobManagerRoutes(unusedRoutes);
2844
- this.blobManager.updateUnusedRoutes(blobManagerRoutes);
2845
- this.dataStores.updateUnusedRoutes(dataStoreRoutes);
2846
- }
2847
-
2848
- /**
2849
- * @deprecated Replaced by deleteSweepReadyNodes.
2850
- */
2851
- public deleteUnusedNodes(unusedRoutes: readonly string[]): string[] {
2852
- throw new Error("deleteUnusedRoutes should not be called");
3051
+ this.channelCollection.updateUsedRoutes(dataStoreRoutes);
2853
3052
  }
2854
3053
 
2855
3054
  /**
@@ -2861,7 +3060,7 @@ export class ContainerRuntime
2861
3060
  const { dataStoreRoutes, blobManagerRoutes } =
2862
3061
  this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
2863
3062
 
2864
- const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
3063
+ const deletedRoutes = this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes);
2865
3064
  return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
2866
3065
  }
2867
3066
 
@@ -2877,7 +3076,7 @@ export class ContainerRuntime
2877
3076
  const { blobManagerRoutes, dataStoreRoutes } =
2878
3077
  this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
2879
3078
  this.blobManager.updateTombstonedRoutes(blobManagerRoutes);
2880
- this.dataStores.updateTombstonedRoutes(dataStoreRoutes);
3079
+ this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
2881
3080
  }
2882
3081
 
2883
3082
  /**
@@ -2897,7 +3096,7 @@ export class ContainerRuntime
2897
3096
  if (this.isBlobPath(nodePath)) {
2898
3097
  return GCNodeType.Blob;
2899
3098
  }
2900
- return this.dataStores.getGCNodeType(nodePath) ?? GCNodeType.Other;
3099
+ return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
2901
3100
  }
2902
3101
 
2903
3102
  /**
@@ -2905,12 +3104,18 @@ export class ContainerRuntime
2905
3104
  * data store or an attachment blob.
2906
3105
  */
2907
3106
  public async getGCNodePackagePath(nodePath: string): Promise<readonly string[] | undefined> {
3107
+ // GC uses "/" when adding "root" references, e.g. for Aliasing or as part of Tombstone Auto-Recovery.
3108
+ // These have no package path so return a special value.
3109
+ if (nodePath === "/") {
3110
+ return ["_gcRoot"];
3111
+ }
3112
+
2908
3113
  switch (this.getNodeType(nodePath)) {
2909
3114
  case GCNodeType.Blob:
2910
3115
  return [BlobManager.basePath];
2911
3116
  case GCNodeType.DataStore:
2912
3117
  case GCNodeType.SubDataStore:
2913
- return this.dataStores.getDataStorePackagePath(nodePath);
3118
+ return this.channelCollection.getDataStorePackagePath(nodePath);
2914
3119
  default:
2915
3120
  assert(false, 0x2de /* "Package path requested for unsupported node type." */);
2916
3121
  }
@@ -2970,7 +3175,10 @@ export class ContainerRuntime
2970
3175
  * @param srcHandle - The handle of the node that added the reference.
2971
3176
  * @param outboundHandle - The handle of the outbound node that is referenced.
2972
3177
  */
2973
- public addedGCOutboundReference(srcHandle: IFluidHandle, outboundHandle: IFluidHandle) {
3178
+ public addedGCOutboundReference(
3179
+ srcHandle: { absolutePath: string },
3180
+ outboundHandle: { absolutePath: string },
3181
+ ) {
2974
3182
  this.garbageCollector.addedOutboundReference(
2975
3183
  srcHandle.absolutePath,
2976
3184
  outboundHandle.absolutePath,
@@ -2986,7 +3194,13 @@ export class ContainerRuntime
2986
3194
  * @param options - options controlling how the summary is generated or submitted
2987
3195
  */
2988
3196
  public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
2989
- const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
3197
+ const {
3198
+ fullTree = false,
3199
+ finalAttempt = false,
3200
+ refreshLatestAck,
3201
+ summaryLogger,
3202
+ latestSummaryRefSeqNum,
3203
+ } = options;
2990
3204
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2991
3205
  // use it for all events logged during this summary.
2992
3206
  const summaryNumber = this.nextSummaryNumber;
@@ -3000,7 +3214,6 @@ export class ContainerRuntime
3000
3214
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
3001
3215
 
3002
3216
  // We close the summarizer and download a new snapshot and reload the container
3003
- let latestSnapshotVersionId: string | undefined;
3004
3217
  if (refreshLatestAck === true) {
3005
3218
  return this.prefetchLatestSummaryThenClose(
3006
3219
  createChildLogger({
@@ -3058,6 +3271,10 @@ export class ContainerRuntime
3058
3271
  this.mc.config.getBoolean(
3059
3272
  "Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
3060
3273
  ) !== true;
3274
+ const shouldValidatePreSummaryState =
3275
+ this.mc.config.getBoolean(
3276
+ "Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState",
3277
+ ) === true;
3061
3278
 
3062
3279
  let summaryRefSeqNum: number | undefined;
3063
3280
 
@@ -3072,7 +3289,33 @@ export class ContainerRuntime
3072
3289
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
3073
3290
  const lastAck = this.summaryCollection.latestAck;
3074
3291
 
3075
- this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
3292
+ const startSummaryResult = this.summarizerNode.startSummary(
3293
+ summaryRefSeqNum,
3294
+ summaryNumberLogger,
3295
+ latestSummaryRefSeqNum,
3296
+ );
3297
+
3298
+ if (
3299
+ startSummaryResult.invalidNodes > 0 ||
3300
+ startSummaryResult.mismatchNumbers.size > 0
3301
+ ) {
3302
+ summaryLogger.sendErrorEvent({
3303
+ eventName: "LatestSummaryRefSeqNumMismatch",
3304
+ details: {
3305
+ ...startSummaryResult,
3306
+ mismatchNumbers: Array.from(startSummaryResult.mismatchNumbers),
3307
+ },
3308
+ });
3309
+
3310
+ if (shouldValidatePreSummaryState && !finalAttempt) {
3311
+ return {
3312
+ stage: "base",
3313
+ referenceSequenceNumber: summaryRefSeqNum,
3314
+ minimumSequenceNumber,
3315
+ error: `Summarizer node state inconsistent with summarizer state.`,
3316
+ };
3317
+ }
3318
+ }
3076
3319
 
3077
3320
  // Helper function to check whether we should still continue between each async step.
3078
3321
  const checkContinue = (): { continue: true } | { continue: false; error: string } => {
@@ -3194,8 +3437,8 @@ export class ContainerRuntime
3194
3437
  : undefined;
3195
3438
 
3196
3439
  const summaryStats: IGeneratedSummaryStats = {
3197
- dataStoreCount: this.dataStores.size,
3198
- summarizedDataStoreCount: this.dataStores.size - handleCount,
3440
+ dataStoreCount: this.channelCollection.size,
3441
+ summarizedDataStoreCount: this.channelCollection.size - handleCount,
3199
3442
  gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
3200
3443
  gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
3201
3444
  gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
@@ -3216,34 +3459,18 @@ export class ContainerRuntime
3216
3459
  return { stage: "generate", ...generateSummaryData, error: continueResult.error };
3217
3460
  }
3218
3461
 
3219
- // It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
3220
- // summary. So if the previous summarizer closes just after submitting the summary and before
3221
- // submitting the summaryOp then we can't rely on summaryAck. So in case we have
3222
- // latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
3223
- // the one fetched from storage as parent as that is the latest.
3224
- let summaryContext: ISummaryContext;
3225
- if (
3226
- lastAck?.summaryAck.contents.handle !== latestSnapshotVersionId &&
3227
- latestSnapshotVersionId !== undefined
3228
- ) {
3229
- summaryContext = {
3230
- proposalHandle: undefined,
3231
- ackHandle: latestSnapshotVersionId,
3232
- referenceSequenceNumber: summaryRefSeqNum,
3233
- };
3234
- } else if (lastAck === undefined) {
3235
- summaryContext = {
3236
- proposalHandle: undefined,
3237
- ackHandle: this.loadedFromVersionId,
3238
- referenceSequenceNumber: summaryRefSeqNum,
3239
- };
3240
- } else {
3241
- summaryContext = {
3242
- proposalHandle: lastAck.summaryOp.contents.handle,
3243
- ackHandle: lastAck.summaryAck.contents.handle,
3244
- referenceSequenceNumber: summaryRefSeqNum,
3245
- };
3246
- }
3462
+ const summaryContext =
3463
+ lastAck === undefined
3464
+ ? {
3465
+ proposalHandle: undefined,
3466
+ ackHandle: this.loadedFromVersionId,
3467
+ referenceSequenceNumber: summaryRefSeqNum,
3468
+ }
3469
+ : {
3470
+ proposalHandle: lastAck.summaryOp.contents.handle,
3471
+ ackHandle: lastAck.summaryAck.contents.handle,
3472
+ referenceSequenceNumber: summaryRefSeqNum,
3473
+ };
3247
3474
 
3248
3475
  let handle: string;
3249
3476
  try {
@@ -3408,28 +3635,15 @@ export class ContainerRuntime
3408
3635
  }
3409
3636
  }
3410
3637
 
3411
- public submitDataStoreOp(
3412
- id: string,
3638
+ public submitMessage(
3639
+ type:
3640
+ | ContainerMessageType.FluidDataStoreOp
3641
+ | ContainerMessageType.Alias
3642
+ | ContainerMessageType.Attach,
3413
3643
  contents: any,
3414
3644
  localOpMetadata: unknown = undefined,
3415
3645
  ): void {
3416
- const envelope: IEnvelope = {
3417
- address: id,
3418
- contents,
3419
- };
3420
- this.submit(
3421
- { type: ContainerMessageType.FluidDataStoreOp, contents: envelope },
3422
- localOpMetadata,
3423
- );
3424
- }
3425
-
3426
- public submitDataStoreAliasOp(contents: any, localOpMetadata: unknown): void {
3427
- const aliasMessage = contents as IDataStoreAliasMessage;
3428
- if (!isDataStoreAliasMessage(aliasMessage)) {
3429
- throw new UsageError("malformedDataStoreAliasMessage");
3430
- }
3431
-
3432
- this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
3646
+ this.submit({ type, contents }, localOpMetadata);
3433
3647
  }
3434
3648
 
3435
3649
  public async uploadBlob(
@@ -3440,35 +3654,22 @@ export class ContainerRuntime
3440
3654
  return this.blobManager.createBlob(blob, signal);
3441
3655
  }
3442
3656
 
3443
- private maybeSubmitIdAllocationOp(type: ContainerMessageType) {
3444
- if (type !== ContainerMessageType.IdAllocation) {
3445
- let idAllocationBatchMessage: BatchMessage | undefined;
3446
- let idRange: IdCreationRange | undefined;
3447
- if (this.idCompressorEnabled) {
3448
- assert(
3449
- this.idCompressor !== undefined,
3450
- 0x67d /* IdCompressor should be defined if enabled */,
3451
- );
3452
- idRange = this.idCompressor.takeNextCreationRange();
3453
- // Don't include the idRange if there weren't any Ids allocated
3454
- idRange = idRange?.ids !== undefined ? idRange : undefined;
3455
- }
3456
-
3457
- if (idRange !== undefined) {
3657
+ private submitIdAllocationOpIfNeeded(): void {
3658
+ if (this._idCompressor) {
3659
+ const idRange = this._idCompressor.takeNextCreationRange();
3660
+ // Don't include the idRange if there weren't any Ids allocated
3661
+ if (idRange?.ids !== undefined) {
3458
3662
  const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
3459
3663
  type: ContainerMessageType.IdAllocation,
3460
3664
  contents: idRange,
3461
3665
  };
3462
- idAllocationBatchMessage = {
3666
+ const idAllocationBatchMessage: BatchMessage = {
3463
3667
  contents: JSON.stringify(idAllocationMessage),
3464
3668
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
3465
3669
  metadata: undefined,
3466
3670
  localOpMetadata: undefined,
3467
3671
  type: ContainerMessageType.IdAllocation,
3468
3672
  };
3469
- }
3470
-
3471
- if (idAllocationBatchMessage !== undefined) {
3472
3673
  this.outbox.submitIdAllocation(idAllocationBatchMessage);
3473
3674
  }
3474
3675
  }
@@ -3509,43 +3710,47 @@ export class ContainerRuntime
3509
3710
  };
3510
3711
 
3511
3712
  try {
3512
- // Submit an IdAllocation op if any Ids have been generated since
3513
- // the last op was submitted. Don't submit another if it's an IdAllocation
3514
- // op as that means we're in resubmission flow and we don't want to send
3515
- // IdRanges out of order.
3516
- this.maybeSubmitIdAllocationOp(type);
3517
-
3518
- // If this is attach message for new data store, and we are in a batch, send this op out of order
3519
- // Is it safe:
3520
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
3521
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
3522
- // is stored in some DDS, i.e. only after some other op.
3523
- // Why:
3524
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
3525
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
3526
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
3527
- // these issues.
3528
- // Cons:
3529
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
3530
- // This change creates new possibility of a lot of newly created data stores never being referenced
3531
- // because client died before it had a change to submit the rest of the ops. This will create more
3532
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
3533
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
3534
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
3535
- // issue than sending.
3536
- // Please note that this does not change file format, so it can be disabled in the future if this
3537
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
3538
- if (
3539
- this.currentlyBatching() &&
3540
- type === ContainerMessageType.Attach &&
3541
- this.disableAttachReorder !== true
3542
- ) {
3543
- this.outbox.submitAttach(message);
3544
- } else if (type === ContainerMessageType.BlobAttach) {
3545
- // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
3546
- this.outbox.submitBlobAttach(message);
3713
+ // If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
3714
+ // op into the correct batch to avoid ranges being finalized out of order.
3715
+ // Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
3716
+ // any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
3717
+ if (type === ContainerMessageType.IdAllocation) {
3718
+ this.outbox.submitIdAllocation(message);
3547
3719
  } else {
3548
- this.outbox.submit(message);
3720
+ this.submitIdAllocationOpIfNeeded();
3721
+
3722
+ // If this is attach message for new data store, and we are in a batch, send this op out of order
3723
+ // Is it safe:
3724
+ // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
3725
+ // They become visible only when aliased, or handle to some sub-element of newly created datastore
3726
+ // is stored in some DDS, i.e. only after some other op.
3727
+ // Why:
3728
+ // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
3729
+ // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
3730
+ // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
3731
+ // these issues.
3732
+ // Cons:
3733
+ // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
3734
+ // This change creates new possibility of a lot of newly created data stores never being referenced
3735
+ // because client died before it had a change to submit the rest of the ops. This will create more
3736
+ // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
3737
+ // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
3738
+ // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
3739
+ // issue than sending.
3740
+ // Please note that this does not change file format, so it can be disabled in the future if this
3741
+ // optimization no longer makes sense (for example, batch compression may make it less appealing).
3742
+ if (
3743
+ this.currentlyBatching() &&
3744
+ type === ContainerMessageType.Attach &&
3745
+ this.disableAttachReorder !== true
3746
+ ) {
3747
+ this.outbox.submitAttach(message);
3748
+ } else if (type === ContainerMessageType.BlobAttach) {
3749
+ // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
3750
+ this.outbox.submitBlobAttach(message);
3751
+ } else {
3752
+ this.outbox.submit(message);
3753
+ }
3549
3754
  }
3550
3755
 
3551
3756
  if (!this.currentlyBatching()) {
@@ -3687,14 +3892,18 @@ export class ContainerRuntime
3687
3892
  localOpMetadata: unknown,
3688
3893
  opMetadata: Record<string, unknown> | undefined,
3689
3894
  ) {
3895
+ assert(
3896
+ !this.isSummarizerClient,
3897
+ 0x8f2 /* Summarizer never reconnects so should never resubmit */,
3898
+ );
3690
3899
  switch (message.type) {
3691
3900
  case ContainerMessageType.FluidDataStoreOp:
3901
+ case ContainerMessageType.Attach:
3902
+ case ContainerMessageType.Alias:
3692
3903
  // For Operations, call resubmitDataStoreOp which will find the right store
3693
3904
  // and trigger resubmission on it.
3694
- this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
3905
+ this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
3695
3906
  break;
3696
- case ContainerMessageType.Attach:
3697
- case ContainerMessageType.Alias:
3698
3907
  case ContainerMessageType.IdAllocation: {
3699
3908
  this.submit(message, localOpMetadata);
3700
3909
  break;
@@ -3708,13 +3917,14 @@ export class ContainerRuntime
3708
3917
  this.submit(message);
3709
3918
  break;
3710
3919
  case ContainerMessageType.GC:
3711
- // GC op is only sent in summarizer which should never reconnect.
3712
- throw new LoggingError("GC op not expected to be resubmitted in summarizer");
3920
+ this.submit(message);
3921
+ break;
3713
3922
  default: {
3714
3923
  // This case should be very rare - it would imply an op was stashed from a
3715
- // future version of runtime code and now is being applied on an older version
3924
+ // future version of runtime code and now is being applied on an older version.
3716
3925
  const compatBehavior = message.compatDetails?.behavior;
3717
3926
  if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
3927
+ // We do not ultimately resubmit it, to be consistent with this version of the code.
3718
3928
  this.logger.sendTelemetryEvent({
3719
3929
  eventName: "resubmitUnrecognizedMessageTypeAllowed",
3720
3930
  messageDetails: { type: message.type, compatBehavior },
@@ -3745,7 +3955,7 @@ export class ContainerRuntime
3745
3955
  case ContainerMessageType.FluidDataStoreOp:
3746
3956
  // For operations, call rollbackDataStoreOp which will find the right store
3747
3957
  // and trigger rollback on it.
3748
- this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
3958
+ this.channelCollection.rollback(type, contents, localOpMetadata);
3749
3959
  break;
3750
3960
  default:
3751
3961
  // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
@@ -3771,7 +3981,7 @@ export class ContainerRuntime
3771
3981
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
3772
3982
  */
3773
3983
  if (!result.isSummaryTracked && result.isSummaryNewer) {
3774
- const fetchResult = await this.fetchLatestSnapshotFromStorage(
3984
+ await this.fetchLatestSnapshotFromStorage(
3775
3985
  summaryLogger,
3776
3986
  {
3777
3987
  eventName: "RefreshLatestSummaryAckFetch",
@@ -3781,32 +3991,7 @@ export class ContainerRuntime
3781
3991
  readAndParseBlob,
3782
3992
  );
3783
3993
 
3784
- /**
3785
- * If the fetched snapshot is older than the one for which the ack was received, close the container.
3786
- * This should never happen because an ack should be sent after the latest summary is updated in the server.
3787
- * However, there are couple of scenarios where it's possible:
3788
- * 1. A file was modified externally resulting in modifying the snapshot's sequence number. This can lead to
3789
- * the document being unusable and we should not proceed.
3790
- * 2. The server DB failed after the ack was sent which may delete the corresponding snapshot. Ideally, in
3791
- * such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
3792
- * state.
3793
- */
3794
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3795
- const error = DataProcessingError.create(
3796
- "Fetched snapshot is older than the received ack",
3797
- "RefreshLatestSummaryAck",
3798
- undefined /* sequencedMessage */,
3799
- {
3800
- ackHandle,
3801
- summaryRefSeq,
3802
- fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3803
- },
3804
- );
3805
- this.disposeFn(error);
3806
- throw error;
3807
- }
3808
-
3809
- await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
3994
+ await this.closeStaleSummarizer();
3810
3995
  return;
3811
3996
  }
3812
3997
 
@@ -3835,7 +4020,7 @@ export class ContainerRuntime
3835
4020
  readAndParseBlob,
3836
4021
  );
3837
4022
 
3838
- await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
4023
+ await this.closeStaleSummarizer();
3839
4024
 
3840
4025
  return {
3841
4026
  stage: "base",
@@ -3845,7 +4030,7 @@ export class ContainerRuntime
3845
4030
  };
3846
4031
  }
3847
4032
 
3848
- private async closeStaleSummarizer(codePath: string): Promise<void> {
4033
+ private async closeStaleSummarizer(): Promise<void> {
3849
4034
  // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
3850
4035
  await delay(this.closeSummarizerDelayMs);
3851
4036
  this._summarizer?.stop("latestSummaryStateStale");
@@ -3859,7 +4044,7 @@ export class ContainerRuntime
3859
4044
  */
3860
4045
  private async fetchLatestSnapshotFromStorage(
3861
4046
  logger: ITelemetryLoggerExt,
3862
- event: ITelemetryGenericEvent,
4047
+ event: ITelemetryGenericEventExt,
3863
4048
  readAndParseBlob: ReadAndParseBlob,
3864
4049
  ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3865
4050
  return PerformanceEvent.timedExecAsync(
@@ -3910,50 +4095,65 @@ export class ContainerRuntime
3910
4095
  );
3911
4096
  }
3912
4097
 
3913
- public async getPendingLocalState(props?: IGetPendingLocalStateProps): Promise<unknown> {
3914
- return PerformanceEvent.timedExecAsync(
3915
- this.mc.logger,
3916
- {
3917
- eventName: "getPendingLocalState",
3918
- notifyImminentClosure: props?.notifyImminentClosure,
3919
- },
3920
- async (event) => {
3921
- this.verifyNotClosed();
3922
- // in case imminentClosure is set to true by future code, we don't
3923
- // try to change its value
3924
- if (!this.imminentClosure) {
3925
- this.imminentClosure = props?.notifyImminentClosure ?? this.imminentClosure;
3926
- }
3927
- const stopBlobAttachingSignal = props?.stopBlobAttachingSignal;
3928
- if (this._orderSequentiallyCalls !== 0) {
3929
- throw new UsageError("can't get state during orderSequentially");
3930
- }
3931
- // Flush pending batch.
3932
- // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3933
- // to close current batch.
3934
- this.flush();
3935
- const pendingAttachmentBlobs = this.imminentClosure
3936
- ? await this.blobManager.attachAndGetPendingBlobs(stopBlobAttachingSignal)
3937
- : undefined;
3938
- const pending = this.pendingStateManager.getLocalState();
3939
- if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3940
- return; // no pending state to save
3941
- }
4098
+ public getPendingLocalState(props?: IGetPendingLocalStateProps): unknown {
4099
+ this.verifyNotClosed();
3942
4100
 
3943
- const pendingIdCompressorState = this.idCompressor?.serialize(true);
4101
+ if (this._orderSequentiallyCalls !== 0) {
4102
+ throw new UsageError("can't get state during orderSequentially");
4103
+ }
4104
+ this.imminentClosure ||= props?.notifyImminentClosure ?? false;
4105
+
4106
+ const getSyncState = (
4107
+ pendingAttachmentBlobs?: IPendingBlobs,
4108
+ ): IPendingRuntimeState | undefined => {
4109
+ const pending = this.pendingStateManager.getLocalState();
4110
+ if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
4111
+ return; // no pending state to save
4112
+ }
3944
4113
 
3945
- const pendingState: IPendingRuntimeState = {
3946
- pending,
3947
- pendingAttachmentBlobs,
3948
- pendingIdCompressorState,
3949
- };
3950
- event.end({
3951
- attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
3952
- pendingOpsSize: pending?.pendingStates.length,
3953
- });
3954
- return pendingState;
3955
- },
3956
- );
4114
+ const pendingIdCompressorState = this._idCompressor?.serialize(true);
4115
+
4116
+ return {
4117
+ pending,
4118
+ pendingIdCompressorState,
4119
+ pendingAttachmentBlobs,
4120
+ sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
4121
+ };
4122
+ };
4123
+ const perfEvent = {
4124
+ eventName: "getPendingLocalState",
4125
+ notifyImminentClosure: props?.notifyImminentClosure,
4126
+ };
4127
+ const logAndReturnPendingState = (
4128
+ event: PerformanceEvent,
4129
+ pendingState?: IPendingRuntimeState,
4130
+ ) => {
4131
+ event.end({
4132
+ attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
4133
+ pendingOpsSize: pendingState?.pending?.pendingStates.length,
4134
+ });
4135
+ return pendingState;
4136
+ };
4137
+
4138
+ // Flush pending batch.
4139
+ // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
4140
+ // to close current batch.
4141
+ this.flush();
4142
+
4143
+ return props?.notifyImminentClosure === true
4144
+ ? PerformanceEvent.timedExecAsync(this.mc.logger, perfEvent, async (event) =>
4145
+ logAndReturnPendingState(
4146
+ event,
4147
+ getSyncState(
4148
+ await this.blobManager.attachAndGetPendingBlobs(
4149
+ props?.stopBlobAttachingSignal,
4150
+ ),
4151
+ ),
4152
+ ),
4153
+ )
4154
+ : PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) =>
4155
+ logAndReturnPendingState(event, getSyncState()),
4156
+ );
3957
4157
  }
3958
4158
 
3959
4159
  public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {