@fluidframework/container-runtime 2.0.0-internal.6.1.1 → 2.0.0-internal.6.3.0

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 (477) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +4 -3
  3. package/dist/batchTracker.d.ts +1 -1
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js +5 -4
  6. package/dist/batchTracker.js.map +1 -1
  7. package/dist/blobManager.d.ts +4 -21
  8. package/dist/blobManager.d.ts.map +1 -1
  9. package/dist/blobManager.js +119 -185
  10. package/dist/blobManager.js.map +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +13 -12
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +99 -16
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +380 -242
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.d.ts.map +1 -1
  19. package/dist/dataStore.js +4 -5
  20. package/dist/dataStore.js.map +1 -1
  21. package/dist/dataStoreContext.d.ts +2 -1
  22. package/dist/dataStoreContext.d.ts.map +1 -1
  23. package/dist/dataStoreContext.js +40 -41
  24. package/dist/dataStoreContext.js.map +1 -1
  25. package/dist/dataStoreContexts.d.ts +1 -2
  26. package/dist/dataStoreContexts.d.ts.map +1 -1
  27. package/dist/dataStoreContexts.js +7 -8
  28. package/dist/dataStoreContexts.js.map +1 -1
  29. package/dist/dataStoreRegistry.js +2 -2
  30. package/dist/dataStoreRegistry.js.map +1 -1
  31. package/dist/dataStores.d.ts.map +1 -1
  32. package/dist/dataStores.js +23 -25
  33. package/dist/dataStores.js.map +1 -1
  34. package/dist/deltaManagerProxyBase.d.ts +1 -1
  35. package/dist/deltaManagerProxyBase.js +2 -2
  36. package/dist/deltaManagerProxyBase.js.map +1 -1
  37. package/dist/deltaScheduler.js +6 -6
  38. package/dist/deltaScheduler.js.map +1 -1
  39. package/dist/error.d.ts +14 -0
  40. package/dist/error.d.ts.map +1 -0
  41. package/dist/error.js +21 -0
  42. package/dist/error.js.map +1 -0
  43. package/dist/gc/garbageCollection.d.ts +4 -6
  44. package/dist/gc/garbageCollection.d.ts.map +1 -1
  45. package/dist/gc/garbageCollection.js +26 -25
  46. package/dist/gc/garbageCollection.js.map +1 -1
  47. package/dist/gc/gcConfigs.d.ts.map +1 -1
  48. package/dist/gc/gcConfigs.js +5 -3
  49. package/dist/gc/gcConfigs.js.map +1 -1
  50. package/dist/gc/gcDefinitions.d.ts +4 -2
  51. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  52. package/dist/gc/gcDefinitions.js.map +1 -1
  53. package/dist/gc/gcHelpers.js +7 -7
  54. package/dist/gc/gcHelpers.js.map +1 -1
  55. package/dist/gc/gcSummaryStateTracker.d.ts +4 -7
  56. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  57. package/dist/gc/gcSummaryStateTracker.js +15 -52
  58. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  59. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  60. package/dist/gc/gcTelemetry.js +2 -0
  61. package/dist/gc/gcTelemetry.js.map +1 -1
  62. package/dist/gc/gcUnreferencedStateTracker.js +4 -4
  63. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  64. package/dist/gc/index.d.ts +1 -1
  65. package/dist/gc/index.d.ts.map +1 -1
  66. package/dist/gc/index.js +1 -2
  67. package/dist/gc/index.js.map +1 -1
  68. package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
  69. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  70. package/dist/id-compressor/appendOnlySortedMap.js +26 -68
  71. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  72. package/dist/id-compressor/finalSpace.d.ts +29 -0
  73. package/dist/id-compressor/finalSpace.d.ts.map +1 -0
  74. package/dist/id-compressor/finalSpace.js +62 -0
  75. package/dist/id-compressor/finalSpace.js.map +1 -0
  76. package/dist/id-compressor/idCompressor.d.ts +25 -250
  77. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  78. package/dist/id-compressor/idCompressor.js +387 -1150
  79. package/dist/id-compressor/idCompressor.js.map +1 -1
  80. package/dist/id-compressor/identifiers.d.ts +32 -0
  81. package/dist/id-compressor/identifiers.d.ts.map +1 -0
  82. package/dist/id-compressor/identifiers.js +15 -0
  83. package/dist/id-compressor/identifiers.js.map +1 -0
  84. package/dist/id-compressor/index.d.ts +5 -6
  85. package/dist/id-compressor/index.d.ts.map +1 -1
  86. package/dist/id-compressor/index.js +20 -26
  87. package/dist/id-compressor/index.js.map +1 -1
  88. package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
  89. package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
  90. package/dist/id-compressor/persistanceUtilities.js +43 -0
  91. package/dist/id-compressor/persistanceUtilities.js.map +1 -0
  92. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  93. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  94. package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
  95. package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  96. package/dist/id-compressor/sessions.d.ts +115 -0
  97. package/dist/id-compressor/sessions.d.ts.map +1 -0
  98. package/dist/id-compressor/sessions.js +305 -0
  99. package/dist/id-compressor/sessions.js.map +1 -0
  100. package/dist/id-compressor/utilities.d.ts +49 -0
  101. package/dist/id-compressor/utilities.d.ts.map +1 -0
  102. package/dist/id-compressor/utilities.js +166 -0
  103. package/dist/id-compressor/utilities.js.map +1 -0
  104. package/dist/index.d.ts +3 -3
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +6 -4
  107. package/dist/index.js.map +1 -1
  108. package/dist/opLifecycle/opCompressor.js +5 -5
  109. package/dist/opLifecycle/opCompressor.js.map +1 -1
  110. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  111. package/dist/opLifecycle/opDecompressor.js +11 -10
  112. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  113. package/dist/opLifecycle/opGroupingManager.js +3 -3
  114. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  115. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  116. package/dist/opLifecycle/opSplitter.js +14 -15
  117. package/dist/opLifecycle/opSplitter.js.map +1 -1
  118. package/dist/opLifecycle/outbox.d.ts +1 -0
  119. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  120. package/dist/opLifecycle/outbox.js +16 -17
  121. package/dist/opLifecycle/outbox.js.map +1 -1
  122. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  123. package/dist/opLifecycle/remoteMessageProcessor.js +11 -5
  124. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  125. package/dist/packageVersion.d.ts +1 -1
  126. package/dist/packageVersion.js +1 -1
  127. package/dist/packageVersion.js.map +1 -1
  128. package/dist/pendingStateManager.d.ts +12 -5
  129. package/dist/pendingStateManager.d.ts.map +1 -1
  130. package/dist/pendingStateManager.js +36 -23
  131. package/dist/pendingStateManager.js.map +1 -1
  132. package/dist/scheduleManager.d.ts.map +1 -1
  133. package/dist/scheduleManager.js +23 -23
  134. package/dist/scheduleManager.js.map +1 -1
  135. package/dist/summary/index.d.ts +3 -3
  136. package/dist/summary/index.d.ts.map +1 -1
  137. package/dist/summary/index.js +2 -1
  138. package/dist/summary/index.js.map +1 -1
  139. package/dist/summary/orderedClientElection.d.ts +2 -3
  140. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  141. package/dist/summary/orderedClientElection.js +8 -8
  142. package/dist/summary/orderedClientElection.js.map +1 -1
  143. package/dist/summary/runWhileConnectedCoordinator.js +3 -3
  144. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  145. package/dist/summary/runningSummarizer.d.ts +27 -4
  146. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  147. package/dist/summary/runningSummarizer.js +246 -74
  148. package/dist/summary/runningSummarizer.js.map +1 -1
  149. package/dist/summary/summarizer.d.ts +6 -5
  150. package/dist/summary/summarizer.d.ts.map +1 -1
  151. package/dist/summary/summarizer.js +73 -69
  152. package/dist/summary/summarizer.js.map +1 -1
  153. package/dist/summary/summarizerClientElection.d.ts +2 -2
  154. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  155. package/dist/summary/summarizerClientElection.js +2 -2
  156. package/dist/summary/summarizerClientElection.js.map +1 -1
  157. package/dist/summary/summarizerHeuristics.js +2 -2
  158. package/dist/summary/summarizerHeuristics.js.map +1 -1
  159. package/dist/summary/summarizerNode/index.d.ts +1 -1
  160. package/dist/summary/summarizerNode/index.d.ts.map +1 -1
  161. package/dist/summary/summarizerNode/index.js.map +1 -1
  162. package/dist/summary/summarizerNode/summarizerNode.d.ts +5 -14
  163. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  164. package/dist/summary/summarizerNode/summarizerNode.js +32 -109
  165. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  166. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  167. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  168. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  169. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
  170. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  171. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +5 -88
  172. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  173. package/dist/summary/summarizerTypes.d.ts +38 -25
  174. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  175. package/dist/summary/summarizerTypes.js.map +1 -1
  176. package/dist/summary/summaryCollection.d.ts +2 -3
  177. package/dist/summary/summaryCollection.d.ts.map +1 -1
  178. package/dist/summary/summaryCollection.js +9 -8
  179. package/dist/summary/summaryCollection.js.map +1 -1
  180. package/dist/summary/summaryFormat.js +2 -2
  181. package/dist/summary/summaryFormat.js.map +1 -1
  182. package/dist/summary/summaryGenerator.d.ts +10 -4
  183. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  184. package/dist/summary/summaryGenerator.js +52 -48
  185. package/dist/summary/summaryGenerator.js.map +1 -1
  186. package/dist/summary/summaryManager.d.ts +7 -6
  187. package/dist/summary/summaryManager.d.ts.map +1 -1
  188. package/dist/summary/summaryManager.js +30 -22
  189. package/dist/summary/summaryManager.js.map +1 -1
  190. package/lib/batchTracker.d.ts +1 -1
  191. package/lib/batchTracker.d.ts.map +1 -1
  192. package/lib/batchTracker.js +3 -2
  193. package/lib/batchTracker.js.map +1 -1
  194. package/lib/blobManager.d.ts +4 -21
  195. package/lib/blobManager.d.ts.map +1 -1
  196. package/lib/blobManager.js +91 -157
  197. package/lib/blobManager.js.map +1 -1
  198. package/lib/connectionTelemetry.d.ts.map +1 -1
  199. package/lib/connectionTelemetry.js +2 -1
  200. package/lib/connectionTelemetry.js.map +1 -1
  201. package/lib/containerRuntime.d.ts +99 -16
  202. package/lib/containerRuntime.d.ts.map +1 -1
  203. package/lib/containerRuntime.js +332 -192
  204. package/lib/containerRuntime.js.map +1 -1
  205. package/lib/dataStore.d.ts.map +1 -1
  206. package/lib/dataStore.js +2 -3
  207. package/lib/dataStore.js.map +1 -1
  208. package/lib/dataStoreContext.d.ts +2 -1
  209. package/lib/dataStoreContext.d.ts.map +1 -1
  210. package/lib/dataStoreContext.js +3 -4
  211. package/lib/dataStoreContext.js.map +1 -1
  212. package/lib/dataStoreContexts.d.ts +1 -2
  213. package/lib/dataStoreContexts.d.ts.map +1 -1
  214. package/lib/dataStoreContexts.js +1 -2
  215. package/lib/dataStoreContexts.js.map +1 -1
  216. package/lib/dataStoreRegistry.js +1 -1
  217. package/lib/dataStoreRegistry.js.map +1 -1
  218. package/lib/dataStores.d.ts.map +1 -1
  219. package/lib/dataStores.js +2 -4
  220. package/lib/dataStores.js.map +1 -1
  221. package/lib/deltaManagerProxyBase.d.ts +1 -1
  222. package/lib/deltaManagerProxyBase.js +1 -1
  223. package/lib/deltaManagerProxyBase.js.map +1 -1
  224. package/lib/deltaScheduler.js +1 -1
  225. package/lib/deltaScheduler.js.map +1 -1
  226. package/lib/error.d.ts +14 -0
  227. package/lib/error.d.ts.map +1 -0
  228. package/lib/error.js +17 -0
  229. package/lib/error.js.map +1 -0
  230. package/lib/gc/garbageCollection.d.ts +4 -6
  231. package/lib/gc/garbageCollection.d.ts.map +1 -1
  232. package/lib/gc/garbageCollection.js +26 -25
  233. package/lib/gc/garbageCollection.js.map +1 -1
  234. package/lib/gc/gcConfigs.d.ts.map +1 -1
  235. package/lib/gc/gcConfigs.js +3 -1
  236. package/lib/gc/gcConfigs.js.map +1 -1
  237. package/lib/gc/gcDefinitions.d.ts +4 -2
  238. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  239. package/lib/gc/gcDefinitions.js.map +1 -1
  240. package/lib/gc/gcHelpers.js +1 -1
  241. package/lib/gc/gcHelpers.js.map +1 -1
  242. package/lib/gc/gcSummaryStateTracker.d.ts +4 -7
  243. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  244. package/lib/gc/gcSummaryStateTracker.js +16 -53
  245. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  246. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  247. package/lib/gc/gcTelemetry.js +2 -0
  248. package/lib/gc/gcTelemetry.js.map +1 -1
  249. package/lib/gc/gcUnreferencedStateTracker.js +1 -1
  250. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  251. package/lib/gc/index.d.ts +1 -1
  252. package/lib/gc/index.d.ts.map +1 -1
  253. package/lib/gc/index.js +1 -1
  254. package/lib/gc/index.js.map +1 -1
  255. package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
  256. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  257. package/lib/id-compressor/appendOnlySortedMap.js +25 -66
  258. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  259. package/lib/id-compressor/finalSpace.d.ts +29 -0
  260. package/lib/id-compressor/finalSpace.d.ts.map +1 -0
  261. package/lib/id-compressor/finalSpace.js +58 -0
  262. package/lib/id-compressor/finalSpace.js.map +1 -0
  263. package/lib/id-compressor/idCompressor.d.ts +25 -250
  264. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  265. package/lib/id-compressor/idCompressor.js +382 -1139
  266. package/lib/id-compressor/idCompressor.js.map +1 -1
  267. package/lib/id-compressor/identifiers.d.ts +32 -0
  268. package/lib/id-compressor/identifiers.d.ts.map +1 -0
  269. package/lib/id-compressor/identifiers.js +11 -0
  270. package/lib/id-compressor/identifiers.js.map +1 -0
  271. package/lib/id-compressor/index.d.ts +5 -6
  272. package/lib/id-compressor/index.d.ts.map +1 -1
  273. package/lib/id-compressor/index.js +5 -6
  274. package/lib/id-compressor/index.js.map +1 -1
  275. package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
  276. package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
  277. package/lib/id-compressor/persistanceUtilities.js +34 -0
  278. package/lib/id-compressor/persistanceUtilities.js.map +1 -0
  279. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  280. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  281. package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
  282. package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  283. package/lib/id-compressor/sessions.d.ts +115 -0
  284. package/lib/id-compressor/sessions.d.ts.map +1 -0
  285. package/lib/id-compressor/sessions.js +290 -0
  286. package/lib/id-compressor/sessions.js.map +1 -0
  287. package/lib/id-compressor/utilities.d.ts +49 -0
  288. package/lib/id-compressor/utilities.d.ts.map +1 -0
  289. package/lib/id-compressor/utilities.js +148 -0
  290. package/lib/id-compressor/utilities.js.map +1 -0
  291. package/lib/index.d.ts +3 -3
  292. package/lib/index.d.ts.map +1 -1
  293. package/lib/index.js +2 -2
  294. package/lib/index.js.map +1 -1
  295. package/lib/opLifecycle/opCompressor.js +3 -3
  296. package/lib/opLifecycle/opCompressor.js.map +1 -1
  297. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  298. package/lib/opLifecycle/opDecompressor.js +2 -1
  299. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  300. package/lib/opLifecycle/opGroupingManager.js +1 -1
  301. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  302. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  303. package/lib/opLifecycle/opSplitter.js +2 -3
  304. package/lib/opLifecycle/opSplitter.js.map +1 -1
  305. package/lib/opLifecycle/outbox.d.ts +1 -0
  306. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  307. package/lib/opLifecycle/outbox.js +7 -8
  308. package/lib/opLifecycle/outbox.js.map +1 -1
  309. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  310. package/lib/opLifecycle/remoteMessageProcessor.js +12 -6
  311. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  312. package/lib/packageVersion.d.ts +1 -1
  313. package/lib/packageVersion.js +1 -1
  314. package/lib/packageVersion.js.map +1 -1
  315. package/lib/pendingStateManager.d.ts +12 -5
  316. package/lib/pendingStateManager.d.ts.map +1 -1
  317. package/lib/pendingStateManager.js +21 -8
  318. package/lib/pendingStateManager.js.map +1 -1
  319. package/lib/scheduleManager.d.ts.map +1 -1
  320. package/lib/scheduleManager.js +3 -3
  321. package/lib/scheduleManager.js.map +1 -1
  322. package/lib/summary/index.d.ts +3 -3
  323. package/lib/summary/index.d.ts.map +1 -1
  324. package/lib/summary/index.js +1 -1
  325. package/lib/summary/index.js.map +1 -1
  326. package/lib/summary/orderedClientElection.d.ts +2 -3
  327. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  328. package/lib/summary/orderedClientElection.js +3 -3
  329. package/lib/summary/orderedClientElection.js.map +1 -1
  330. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  331. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  332. package/lib/summary/runningSummarizer.d.ts +27 -4
  333. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  334. package/lib/summary/runningSummarizer.js +240 -68
  335. package/lib/summary/runningSummarizer.js.map +1 -1
  336. package/lib/summary/summarizer.d.ts +6 -5
  337. package/lib/summary/summarizer.d.ts.map +1 -1
  338. package/lib/summary/summarizer.js +69 -65
  339. package/lib/summary/summarizer.js.map +1 -1
  340. package/lib/summary/summarizerClientElection.d.ts +2 -2
  341. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  342. package/lib/summary/summarizerClientElection.js +1 -1
  343. package/lib/summary/summarizerClientElection.js.map +1 -1
  344. package/lib/summary/summarizerHeuristics.js +1 -1
  345. package/lib/summary/summarizerHeuristics.js.map +1 -1
  346. package/lib/summary/summarizerNode/index.d.ts +1 -1
  347. package/lib/summary/summarizerNode/index.d.ts.map +1 -1
  348. package/lib/summary/summarizerNode/index.js.map +1 -1
  349. package/lib/summary/summarizerNode/summarizerNode.d.ts +5 -14
  350. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  351. package/lib/summary/summarizerNode/summarizerNode.js +16 -93
  352. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  353. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
  354. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  355. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  356. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
  357. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  358. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -86
  359. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  360. package/lib/summary/summarizerTypes.d.ts +38 -25
  361. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  362. package/lib/summary/summarizerTypes.js.map +1 -1
  363. package/lib/summary/summaryCollection.d.ts +2 -3
  364. package/lib/summary/summaryCollection.d.ts.map +1 -1
  365. package/lib/summary/summaryCollection.js +2 -1
  366. package/lib/summary/summaryCollection.js.map +1 -1
  367. package/lib/summary/summaryFormat.js +1 -1
  368. package/lib/summary/summaryFormat.js.map +1 -1
  369. package/lib/summary/summaryGenerator.d.ts +10 -4
  370. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  371. package/lib/summary/summaryGenerator.js +46 -42
  372. package/lib/summary/summaryGenerator.js.map +1 -1
  373. package/lib/summary/summaryManager.d.ts +7 -6
  374. package/lib/summary/summaryManager.d.ts.map +1 -1
  375. package/lib/summary/summaryManager.js +26 -18
  376. package/lib/summary/summaryManager.js.map +1 -1
  377. package/package.json +30 -29
  378. package/src/batchTracker.ts +3 -2
  379. package/src/blobManager.ts +105 -185
  380. package/src/connectionTelemetry.ts +2 -1
  381. package/src/containerRuntime.ts +481 -267
  382. package/src/dataStore.ts +2 -3
  383. package/src/dataStoreContext.ts +5 -8
  384. package/src/dataStoreContexts.ts +2 -4
  385. package/src/dataStoreRegistry.ts +1 -1
  386. package/src/dataStores.ts +4 -7
  387. package/src/deltaManagerProxyBase.ts +1 -1
  388. package/src/deltaScheduler.ts +1 -1
  389. package/src/error.ts +18 -0
  390. package/src/gc/garbageCollection.ts +39 -41
  391. package/src/gc/gcConfigs.ts +4 -2
  392. package/src/gc/gcDefinitions.ts +4 -6
  393. package/src/gc/gcHelpers.ts +1 -1
  394. package/src/gc/gcSummaryStateTracker.ts +19 -65
  395. package/src/gc/gcTelemetry.ts +2 -0
  396. package/src/gc/gcUnreferencedStateTracker.ts +1 -1
  397. package/src/gc/index.ts +0 -1
  398. package/src/id-compressor/appendOnlySortedMap.ts +26 -87
  399. package/src/id-compressor/finalSpace.ts +67 -0
  400. package/src/id-compressor/idCompressor.ts +456 -1681
  401. package/src/id-compressor/identifiers.ts +42 -0
  402. package/src/id-compressor/index.ts +11 -20
  403. package/src/id-compressor/persistanceUtilities.ts +58 -0
  404. package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
  405. package/src/id-compressor/sessions.ts +405 -0
  406. package/src/id-compressor/utilities.ts +187 -0
  407. package/src/index.ts +7 -1
  408. package/src/opLifecycle/opCompressor.ts +3 -3
  409. package/src/opLifecycle/opDecompressor.ts +2 -1
  410. package/src/opLifecycle/opGroupingManager.ts +1 -1
  411. package/src/opLifecycle/opSplitter.ts +4 -4
  412. package/src/opLifecycle/outbox.ts +14 -11
  413. package/src/opLifecycle/remoteMessageProcessor.ts +19 -6
  414. package/src/packageVersion.ts +1 -1
  415. package/src/pendingStateManager.ts +50 -29
  416. package/src/scheduleManager.ts +6 -4
  417. package/src/summary/index.ts +4 -3
  418. package/src/summary/orderedClientElection.ts +8 -5
  419. package/src/summary/runWhileConnectedCoordinator.ts +1 -1
  420. package/src/summary/runningSummarizer.ts +273 -97
  421. package/src/summary/summarizer.ts +23 -12
  422. package/src/summary/summarizerClientElection.ts +2 -2
  423. package/src/summary/summarizerHeuristics.ts +1 -1
  424. package/src/summary/summarizerNode/index.ts +1 -2
  425. package/src/summary/summarizerNode/summarizerNode.ts +23 -145
  426. package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -38
  427. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +3 -123
  428. package/src/summary/summarizerTypes.ts +40 -25
  429. package/src/summary/summaryCollection.ts +3 -3
  430. package/src/summary/summaryFormat.ts +1 -1
  431. package/src/summary/summaryGenerator.ts +52 -55
  432. package/src/summary/summaryManager.ts +36 -13
  433. package/dist/id-compressor/idRange.d.ts +0 -11
  434. package/dist/id-compressor/idRange.d.ts.map +0 -1
  435. package/dist/id-compressor/idRange.js +0 -29
  436. package/dist/id-compressor/idRange.js.map +0 -1
  437. package/dist/id-compressor/numericUuid.d.ts +0 -59
  438. package/dist/id-compressor/numericUuid.d.ts.map +0 -1
  439. package/dist/id-compressor/numericUuid.js +0 -325
  440. package/dist/id-compressor/numericUuid.js.map +0 -1
  441. package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
  442. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  443. package/dist/id-compressor/sessionIdNormalizer.js +0 -483
  444. package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
  445. package/dist/id-compressor/utils.d.ts +0 -57
  446. package/dist/id-compressor/utils.d.ts.map +0 -1
  447. package/dist/id-compressor/utils.js +0 -90
  448. package/dist/id-compressor/utils.js.map +0 -1
  449. package/dist/id-compressor/uuidUtilities.d.ts +0 -28
  450. package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
  451. package/dist/id-compressor/uuidUtilities.js +0 -104
  452. package/dist/id-compressor/uuidUtilities.js.map +0 -1
  453. package/lib/id-compressor/idRange.d.ts +0 -11
  454. package/lib/id-compressor/idRange.d.ts.map +0 -1
  455. package/lib/id-compressor/idRange.js +0 -25
  456. package/lib/id-compressor/idRange.js.map +0 -1
  457. package/lib/id-compressor/numericUuid.d.ts +0 -59
  458. package/lib/id-compressor/numericUuid.d.ts.map +0 -1
  459. package/lib/id-compressor/numericUuid.js +0 -315
  460. package/lib/id-compressor/numericUuid.js.map +0 -1
  461. package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
  462. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  463. package/lib/id-compressor/sessionIdNormalizer.js +0 -479
  464. package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
  465. package/lib/id-compressor/utils.d.ts +0 -57
  466. package/lib/id-compressor/utils.d.ts.map +0 -1
  467. package/lib/id-compressor/utils.js +0 -79
  468. package/lib/id-compressor/utils.js.map +0 -1
  469. package/lib/id-compressor/uuidUtilities.d.ts +0 -28
  470. package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
  471. package/lib/id-compressor/uuidUtilities.js +0 -96
  472. package/lib/id-compressor/uuidUtilities.js.map +0 -1
  473. package/src/id-compressor/idRange.ts +0 -35
  474. package/src/id-compressor/numericUuid.ts +0 -383
  475. package/src/id-compressor/sessionIdNormalizer.ts +0 -609
  476. package/src/id-compressor/utils.ts +0 -114
  477. package/src/id-compressor/uuidUtilities.ts +0 -120
