@fluidframework/container-runtime 2.0.0-internal.6.1.1 → 2.0.0-internal.6.2.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 (363) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +4 -3
  3. package/dist/batchTracker.d.ts +1 -1
  4. package/dist/batchTracker.js +1 -1
  5. package/dist/batchTracker.js.map +1 -1
  6. package/dist/blobManager.d.ts +4 -20
  7. package/dist/blobManager.d.ts.map +1 -1
  8. package/dist/blobManager.js +47 -125
  9. package/dist/blobManager.js.map +1 -1
  10. package/dist/containerRuntime.d.ts +82 -14
  11. package/dist/containerRuntime.d.ts.map +1 -1
  12. package/dist/containerRuntime.js +236 -138
  13. package/dist/containerRuntime.js.map +1 -1
  14. package/dist/dataStore.d.ts.map +1 -1
  15. package/dist/dataStore.js +1 -2
  16. package/dist/dataStore.js.map +1 -1
  17. package/dist/dataStoreContext.d.ts.map +1 -1
  18. package/dist/dataStoreContext.js +4 -5
  19. package/dist/dataStoreContext.js.map +1 -1
  20. package/dist/dataStoreContexts.d.ts +1 -2
  21. package/dist/dataStoreContexts.d.ts.map +1 -1
  22. package/dist/dataStoreContexts.js.map +1 -1
  23. package/dist/dataStoreRegistry.js +2 -2
  24. package/dist/dataStoreRegistry.js.map +1 -1
  25. package/dist/dataStores.d.ts.map +1 -1
  26. package/dist/dataStores.js +4 -5
  27. package/dist/dataStores.js.map +1 -1
  28. package/dist/error.d.ts +14 -0
  29. package/dist/error.d.ts.map +1 -0
  30. package/dist/error.js +21 -0
  31. package/dist/error.js.map +1 -0
  32. package/dist/gc/garbageCollection.d.ts +1 -1
  33. package/dist/gc/garbageCollection.d.ts.map +1 -1
  34. package/dist/gc/garbageCollection.js +23 -5
  35. package/dist/gc/garbageCollection.js.map +1 -1
  36. package/dist/gc/gcConfigs.d.ts.map +1 -1
  37. package/dist/gc/gcConfigs.js +5 -3
  38. package/dist/gc/gcConfigs.js.map +1 -1
  39. package/dist/gc/gcDefinitions.d.ts +2 -0
  40. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  41. package/dist/gc/gcDefinitions.js.map +1 -1
  42. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  43. package/dist/gc/gcTelemetry.js +2 -0
  44. package/dist/gc/gcTelemetry.js.map +1 -1
  45. package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
  46. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  47. package/dist/id-compressor/appendOnlySortedMap.js +25 -67
  48. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
  49. package/dist/id-compressor/finalSpace.d.ts +29 -0
  50. package/dist/id-compressor/finalSpace.d.ts.map +1 -0
  51. package/dist/id-compressor/finalSpace.js +62 -0
  52. package/dist/id-compressor/finalSpace.js.map +1 -0
  53. package/dist/id-compressor/idCompressor.d.ts +25 -250
  54. package/dist/id-compressor/idCompressor.d.ts.map +1 -1
  55. package/dist/id-compressor/idCompressor.js +385 -1149
  56. package/dist/id-compressor/idCompressor.js.map +1 -1
  57. package/dist/id-compressor/identifiers.d.ts +32 -0
  58. package/dist/id-compressor/identifiers.d.ts.map +1 -0
  59. package/dist/id-compressor/identifiers.js +15 -0
  60. package/dist/id-compressor/identifiers.js.map +1 -0
  61. package/dist/id-compressor/index.d.ts +5 -6
  62. package/dist/id-compressor/index.d.ts.map +1 -1
  63. package/dist/id-compressor/index.js +20 -26
  64. package/dist/id-compressor/index.js.map +1 -1
  65. package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
  66. package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
  67. package/dist/id-compressor/persistanceUtilities.js +43 -0
  68. package/dist/id-compressor/persistanceUtilities.js.map +1 -0
  69. package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  70. package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  71. package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
  72. package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  73. package/dist/id-compressor/sessions.d.ts +115 -0
  74. package/dist/id-compressor/sessions.d.ts.map +1 -0
  75. package/dist/id-compressor/sessions.js +305 -0
  76. package/dist/id-compressor/sessions.js.map +1 -0
  77. package/dist/id-compressor/utilities.d.ts +49 -0
  78. package/dist/id-compressor/utilities.d.ts.map +1 -0
  79. package/dist/id-compressor/utilities.js +166 -0
  80. package/dist/id-compressor/utilities.js.map +1 -0
  81. package/dist/index.d.ts +3 -3
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +6 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  86. package/dist/opLifecycle/opCompressor.js +1 -2
  87. package/dist/opLifecycle/opCompressor.js.map +1 -1
  88. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  89. package/dist/opLifecycle/opSplitter.js +2 -3
  90. package/dist/opLifecycle/opSplitter.js.map +1 -1
  91. package/dist/opLifecycle/outbox.d.ts +1 -0
  92. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  93. package/dist/opLifecycle/outbox.js +10 -11
  94. package/dist/opLifecycle/outbox.js.map +1 -1
  95. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  96. package/dist/opLifecycle/remoteMessageProcessor.js +11 -5
  97. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  98. package/dist/packageVersion.d.ts +1 -1
  99. package/dist/packageVersion.js +1 -1
  100. package/dist/packageVersion.js.map +1 -1
  101. package/dist/pendingStateManager.d.ts +12 -5
  102. package/dist/pendingStateManager.d.ts.map +1 -1
  103. package/dist/pendingStateManager.js +24 -10
  104. package/dist/pendingStateManager.js.map +1 -1
  105. package/dist/scheduleManager.d.ts.map +1 -1
  106. package/dist/scheduleManager.js +4 -5
  107. package/dist/scheduleManager.js.map +1 -1
  108. package/dist/summary/index.d.ts +2 -2
  109. package/dist/summary/index.d.ts.map +1 -1
  110. package/dist/summary/index.js +2 -1
  111. package/dist/summary/index.js.map +1 -1
  112. package/dist/summary/orderedClientElection.d.ts +1 -2
  113. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  114. package/dist/summary/orderedClientElection.js +2 -3
  115. package/dist/summary/orderedClientElection.js.map +1 -1
  116. package/dist/summary/runningSummarizer.d.ts +27 -4
  117. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  118. package/dist/summary/runningSummarizer.js +237 -66
  119. package/dist/summary/runningSummarizer.js.map +1 -1
  120. package/dist/summary/summarizer.d.ts +6 -5
  121. package/dist/summary/summarizer.d.ts.map +1 -1
  122. package/dist/summary/summarizer.js +70 -67
  123. package/dist/summary/summarizer.js.map +1 -1
  124. package/dist/summary/summarizerClientElection.d.ts +1 -1
  125. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  126. package/dist/summary/summarizerClientElection.js.map +1 -1
  127. package/dist/summary/summarizerTypes.d.ts +38 -25
  128. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  129. package/dist/summary/summarizerTypes.js.map +1 -1
  130. package/dist/summary/summaryCollection.d.ts +1 -2
  131. package/dist/summary/summaryCollection.d.ts.map +1 -1
  132. package/dist/summary/summaryCollection.js.map +1 -1
  133. package/dist/summary/summaryGenerator.d.ts +9 -3
  134. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  135. package/dist/summary/summaryGenerator.js +42 -38
  136. package/dist/summary/summaryGenerator.js.map +1 -1
  137. package/dist/summary/summaryManager.d.ts +7 -6
  138. package/dist/summary/summaryManager.d.ts.map +1 -1
  139. package/dist/summary/summaryManager.js +22 -15
  140. package/dist/summary/summaryManager.js.map +1 -1
  141. package/lib/batchTracker.d.ts +1 -1
  142. package/lib/batchTracker.js +1 -1
  143. package/lib/batchTracker.js.map +1 -1
  144. package/lib/blobManager.d.ts +4 -20
  145. package/lib/blobManager.d.ts.map +1 -1
  146. package/lib/blobManager.js +46 -124
  147. package/lib/blobManager.js.map +1 -1
  148. package/lib/containerRuntime.d.ts +82 -14
  149. package/lib/containerRuntime.d.ts.map +1 -1
  150. package/lib/containerRuntime.js +223 -123
  151. package/lib/containerRuntime.js.map +1 -1
  152. package/lib/dataStore.d.ts.map +1 -1
  153. package/lib/dataStore.js +1 -2
  154. package/lib/dataStore.js.map +1 -1
  155. package/lib/dataStoreContext.d.ts.map +1 -1
  156. package/lib/dataStoreContext.js +1 -2
  157. package/lib/dataStoreContext.js.map +1 -1
  158. package/lib/dataStoreContexts.d.ts +1 -2
  159. package/lib/dataStoreContexts.d.ts.map +1 -1
  160. package/lib/dataStoreContexts.js.map +1 -1
  161. package/lib/dataStoreRegistry.js +1 -1
  162. package/lib/dataStoreRegistry.js.map +1 -1
  163. package/lib/dataStores.d.ts.map +1 -1
  164. package/lib/dataStores.js +1 -2
  165. package/lib/dataStores.js.map +1 -1
  166. package/lib/error.d.ts +14 -0
  167. package/lib/error.d.ts.map +1 -0
  168. package/lib/error.js +17 -0
  169. package/lib/error.js.map +1 -0
  170. package/lib/gc/garbageCollection.d.ts +1 -1
  171. package/lib/gc/garbageCollection.d.ts.map +1 -1
  172. package/lib/gc/garbageCollection.js +22 -4
  173. package/lib/gc/garbageCollection.js.map +1 -1
  174. package/lib/gc/gcConfigs.d.ts.map +1 -1
  175. package/lib/gc/gcConfigs.js +3 -1
  176. package/lib/gc/gcConfigs.js.map +1 -1
  177. package/lib/gc/gcDefinitions.d.ts +2 -0
  178. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  179. package/lib/gc/gcDefinitions.js.map +1 -1
  180. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  181. package/lib/gc/gcTelemetry.js +2 -0
  182. package/lib/gc/gcTelemetry.js.map +1 -1
  183. package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
  184. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
  185. package/lib/id-compressor/appendOnlySortedMap.js +24 -65
  186. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
  187. package/lib/id-compressor/finalSpace.d.ts +29 -0
  188. package/lib/id-compressor/finalSpace.d.ts.map +1 -0
  189. package/lib/id-compressor/finalSpace.js +58 -0
  190. package/lib/id-compressor/finalSpace.js.map +1 -0
  191. package/lib/id-compressor/idCompressor.d.ts +25 -250
  192. package/lib/id-compressor/idCompressor.d.ts.map +1 -1
  193. package/lib/id-compressor/idCompressor.js +381 -1139
  194. package/lib/id-compressor/idCompressor.js.map +1 -1
  195. package/lib/id-compressor/identifiers.d.ts +32 -0
  196. package/lib/id-compressor/identifiers.d.ts.map +1 -0
  197. package/lib/id-compressor/identifiers.js +11 -0
  198. package/lib/id-compressor/identifiers.js.map +1 -0
  199. package/lib/id-compressor/index.d.ts +5 -6
  200. package/lib/id-compressor/index.d.ts.map +1 -1
  201. package/lib/id-compressor/index.js +5 -6
  202. package/lib/id-compressor/index.js.map +1 -1
  203. package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
  204. package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
  205. package/lib/id-compressor/persistanceUtilities.js +34 -0
  206. package/lib/id-compressor/persistanceUtilities.js.map +1 -0
  207. package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
  208. package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
  209. package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
  210. package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
  211. package/lib/id-compressor/sessions.d.ts +115 -0
  212. package/lib/id-compressor/sessions.d.ts.map +1 -0
  213. package/lib/id-compressor/sessions.js +290 -0
  214. package/lib/id-compressor/sessions.js.map +1 -0
  215. package/lib/id-compressor/utilities.d.ts +49 -0
  216. package/lib/id-compressor/utilities.d.ts.map +1 -0
  217. package/lib/id-compressor/utilities.js +148 -0
  218. package/lib/id-compressor/utilities.js.map +1 -0
  219. package/lib/index.d.ts +3 -3
  220. package/lib/index.d.ts.map +1 -1
  221. package/lib/index.js +2 -2
  222. package/lib/index.js.map +1 -1
  223. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  224. package/lib/opLifecycle/opCompressor.js +1 -2
  225. package/lib/opLifecycle/opCompressor.js.map +1 -1
  226. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  227. package/lib/opLifecycle/opSplitter.js +1 -2
  228. package/lib/opLifecycle/opSplitter.js.map +1 -1
  229. package/lib/opLifecycle/outbox.d.ts +1 -0
  230. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  231. package/lib/opLifecycle/outbox.js +6 -7
  232. package/lib/opLifecycle/outbox.js.map +1 -1
  233. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  234. package/lib/opLifecycle/remoteMessageProcessor.js +12 -6
  235. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  236. package/lib/packageVersion.d.ts +1 -1
  237. package/lib/packageVersion.js +1 -1
  238. package/lib/packageVersion.js.map +1 -1
  239. package/lib/pendingStateManager.d.ts +12 -5
  240. package/lib/pendingStateManager.d.ts.map +1 -1
  241. package/lib/pendingStateManager.js +21 -7
  242. package/lib/pendingStateManager.js.map +1 -1
  243. package/lib/scheduleManager.d.ts.map +1 -1
  244. package/lib/scheduleManager.js +1 -2
  245. package/lib/scheduleManager.js.map +1 -1
  246. package/lib/summary/index.d.ts +2 -2
  247. package/lib/summary/index.d.ts.map +1 -1
  248. package/lib/summary/index.js +1 -1
  249. package/lib/summary/index.js.map +1 -1
  250. package/lib/summary/orderedClientElection.d.ts +1 -2
  251. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  252. package/lib/summary/orderedClientElection.js +1 -2
  253. package/lib/summary/orderedClientElection.js.map +1 -1
  254. package/lib/summary/runningSummarizer.d.ts +27 -4
  255. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  256. package/lib/summary/runningSummarizer.js +237 -66
  257. package/lib/summary/runningSummarizer.js.map +1 -1
  258. package/lib/summary/summarizer.d.ts +6 -5
  259. package/lib/summary/summarizer.d.ts.map +1 -1
  260. package/lib/summary/summarizer.js +68 -65
  261. package/lib/summary/summarizer.js.map +1 -1
  262. package/lib/summary/summarizerClientElection.d.ts +1 -1
  263. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  264. package/lib/summary/summarizerClientElection.js.map +1 -1
  265. package/lib/summary/summarizerTypes.d.ts +38 -25
  266. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  267. package/lib/summary/summarizerTypes.js.map +1 -1
  268. package/lib/summary/summaryCollection.d.ts +1 -2
  269. package/lib/summary/summaryCollection.d.ts.map +1 -1
  270. package/lib/summary/summaryCollection.js.map +1 -1
  271. package/lib/summary/summaryGenerator.d.ts +9 -3
  272. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  273. package/lib/summary/summaryGenerator.js +43 -39
  274. package/lib/summary/summaryGenerator.js.map +1 -1
  275. package/lib/summary/summaryManager.d.ts +7 -6
  276. package/lib/summary/summaryManager.d.ts.map +1 -1
  277. package/lib/summary/summaryManager.js +23 -16
  278. package/lib/summary/summaryManager.js.map +1 -1
  279. package/package.json +27 -24
  280. package/src/batchTracker.ts +1 -1
  281. package/src/blobManager.ts +57 -146
  282. package/src/containerRuntime.ts +331 -158
  283. package/src/dataStore.ts +1 -2
  284. package/src/dataStoreContext.ts +3 -6
  285. package/src/dataStoreContexts.ts +1 -2
  286. package/src/dataStoreRegistry.ts +1 -1
  287. package/src/dataStores.ts +3 -5
  288. package/src/error.ts +18 -0
  289. package/src/gc/garbageCollection.ts +38 -5
  290. package/src/gc/gcConfigs.ts +4 -2
  291. package/src/gc/gcDefinitions.ts +2 -0
  292. package/src/gc/gcTelemetry.ts +2 -0
  293. package/src/id-compressor/appendOnlySortedMap.ts +25 -86
  294. package/src/id-compressor/finalSpace.ts +67 -0
  295. package/src/id-compressor/idCompressor.ts +455 -1681
  296. package/src/id-compressor/identifiers.ts +42 -0
  297. package/src/id-compressor/index.ts +11 -20
  298. package/src/id-compressor/persistanceUtilities.ts +58 -0
  299. package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
  300. package/src/id-compressor/sessions.ts +405 -0
  301. package/src/id-compressor/utilities.ts +187 -0
  302. package/src/index.ts +7 -1
  303. package/src/opLifecycle/opCompressor.ts +1 -2
  304. package/src/opLifecycle/opSplitter.ts +4 -4
  305. package/src/opLifecycle/outbox.ts +13 -10
  306. package/src/opLifecycle/remoteMessageProcessor.ts +19 -6
  307. package/src/packageVersion.ts +1 -1
  308. package/src/pendingStateManager.ts +49 -27
  309. package/src/scheduleManager.ts +5 -4
  310. package/src/summary/index.ts +3 -1
  311. package/src/summary/orderedClientElection.ts +6 -4
  312. package/src/summary/runningSummarizer.ts +276 -95
  313. package/src/summary/summarizer.ts +22 -12
  314. package/src/summary/summarizerClientElection.ts +1 -1
  315. package/src/summary/summarizerTypes.ts +40 -25
  316. package/src/summary/summaryCollection.ts +1 -2
  317. package/src/summary/summaryGenerator.ts +49 -52
  318. package/src/summary/summaryManager.ts +33 -11
  319. package/dist/id-compressor/idRange.d.ts +0 -11
  320. package/dist/id-compressor/idRange.d.ts.map +0 -1
  321. package/dist/id-compressor/idRange.js +0 -29
  322. package/dist/id-compressor/idRange.js.map +0 -1
  323. package/dist/id-compressor/numericUuid.d.ts +0 -59
  324. package/dist/id-compressor/numericUuid.d.ts.map +0 -1
  325. package/dist/id-compressor/numericUuid.js +0 -325
  326. package/dist/id-compressor/numericUuid.js.map +0 -1
  327. package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
  328. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  329. package/dist/id-compressor/sessionIdNormalizer.js +0 -483
  330. package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
  331. package/dist/id-compressor/utils.d.ts +0 -57
  332. package/dist/id-compressor/utils.d.ts.map +0 -1
  333. package/dist/id-compressor/utils.js +0 -90
  334. package/dist/id-compressor/utils.js.map +0 -1
  335. package/dist/id-compressor/uuidUtilities.d.ts +0 -28
  336. package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
  337. package/dist/id-compressor/uuidUtilities.js +0 -104
  338. package/dist/id-compressor/uuidUtilities.js.map +0 -1
  339. package/lib/id-compressor/idRange.d.ts +0 -11
  340. package/lib/id-compressor/idRange.d.ts.map +0 -1
  341. package/lib/id-compressor/idRange.js +0 -25
  342. package/lib/id-compressor/idRange.js.map +0 -1
  343. package/lib/id-compressor/numericUuid.d.ts +0 -59
  344. package/lib/id-compressor/numericUuid.d.ts.map +0 -1
  345. package/lib/id-compressor/numericUuid.js +0 -315
  346. package/lib/id-compressor/numericUuid.js.map +0 -1
  347. package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
  348. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
  349. package/lib/id-compressor/sessionIdNormalizer.js +0 -479
  350. package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
  351. package/lib/id-compressor/utils.d.ts +0 -57
  352. package/lib/id-compressor/utils.d.ts.map +0 -1
  353. package/lib/id-compressor/utils.js +0 -79
  354. package/lib/id-compressor/utils.js.map +0 -1
  355. package/lib/id-compressor/uuidUtilities.d.ts +0 -28
  356. package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
  357. package/lib/id-compressor/uuidUtilities.js +0 -96
  358. package/lib/id-compressor/uuidUtilities.js.map +0 -1
  359. package/src/id-compressor/idRange.ts +0 -35
  360. package/src/id-compressor/numericUuid.ts +0 -383
  361. package/src/id-compressor/sessionIdNormalizer.ts +0 -609
  362. package/src/id-compressor/utils.ts +0 -114
  363. package/src/id-compressor/uuidUtilities.ts +0 -120
