@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
@@ -27,23 +27,22 @@ import {
27
27
  IContainerRuntime,
28
28
  IContainerRuntimeEvents,
29
29
  } from "@fluidframework/container-runtime-definitions";
30
- import {
31
- assert,
32
- delay,
33
- Trace,
34
- TypedEventEmitter,
35
- unreachableCase,
36
- } from "@fluidframework/common-utils";
37
- import { LazyPromise } from "@fluidframework/core-utils";
30
+ import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
31
+ import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
38
32
  import {
39
33
  createChildLogger,
34
+ createChildMonitoringContext,
35
+ DataCorruptionError,
36
+ DataProcessingError,
37
+ GenericError,
40
38
  raiseConnectedEvent,
41
39
  PerformanceEvent,
40
+ // eslint-disable-next-line import/no-deprecated
42
41
  TaggedLoggerAdapter,
43
42
  MonitoringContext,
44
43
  wrapError,
45
44
  ITelemetryLoggerExt,
46
- createChildMonitoringContext,
45
+ UsageError,
47
46
  } from "@fluidframework/telemetry-utils";
48
47
  import {
49
48
  DriverHeader,
@@ -52,12 +51,6 @@ import {
52
51
  ISummaryContext,
53
52
  } from "@fluidframework/driver-definitions";
54
53
  import { readAndParse } from "@fluidframework/driver-utils";
55
- import {
56
- DataCorruptionError,
57
- DataProcessingError,
58
- GenericError,
59
- UsageError,
60
- } from "@fluidframework/container-utils";
61
54
  import {
62
55
  IClientDetails,
63
56
  IDocumentMessage,
@@ -133,7 +126,6 @@ import {
133
126
  IContainerRuntimeMetadata,
134
127
  ICreateContainerMetadata,
135
128
  idCompressorBlobName,
136
- IFetchSnapshotResult,
137
129
  IRootSummarizerNodeWithGC,
138
130
  ISummaryMetadataMessage,
139
131
  metadataBlobName,
@@ -157,6 +149,12 @@ import {
157
149
  RunWhileConnectedCoordinator,
158
150
  IGenerateSummaryTreeResult,
159
151
  RetriableSummaryError,
152
+ IOnDemandSummarizeOptions,
153
+ ISummarizeResults,
154
+ IEnqueueSummarizeOptions,
155
+ EnqueueSummarizeResult,
156
+ ISummarizerEvents,
157
+ IBaseSummarizeResult,
160
158
  } from "./summary";
161
159
  import { formExponentialFn, Throttler } from "./throttler";
162
160
  import {
@@ -214,11 +212,64 @@ export enum ContainerMessageType {
214
212
  IdAllocation = "idAllocation",
215
213
  }
216
214
 
215
+ /**
216
+ * How should an older client handle an unrecognized remote op type?
217
+ *
218
+ * @internal
219
+ */
220
+ export type CompatModeBehavior =
221
+ /** Ignore the op. It won't be persisted if this client summarizes */
222
+ | "Ignore"
223
+ /** Fail processing immediately. (The container will close) */
224
+ | "FailToProcess";
225
+
226
+ /**
227
+ * All the info an older client would need to know how to handle an unrecognized remote op type
228
+ *
229
+ * @internal
230
+ */
231
+ export interface IContainerRuntimeMessageCompatDetails {
232
+ /** How should an older client handle an unrecognized remote op type? */
233
+ behavior: CompatModeBehavior;
234
+ }
235
+
236
+ /**
237
+ * Utility to implement compat behaviors given an unknown message type
238
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
239
+ *
240
+ * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
241
+ * handled before calling this function (e.g. in a switch statement).
242
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
243
+ */
244
+ function compatBehaviorAllowsMessageType(
245
+ _unknownContainerRuntimeMessageType: never,
246
+ compatBehavior: "Ignore" | "FailToProcess" | undefined,
247
+ ): boolean {
248
+ // undefined defaults to same behavior as "FailToProcess"
249
+ return compatBehavior === "Ignore";
250
+ }
251
+
252
+ /**
253
+ * The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime
254
+ *
255
+ * IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.
256
+ * This way stringified values can be compared.
257
+ */
217
258
  export interface ContainerRuntimeMessage {
218
- contents: any;
259
+ /** Type of the op, within the ContainerRuntime's domain */
219
260
  type: ContainerMessageType;
261
+ /** Domain-specific contents, interpreted according to the type */
262
+ contents: any;
263
+ /** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
264
+ compatDetails?: IContainerRuntimeMessageCompatDetails;
220
265
  }
221
266
 
267
+ /**
268
+ * An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
269
+ * promoted up to the outer object
270
+ */
271
+ export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
272
+
222
273
  export interface ISummaryBaseConfiguration {
223
274
  /**
224
275
  * Delay before first attempt to spawn summarizing container.
@@ -457,9 +508,13 @@ export enum RuntimeHeaders {
457
508
 
458
509
  /** True if a tombstoned object should be returned without erroring */
459
510
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
511
+ /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
512
+ export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
460
513
 
461
514
  /** Tombstone error responses will have this header set to true */
462
515
  export const TombstoneResponseHeaderKey = "isTombstoned";
516
+ /** Inactive error responses will have this header set to true */
517
+ export const InactiveResponseHeaderKey = "isInactive";
463
518
 
464
519
  /**
465
520
  * The full set of parsed header data that may be found on Runtime requests
@@ -500,7 +555,7 @@ interface OldContainerContextWithLogger extends Omit<IContainerContext, "taggedL
500
555
  * instantiated runtime in a new instance of the container, so it can load to the
501
556
  * same state
502
557
  */
503
- interface IPendingRuntimeState {
558
+ export interface IPendingRuntimeState {
504
559
  /**
505
560
  * Pending ops from PendingStateManager
506
561
  */
@@ -529,6 +584,11 @@ const defaultCompressionConfig = {
529
584
 
530
585
  const defaultChunkSizeInBytes = 204800;
531
586
 
587
+ /** The default time to wait for pending ops to be processed during summarization */
588
+ export const defaultPendingOpsWaitTimeoutMs = 1000;
589
+ /** The default time to delay a summarization retry attempt when there are pending ops */
590
+ export const defaultPendingOpsRetryDelayMs = 1000;
591
+
532
592
  /**
533
593
  * Instead of refreshing from latest because we do not have 100% confidence in the state
534
594
  * of the current system, we should close the summarizer and let it recover.
@@ -605,7 +665,7 @@ export const makeLegacySendBatchFn =
605
665
  * It will define the store level mappings.
606
666
  */
607
667
  export class ContainerRuntime
608
- extends TypedEventEmitter<IContainerRuntimeEvents>
668
+ extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
609
669
  implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
610
670
  {
611
671
  /**
@@ -665,16 +725,30 @@ export class ContainerRuntime
665
725
  * - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
666
726
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
667
727
  */
668
- public static async loadRuntime(params: {
669
- context: IContainerContext;
670
- registryEntries: NamedFluidDataStoreRegistryEntries;
671
- existing: boolean;
672
- requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
673
- runtimeOptions?: IContainerRuntimeOptions;
674
- containerScope?: FluidObject;
675
- containerRuntimeCtor?: typeof ContainerRuntime;
676
- initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
677
- }): Promise<ContainerRuntime> {
728
+ public static async loadRuntime(
729
+ params: {
730
+ context: IContainerContext;
731
+ registryEntries: NamedFluidDataStoreRegistryEntries;
732
+ existing: boolean;
733
+ runtimeOptions?: IContainerRuntimeOptions;
734
+ containerScope?: FluidObject;
735
+ containerRuntimeCtor?: typeof ContainerRuntime;
736
+ } & (
737
+ | {
738
+ requestHandler?: (
739
+ request: IRequest,
740
+ runtime: IContainerRuntime,
741
+ ) => Promise<IResponse>;
742
+ initializeEntryPoint?: undefined;
743
+ }
744
+ | {
745
+ requestHandler?: undefined;
746
+ initializeEntryPoint: (
747
+ containerRuntime: IContainerRuntime,
748
+ ) => Promise<FluidObject>;
749
+ }
750
+ ),
751
+ ): Promise<ContainerRuntime> {
678
752
  const {
679
753
  context,
680
754
  registryEntries,
@@ -683,14 +757,25 @@ export class ContainerRuntime
683
757
  runtimeOptions = {},
684
758
  containerScope = {},
685
759
  containerRuntimeCtor = ContainerRuntime,
686
- initializeEntryPoint,
687
760
  } = params;
688
761
 
762
+ const initializeEntryPoint =
763
+ params.initializeEntryPoint ??
764
+ (async (containerRuntime: IContainerRuntime) => ({
765
+ get IFluidRouter() {
766
+ return this;
767
+ },
768
+ async request(req) {
769
+ return containerRuntime.request(req);
770
+ },
771
+ }));
772
+
689
773
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
690
774
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
691
775
  const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
692
776
  const passLogger =
693
777
  backCompatContext.taggedLogger ??
778
+ // eslint-disable-next-line import/no-deprecated
694
779
  new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
695
780
  const logger = createChildLogger({
696
781
  logger: passLogger,
@@ -785,7 +870,7 @@ export class ContainerRuntime
785
870
  idCompressor =
786
871
  serializedIdCompressor !== undefined
787
872
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
788
- : new IdCompressor(createSessionId(), logger);
873
+ : IdCompressor.create(logger);
789
874
  }
790
875
 
791
876
  const runtime = new containerRuntimeCtor(
@@ -818,6 +903,7 @@ export class ContainerRuntime
818
903
  initializeEntryPoint,
819
904
  );
820
905
 
906
+ await runtime.blobManager.processStashedChanges();
821
907
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
822
908
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
823
909
  await runtime.pendingStateManager.applyStashedOpsAt(0);
@@ -849,6 +935,7 @@ export class ContainerRuntime
849
935
  localOpMetadata: unknown,
850
936
  opMetadata: Record<string, unknown> | undefined,
851
937
  ) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
938
+ // Note: compatDetails is not included in this deprecated API
852
939
  }
853
940
 
854
941
  private readonly submitFn: (
@@ -984,7 +1071,6 @@ export class ContainerRuntime
984
1071
  private emitDirtyDocumentEvent = true;
985
1072
  private readonly enableOpReentryCheck: boolean;
986
1073
  private readonly disableAttachReorder: boolean | undefined;
987
- private readonly summaryStateUpdateMethod: string | undefined;
988
1074
  private readonly closeSummarizerDelayMs: number;
989
1075
  /**
990
1076
  * If true, summary generated is validate before uploading it to the server. With single commit summaries,
@@ -994,7 +1080,7 @@ export class ContainerRuntime
994
1080
  private readonly validateSummaryBeforeUpload: boolean;
995
1081
 
996
1082
  private readonly defaultTelemetrySignalSampleCount = 100;
997
- private _perfSignalData: IPerfSignalReport = {
1083
+ private readonly _perfSignalData: IPerfSignalReport = {
998
1084
  signalsLost: 0,
999
1085
  signalSequenceNumber: 0,
1000
1086
  signalTimestamp: 0,
@@ -1464,22 +1550,17 @@ export class ContainerRuntime
1464
1550
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1465
1551
  this._audience = audience!;
1466
1552
 
1467
- this.summaryStateUpdateMethod = this.mc.config.getString(
1468
- "Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2",
1469
- );
1470
1553
  const closeSummarizerDelayOverride = this.mc.config.getNumber(
1471
1554
  "Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
1472
1555
  );
1473
1556
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
1474
1557
  this.validateSummaryBeforeUpload =
1475
- this.mc.config.getBoolean("Fluid.ContainerRuntime.Test.ValidateSummaryBeforeUpload") ??
1476
- false;
1558
+ this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
1477
1559
 
1478
1560
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
1479
1561
 
1480
1562
  this.dirtyContainer =
1481
- this.attachState !== AttachState.Attached ||
1482
- this.pendingStateManager.hasPendingMessages();
1563
+ this.attachState !== AttachState.Attached || this.hasPendingMessages();
1483
1564
  context.updateDirtyContainerState(this.dirtyContainer);
1484
1565
 
1485
1566
  if (this.summariesDisabled) {
@@ -1564,6 +1645,9 @@ export class ContainerRuntime
1564
1645
  },
1565
1646
  this.heuristicsDisabled,
1566
1647
  );
1648
+ this.summaryManager.on("summarize", (eventProps) => {
1649
+ this.emit("summarize", eventProps);
1650
+ });
1567
1651
  this.summaryManager.start();
1568
1652
  }
1569
1653
  }
@@ -1619,7 +1703,6 @@ export class ContainerRuntime
1619
1703
  disableAttachReorder: this.disableAttachReorder,
1620
1704
  disablePartialFlush,
1621
1705
  idCompressorEnabled: this.idCompressorEnabled,
1622
- summaryStateUpdateMethod: this.summaryStateUpdateMethod,
1623
1706
  closeSummarizerDelayOverride,
1624
1707
  }),
1625
1708
  telemetryDocumentId: this.telemetryDocumentId,
@@ -1736,7 +1819,7 @@ export class ContainerRuntime
1736
1819
  subRequest.url.startsWith("/"),
1737
1820
  0x126 /* "Expected createSubRequest url to include a leading slash" */,
1738
1821
  );
1739
- return dataStore.IFluidRouter.request(subRequest);
1822
+ return dataStore.request(subRequest);
1740
1823
  }
1741
1824
 
1742
1825
  return create404Response(request);
@@ -1784,6 +1867,7 @@ export class ContainerRuntime
1784
1867
  dataStoreContext.packagePath,
1785
1868
  request?.headers,
1786
1869
  );
1870
+
1787
1871
  return dataStoreChannel;
1788
1872
  }
1789
1873
 
@@ -1878,7 +1962,7 @@ export class ContainerRuntime
1878
1962
  this.mc.logger.sendTelemetryEvent({
1879
1963
  eventName: "ReconnectsWithNoProgress",
1880
1964
  attempts: this.consecutiveReconnects,
1881
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1965
+ pendingMessages: this.pendingMessagesCount,
1882
1966
  });
1883
1967
  }
1884
1968
 
@@ -1947,14 +2031,15 @@ export class ContainerRuntime
1947
2031
  */
1948
2032
  private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
1949
2033
  assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1950
- const { type, contents } = JSON.parse(serializedContent);
2034
+ const { type, contents, compatDetails }: ContainerRuntimeMessage =
2035
+ JSON.parse(serializedContent);
1951
2036
  assert(type !== undefined, 0x6d6 /* incorrect op content format */);
1952
- return { type, contents };
2037
+ return { type, contents, compatDetails };
1953
2038
  }
1954
2039
 
1955
2040
  private async applyStashedOp(op: string): Promise<unknown> {
1956
2041
  // Need to parse from string for back-compat
1957
- const { type, contents } = this.parseOpContent(op);
2042
+ const { type, contents, compatDetails } = this.parseOpContent(op);
1958
2043
  switch (type) {
1959
2044
  case ContainerMessageType.FluidDataStoreOp:
1960
2045
  return this.dataStores.applyStashedOp(contents as IEnvelope);
@@ -1973,8 +2058,27 @@ export class ContainerRuntime
1973
2058
  throw new Error("chunkedOp not expected here");
1974
2059
  case ContainerMessageType.Rejoin:
1975
2060
  throw new Error("rejoin not expected here");
1976
- default:
1977
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
2061
+ default: {
2062
+ // This should be extremely rare for stashed ops.
2063
+ // It would require a newer runtime stashing ops and then an older one applying them,
2064
+ // e.g. if an app rolled back its container version
2065
+ const compatBehavior = compatDetails?.behavior;
2066
+ if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
2067
+ const error = DataProcessingError.create(
2068
+ "Stashed runtime message of unknown type",
2069
+ "applyStashedOp",
2070
+ undefined /* sequencedMessage */,
2071
+ {
2072
+ messageDetails: JSON.stringify({
2073
+ type,
2074
+ compatBehavior,
2075
+ }),
2076
+ },
2077
+ );
2078
+ this.closeFn(error);
2079
+ throw error;
2080
+ }
2081
+ }
1978
2082
  }
1979
2083
  }
1980
2084
 
@@ -1988,32 +2092,6 @@ export class ContainerRuntime
1988
2092
  return;
1989
2093
  }
1990
2094
 
1991
- // If attachment blobs were added while disconnected, we need to delay
1992
- // propagation of the "connected" event until we have uploaded them to
1993
- // ensure we don't submit ops referencing a blob that has not been uploaded
1994
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1995
- const connecting =
1996
- connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1997
- if (connecting && this.blobManager.hasPendingOfflineUploads) {
1998
- assert(
1999
- !this.delayConnectClientId,
2000
- 0x392 /* Connect event delay must be canceled before subsequent connect event */,
2001
- );
2002
- assert(!!clientId, 0x393 /* Must have clientId when connecting */);
2003
- this.delayConnectClientId = clientId;
2004
- this.blobManager.onConnected().then(
2005
- () => {
2006
- // make sure we didn't reconnect before the promise resolved
2007
- if (this.delayConnectClientId === clientId && !this.disposed) {
2008
- this.delayConnectClientId = undefined;
2009
- this.setConnectionStateCore(connected, clientId);
2010
- }
2011
- },
2012
- (error) => this.closeFn(error),
2013
- );
2014
- return;
2015
- }
2016
-
2017
2095
  this.setConnectionStateCore(connected, clientId);
2018
2096
  }
2019
2097
 
@@ -2061,7 +2139,7 @@ export class ContainerRuntime
2061
2139
  {
2062
2140
  dataLoss: 1,
2063
2141
  attempts: this.consecutiveReconnects,
2064
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
2142
+ pendingMessages: this.pendingMessagesCount,
2065
2143
  },
2066
2144
  ),
2067
2145
  );
@@ -2086,15 +2164,15 @@ export class ContainerRuntime
2086
2164
  public process(messageArg: ISequencedDocumentMessage, local: boolean) {
2087
2165
  this.verifyNotClosed();
2088
2166
 
2089
- // Whether or not the message is actually a runtime message.
2167
+ // Whether or not the message appears to be a runtime message from an up-to-date client.
2090
2168
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
2091
2169
  // or something different, like a system message.
2092
- const runtimeMessage = messageArg.type === MessageType.Operation;
2170
+ const modernRuntimeMessage = messageArg.type === MessageType.Operation;
2093
2171
 
2094
2172
  // Do shallow copy of message, as the processing flow will modify it.
2095
2173
  const messageCopy = { ...messageArg };
2096
2174
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
2097
- this.processCore(message, local, runtimeMessage);
2175
+ this.processCore(message, local, modernRuntimeMessage);
2098
2176
  }
2099
2177
  }