@@ -19,14 +19,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
19
19
  return result;
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.TombstoneResponseHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
22
+ exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
23
23
  const container_definitions_1 = require("@fluidframework/container-definitions");
24
- const common_utils_1 = require("@fluidframework/common-utils");
25
24
  const core_utils_1 = require("@fluidframework/core-utils");
25
+ const client_utils_1 = require("@fluid-internal/client-utils");
26
26
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
27
27
  const driver_definitions_1 = require("@fluidframework/driver-definitions");
28
28
  const driver_utils_1 = require("@fluidframework/driver-utils");
29
- const container_utils_1 = require("@fluidframework/container-utils");
30
29
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
31
30
  const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
32
31
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
@@ -67,6 +66,18 @@ var ContainerMessageType;
67
66
  */
68
67
  ContainerMessageType["IdAllocation"] = "idAllocation";
69
68
  })(ContainerMessageType = exports.ContainerMessageType || (exports.ContainerMessageType = {}));
69
+ /**
70
+ * Utility to implement compat behaviors given an unknown message type
71
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
72
+ *
73
+ * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
74
+ * handled before calling this function (e.g. in a switch statement).
75
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
76
+ */
77
+ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
78
+ // undefined defaults to same behavior as "FailToProcess"
79
+ return compatBehavior === "Ignore";
80
+ }
70
81
  exports.DefaultSummaryConfiguration = {
71
82
  state: "enabled",
72
83
  minIdleTime: 0,
@@ -93,8 +104,12 @@ var RuntimeHeaders;
93
104
  })(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
94
105
  /** True if a tombstoned object should be returned without erroring */
95
106
  exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
107
+ /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
108
+ exports.AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
96
109
  /** Tombstone error responses will have this header set to true */
97
110
  exports.TombstoneResponseHeaderKey = "isTombstoned";
111
+ /** Inactive error responses will have this header set to true */
112
+ exports.InactiveResponseHeaderKey = "isInactive";
98
113
  /** Default values for Runtime Headers */
99
114
  exports.defaultRuntimeHeaderData = {
100
115
  wait: true,
@@ -121,6 +136,10 @@ const defaultCompressionConfig = {
121
136
  compressionAlgorithm: CompressionAlgorithms.lz4,
122
137
  };
123
138
  const defaultChunkSizeInBytes = 204800;
139
+ /** The default time to wait for pending ops to be processed during summarization */
140
+ exports.defaultPendingOpsWaitTimeoutMs = 1000;
141
+ /** The default time to delay a summarization retry attempt when there are pending ops */
142
+ exports.defaultPendingOpsRetryDelayMs = 1000;
124
143
  /**
125
144
  * Instead of refreshing from latest because we do not have 100% confidence in the state
126
145
  * of the current system, we should close the summarizer and let it recover.
@@ -186,7 +205,7 @@ exports.makeLegacySendBatchFn = makeLegacySendBatchFn;
186
205
  * Represents the runtime of the container. Contains helper functions/state of the container.
187
206
  * It will define the store level mappings.
188
207
  */
189
- class ContainerRuntime extends common_utils_1.TypedEventEmitter {
208
+ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
190
209
  /**
191
210
  * @internal
192
211
  */
@@ -225,34 +244,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
225
244
  signalTimestamp: 0,
226
245
  trackingSignalSequenceNumber: undefined,
227
246
  };
228
- this.summarizeOnDemand = (...args) => {
229
- if (this.isSummarizerClient) {
230
- return this.summarizer.summarizeOnDemand(...args);
231
- }
232
- else if (this.summaryManager !== undefined) {
233
- return this.summaryManager.summarizeOnDemand(...args);
234
- }
235
- else {
236
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
237
- // disableSummaries is turned on. We are throwing instead of returning a failure here,
238
- // because it is a misuse of the API rather than an expected failure.
239
- throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
240
- }
241
- };
242
- this.enqueueSummarize = (...args) => {
243
- if (this.isSummarizerClient) {
244
- return this.summarizer.enqueueSummarize(...args);
245
- }
246
- else if (this.summaryManager !== undefined) {
247
- return this.summaryManager.enqueueSummarize(...args);
248
- }
249
- else {
250
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
251
- // generateSummaries is turned off. We are throwing instead of returning a failure here,
252
- // because it is a misuse of the API rather than an expected failure.
253
- throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
254
- }
255
- };
256
247
  const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
257
248
  this.innerDeltaManager = deltaManager;
258
249
  this.deltaManager = new deltaManagerSummarizerProxy_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
@@ -368,7 +359,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
368
359
  // This is a runtime enforcement of what's already explicit in the policy's type itself,
369
360
  // which dictates the value is either undefined or exactly 5 days in ms.
370
361
  // As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
371
- throw new container_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
362
+ throw new telemetry_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
372
363
  }
373
364
  this.garbageCollector = gc_1.GarbageCollector.create({
374
365
  runtime: this,
@@ -467,16 +458,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
467
458
  });
468
459
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
469
460
  this._audience = audience;
470
- this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
471
461
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
472
462
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
473
463
  this.validateSummaryBeforeUpload =
474
- this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
475
- false;
464
+ this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
476
465
  this.summaryCollection = new summary_1.SummaryCollection(this.deltaManager, this.logger);
477
466
  this.dirtyContainer =
478
- this.attachState !== container_definitions_1.AttachState.Attached ||
479
- this.pendingStateManager.hasPendingMessages();
467
+ this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
480
468
  context.updateDirtyContainerState(this.dirtyContainer);
481
469
  if (this.summariesDisabled) {
482
470
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
@@ -524,6 +512,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
524
512
  (0, throttler_1.formExponentialFn)({ coefficient: 20, initialDelay: 0 })), {
525
513
  initialDelayMs: this.initialSummarizerDelayMs,
526
514
  }, this.heuristicsDisabled);