@@ -1,10 +1,11 @@
1
1
  import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
2
- import { assert, delay, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
2
+ import { assert, delay, Trace, TypedEventEmitter } from "@fluidframework/common-utils";
3
3
  import { LazyPromise } from "@fluidframework/core-utils";
4
- import { createChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, wrapError, createChildMonitoringContext, } from "@fluidframework/telemetry-utils";
4
+ import { createChildLogger, createChildMonitoringContext, DataCorruptionError, DataProcessingError, GenericError, raiseConnectedEvent, PerformanceEvent,
5
+ // eslint-disable-next-line import/no-deprecated
6
+ TaggedLoggerAdapter, wrapError, UsageError, } from "@fluidframework/telemetry-utils";
5
7
  import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
6
8
  import { readAndParse } from "@fluidframework/driver-utils";
7
- import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
8
9
  import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
9
10
  import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
10
11
  import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
@@ -45,6 +46,18 @@ export var ContainerMessageType;
45
46
  */
46
47
  ContainerMessageType["IdAllocation"] = "idAllocation";
47
48
  })(ContainerMessageType || (ContainerMessageType = {}));
49
+ /**
50
+ * Utility to implement compat behaviors given an unknown message type
51
+ * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
52
+ *
53
+ * @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
54
+ * handled before calling this function (e.g. in a switch statement).
55
+ * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
56
+ */
57
+ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
58
+ // undefined defaults to same behavior as "FailToProcess"
59
+ return compatBehavior === "Ignore";
60
+ }
48
61
  export const DefaultSummaryConfiguration = {
49
62
  state: "enabled",
50
63
  minIdleTime: 0,
@@ -71,8 +84,12 @@ export var RuntimeHeaders;
71
84
  })(RuntimeHeaders || (RuntimeHeaders = {}));