2100
2178
 
@@ -2104,12 +2182,12 @@ export class ContainerRuntime
2104
2182
  * Direct the message to the correct subsystem for processing, and implement other side effects
2105
2183
  * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
2106
2184
  * @param local - Did this client send the op?
2107
- * @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
2185
+ * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
2108
2186
  */
2109
2187
  private processCore(
2110
- message: ISequencedDocumentMessage,
2188
+ message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
2111
2189
  local: boolean,
2112
- runtimeMessage: boolean,
2190
+ modernRuntimeMessage: boolean,
2113
2191
  ) {
2114
2192
  // Surround the actual processing of the operation with messages to the schedule manager indicating
2115
2193
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
@@ -2120,8 +2198,10 @@ export class ContainerRuntime
2120
2198
 
2121
2199
  try {
2122
2200
  let localOpMetadata: unknown;
2123
- if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2124
- localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
2201
+ if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
2202
+ localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
2203
+ message as SequencedContainerRuntimeMessage,
2204
+ );
2125
2205
  }
2126
2206
 
2127
2207
  // If there are no more pending messages after processing a local message,
@@ -2130,51 +2210,14 @@ export class ContainerRuntime
2130
2210
  this.updateDocumentDirtyState(false);
2131
2211
  }
2132
2212
 