515
+ this.summaryManager.on("summarize", (eventProps) => {
516
+ this.emit("summarize", eventProps);
517
+ });
527
518
  this.summaryManager.start();
528
519
  }
529
520
  }
@@ -531,7 +522,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
531
522
  // we accumulate ops while being in read-only state.
532
523
  // once user gets write permissions and we have active connection, flush all pending ops.
533
524
  // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
534
- (0, common_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
525
+ (0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
535
526
  // We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
536
527
  // when we either never send an op, or attempted to send it but we know for sure it was not
537
528
  // sequenced by server and will never be sequenced (i.e. was lost)
@@ -544,7 +535,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
544
535
  // can rely on same safety mechanism and resend ops only when we establish new connection.
545
536
  // This is applicable for read-only permissions (event is raised before connection is properly registered),
546
537
  // but it's an extra requirement for Container.forceReadonly() API
547
- (0, common_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
538
+ (0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
548
539
  this.replayPendingStates();
549
540
  });
550
541
  // logging hardware telemetry
@@ -568,7 +559,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
568
559
  disableAttachReorder: this.disableAttachReorder,
569
560
  disablePartialFlush,
570
561
  idCompressorEnabled: this.idCompressorEnabled,
571
- summaryStateUpdateMethod: this.summaryStateUpdateMethod,
572
562
  closeSummarizerDelayOverride,
573
563
  }),