72
85
  /** True if a tombstoned object should be returned without erroring */
73
86
  export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
87
+ /** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
88
+ export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
74
89
  /** Tombstone error responses will have this header set to true */
75
90
  export const TombstoneResponseHeaderKey = "isTombstoned";
91
+ /** Inactive error responses will have this header set to true */
92
+ export const InactiveResponseHeaderKey = "isInactive";
76
93
  /** Default values for Runtime Headers */
77
94
  export const defaultRuntimeHeaderData = {
78
95
  wait: true,
@@ -200,34 +217,6 @@ export class ContainerRuntime extends TypedEventEmitter {
200
217
  signalTimestamp: 0,
201
218
  trackingSignalSequenceNumber: undefined,
202
219
  };
203
- this.summarizeOnDemand = (...args) => {
204
- if (this.isSummarizerClient) {
205
- return this.summarizer.summarizeOnDemand(...args);
206
- }
207
- else if (this.summaryManager !== undefined) {
208
- return this.summaryManager.summarizeOnDemand(...args);
209
- }
210
- else {
211
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
212
- // disableSummaries is turned on. We are throwing instead of returning a failure here,
213
- // because it is a misuse of the API rather than an expected failure.
214
- throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
215
- }
216
- };
217
- this.enqueueSummarize = (...args) => {
218
- if (this.isSummarizerClient) {
219
- return this.summarizer.enqueueSummarize(...args);
220
- }
221
- else if (this.summaryManager !== undefined) {
222
- return this.summaryManager.enqueueSummarize(...args);
223
- }
224
- else {
225
- // If we're not the summarizer, and we don't have a summaryManager, we expect that
226
- // generateSummaries is turned off. We are throwing instead of returning a failure here,
227
- // because it is a misuse of the API rather than an expected failure.
228
- throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
229
- }
230
- };
231
220
  const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
232
221
  this.innerDeltaManager = deltaManager;
233
222
  this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
@@ -450,8 +439,7 @@ export class ContainerRuntime extends TypedEventEmitter {
450
439
  false;
451
440
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
452
441
  this.dirtyContainer =
453
- this.attachState !== AttachState.Attached ||
454
- this.pendingStateManager.hasPendingMessages();
442
+ this.attachState !== AttachState.Attached || this.hasPendingMessages();
455
443
  context.updateDirtyContainerState(this.dirtyContainer);
456
444
  if (this.summariesDisabled) {
457
445
  this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
@@ -499,6 +487,9 @@ export class ContainerRuntime extends TypedEventEmitter {
499
487
  formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
500
488
  initialDelayMs: this.initialSummarizerDelayMs,
501
489
  }, this.heuristicsDisabled);
490
+ this.summaryManager.on("summarize", (eventProps) => {
491
+ this.emit("summarize", eventProps);
492
+ });
502
493
  this.summaryManager.start();
503
494
  }
504
495
  }