2133
- const type = message.type as ContainerMessageType;
2134
- switch (type) {
2135
- case ContainerMessageType.Attach:
2136
- this.dataStores.processAttachMessage(message, local);
2137
- break;
2138
- case ContainerMessageType.Alias:
2139
- this.processAliasMessage(message, localOpMetadata, local);
2140
- break;
2141
- case ContainerMessageType.FluidDataStoreOp:
2142
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2143
- break;
2144
- case ContainerMessageType.BlobAttach:
2145
- this.blobManager.processBlobAttachOp(message, local);
2146
- break;
2147
- case ContainerMessageType.IdAllocation:
2148
- assert(
2149
- this.idCompressor !== undefined,
2150
- 0x67c /* IdCompressor should be defined if enabled */,
2151
- );
2152
- this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2153
- break;
2154
- case ContainerMessageType.ChunkedOp:
2155
- case ContainerMessageType.Rejoin:
2156
- break;
2157
- default:
2158
- if (runtimeMessage) {
2159
- const error = DataProcessingError.create(
2160
- // Former assert 0x3ce
2161
- "Runtime message of unknown type",
2162
- "OpProcessing",
2163
- message,
2164
- {
2165
- local,
2166
- type: message.type,
2167
- contentType: typeof message.contents,
2168
- batch: (message.metadata as IBatchMetadata | undefined)?.batch,
2169
- compression: message.compression,
2170
- },
2171
- );
2172
- this.closeFn(error);
2173
- throw error;
2174
- }
2175
- }
2213
+ this.validateAndProcessRuntimeMessage(
2214
+ message,
2215
+ localOpMetadata,
2216
+ local,
2217
+ modernRuntimeMessage,
2218
+ );
2176
2219
 