574
564
  telemetryDocumentId: this.telemetryDocumentId,
@@ -578,7 +568,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
578
568
  (0, batchTracker_1.BindBatchTracker)(this, this.logger);
579
569
  this.entryPoint = new core_utils_1.LazyPromise(async () => {
580
570
  if (this.isSummarizerClient) {
581
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
571
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
582
572
  return this._summarizer;
583
573
  }
584
574
  return initializeEntryPoint?.(this);
@@ -632,11 +622,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
632
622
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
633
623
  */
634
624
  static async loadRuntime(params) {
635
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
625
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
626
+ const initializeEntryPoint = params.initializeEntryPoint ??
627
+ (async (containerRuntime) => ({
628
+ get IFluidRouter() {
629
+ return this;
630
+ },
631
+ async request(req) {
632
+ return containerRuntime.request(req);
633
+ },
634
+ }));
636
635
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
637
636
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
638
637
  const backCompatContext = context;
639
638
  const passLogger = backCompatContext.taggedLogger ??
639
+ // eslint-disable-next-line import/no-deprecated
640
640
  new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
641
641
  const logger = (0, telemetry_utils_1.createChildLogger)({
642
642
  logger: passLogger,
@@ -653,7 +653,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
653
653
  if (context.baseSnapshot && blobId) {
654
654
  // IContainerContext storage api return type still has undefined in 0.39 package version.
655
655
  // So once we release 0.40 container-defn package we can remove this check.
656
- (0, common_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
656
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
657
657
  return (0, driver_utils_1.readAndParse)(context.storage, blobId);
658
658
  }
659
659
  };
@@ -668,7 +668,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
668
668
  const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
669
669
  // IContainerContext storage api return type still has undefined in 0.39 package version.
670
670
  // So once we release 0.40 container-defn package we can remove this check.
671
- (0, common_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
671
+ (0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
672
672
  return (0, driver_utils_1.readAndParse)(context.storage, id);
673
673
  });
674
674
  // Verify summary runtime sequence number matches protocol sequence number.
@@ -680,7 +680,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
680
680
  if (loadSequenceNumberVerification !== "bypass" &&
681
681
  runtimeSequenceNumber !== protocolSequenceNumber) {
682
682
  // "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
683
- const error = new container_utils_1.DataCorruptionError(
683
+ const error = new telemetry_utils_1.DataCorruptionError(
684
684
  // pre-0.58 error message: SummaryMetadataMismatch
685
685
  "Summary metadata mismatch", { runtimeVersion: packageVersion_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
686
686
  if (loadSequenceNumberVerification === "log") {
@@ -698,7 +698,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
698
698
  idCompressor =
699
699
  serializedIdCompressor !== undefined
700
700
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
701
- : new IdCompressor(createSessionId(), logger);
701
+ : IdCompressor.create(logger);
702
702
  }
703
703
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
704
704
  summaryOptions,
@@ -713,6 +713,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
713
713
  enableGroupedBatching,
714
714
  }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
715
715
  initializeEntryPoint);
716
+ await runtime.blobManager.processStashedChanges();
716
717
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
717
718
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
718
719
  await runtime.pendingStateManager.applyStashedOpsAt(0);
@@ -729,6 +730,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
729
730
  /** @deprecated - The functionality is no longer exposed publicly */
730
731
  get reSubmitFn() {
731
732
  return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
733
+ // Note: compatDetails is not included in this deprecated API
732
734
  }
733
735
  get flushMode() {
734
736
  return this._flushMode;
@@ -773,7 +775,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
773
775
  return this._disposed;
774
776
  }
775
777
  get summarizer() {
776
- (0, common_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
778
+ (0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
777
779
  return this._summarizer;
778
780
  }
779
781
  isSummariesDisabled() {
@@ -878,8 +880,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
878
880
  const subRequest = requestParser.createSubRequest(1);
879
881
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
880
882
  // unintentionally modifying the url if that changes.
881
- (0, common_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
882
- return dataStore.IFluidRouter.request(subRequest);
883
+ (0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
884
+ return dataStore.request(subRequest);
883
885
  }
884
886
  return (0, runtime_utils_1.create404Response)(request);
885
887
  }
@@ -937,7 +939,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
937
939
  addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
938
940
  this.addMetadataToSummary(summaryTree);
939
941
  if (this.idCompressorEnabled) {
940
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
942
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
941
943
  const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
942
944
  (0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.idCompressorBlobName, idCompressorState);
943
945
  }
@@ -987,7 +989,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
987
989
  this.mc.logger.sendTelemetryEvent({
988
990
  eventName: "ReconnectsWithNoProgress",
989
991
  attempts: this.consecutiveReconnects,
990
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
992
+ pendingMessages: this.pendingMessagesCount,
991
993
  });
992
994
  }
993
995
  return this.consecutiveReconnects < this.maxConsecutiveReconnects;
@@ -1012,7 +1014,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1012
1014
  // Save the old state, reset to false, disable event emit
1013
1015
  const oldState = this.dirtyContainer;
1014
1016
  this.dirtyContainer = false;
1015
- (0, common_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1017
+ (0, core_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
1016
1018
  this.emitDirtyDocumentEvent = false;
1017
1019
  let newState;
1018
1020
  try {
@@ -1046,21 +1048,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1046
1048
  * ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
1047
1049
  */
1048
1050
  parseOpContent(serializedContent) {
1049
- (0, common_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1050
- const { type, contents } = JSON.parse(serializedContent);
1051
- (0, common_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1052
- return { type, contents };
1051
+ (0, core_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1052
+ const { type, contents, compatDetails } = JSON.parse(serializedContent);
1053
+ (0, core_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
1054
+ return { type, contents, compatDetails };
1053
1055
  }
1054
1056
  async applyStashedOp(op) {
1055
1057
  // Need to parse from string for back-compat
1056
- const { type, contents } = this.parseOpContent(op);
1058
+ const { type, contents, compatDetails } = this.parseOpContent(op);
1057
1059
  switch (type) {
1058
1060
  case ContainerMessageType.FluidDataStoreOp:
1059
1061
  return this.dataStores.applyStashedOp(contents);
1060
1062
  case ContainerMessageType.Attach:
1061
1063
  return this.dataStores.applyStashedAttachOp(contents);
1062
1064
  case ContainerMessageType.IdAllocation:
1063
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1065
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
1064
1066
  return this.applyStashedIdAllocationOp(contents);
1065
1067
  case ContainerMessageType.Alias:
1066
1068
  case ContainerMessageType.BlobAttach:
@@ -1069,8 +1071,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1069
1071
  throw new Error("chunkedOp not expected here");
1070
1072
  case ContainerMessageType.Rejoin:
1071
1073
  throw new Error("rejoin not expected here");
1072
- default:
1073
- (0, common_utils_1.unreachableCase)(type, `Unknown ContainerMessageType: ${type}`);
1074
+ default: {
1075
+ // This should be extremely rare for stashed ops.
1076
+ // It would require a newer runtime stashing ops and then an older one applying them,
1077
+ // e.g. if an app rolled back its container version
1078
+ const compatBehavior = compatDetails?.behavior;
1079
+ if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
1080
+ const error = telemetry_utils_1.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1081
+ messageDetails: JSON.stringify({
1082
+ type,
1083
+ compatBehavior,
1084
+ }),
1085
+ });
1086
+ this.closeFn(error);
1087
+ throw error;
1088
+ }
1089
+ }
1074
1090
  }
1075
1091
  }
1076
1092
  setConnectionState(connected, clientId) {
@@ -1082,28 +1098,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1082
1098
  // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1083
1099
  return;
1084
1100
  }
1085
- // If attachment blobs were added while disconnected, we need to delay
1086
- // propagation of the "connected" event until we have uploaded them to
1087
- // ensure we don't submit ops referencing a blob that has not been uploaded
1088
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1089
- const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1090
- if (connecting && this.blobManager.hasPendingOfflineUploads) {
1091
- (0, common_utils_1.assert)(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
1092
- (0, common_utils_1.assert)(!!clientId, 0x393 /* Must have clientId when connecting */);
1093
- this.delayConnectClientId = clientId;
1094
- this.blobManager.onConnected().then(() => {
1095
- // make sure we didn't reconnect before the promise resolved
1096
- if (this.delayConnectClientId === clientId && !this.disposed) {
1097
- this.delayConnectClientId = undefined;
1098
- this.setConnectionStateCore(connected, clientId);
1099
- }
1100
- }, (error) => this.closeFn(error));
1101
- return;
1102
- }
1103
1101
  this.setConnectionStateCore(connected, clientId);
1104
1102
  }
1105
1103
  setConnectionStateCore(connected, clientId) {
1106
- (0, common_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1104
+ (0, core_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
1107
1105
  this.verifyNotClosed();
1108
1106
  // There might be no change of state due to Container calling this API after loading runtime.
1109
1107
  const changeOfState = this._connected !== connected;
@@ -1121,16 +1119,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1121
1119
  this._perfSignalData.trackingSignalSequenceNumber = undefined;
1122
1120
  }
1123
1121
  else {
1124
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1122
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
1125
1123
  }
1126
1124
  // Fail while disconnected
1127
1125
  if (reconnection) {
1128
1126
  this.consecutiveReconnects++;
1129
1127
  if (!this.shouldContinueReconnecting()) {
1130
- this.closeFn(container_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
1128
+ this.closeFn(telemetry_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
1131
1129
  dataLoss: 1,
1132
1130
  attempts: this.consecutiveReconnects,
1133
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1131
+ pendingMessages: this.pendingMessagesCount,
1134
1132
  }));
1135
1133
  return;
1136
1134
  }
@@ -1147,23 +1145,23 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1147
1145
  }
1148
1146
  process(messageArg, local) {
1149
1147
  this.verifyNotClosed();
1150
- // Whether or not the message is actually a runtime message.
1148
+ // Whether or not the message appears to be a runtime message from an up-to-date client.
1151
1149
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
1152
1150
  // or something different, like a system message.
1153
- const runtimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
1151
+ const modernRuntimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
1154
1152
  // Do shallow copy of message, as the processing flow will modify it.
1155
1153
  const messageCopy = { ...messageArg };
1156
1154
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1157
- this.processCore(message, local, runtimeMessage);
1155
+ this.processCore(message, local, modernRuntimeMessage);
1158
1156
  }
1159
1157
  }
1160
1158
  /**
1161
1159
  * Direct the message to the correct subsystem for processing, and implement other side effects
1162
1160
  * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
1163
1161
  * @param local - Did this client send the op?
1164
- * @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
1162
+ * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
1165
1163
  */
1166
- processCore(message, local, runtimeMessage) {
1164
+ processCore(message, local, modernRuntimeMessage) {
1167
1165
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1168
1166
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1169
1167
  // messages once a batch has been fully processed.
@@ -1171,7 +1169,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1171
1169
  this._processedClientSequenceNumber = message.clientSequenceNumber;
1172
1170
  try {
1173
1171
  let localOpMetadata;
1174
- if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1172
+ if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1175
1173
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1176
1174
  }
1177
1175
  // If there are no more pending messages after processing a local message,
@@ -1179,43 +1177,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1179
1177
  if (!this.hasPendingMessages()) {
1180
1178
  this.updateDocumentDirtyState(false);
1181
1179
  }
1182
- const type = message.type;
1183
- switch (type) {
1184
- case ContainerMessageType.Attach:
1185
- this.dataStores.processAttachMessage(message, local);
1186
- break;
1187
- case ContainerMessageType.Alias:
1188
- this.processAliasMessage(message, localOpMetadata, local);
1189
- break;
1190
- case ContainerMessageType.FluidDataStoreOp:
1191
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1192
- break;
1193
- case ContainerMessageType.BlobAttach:
1194
- this.blobManager.processBlobAttachOp(message, local);
1195
- break;
1196
- case ContainerMessageType.IdAllocation:
1197
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1198
- this.idCompressor.finalizeCreationRange(message.contents);
1199
- break;
1200
- case ContainerMessageType.ChunkedOp:
1201
- case ContainerMessageType.Rejoin:
1202
- break;
1203
- default:
1204
- if (runtimeMessage) {
1205
- const error = container_utils_1.DataProcessingError.create(
1206
- // Former assert 0x3ce
1207
- "Runtime message of unknown type", "OpProcessing", message, {
1208
- local,
1209
- type: message.type,
1210
- contentType: typeof message.contents,
1211
- batch: message.metadata?.batch,
1212
- compression: message.compression,
1213
- });
1214
- this.closeFn(error);
1215
- throw error;
1216
- }
1217
- }
1218
- this.emit("op", message, runtimeMessage);
1180
+ this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
1181
+ this.emit("op", message, modernRuntimeMessage);
1219
1182
  this.scheduleManager.afterOpProcessing(undefined, message);
1220
1183
  if (local) {
1221
1184
  // If we have processed a local op, this means that the container is
@@ -1229,8 +1192,59 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1229
1192
  throw e;
1230
1193
  }
1231
1194
  }
1232
- processAliasMessage(message, localOpMetadata, local) {
1233
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1195
+ /**
1196
+ * Assuming the given message is also a ContainerRuntimeMessage,
1197
+ * checks its type and dispatches the message to the appropriate handler in the runtime.
1198
+ * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
1199
+ */
1200
+ validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
1201
+ // Optimistically extract ContainerRuntimeMessage-specific props from the message
1202
+ const { type: maybeContainerMessageType, compatDetails } = message;
1203
+ switch (maybeContainerMessageType) {
1204
+ case ContainerMessageType.Attach:
1205
+ this.dataStores.processAttachMessage(message, local);
1206
+ break;
1207
+ case ContainerMessageType.Alias:
1208
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
1209
+ break;
1210
+ case ContainerMessageType.FluidDataStoreOp:
1211
+ this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1212
+ break;
1213
+ case ContainerMessageType.BlobAttach:
1214
+ this.blobManager.processBlobAttachOp(message, local);
1215
+ break;
1216
+ case ContainerMessageType.IdAllocation:
1217
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1218
+ this.idCompressor.finalizeCreationRange(message.contents);
1219
+ break;
1220
+ case ContainerMessageType.ChunkedOp:
1221
+ case ContainerMessageType.Rejoin:
1222
+ break;
1223
+ default: {
1224
+ // If we didn't necessarily expect a runtime message type, then no worries - just return
1225
+ // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
1226
+ if (!expectRuntimeMessageType) {
1227
+ return;
1228
+ }
1229
+ const compatBehavior = compatDetails?.behavior;
1230
+ if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
1231
+ const error = telemetry_utils_1.DataProcessingError.create(
1232
+ // Former assert 0x3ce
1233
+ "Runtime message of unknown type", "OpProcessing", message, {
1234
+ local,
1235
+ messageDetails: JSON.stringify({
1236
+ type: message.type,
1237
+ contentType: typeof message.contents,
1238
+ compatBehavior,
1239
+ batch: message.metadata?.batch,
1240
+ compression: message.compression,
1241
+ }),
1242
+ });
1243
+ this.closeFn(error);
1244
+ throw error;
1245
+ }
1246
+ }
1247
+ }
1234
1248
  }
1235
1249
  /**
1236
1250
  * Emits the Signal event and update the perf signal data.
@@ -1298,7 +1312,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1298
1312
  await this.dataStores.waitIfPendingAlias(id);
1299
1313
  const internalId = this.internalId(id);
1300
1314
  const context = await this.dataStores.getDataStore(internalId, { wait });
1301
- (0, common_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1315
+ (0, core_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
1302
1316
  return context.realize();
1303
1317
  }
1304
1318
  /**
@@ -1306,9 +1320,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1306
1320
  * This method is expected to be called at the end of a batch.
1307
1321
  */
1308
1322
  flush() {
1309
- (0, common_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1323
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
1310
1324
  this.outbox.flush();
1311
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1325
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
1312
1326
  }
1313
1327
  orderSequentially(callback) {
1314
1328
  let checkpoint;
@@ -1331,7 +1345,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1331
1345
  }
1332
1346
  catch (err) {
1333
1347
  const error2 = (0, telemetry_utils_1.wrapError)(err, (message) => {
1334
- return container_utils_1.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
1348
+ return telemetry_utils_1.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
1335
1349
  });
1336
1350
  this.closeFn(error2);
1337
1351
  throw error2;
@@ -1339,7 +1353,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1339
1353
  }
1340
1354
  else {
1341
1355
  // pre-0.58 error message: orderSequentiallyCallbackException
1342
- this.closeFn(new container_utils_1.GenericError("orderSequentially callback exception", error));
1356
+ this.closeFn(new telemetry_utils_1.GenericError("orderSequentially callback exception", error));
1343
1357
  }
1344
1358
  throw error; // throw the original error for the consumer of the runtime
1345
1359
  }
@@ -1368,13 +1382,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1368
1382
  }
1369
1383
  const channel = await context.realize();
1370
1384
  if (channel.entryPoint === undefined) {
1371
- throw new container_utils_1.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1385
+ throw new telemetry_utils_1.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1372
1386
  }
1373
1387
  return channel.entryPoint;
1374
1388
  }
1375
1389
  createDetachedRootDataStore(pkg, rootDataStoreId) {
1376
1390
  if (rootDataStoreId.includes("/")) {
1377
- throw new container_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1391
+ throw new telemetry_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
1378
1392
  }
1379
1393
  return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
1380
1394
  }
@@ -1468,10 +1482,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1468
1482
  }
1469
1483
  setAttachState(attachState) {
1470
1484
  if (attachState === container_definitions_1.AttachState.Attaching) {
1471
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1485
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
1472
1486
  }
1473
1487
  else {
1474
- (0, common_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1488
+ (0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
1475
1489
  this.emit("attached");
1476
1490
  }
1477
1491
  if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
@@ -1529,7 +1543,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1529
1543
  await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
1530
1544
  }
1531
1545
  const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
1532
- (0, common_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1546
+ (0, core_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
1533
1547
  return { stats, summary };
1534
1548
  }
1535
1549
  finally {
@@ -1641,7 +1655,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1641
1655
  case gc_1.GCNodeType.SubDataStore:
1642
1656
  return this.dataStores.getDataStorePackagePath(nodePath);
1643
1657
  default:
1644
- (0, common_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1658
+ (0, core_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
1645
1659
  }
1646
1660
  }
1647
1661
  /**
@@ -1698,7 +1712,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1698
1712
  * @param options - options controlling how the summary is generated or submitted
1699
1713
  */
1700
1714
  async submitSummary(options) {
1701
- const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1715
+ const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
1702
1716
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1703
1717
  // use it for all events logged during this summary.
1704
1718
  const summaryNumber = this.nextSummaryNumber;
@@ -1708,7 +1722,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1708
1722
  all: { summaryNumber },
1709
1723
  },
1710
1724
  });
1711
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1725
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
1712
1726
  let latestSnapshotVersionId;
1713
1727
  if (refreshLatestAck) {
1714
1728
  const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer((0, telemetry_utils_1.createChildLogger)({
@@ -1720,6 +1734,40 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1720
1734
  // We might need to catch up to the latest summary's reference sequence number before pausing.
1721
1735
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
1722
1736
  }
1737
+ // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
1738
+ // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
1739
+ // within the timeout, check if it should be failed or can continue.
1740
+ if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
1741
+ const countBefore = this.pendingMessagesCount;
1742
+ // The timeout for waiting for pending ops can be overridden via configurations.
1743
+ const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
1744
+ exports.defaultPendingOpsWaitTimeoutMs;
1745
+ await new Promise((resolve, reject) => {
1746
+ const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
1747
+ this.once("saved", () => {
1748
+ clearTimeout(timeoutId);
1749
+ resolve();
1750
+ });
1751
+ this.once("dispose", () => {
1752
+ clearTimeout(timeoutId);
1753
+ reject(new Error("Runtime is disposed while summarizing"));
1754
+ });
1755
+ });
1756
+ // Log that there are pending ops while summarizing. This will help us gather data on how often this
1757
+ // happens, whether we attempted to wait for these ops to be acked and what was the result.
1758
+ summaryNumberLogger.sendTelemetryEvent({
1759
+ eventName: "PendingOpsWhileSummarizing",
1760
+ saved: this.hasPendingMessages() ? false : true,
1761
+ timeout: pendingOpsTimeout,
1762
+ countBefore,
1763
+ countAfter: this.pendingMessagesCount,
1764
+ });
1765
+ // There could still be pending ops. Check if summary should fail or continue.
1766
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, this.deltaManager.lastSequenceNumber, this.deltaManager.minimumSequenceNumber, finalAttempt, true /* beforeSummaryGeneration */);
1767
+ if (pendingMessagesFailResult !== undefined) {
1768
+ return pendingMessagesFailResult;
1769
+ }
1770
+ }
1723
1771
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
1724
1772
  let summaryRefSeqNum;
1725
1773
  try {
@@ -1746,7 +1794,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1746
1794
  // That said, we rely on submitSystemMessage() that today only works in connected state.
1747
1795
  // So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
1748
1796
  // OR that design changed and we need to remove this check and fix submitSystemMessage.
1749
- (0, common_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1797
+ (0, core_utils_1.assert)(this.connected, 0x258 /* "connected" */);
1750
1798
  // Ensure that lastSequenceNumber has not changed after pausing.
1751
1799
  // We need the summary op's reference sequence number to match our summary sequence number,
1752
1800
  // otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
@@ -1756,7 +1804,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1756
1804
  error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
1757
1805
  };
1758
1806
  }
1759
- (0, common_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1807
+ (0, core_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
1760
1808
  if (lastAck !== this.summaryCollection.latestAck) {
1761
1809
  return {
1762
1810
  continue: false,
@@ -1774,7 +1822,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1774
1822
  error: continueResult.error,
1775
1823
  };
1776
1824
  }
1777
- const trace = common_utils_1.Trace.start();
1825
+ const trace = client_utils_1.Trace.start();
1778
1826
  let summarizeResult;
1779
1827
  // If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
1780
1828
  // state of all the nodes.
@@ -1795,9 +1843,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1795
1843
  error,
1796
1844
  };
1797
1845
  }
1798
- // If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
1799
- // correct before this summary is uploaded.
1846
+ // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
1800
1847
  if (this.validateSummaryBeforeUpload) {
1848
+ // Validate that the summaries generated by summarize nodes is correct.
1801
1849
  const validateResult = this.summarizerNode.validateSummary();
1802
1850
  if (!validateResult.success) {
1803
1851
  const { success, ...loggingProps } = validateResult;
@@ -1809,6 +1857,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1809
1857
  error,
1810
1858
  };
1811
1859
  }
1860
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
1861
+ if (pendingMessagesFailResult !== undefined) {
1862
+ return pendingMessagesFailResult;
1863
+ }
1812
1864
  }
1813
1865
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
1814
1866
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -1817,7 +1869,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1817
1869
  // Because handles are unchanged dataStores in the current logic,
1818
1870
  // summarized dataStore count is total dataStore count minus handle count
1819
1871
  const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
1820
- (0, common_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1872
+ (0, core_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
1821
1873
  const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
1822
1874
  const gcSummaryTreeStats = summaryTree.tree[runtime_definitions_1.gcTreeKey]
1823
1875
  ? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
@@ -1929,16 +1981,63 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1929
1981
  }
1930
1982
  }
1931
1983
  }
1984
+ /**
1985
+ * This helper is called during summarization. If there are pending ops, it will return a failed summarize result
1986
+ * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
1987
+ * @param logger - The logger to be used for sending telemetry.
1988
+ * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
1989
+ * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
1990
+ * @param finalAttempt - Whether this is the final summary attempt.
1991
+ * @param beforeSummaryGeneration - Whether this is called before summary generation or after.
1992
+ * @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
1993
+ */
1994
+ async shouldFailSummaryOnPendingOps(logger, referenceSequenceNumber, minimumSequenceNumber, finalAttempt, beforeSummaryGeneration) {
1995
+ if (!this.hasPendingMessages()) {
1996
+ return;
1997
+ }
1998
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
1999
+ // This is a fallback to make progress in documents where there are consistently pending ops in
2000
+ // the summarizer.
2001
+ if (finalAttempt &&
2002
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
2003
+ const error = telemetry_utils_1.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
2004
+ logger.sendErrorEvent({
2005
+ eventName: "SkipFailingIncorrectSummary",
2006
+ referenceSequenceNumber,
2007
+ minimumSequenceNumber,
2008
+ beforeGenerate: beforeSummaryGeneration,
2009
+ }, error);
2010
+ }
2011
+ else {
2012
+ // The retry delay when there are pending ops can be overridden via config so that we can adjust it
2013
+ // based on telemetry while we decide on a stable number.
2014
+ const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
2015
+ exports.defaultPendingOpsRetryDelayMs;
2016
+ const error = new summary_1.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
2017
+ count: this.pendingMessagesCount,
2018
+ beforeGenerate: beforeSummaryGeneration,
2019
+ });
2020
+ return {
2021
+ stage: "base",
2022
+ referenceSequenceNumber,
2023
+ minimumSequenceNumber,
2024
+ error,
2025
+ };
2026
+ }
2027
+ }
2028
+ get pendingMessagesCount() {
2029
+ return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
2030
+ }
1932
2031
  hasPendingMessages() {
1933
- return this.pendingStateManager.hasPendingMessages() || !this.outbox.isEmpty;
2032
+ return this.pendingMessagesCount !== 0;
1934
2033
  }
1935
2034
  updateDocumentDirtyState(dirty) {
1936
2035
  if (this.attachState !== container_definitions_1.AttachState.Attached) {
1937
- (0, common_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
2036
+ (0, core_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
1938
2037
  }
1939
2038
  else {
1940
2039
  // Other way is not true = see this.isContainerMessageDirtyable()
1941
- (0, common_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
2040
+ (0, core_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
1942
2041
  }
1943
2042
  if (this.dirtyContainer === dirty) {
1944
2043
  return;
@@ -1958,7 +2057,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1958
2057
  submitDataStoreAliasOp(contents, localOpMetadata) {
1959
2058
  const aliasMessage = contents;
1960
2059
  if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
1961
- throw new container_utils_1.UsageError("malformedDataStoreAliasMessage");
2060
+ throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
1962
2061
  }
1963
2062
  this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
1964
2063
  }
@@ -1971,10 +2070,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1971
2070
  let idAllocationBatchMessage;
1972
2071
  let idRange;
1973
2072
  if (this.idCompressorEnabled) {
1974
- (0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
2073
+ (0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
1975
2074
  idRange = this.idCompressor.takeNextCreationRange();
1976
2075
  // Don't include the idRange if there weren't any Ids allocated
1977
- idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
2076
+ idRange = idRange?.ids !== undefined ? idRange : undefined;
1978
2077
  }
1979
2078
  if (idRange !== undefined) {
1980
2079
  const idAllocationMessage = {
@@ -1998,7 +2097,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
1998
2097
  this.verifyNotClosed();
1999
2098
  this.verifyCanSubmitOps();
2000
2099
  // There should be no ops in detached container state!
2001
- (0, common_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2100
+ (0, core_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2002
2101
  const serializedContent = JSON.stringify(containerRuntimeMessage);
2003
2102
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2004
2103
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
@@ -2098,15 +2197,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2098
2197
  setTimeout(flush, 0);
2099
2198
  break;
2100
2199
  default:
2101
- (0, common_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2200
+ (0, core_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
2102
2201
  break;
2103
2202
  }
2104
2203
  }
2105
2204
  submitSummaryMessage(contents, referenceSequenceNumber) {
2106
2205
  this.verifyNotClosed();
2107
- (0, common_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2206
+ (0, core_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
2108
2207
  // System message should not be sent in the middle of the batch.
2109
- (0, common_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2208
+ (0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
2110
2209
  // back-compat: ADO #1385: Make this call unconditional in the future
2111
2210
  return this.submitSummaryFn !== undefined
2112
2211
  ? this.submitSummaryFn(contents, referenceSequenceNumber)
@@ -2127,7 +2226,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2127
2226
  if (this.opReentryCallsToReport > 0) {
2128
2227
  this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
2129
2228
  // We need to capture the call stack in order to inspect the source of this usage pattern
2130
- (0, opLifecycle_1.getLongStack)(() => new container_utils_1.UsageError(errorMessage)));
2229
+ (0, opLifecycle_1.getLongStack)(() => new telemetry_utils_1.UsageError(errorMessage)));
2131
2230
  this.opReentryCallsToReport--;
2132
2231
  }
2133
2232
  // Creating ops while processing ops can lead
@@ -2143,7 +2242,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2143
2242
  // The runtime must enforce op coherence by not allowing ops to be submitted
2144
2243
  // while ops are being processed.
2145
2244
  if (this.enableOpReentryCheck) {
2146
- throw new container_utils_1.UsageError(errorMessage);
2245
+ throw new telemetry_utils_1.UsageError(errorMessage);
2147
2246
  }
2148
2247
  }
2149
2248
  }
@@ -2193,8 +2292,27 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2193
2292
  case ContainerMessageType.Rejoin:
2194
2293
  this.submit(message);
2195
2294
  break;
2196
- default:
2197
- (0, common_utils_1.unreachableCase)(message.type, `Unknown ContainerMessageType [type: ${message.type}]`);
2295
+ default: {
2296
+ // This case should be very rare - it would imply an op was stashed from a
2297
+ // future version of runtime code and now is being applied on an older version
2298
+ const compatBehavior = message.compatDetails?.behavior;
2299
+ if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
2300
+ this.logger.sendTelemetryEvent({
2301
+ eventName: "resubmitUnrecognizedMessageTypeAllowed",
2302
+ messageDetails: { type: message.type, compatBehavior },
2303
+ });
2304
+ }
2305
+ else {
2306
+ const error = telemetry_utils_1.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2307
+ messageDetails: JSON.stringify({
2308
+ type: message.type,
2309
+ compatBehavior,
2310
+ }),
2311
+ });
2312
+ this.closeFn(error);
2313
+ throw error;
2314
+ }
2315
+ }
2198
2316
  }
2199
2317
  }
2200
2318
  rollback(content, localOpMetadata) {
@@ -2207,6 +2325,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2207
2325
  this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
2208
2326
  break;
2209
2327
  default:
2328
+ // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
2210
2329
  throw new Error(`Can't rollback ${type}`);
2211
2330
  }
2212
2331
  }
@@ -2224,29 +2343,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2224
2343
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
2225
2344
  async refreshLatestSummaryAck(options) {
2226
2345
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
2346
+ // proposalHandle is always passed from RunningSummarizer.
2347
+ (0, core_utils_1.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
2227
2348
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2228
- // The call to fetch the snapshot is very expensive and not always needed.
2229
- // It should only be done by the summarizerNode, if required.
2230
- // When fetching from storage we will always get the latest version and do not use the ackHandle.
2231
- const fetchLatestSnapshot = async () => {
2232
- let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2349
+ const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
2350
+ /**
2351
+ * When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
2352
+ * current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
2353
+ * it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
2354
+ * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2355
+ */
2356
+ if (!result.isSummaryTracked && result.isSummaryNewer) {
2357
+ const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
2233
2358
  eventName: "RefreshLatestSummaryAckFetch",
2234
2359
  ackHandle,
2235
2360
  targetSequenceNumber: summaryRefSeq,
2236
- }, readAndParseBlob);
2237
- /**
2238
- * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
2239
- * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
2240
- * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
2241
- * change that started fetching latest snapshot always.
2242
- */
2243
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2244
- fetchResult = await this.fetchSnapshotFromStorageAndClose(summaryLogger, {
2245
- eventName: "RefreshLatestSummaryAckFetchBackCompat",
2246
- ackHandle,
2247
- targetSequenceNumber: summaryRefSeq,
2248
- }, readAndParseBlob, ackHandle);
2249
- }
2361
+ }, readAndParseBlob, null);
2250
2362
  /**
2251
2363
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
2252
2364
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -2258,7 +2370,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2258
2370
  * state.
2259
2371
  */
2260
2372
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2261
- const error = container_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
2373
+ const error = telemetry_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
2262
2374
  ackHandle,
2263
2375
  summaryRefSeq,
2264
2376
  fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
@@ -2266,17 +2378,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2266
2378
  this.disposeFn(error);
2267
2379
  throw error;
2268
2380
  }
2269
- // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
2270
- // wait for the delta manager to catch up before refreshing the latest Summary.
2271
- await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
2272
- return {
2273
- snapshotTree: fetchResult.snapshotTree,
2274
- snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
2275
- };
2276
- };
2277
- const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2381
+ await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
2382
+ return;
2383
+ }
2278
2384
  // Notify the garbage collector so it can update its latest summary state.
2279
- await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
2385
+ await this.garbageCollector.refreshLatestSummary(result);
2280
2386
  }
2281
2387
  /**
2282
2388
  * Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
@@ -2286,30 +2392,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2286
2392
  */
2287
2393
  async refreshLatestSummaryAckFromServer(summaryLogger) {
2288
2394
  const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
2289
- const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2395
+ const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
2290
2396
  eventName: "RefreshLatestSummaryFromServerFetch",
2291
- }, readAndParseBlob);
2292
- const fetchLatestSnapshot = {
2293
- snapshotTree,
2294
- snapshotRefSeq: latestSnapshotRefSeq,
2295
- };
2296
- const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
2297
- // Notify the garbage collector so it can update its latest summary state.
2298
- await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
2397
+ }, readAndParseBlob, null);
2398
+ await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
2299
2399
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2300
2400
  }
2301
- async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2302
- return this.fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, null /* latest */);
2401
+ async closeStaleSummarizer(codePath) {
2402
+ this.mc.logger.sendTelemetryEvent({
2403
+ eventName: "ClosingSummarizerOnSummaryStale",
2404
+ codePath,
2405
+ message: "Stopping fetch from storage",
2406
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2407
+ }, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2408
+ // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2409
+ await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
2410
+ this._summarizer?.stop("latestSummaryStateStale");
2411
+ this.disposeFn();
2303
2412
  }
2304
- async fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, versionId) {
2305
- const snapshotResults = await telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2413
+ /**
2414
+ * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2415
+ * By default, it also closes the container after downloading the snapshot. However, this may be
2416
+ * overridden via options.
2417
+ */
2418
+ async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
2419
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2306
2420
  const stats = {};
2307
- const trace = common_utils_1.Trace.start();
2421
+ const trace = client_utils_1.Trace.start();
2308
2422
  const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
2309
- (0, common_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2423
+ (0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
2310
2424
  stats.getVersionDuration = trace.trace().duration;
2311
2425
  const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
2312
- (0, common_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2426
+ (0, core_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
2313
2427
  stats.getSnapshotDuration = trace.trace().duration;
2314
2428
  const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(maybeSnapshot, readAndParseBlob);
2315
2429
  stats.snapshotRefSeq = latestSnapshotRefSeq;
@@ -2321,41 +2435,65 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2321
2435
  latestSnapshotRefSeq,
2322
2436
  };
2323
2437
  });
2324
- // We choose to close the summarizer after the snapshot cache is updated to avoid
2325
- // situations which the main client (which is likely to be re-elected as the leader again)
2326
- // loads the summarizer from cache.
2327
- if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
2328
- this.mc.logger.sendTelemetryEvent({
2329
- ...event,
2330
- eventName: "ClosingSummarizerOnSummaryStale",
2331
- codePath: event.eventName,
2332
- message: "Stopping fetch from storage",
2333
- versionId: versionId != null ? versionId : undefined,
2334
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
2335
- }, new container_utils_1.GenericError("Restarting summarizer instead of refreshing"));
2336
- // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2337
- await (0, common_utils_1.delay)(this.closeSummarizerDelayMs);
2338
- this._summarizer?.stop("latestSummaryStateStale");
2339
- this.disposeFn();
2340
- }
2341
- return snapshotResults;
2342
2438
  }
2343
2439
  notifyAttaching() { } // do nothing (deprecated method)
2344
2440
  async getPendingLocalState(props) {
2345
- this.verifyNotClosed();
2346
- const waitBlobsToAttach = props?.notifyImminentClosure;
2347
- if (this._orderSequentiallyCalls !== 0) {
2348
- throw new container_utils_1.UsageError("can't get state during orderSequentially");
2349
- }
2350
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2351
- // Flush pending batch.
2352
- // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2353
- // to close current batch.
2354
- this.flush();
2355
- return {
2356
- pending: this.pendingStateManager.getLocalState(),
2357
- pendingAttachmentBlobs,
2358
- };
2441
+ return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
2442
+ eventName: "getPendingLocalState",
2443
+ notifyImminentClosure: props?.notifyImminentClosure,
2444
+ }, async (event) => {
2445
+ this.verifyNotClosed();
2446
+ const waitBlobsToAttach = props?.notifyImminentClosure;
2447
+ if (this._orderSequentiallyCalls !== 0) {
2448
+ throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
2449
+ }
2450
+ const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2451
+ const pending = this.pendingStateManager.getLocalState();
2452
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2453
+ return; // no pending state to save
2454
+ }
2455
+ // Flush pending batch.
2456
+ // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2457
+ // to close current batch.
2458
+ this.flush();
2459
+ const pendingState = {
2460
+ pending,
2461
+ pendingAttachmentBlobs,
2462
+ };
2463
+ event.end({
2464
+ attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
2465
+ pendingOpsSize: pending?.pendingStates.length,
2466
+ });
2467
+ return pendingState;
2468
+ });
2469
+ }
2470
+ summarizeOnDemand(options) {
2471
+ if (this.isSummarizerClient) {
2472
+ return this.summarizer.summarizeOnDemand(options);
2473
+ }
2474
+ else if (this.summaryManager !== undefined) {
2475
+ return this.summaryManager.summarizeOnDemand(options);
2476
+ }
2477
+ else {
2478
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2479
+ // disableSummaries is turned on. We are throwing instead of returning a failure here,
2480
+ // because it is a misuse of the API rather than an expected failure.
2481
+ throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2482
+ }
2483
+ }
2484
+ enqueueSummarize(options) {
2485
+ if (this.isSummarizerClient) {
2486
+ return this.summarizer.enqueueSummarize(options);
2487
+ }
2488
+ else if (this.summaryManager !== undefined) {
2489
+ return this.summaryManager.enqueueSummarize(options);
2490
+ }
2491
+ else {
2492
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2493
+ // generateSummaries is turned off. We are throwing instead of returning a failure here,
2494
+ // because it is a misuse of the API rather than an expected failure.
2495
+ throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2496
+ }
2359
2497
  }
2360
2498
  /**
2361
2499
  * * Forms a function that will request a Summarizer.
@@ -2378,7 +2516,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2378
2516
  const fluidObject = await (0, runtime_utils_1.requestFluidObject)(loaderRouter, request);
2379
2517
  const summarizer = fluidObject.ISummarizer;
2380
2518
  if (!summarizer) {
2381
- throw new container_utils_1.UsageError("Fluid object does not implement ISummarizer");
2519
+ throw new telemetry_utils_1.UsageError("Fluid object does not implement ISummarizer");
2382
2520
  }
2383
2521
  return summarizer;
2384
2522
  };
@@ -2387,11 +2525,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
2387
2525
  // eslint-disable-next-line no-restricted-syntax
2388
2526
  for (const prop in configuration) {
2389
2527
  if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
2390
- throw new container_utils_1.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
2528
+ throw new telemetry_utils_1.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
2391
2529
  }
2392
2530
  }
2393
2531
  if (configuration.minIdleTime > configuration.maxIdleTime) {
2394
- throw new container_utils_1.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
2532
+ throw new telemetry_utils_1.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
2395
2533
  }
2396
2534
  }
2397
2535
  get groupedBatchingEnabled() {