@@ -607,11 +598,21 @@ export class ContainerRuntime extends TypedEventEmitter {
607
598
  * This object should provide all the functionality that the Container is expected to provide to the loader layer.
608
599
  */
609
600
  static async loadRuntime(params) {
610
- const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
601
+ const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
602
+ const initializeEntryPoint = params.initializeEntryPoint ??
603
+ (async (containerRuntime) => ({
604
+ get IFluidRouter() {
605
+ return this;
606
+ },
607
+ async request(req) {
608
+ return containerRuntime.request(req);
609
+ },
610
+ }));
611
611
  // If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
612
612
  // back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
613
613
  const backCompatContext = context;
614
614
  const passLogger = backCompatContext.taggedLogger ??
615
+ // eslint-disable-next-line import/no-deprecated
615
616
  new TaggedLoggerAdapter(backCompatContext.logger);
616
617
  const logger = createChildLogger({
617
618
  logger: passLogger,
@@ -673,7 +674,7 @@ export class ContainerRuntime extends TypedEventEmitter {
673
674
  idCompressor =
674
675
  serializedIdCompressor !== undefined
675
676
  ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
676
- : new IdCompressor(createSessionId(), logger);
677
+ : IdCompressor.create(logger);
677
678
  }
678
679
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
679
680
  summaryOptions,
@@ -688,6 +689,7 @@ export class ContainerRuntime extends TypedEventEmitter {
688
689
  enableGroupedBatching,
689
690
  }, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
690
691
  initializeEntryPoint);
692
+ await runtime.blobManager.processStashedChanges();
691
693
  // It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
692
694
  // at 1, so we won't see a replayed saved op with a sequence number of 0.
693
695
  await runtime.pendingStateManager.applyStashedOpsAt(0);
@@ -704,6 +706,7 @@ export class ContainerRuntime extends TypedEventEmitter {
704
706
  /** @deprecated - The functionality is no longer exposed publicly */
705
707
  get reSubmitFn() {
706
708
  return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
709
+ // Note: compatDetails is not included in this deprecated API
707
710
  }
708
711
  get flushMode() {
709
712
  return this._flushMode;
@@ -854,7 +857,7 @@ export class ContainerRuntime extends TypedEventEmitter {
854
857
  // We always expect createSubRequest to include a leading slash, but asserting here to protect against
855
858
  // unintentionally modifying the url if that changes.
856
859
  assert(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
857
- return dataStore.IFluidRouter.request(subRequest);
860
+ return dataStore.request(subRequest);
858
861
  }
859
862
  return create404Response(request);
860
863
  }
@@ -962,7 +965,7 @@ export class ContainerRuntime extends TypedEventEmitter {
962
965
  this.mc.logger.sendTelemetryEvent({
963
966
  eventName: "ReconnectsWithNoProgress",
964
967
  attempts: this.consecutiveReconnects,
965
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
968
+ pendingMessages: this.pendingMessagesCount,
966
969
  });
967
970
  }
968
971
  return this.consecutiveReconnects < this.maxConsecutiveReconnects;
@@ -1022,13 +1025,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1022
1025
  */
1023
1026
  parseOpContent(serializedContent) {
1024
1027
  assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
1025
- const { type, contents } = JSON.parse(serializedContent);
1028
+ const { type, contents, compatDetails } = JSON.parse(serializedContent);
1026
1029
  assert(type !== undefined, 0x6d6 /* incorrect op content format */);
1027
- return { type, contents };
1030
+ return { type, contents, compatDetails };
1028
1031
  }
1029
1032
  async applyStashedOp(op) {
1030
1033
  // Need to parse from string for back-compat
1031
- const { type, contents } = this.parseOpContent(op);
1034
+ const { type, contents, compatDetails } = this.parseOpContent(op);
1032
1035
  switch (type) {
1033
1036
  case ContainerMessageType.FluidDataStoreOp:
1034
1037
  return this.dataStores.applyStashedOp(contents);
@@ -1044,8 +1047,22 @@ export class ContainerRuntime extends TypedEventEmitter {
1044
1047
  throw new Error("chunkedOp not expected here");
1045
1048
  case ContainerMessageType.Rejoin:
1046
1049
  throw new Error("rejoin not expected here");
1047
- default:
1048
- unreachableCase(type, `Unknown ContainerMessageType: ${type}`);
1050
+ default: {
1051
+ // This should be extremely rare for stashed ops.
1052
+ // It would require a newer runtime stashing ops and then an older one applying them,
1053
+ // e.g. if an app rolled back its container version
1054
+ const compatBehavior = compatDetails?.behavior;
1055
+ if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
1056
+ const error = DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1057
+ messageDetails: JSON.stringify({
1058
+ type,
1059
+ compatBehavior,
1060
+ }),
1061
+ });
1062
+ this.closeFn(error);
1063
+ throw error;
1064
+ }
1065
+ }
1049
1066
  }
1050
1067
  }
1051
1068
  setConnectionState(connected, clientId) {
@@ -1057,24 +1074,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1057
1074
  // Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
1058
1075
  return;
1059
1076
  }
1060
- // If attachment blobs were added while disconnected, we need to delay
1061
- // propagation of the "connected" event until we have uploaded them to
1062
- // ensure we don't submit ops referencing a blob that has not been uploaded
1063
- // Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
1064
- const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
1065
- if (connecting && this.blobManager.hasPendingOfflineUploads) {
1066
- assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
1067
- assert(!!clientId, 0x393 /* Must have clientId when connecting */);
1068
- this.delayConnectClientId = clientId;
1069
- this.blobManager.onConnected().then(() => {
1070
- // make sure we didn't reconnect before the promise resolved
1071
- if (this.delayConnectClientId === clientId && !this.disposed) {
1072
- this.delayConnectClientId = undefined;
1073
- this.setConnectionStateCore(connected, clientId);
1074
- }
1075
- }, (error) => this.closeFn(error));
1076
- return;
1077
- }
1078
1077
  this.setConnectionStateCore(connected, clientId);
1079
1078
  }
1080
1079
  setConnectionStateCore(connected, clientId) {
@@ -1105,7 +1104,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1105
1104
  this.closeFn(DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
1106
1105
  dataLoss: 1,
1107
1106
  attempts: this.consecutiveReconnects,
1108
- pendingMessages: this.pendingStateManager.pendingMessagesCount,
1107
+ pendingMessages: this.pendingMessagesCount,
1109
1108
  }));
1110
1109
  return;
1111
1110
  }