2177
- this.emit("op", message, runtimeMessage);
2220
+ this.emit("op", message, modernRuntimeMessage);
2178
2221
 
2179
2222
  this.scheduleManager.afterOpProcessing(undefined, message);
2180
2223
 
@@ -2189,13 +2232,74 @@ export class ContainerRuntime
2189
2232
  throw e;
2190
2233
  }
2191
2234
  }
2192
-
2193
- private processAliasMessage(
2235
+ /**
2236
+ * Assuming the given message is also a ContainerRuntimeMessage,
2237
+ * checks its type and dispatches the message to the appropriate handler in the runtime.
2238
+ * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
2239
+ */
2240
+ private validateAndProcessRuntimeMessage(
2194
2241
  message: ISequencedDocumentMessage,
2195
2242
  localOpMetadata: unknown,
2196
2243
  local: boolean,
2197
- ) {
2198
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
2244
+ expectRuntimeMessageType: boolean,
2245
+ ): asserts message is SequencedContainerRuntimeMessage {
2246
+ // Optimistically extract ContainerRuntimeMessage-specific props from the message
2247
+ const { type: maybeContainerMessageType, compatDetails } =
2248
+ message as ContainerRuntimeMessage;
2249
+
2250
+ switch (maybeContainerMessageType) {
2251
+ case ContainerMessageType.Attach:
2252
+ this.dataStores.processAttachMessage(message, local);
2253
+ break;
2254
+ case ContainerMessageType.Alias:
2255
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
2256
+ break;
2257
+ case ContainerMessageType.FluidDataStoreOp:
2258
+ this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
2259
+ break;
2260
+ case ContainerMessageType.BlobAttach:
2261
+ this.blobManager.processBlobAttachOp(message, local);
2262
+ break;
2263
+ case ContainerMessageType.IdAllocation:
2264
+ assert(
2265
+ this.idCompressor !== undefined,
2266
+ 0x67c /* IdCompressor should be defined if enabled */,
2267
+ );
2268
+ this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
2269
+ break;
2270
+ case ContainerMessageType.ChunkedOp:
2271
+ case ContainerMessageType.Rejoin:
2272
+ break;
2273
+ default: {
2274
+ // If we didn't necessarily expect a runtime message type, then no worries - just return
2275
+ // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
2276
+ if (!expectRuntimeMessageType) {
2277
+ return;
2278
+ }
2279
+
2280
+ const compatBehavior = compatDetails?.behavior;
2281
+ if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
2282
+ const error = DataProcessingError.create(
2283
+ // Former assert 0x3ce
2284
+ "Runtime message of unknown type",
2285
+ "OpProcessing",
2286
+ message,
2287
+ {
2288
+ local,
2289
+ messageDetails: JSON.stringify({
2290
+ type: message.type,
2291
+ contentType: typeof message.contents,
2292
+ compatBehavior,
2293
+ batch: (message.metadata as IBatchMetadata | undefined)?.batch,
2294
+ compression: message.compression,
2295
+ }),
2296
+ },
2297
+ );
2298
+ this.closeFn(error);
2299
+ throw error;
2300
+ }
2301
+ }
2302
+ }
2199
2303
  }