@@ -1122,23 +1121,23 @@ export class ContainerRuntime extends TypedEventEmitter {
1122
1121
  }
1123
1122
  process(messageArg, local) {
1124
1123
  this.verifyNotClosed();
1125
- // Whether or not the message is actually a runtime message.
1124
+ // Whether or not the message appears to be a runtime message from an up-to-date client.
1126
1125
  // It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
1127
1126
  // or something different, like a system message.
1128
- const runtimeMessage = messageArg.type === MessageType.Operation;
1127
+ const modernRuntimeMessage = messageArg.type === MessageType.Operation;
1129
1128
  // Do shallow copy of message, as the processing flow will modify it.
1130
1129
  const messageCopy = { ...messageArg };
1131
1130
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1132
- this.processCore(message, local, runtimeMessage);
1131
+ this.processCore(message, local, modernRuntimeMessage);
1133
1132
  }
1134
1133
  }
1135
1134
  /**
1136
1135
  * Direct the message to the correct subsystem for processing, and implement other side effects
1137
1136
  * @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
1138
1137
  * @param local - Did this client send the op?
1139
- * @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
1138
+ * @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
1140
1139
  */
1141
- processCore(message, local, runtimeMessage) {
1140
+ processCore(message, local, modernRuntimeMessage) {
1142
1141
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1143
1142
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1144
1143
  // messages once a batch has been fully processed.
@@ -1146,7 +1145,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1146
1145
  this._processedClientSequenceNumber = message.clientSequenceNumber;
1147
1146
  try {
1148
1147
  let localOpMetadata;
1149
- if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1148
+ if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
1150
1149
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
1151
1150
  }
1152
1151
  // If there are no more pending messages after processing a local message,
@@ -1154,43 +1153,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1154
1153
  if (!this.hasPendingMessages()) {
1155
1154
  this.updateDocumentDirtyState(false);
1156
1155
  }
1157
- const type = message.type;
1158
- switch (type) {
1159
- case ContainerMessageType.Attach:
1160
- this.dataStores.processAttachMessage(message, local);
1161
- break;
1162
- case ContainerMessageType.Alias:
1163
- this.processAliasMessage(message, localOpMetadata, local);
1164
- break;
1165
- case ContainerMessageType.FluidDataStoreOp:
1166
- this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1167
- break;
1168
- case ContainerMessageType.BlobAttach:
1169
- this.blobManager.processBlobAttachOp(message, local);
1170
- break;
1171
- case ContainerMessageType.IdAllocation:
1172
- assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1173
- this.idCompressor.finalizeCreationRange(message.contents);
1174
- break;
1175
- case ContainerMessageType.ChunkedOp:
1176
- case ContainerMessageType.Rejoin:
1177
- break;
1178
- default:
1179
- if (runtimeMessage) {
1180
- const error = DataProcessingError.create(
1181
- // Former assert 0x3ce
1182
- "Runtime message of unknown type", "OpProcessing", message, {
1183
- local,
1184
- type: message.type,
1185
- contentType: typeof message.contents,
1186
- batch: message.metadata?.batch,
1187
- compression: message.compression,
1188
- });
1189
- this.closeFn(error);
1190
- throw error;
1191
- }
1192
- }
1193
- this.emit("op", message, runtimeMessage);
1156
+ this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
1157
+ this.emit("op", message, modernRuntimeMessage);
1194
1158
  this.scheduleManager.afterOpProcessing(undefined, message);
1195
1159
  if (local) {
1196
1160
  // If we have processed a local op, this means that the container is
@@ -1204,8 +1168,59 @@ export class ContainerRuntime extends TypedEventEmitter {
1204
1168
  throw e;
1205
1169
  }
1206
1170
  }
1207
- processAliasMessage(message, localOpMetadata, local) {
1208
- this.dataStores.processAliasMessage(message, localOpMetadata, local);
1171
+ /**
1172
+ * Assuming the given message is also a ContainerRuntimeMessage,
1173
+ * checks its type and dispatches the message to the appropriate handler in the runtime.
1174
+ * Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
1175
+ */
1176
+ validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
1177
+ // Optimistically extract ContainerRuntimeMessage-specific props from the message
1178
+ const { type: maybeContainerMessageType, compatDetails } = message;
1179
+ switch (maybeContainerMessageType) {
1180
+ case ContainerMessageType.Attach:
1181
+ this.dataStores.processAttachMessage(message, local);
1182
+ break;
1183
+ case ContainerMessageType.Alias:
1184
+ this.dataStores.processAliasMessage(message, localOpMetadata, local);
1185
+ break;
1186
+ case ContainerMessageType.FluidDataStoreOp:
1187
+ this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
1188
+ break;
1189
+ case ContainerMessageType.BlobAttach:
1190
+ this.blobManager.processBlobAttachOp(message, local);
1191
+ break;
1192
+ case ContainerMessageType.IdAllocation:
1193
+ assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
1194
+ this.idCompressor.finalizeCreationRange(message.contents);
1195
+ break;
1196
+ case ContainerMessageType.ChunkedOp:
1197
+ case ContainerMessageType.Rejoin:
1198
+ break;
1199
+ default: {
1200
+ // If we didn't necessarily expect a runtime message type, then no worries - just return
1201
+ // e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
1202
+ if (!expectRuntimeMessageType) {
1203
+ return;
1204
+ }
1205
+ const compatBehavior = compatDetails?.behavior;
1206
+ if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
1207
+ const error = DataProcessingError.create(
1208
+ // Former assert 0x3ce
1209
+ "Runtime message of unknown type", "OpProcessing", message, {
1210
+ local,
1211
+ messageDetails: JSON.stringify({
1212
+ type: message.type,
1213
+ contentType: typeof message.contents,
1214
+ compatBehavior,
1215
+ batch: message.metadata?.batch,
1216
+ compression: message.compression,
1217
+ }),
1218
+ });
1219
+ this.closeFn(error);
1220
+ throw error;
1221
+ }
1222
+ }
1223
+ }
1209
1224
  }
1210
1225
  /**
1211
1226
  * Emits the Signal event and update the perf signal data.
@@ -1673,7 +1688,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1673
1688
  * @param options - options controlling how the summary is generated or submitted
1674
1689
  */
1675
1690
  async submitSummary(options) {
1676
- const { fullTree = false, refreshLatestAck, summaryLogger } = options;
1691
+ const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
1677
1692
  // The summary number for this summary. This will be updated during the summary process, so get it now and
1678
1693
  // use it for all events logged during this summary.
1679
1694
  const summaryNumber = this.nextSummaryNumber;
@@ -1770,9 +1785,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1770
1785
  error,
1771
1786
  };
1772
1787
  }
1773
- // If validateSummaryBeforeUpload is true, validate that the summary generated by the summarizer nodes is
1774
- // correct before this summary is uploaded.
1788
+ // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
1775
1789
  if (this.validateSummaryBeforeUpload) {
1790
+ // Validate that the summaries generated by summarize nodes is correct.
1776
1791
  const validateResult = this.summarizerNode.validateSummary();
1777
1792
  if (!validateResult.success) {
1778
1793
  const { success, ...loggingProps } = validateResult;
@@ -1784,6 +1799,34 @@ export class ContainerRuntime extends TypedEventEmitter {
1784
1799
  error,
1785
1800
  };
1786
1801
  }
1802
+ // If there are pending messages, the summary has more data than at the summaryRefSeqNum.
1803
+ if (this.hasPendingMessages()) {
1804
+ // If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
1805
+ // This is a fallback to make progress in documents where there are consistently pending ops in
1806
+ // the summarizer.
1807
+ if (finalAttempt &&
1808
+ this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
1809
+ const error = DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
1810
+ summaryNumberLogger.sendErrorEvent({
1811
+ eventName: "SkipFailingIncorrectSummary",
1812
+ referenceSequenceNumber: summaryRefSeqNum,
1813
+ minimumSequenceNumber,
1814
+ }, error);
1815
+ }
1816
+ else {
1817
+ // Default retry delay is 1 second. This can be overridden via config so that we can adjust it
1818
+ // based on telemetry while we decide on a stable number.
1819
+ const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
1820
+ 1000;
1821
+ const error = new RetriableSummaryError("PendingMessagesInSummary", retryDelayMs / 1000, { count: this.pendingMessagesCount });
1822
+ return {
1823
+ stage: "base",
1824
+ referenceSequenceNumber: summaryRefSeqNum,
1825
+ minimumSequenceNumber,
1826
+ error,
1827
+ };
1828
+ }
1829
+ }
1787
1830
  }