2200
2304
 
2201
2305
  /**
@@ -2834,7 +2938,7 @@ export class ContainerRuntime
2834
2938
  * @param options - options controlling how the summary is generated or submitted
2835
2939
  */
2836
2940
  public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
2837
- const { fullTree = false, refreshLatestAck, summaryLogger } = options;
2941
+ const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
2838
2942
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2839
2943
  // use it for all events logged during this summary.
2840
2944
  const summaryNumber = this.nextSummaryNumber;
@@ -2862,6 +2966,50 @@ export class ContainerRuntime
2862
2966
  await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
2863
2967
  }
2864
2968
 
2969
+ // If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
2970
+ // incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
2971
+ // within the timeout, check if it should be failed or can continue.
2972
+ if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
2973
+ const countBefore = this.pendingMessagesCount;
2974
+ // The timeout for waiting for pending ops can be overridden via configurations.
2975
+ const pendingOpsTimeout =
2976
+ this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
2977
+ defaultPendingOpsWaitTimeoutMs;
2978
+ await new Promise<void>((resolve, reject) => {
2979
+ const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
2980
+ this.once("saved", () => {
2981
+ clearTimeout(timeoutId);
2982
+ resolve();
2983
+ });
2984
+ this.once("dispose", () => {
2985
+ clearTimeout(timeoutId);
2986
+ reject(new Error("Runtime is disposed while summarizing"));
2987
+ });
2988
+ });
2989
+
2990
+ // Log that there are pending ops while summarizing. This will help us gather data on how often this
2991
+ // happens, whether we attempted to wait for these ops to be acked and what was the result.
2992
+ summaryNumberLogger.sendTelemetryEvent({
2993
+ eventName: "PendingOpsWhileSummarizing",
2994
+ saved: this.hasPendingMessages() ? false : true,
2995
+ timeout: pendingOpsTimeout,
2996
+ countBefore,
2997
+ countAfter: this.pendingMessagesCount,
2998
+ });
2999
+
3000
+ // There could still be pending ops. Check if summary should fail or continue.
3001
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(
3002
+ summaryNumberLogger,
3003
+ this.deltaManager.lastSequenceNumber,
3004
+ this.deltaManager.minimumSequenceNumber,
3005
+ finalAttempt,
3006
+ true /* beforeSummaryGeneration */,
3007
+ );
3008
+ if (pendingMessagesFailResult !== undefined) {
3009
+ return pendingMessagesFailResult;
3010
+ }
3011
+ }
3012
+
2865
3013
  const shouldPauseInboundSignal =
2866
3014
  this.mc.config.getBoolean(
2867
3015
  "Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
@@ -2952,9 +3100,9 @@ export class ContainerRuntime
2952
3100
  };
2953
3101
  }
2954
3102
 
2955
- // If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
2956
- // correct before this summary is uploaded.
3103
+ // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
2957
3104
  if (this.validateSummaryBeforeUpload) {
3105
+ // Validate that the summaries generated by summarize nodes is correct.
2958
3106
  const validateResult = this.summarizerNode.validateSummary();
2959
3107
  if (!validateResult.success) {
2960
3108
  const { success, ...loggingProps } = validateResult;
@@ -2970,6 +3118,17 @@ export class ContainerRuntime
2970
3118
  error,
2971
3119
  };
2972
3120
  }
3121
+
3122
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(
3123
+ summaryNumberLogger,
3124
+ summaryRefSeqNum,
3125
+ minimumSequenceNumber,
3126
+ finalAttempt,
3127
+ false /* beforeSummaryGeneration */,
3128
+ );
3129
+ if (pendingMessagesFailResult !== undefined) {
3130
+ return pendingMessagesFailResult;
3131
+ }
2973
3132
  }