1788
1831
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
1789
1832
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -1904,8 +1947,11 @@ export class ContainerRuntime extends TypedEventEmitter {
1904
1947
  }
1905
1948
  }
1906
1949
  }
1950
+ get pendingMessagesCount() {
1951
+ return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
1952
+ }
1907
1953
  hasPendingMessages() {
1908
- return this.pendingStateManager.hasPendingMessages() || !this.outbox.isEmpty;
1954
+ return this.pendingMessagesCount !== 0;
1909
1955
  }
1910
1956
  updateDocumentDirtyState(dirty) {
1911
1957
  if (this.attachState !== AttachState.Attached) {
@@ -1949,7 +1995,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1949
1995
  assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
1950
1996
  idRange = this.idCompressor.takeNextCreationRange();
1951
1997
  // Don't include the idRange if there weren't any Ids allocated
1952
- idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
1998
+ idRange = idRange?.ids !== undefined ? idRange : undefined;
1953
1999
  }
1954
2000
  if (idRange !== undefined) {
1955
2001
  const idAllocationMessage = {
@@ -2168,8 +2214,27 @@ export class ContainerRuntime extends TypedEventEmitter {
2168
2214
  case ContainerMessageType.Rejoin:
2169
2215
  this.submit(message);
2170
2216
  break;
2171
- default:
2172
- unreachableCase(message.type, `Unknown ContainerMessageType [type: ${message.type}]`);
2217
+ default: {
2218
+ // This case should be very rare - it would imply an op was stashed from a
2219
+ // future version of runtime code and now is being applied on an older version
2220
+ const compatBehavior = message.compatDetails?.behavior;
2221
+ if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
2222
+ this.logger.sendTelemetryEvent({
2223
+ eventName: "resubmitUnrecognizedMessageTypeAllowed",
2224
+ messageDetails: { type: message.type, compatBehavior },
2225
+ });
2226
+ }
2227
+ else {
2228
+ const error = DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2229
+ messageDetails: JSON.stringify({
2230
+ type: message.type,
2231
+ compatBehavior,
2232
+ }),
2233
+ });
2234
+ this.closeFn(error);
2235
+ throw error;
2236
+ }
2237
+ }
2173
2238
  }
2174
2239
  }
2175
2240
  rollback(content, localOpMetadata) {
@@ -2182,6 +2247,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2182
2247
  this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
2183
2248
  break;
2184
2249
  default:
2250
+ // Don't check message.compatDetails because this is for rolling back a local op so the type will be known
2185
2251
  throw new Error(`Can't rollback ${type}`);
2186
2252
  }
2187
2253
  }
@@ -2204,11 +2270,11 @@ export class ContainerRuntime extends TypedEventEmitter {
2204
2270
  // It should only be done by the summarizerNode, if required.
2205
2271
  // When fetching from storage we will always get the latest version and do not use the ackHandle.
2206
2272
  const fetchLatestSnapshot = async () => {
2207
- let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2273
+ let fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2208
2274
  eventName: "RefreshLatestSummaryAckFetch",
2209
2275
  ackHandle,
2210
2276
  targetSequenceNumber: summaryRefSeq,
2211
- }, readAndParseBlob);
2277
+ }, readAndParseBlob, null);
2212
2278
  /**
2213
2279
  * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
2214
2280
  * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
@@ -2216,7 +2282,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2216
2282
  * change that started fetching latest snapshot always.
2217
2283
  */
2218
2284
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
2219
- fetchResult = await this.fetchSnapshotFromStorageAndClose(summaryLogger, {
2285
+ fetchResult = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2220
2286
  eventName: "RefreshLatestSummaryAckFetchBackCompat",
2221
2287
  ackHandle,
2222
2288
  targetSequenceNumber: summaryRefSeq,
@@ -2261,9 +2327,9 @@ export class ContainerRuntime extends TypedEventEmitter {
2261
2327
  */
2262
2328
  async refreshLatestSummaryAckFromServer(summaryLogger) {
2263
2329
  const readAndParseBlob = async (id) => readAndParse(this.storage, id);
2264
- const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2330
+ const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorageAndMaybeClose(summaryLogger, {
2265
2331
  eventName: "RefreshLatestSummaryFromServerFetch",
2266
- }, readAndParseBlob);
2332
+ }, readAndParseBlob, null);
2267
2333
  const fetchLatestSnapshot = {
2268
2334
  snapshotTree,
2269
2335
  snapshotRefSeq: latestSnapshotRefSeq,
@@ -2273,10 +2339,12 @@ export class ContainerRuntime extends TypedEventEmitter {
2273
2339
  await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
2274
2340
  return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
2275
2341
  }
2276
- async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2277
- return this.fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, null /* latest */);
2278
- }
2279
- async fetchSnapshotFromStorageAndClose(logger, event, readAndParseBlob, versionId) {
2342
+ /**
2343
+ * Downloads snapshot from storage with the given versionId or latest if versionId is null.
2344
+ * By default, it also closes the container after downloading the snapshot. However, this may be
2345
+ * overridden via options.
2346
+ */
2347
+ async fetchSnapshotFromStorageAndMaybeClose(logger, event, readAndParseBlob, versionId) {
2280
2348
  const snapshotResults = await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2281
2349
  const stats = {};
2282
2350
  const trace = Trace.start();
@@ -2323,14 +2391,46 @@ export class ContainerRuntime extends TypedEventEmitter {
2323
2391
  throw new UsageError("can't get state during orderSequentially");
2324
2392
  }
2325
2393
  const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
2394
+ if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
2395
+ return; // no pending state to save
2396
+ }
2326
2397
  // Flush pending batch.
2327
2398
  // getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
2328
2399
  // to close current batch.
2329
2400
  this.flush();
2330
- return {
2401
+ const pendingState = {
2331
2402
  pending: this.pendingStateManager.getLocalState(),
2332
2403
  pendingAttachmentBlobs,
2333
2404
  };
2405
+ return pendingState;
2406
+ }
2407
+ summarizeOnDemand(options) {
2408
+ if (this.isSummarizerClient) {
2409
+ return this.summarizer.summarizeOnDemand(options);
2410
+ }
2411
+ else if (this.summaryManager !== undefined) {
2412
+ return this.summaryManager.summarizeOnDemand(options);
2413
+ }
2414
+ else {
2415
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2416
+ // disableSummaries is turned on. We are throwing instead of returning a failure here,
2417
+ // because it is a misuse of the API rather than an expected failure.
2418
+ throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2419
+ }
2420
+ }
2421
+ enqueueSummarize(options) {
2422
+ if (this.isSummarizerClient) {
2423
+ return this.summarizer.enqueueSummarize(options);
2424
+ }
2425
+ else if (this.summaryManager !== undefined) {
2426
+ return this.summaryManager.enqueueSummarize(options);
2427
+ }
2428
+ else {
2429
+ // If we're not the summarizer, and we don't have a summaryManager, we expect that
2430
+ // generateSummaries is turned off. We are throwing instead of returning a failure here,
2431
+ // because it is a misuse of the API rather than an expected failure.
2432
+ throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
2433
+ }
2334
2434
  }
2335
2435
  /**
2336
2436
  * * Forms a function that will request a Summarizer.