2974
3133
 
2975
3134
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
@@ -3110,8 +3269,78 @@ export class ContainerRuntime
3110
3269
  }
3111
3270
  }
3112
3271
 
3272
+ /**
3273
+ * This helper is called during summarization. If there are pending ops, it will return a failed summarize result
3274
+ * (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
3275
+ * @param logger - The logger to be used for sending telemetry.
3276
+ * @param referenceSequenceNumber - The reference sequence number of the summary attempt.
3277
+ * @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
3278
+ * @param finalAttempt - Whether this is the final summary attempt.
3279
+ * @param beforeSummaryGeneration - Whether this is called before summary generation or after.
3280
+ * @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
3281
+ */
3282
+ private async shouldFailSummaryOnPendingOps(
3283
+ logger: ITelemetryLoggerExt,
3284
+ referenceSequenceNumber: number,
3285
+ minimumSequenceNumber: number,
3286
+ finalAttempt: boolean,
3287
+ beforeSummaryGeneration: boolean,
3288
+ ): Promise<IBaseSummarizeResult | undefined> {
3289
+ if (!this.hasPendingMessages()) {
3290
+ return;
3291
+ }
3292
+
3293
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
3294
+ // This is a fallback to make progress in documents where there are consistently pending ops in
3295
+ // the summarizer.
3296
+ if (
3297
+ finalAttempt &&
3298
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")
3299
+ ) {
3300
+ const error = DataProcessingError.create(
3301
+ "Pending ops during summarization",
3302
+ "submitSummary",
3303
+ undefined,
3304
+ { pendingMessages: this.pendingMessagesCount },
3305
+ );
3306
+ logger.sendErrorEvent(
3307
+ {
3308
+ eventName: "SkipFailingIncorrectSummary",
3309
+ referenceSequenceNumber,
3310
+ minimumSequenceNumber,
3311
+ beforeGenerate: beforeSummaryGeneration,
3312
+ },
3313
+ error,
3314
+ );
3315
+ } else {
3316
+ // The retry delay when there are pending ops can be overridden via config so that we can adjust it
3317
+ // based on telemetry while we decide on a stable number.
3318
+ const retryDelayMs =
3319
+ this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
3320
+ defaultPendingOpsRetryDelayMs;
3321
+ const error = new RetriableSummaryError(
3322
+ "PendingOpsWhileSummarizing",
3323
+ retryDelayMs / 1000,
3324
+ {
3325
+ count: this.pendingMessagesCount,
3326
+ beforeGenerate: beforeSummaryGeneration,
3327
+ },
3328
+ );
3329
+ return {
3330
+ stage: "base",
3331
+ referenceSequenceNumber,
3332
+ minimumSequenceNumber,
3333
+ error,
3334
+ };
3335
+ }
3336
+ }
3337
+
3338
+ private get pendingMessagesCount(): number {
3339
+ return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
3340
+ }
3341
+
3113
3342
  private hasPendingMessages() {
3114
- return this.pendingStateManager.hasPendingMessages() || !this.outbox.isEmpty;
3343
+ return this.pendingMessagesCount !== 0;
3115
3344
  }
3116
3345
 
3117
3346
  private updateDocumentDirtyState(dirty: boolean) {
@@ -3178,7 +3407,7 @@ export class ContainerRuntime
3178
3407
  );
3179
3408
  idRange = this.idCompressor.takeNextCreationRange();
3180
3409
  // Don't include the idRange if there weren't any Ids allocated
3181
- idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
3410
+ idRange = idRange?.ids !== undefined ? idRange : undefined;
3182
3411
  }
3183
3412
 
3184
3413
  if (idRange !== undefined) {
@@ -3439,11 +3668,31 @@ export class ContainerRuntime
3439
3668
  case ContainerMessageType.Rejoin:
3440
3669
  this.submit(message);
3441
3670
  break;
3442
- default:
3443
- unreachableCase(
3444
- message.type,
3445
- `Unknown ContainerMessageType [type: ${message.type}]`,
3446
- );
3671
+ default: {
3672
+ // This case should be very rare - it would imply an op was stashed from a
3673
+ // future version of runtime code and now is being applied on an older version
3674
+ const compatBehavior = message.compatDetails?.behavior;
3675
+ if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
3676
+ this.logger.sendTelemetryEvent({
3677
+ eventName: "resubmitUnrecognizedMessageTypeAllowed",
3678
+ messageDetails: { type: message.type, compatBehavior },
3679
+ });
3680
+ } else {
3681
+ const error = DataProcessingError.create(
3682
+ "Resubmitting runtime message of unknown type",
3683
+ "reSubmitCore",
3684
+ undefined /* sequencedMessage */,
3685
+ {
3686
+ messageDetails: JSON.stringify({
3687
+ type: message.type,
3688
+ compatBehavior,
3689
+ }),
3690
+ },
3691
+ );
3692
+ this.closeFn(error);
3693
+ throw error;
3694
+ }
3695
+ }
3447
3696
  }
3448
3697
  }
3449
3698
 
@@ -3457,6 +3706,7 @@ export class ContainerRuntime
3457
3706
  this.dataStores.rollbackDataStoreOp(contents as IEnvelope, localOpMetadata);
3458
3707
  break;
3459
3708
  default:
3709
+ // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
3460
3710
  throw new Error(`Can't rollback ${type}`);
3461
3711
  }
3462
3712
  }
@@ -3484,12 +3734,22 @@ export class ContainerRuntime
3484
3734
  /** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
3485
3735
  public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
3486
3736
  const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
3737
+ // proposalHandle is always passed from RunningSummarizer.
3738
+ assert(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
3487
3739
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3488
- // The call to fetch the snapshot is very expensive and not always needed.
3489
- // It should only be done by the summarizerNode, if required.
3490
- // When fetching from storage we will always get the latest version and do not use the ackHandle.
3491
- const fetchLatestSnapshot: () => Promise<IFetchSnapshotResult> = async () => {
3492
- let fetchResult = await this.fetchLatestSnapshotFromStorage(
3740
+ const result = await this.summarizerNode.refreshLatestSummary(
3741
+ proposalHandle,
3742
+ summaryRefSeq,
3743
+ );
3744
+
3745
+ /**
3746
+ * When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
3747
+ * current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
3748
+ * it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
3749
+ * and then close as the current main client is likely to be re-elected as the parent summarizer again.
3750
+ */
3751
+ if (!result.isSummaryTracked && result.isSummaryNewer) {
3752
+ const fetchResult = await this.fetchSnapshotFromStorage(
3493
3753
  summaryLogger,
3494
3754
  {
3495
3755
  eventName: "RefreshLatestSummaryAckFetch",
@@ -3497,27 +3757,9 @@ export class ContainerRuntime
3497
3757
  targetSequenceNumber: summaryRefSeq,
3498
3758
  },
3499
3759
  readAndParseBlob,
3760
+ null,
3500
3761
  );
3501
3762
 
3502
- /**
3503
- * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
3504
- * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
3505
- * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
3506
- * change that started fetching latest snapshot always.
3507
- */
3508
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3509
- fetchResult = await this.fetchSnapshotFromStorageAndClose(
3510
- summaryLogger,
3511
- {
3512
- eventName: "RefreshLatestSummaryAckFetchBackCompat",
3513
- ackHandle,
3514
- targetSequenceNumber: summaryRefSeq,
3515
- },
3516
- readAndParseBlob,
3517
- ackHandle,
3518
- );
3519
- }
3520
-
3521
3763
  /**
3522
3764
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
3523
3765
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -3543,29 +3785,12 @@ export class ContainerRuntime
3543
3785
  throw error;
3544
3786
  }
3545
3787
 
3546
- // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
3547
- // wait for the delta manager to catch up before refreshing the latest Summary.
3548
- await this.waitForDeltaManagerToCatchup(
3549
- fetchResult.latestSnapshotRefSeq,
3550
- summaryLogger,
3551
- );
3552
-
3553
- return {
3554
- snapshotTree: fetchResult.snapshotTree,
3555
- snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3556
- };
3557
- };
3558
-
3559
- const result = await this.summarizerNode.refreshLatestSummary(
3560
- proposalHandle,
3561
- summaryRefSeq,
3562
- fetchLatestSnapshot,
3563
- readAndParseBlob,
3564
- summaryLogger,
3565
- );
3788
+ await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
3789
+ return;
3790
+ }
3566
3791
 
3567
3792
  // Notify the garbage collector so it can update its latest summary state.
3568
- await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
3793
+ await this.garbageCollector.refreshLatestSummary(result);
3569
3794
  }
3570
3795
 
3571
3796
  /**
@@ -3578,56 +3803,49 @@ export class ContainerRuntime
3578
3803
  summaryLogger: ITelemetryLoggerExt,
3579
3804
  ): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
3580
3805
  const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
3581
- const { snapshotTree, versionId, latestSnapshotRefSeq } =
3582
- await this.fetchLatestSnapshotFromStorage(
3583
- summaryLogger,
3584
- {
3585
- eventName: "RefreshLatestSummaryFromServerFetch",
3586
- },
3587
- readAndParseBlob,
3588
- );
3589
- const fetchLatestSnapshot: IFetchSnapshotResult = {
3590
- snapshotTree,
3591
- snapshotRefSeq: latestSnapshotRefSeq,
3592
- };
3593
- const result = await this.summarizerNode.refreshLatestSummary(
3594
- undefined /* proposalHandle */,
3595
- latestSnapshotRefSeq,
3596
- async () => fetchLatestSnapshot,
3597
- readAndParseBlob,
3806
+ const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(
3598
3807
  summaryLogger,
3599
- );
3600
-
3601
- // Notify the garbage collector so it can update its latest summary state.
3602
- await this.garbageCollector.refreshLatestSummary(
3603
- undefined /* proposalHandle */,
3604
- result,
3808
+ {
3809
+ eventName: "RefreshLatestSummaryFromServerFetch",
3810
+ },
3605
3811
  readAndParseBlob,
3812
+ null,
3606
3813
  );
3607
3814
 
3815
+ await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
3816
+
3608
3817
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
3609
3818
  }
3610
3819
 
3611
- private async fetchLatestSnapshotFromStorage(
3612
- logger: ITelemetryLoggerExt,
3613
- event: ITelemetryGenericEvent,
3614
- readAndParseBlob: ReadAndParseBlob,
3615
- ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3616
- return this.fetchSnapshotFromStorageAndClose(
3617
- logger,
3618
- event,
3619
- readAndParseBlob,
3620
- null /* latest */,
3820
+ private async closeStaleSummarizer(codePath: string): Promise<void> {
3821
+ this.mc.logger.sendTelemetryEvent(
3822
+ {
3823
+ eventName: "ClosingSummarizerOnSummaryStale",
3824
+ codePath,
3825
+ message: "Stopping fetch from storage",
3826
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
3827
+ },
3828
+ new GenericError("Restarting summarizer instead of refreshing"),
3621
3829
  );
3830
+
3831
+ // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
3832
+ await delay(this.closeSummarizerDelayMs);
3833
+ this._summarizer?.stop("latestSummaryStateStale");
3834
+ this.disposeFn();
3622
3835
  }
3623
3836
 
3624
- private async fetchSnapshotFromStorageAndClose(
3837
+ /**
3838
+ * Downloads snapshot from storage with the given versionId or latest if versionId is null.
3839
+ * By default, it also closes the container after downloading the snapshot. However, this may be
3840
+ * overridden via options.
3841
+ */
3842
+ private async fetchSnapshotFromStorage(
3625
3843
  logger: ITelemetryLoggerExt,
3626
3844
  event: ITelemetryGenericEvent,
3627
3845
  readAndParseBlob: ReadAndParseBlob,
3628
3846
  versionId: string | null,
3629
3847
  ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3630
- const snapshotResults = await PerformanceEvent.timedExecAsync(
3848
+ return PerformanceEvent.timedExecAsync(
3631
3849
  logger,
3632
3850
  event,
3633
3851
  async (perfEvent: {
@@ -3673,30 +3891,6 @@ export class ContainerRuntime
3673
3891
  };
3674
3892
  },
3675
3893
  );
3676
-
3677
- // We choose to close the summarizer after the snapshot cache is updated to avoid
3678
- // situations which the main client (which is likely to be re-elected as the leader again)
3679
- // loads the summarizer from cache.
3680
- if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
3681
- this.mc.logger.sendTelemetryEvent(
3682
- {
3683
- ...event,
3684
- eventName: "ClosingSummarizerOnSummaryStale",
3685
- codePath: event.eventName,
3686
- message: "Stopping fetch from storage",
3687
- versionId: versionId != null ? versionId : undefined,
3688
- closeSummarizerDelayMs: this.closeSummarizerDelayMs,
3689
- },
3690
- new GenericError("Restarting summarizer instead of refreshing"),
3691
- );
3692
-
3693
- // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
3694
- await delay(this.closeSummarizerDelayMs);
3695
- this._summarizer?.stop("latestSummaryStateStale");
3696
- this.disposeFn();
3697
- }
3698
-
3699
- return snapshotResults;
3700
3894
  }
3701
3895
 
3702
3896
  public notifyAttaching() {} // do nothing (deprecated method)
@@ -3704,48 +3898,68 @@ export class ContainerRuntime
3704
3898
  public async getPendingLocalState(props?: {
3705
3899
  notifyImminentClosure: boolean;
3706
3900
  }): Promise<unknown> {
3707
- this.verifyNotClosed();
3708
- const waitBlobsToAttach = props?.notifyImminentClosure;
3709
- if (this._orderSequentiallyCalls !== 0) {
3710
- throw new UsageError("can't get state during orderSequentially");
3711
- }
3712
- const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
3713
- // Flush pending batch.
3714
- // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3715
- // to close current batch.
3716
- this.flush();
3901
+ return PerformanceEvent.timedExecAsync(
3902
+ this.mc.logger,
3903
+ {
3904
+ eventName: "getPendingLocalState",
3905
+ notifyImminentClosure: props?.notifyImminentClosure,
3906
+ },
3907
+ async (event) => {
3908
+ this.verifyNotClosed();
3909
+ const waitBlobsToAttach = props?.notifyImminentClosure;
3910
+ if (this._orderSequentiallyCalls !== 0) {
3911
+ throw new UsageError("can't get state during orderSequentially");
3912
+ }
3913
+ const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(
3914
+ waitBlobsToAttach,
3915
+ );
3916
+ const pending = this.pendingStateManager.getLocalState();
3917
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
3918
+ return; // no pending state to save
3919
+ }
3920
+ // Flush pending batch.
3921
+ // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
3922
+ // to close current batch.
3923
+ this.flush();
3717
3924
 
3718
- return {
3719
- pending: this.pendingStateManager.getLocalState(),
3720
- pendingAttachmentBlobs,
3721
- };
3925
+ const pendingState: IPendingRuntimeState = {
3926
+ pending,
3927
+ pendingAttachmentBlobs,
3928
+ };
3929
+ event.end({
3930
+ attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
3931
+ pendingOpsSize: pending?.pendingStates.length,
3932
+ });
3933
+ return pendingState;
3934
+ },
3935
+ );
3722
3936
  }
3723
3937
 
3724
- public readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"] = (...args) => {
3938
+ public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
3725
3939
  if (this.isSummarizerClient) {
3726
- return this.summarizer.summarizeOnDemand(...args);
3940
+ return this.summarizer.summarizeOnDemand(options);
3727
3941
  } else if (this.summaryManager !== undefined) {
3728
- return this.summaryManager.summarizeOnDemand(...args);
3942
+ return this.summaryManager.summarizeOnDemand(options);
3729
3943
  } else {
3730
3944
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
3731
3945
  // disableSummaries is turned on. We are throwing instead of returning a failure here,
3732
3946
  // because it is a misuse of the API rather than an expected failure.
3733
3947
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
3734
3948
  }
3735
- };
3949
+ }
3736
3950
 
3737
- public readonly enqueueSummarize: ISummarizer["enqueueSummarize"] = (...args) => {
3951
+ public enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
3738
3952
  if (this.isSummarizerClient) {
3739
- return this.summarizer.enqueueSummarize(...args);
3953
+ return this.summarizer.enqueueSummarize(options);
3740
3954
  } else if (this.summaryManager !== undefined) {
3741
- return this.summaryManager.enqueueSummarize(...args);
3955
+ return this.summaryManager.enqueueSummarize(options);
3742
3956
  } else {
3743
3957
  // If we're not the summarizer, and we don't have a summaryManager, we expect that
3744
3958
  // generateSummaries is turned off. We are throwing instead of returning a failure here,
3745
3959
  // because it is a misuse of the API rather than an expected failure.
3746
3960
  throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
3747
3961
  }
3748
- };
3962
+ }
3749
3963
 
3750
3964
  /**
3751
3965
  * * Forms a function that will request a Summarizer.