@fluidframework/container-runtime 2.0.0-dev-rc.4.0.0.261659 → 2.0.0-dev-rc.5.0.0.265721

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 (322) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/api-report/container-runtime.api.md +60 -29
  3. package/dist/batchTracker.js.map +1 -1
  4. package/dist/blobManager.d.ts +9 -9
  5. package/dist/blobManager.d.ts.map +1 -1
  6. package/dist/blobManager.js +3 -5
  7. package/dist/blobManager.js.map +1 -1
  8. package/dist/channelCollection.d.ts +8 -6
  9. package/dist/channelCollection.d.ts.map +1 -1
  10. package/dist/channelCollection.js +22 -11
  11. package/dist/channelCollection.js.map +1 -1
  12. package/dist/connectionTelemetry.d.ts +1 -1
  13. package/dist/connectionTelemetry.d.ts.map +1 -1
  14. package/dist/connectionTelemetry.js.map +1 -1
  15. package/dist/containerHandleContext.d.ts +2 -1
  16. package/dist/containerHandleContext.d.ts.map +1 -1
  17. package/dist/containerHandleContext.js.map +1 -1
  18. package/dist/containerRuntime.d.ts +14 -24
  19. package/dist/containerRuntime.d.ts.map +1 -1
  20. package/dist/containerRuntime.js +125 -140
  21. package/dist/containerRuntime.js.map +1 -1
  22. package/dist/dataStore.d.ts.map +1 -1
  23. package/dist/dataStore.js.map +1 -1
  24. package/dist/dataStoreContext.d.ts +13 -10
  25. package/dist/dataStoreContext.d.ts.map +1 -1
  26. package/dist/dataStoreContext.js +21 -8
  27. package/dist/dataStoreContext.js.map +1 -1
  28. package/dist/dataStoreContexts.js.map +1 -1
  29. package/dist/dataStoreRegistry.js.map +1 -1
  30. package/dist/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
  31. package/dist/deltaManagerProxies.d.ts.map +1 -0
  32. package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +38 -2
  33. package/dist/deltaManagerProxies.js.map +1 -0
  34. package/dist/deltaScheduler.d.ts +1 -1
  35. package/dist/deltaScheduler.d.ts.map +1 -1
  36. package/dist/deltaScheduler.js.map +1 -1
  37. package/dist/gc/garbageCollection.d.ts +1 -2
  38. package/dist/gc/garbageCollection.d.ts.map +1 -1
  39. package/dist/gc/garbageCollection.js +1 -1
  40. package/dist/gc/garbageCollection.js.map +1 -1
  41. package/dist/gc/gcConfigs.d.ts.map +1 -1
  42. package/dist/gc/gcConfigs.js +14 -19
  43. package/dist/gc/gcConfigs.js.map +1 -1
  44. package/dist/gc/gcDefinitions.d.ts +4 -22
  45. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  46. package/dist/gc/gcDefinitions.js +3 -3
  47. package/dist/gc/gcDefinitions.js.map +1 -1
  48. package/dist/gc/gcHelpers.d.ts +1 -2
  49. package/dist/gc/gcHelpers.d.ts.map +1 -1
  50. package/dist/gc/gcHelpers.js.map +1 -1
  51. package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
  52. package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
  53. package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -1
  54. package/dist/gc/gcSummaryDefinitions.js.map +1 -1
  55. package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
  56. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  57. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  58. package/dist/gc/gcTelemetry.d.ts +1 -1
  59. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  60. package/dist/gc/gcTelemetry.js +2 -2
  61. package/dist/gc/gcTelemetry.js.map +1 -1
  62. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  63. package/dist/gc/index.d.ts +1 -1
  64. package/dist/gc/index.d.ts.map +1 -1
  65. package/dist/gc/index.js +2 -2
  66. package/dist/gc/index.js.map +1 -1
  67. package/dist/index.d.ts +1 -1
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js.map +1 -1
  70. package/dist/legacy.d.ts +6 -1
  71. package/dist/messageTypes.d.ts +5 -2
  72. package/dist/messageTypes.d.ts.map +1 -1
  73. package/dist/messageTypes.js.map +1 -1
  74. package/dist/opLifecycle/batchManager.d.ts +4 -0
  75. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  76. package/dist/opLifecycle/batchManager.js.map +1 -1
  77. package/dist/opLifecycle/opCompressor.js.map +1 -1
  78. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  79. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  80. package/dist/opLifecycle/opSplitter.js.map +1 -1
  81. package/dist/opLifecycle/outbox.d.ts +1 -0
  82. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  83. package/dist/opLifecycle/outbox.js +7 -20
  84. package/dist/opLifecycle/outbox.js.map +1 -1
  85. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  86. package/dist/packageVersion.d.ts +1 -1
  87. package/dist/packageVersion.js +1 -1
  88. package/dist/packageVersion.js.map +1 -1
  89. package/dist/pendingStateManager.d.ts +6 -0
  90. package/dist/pendingStateManager.d.ts.map +1 -1
  91. package/dist/pendingStateManager.js +10 -1
  92. package/dist/pendingStateManager.js.map +1 -1
  93. package/dist/scheduleManager.d.ts +1 -1
  94. package/dist/scheduleManager.d.ts.map +1 -1
  95. package/dist/scheduleManager.js.map +1 -1
  96. package/dist/storageServiceWithAttachBlobs.js.map +1 -1
  97. package/dist/summary/documentSchema.js +2 -2
  98. package/dist/summary/documentSchema.js.map +1 -1
  99. package/dist/summary/index.d.ts +2 -2
  100. package/dist/summary/index.d.ts.map +1 -1
  101. package/dist/summary/index.js.map +1 -1
  102. package/dist/summary/orderedClientElection.d.ts +4 -2
  103. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  104. package/dist/summary/orderedClientElection.js +35 -13
  105. package/dist/summary/orderedClientElection.js.map +1 -1
  106. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  107. package/dist/summary/runningSummarizer.d.ts +0 -5
  108. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  109. package/dist/summary/runningSummarizer.js +28 -113
  110. package/dist/summary/runningSummarizer.js.map +1 -1
  111. package/dist/summary/summarizer.d.ts +1 -1
  112. package/dist/summary/summarizer.d.ts.map +1 -1
  113. package/dist/summary/summarizer.js +4 -1
  114. package/dist/summary/summarizer.js.map +1 -1
  115. package/dist/summary/summarizerClientElection.js.map +1 -1
  116. package/dist/summary/summarizerHeuristics.js.map +1 -1
  117. package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -2
  118. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  119. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  120. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  121. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  122. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  123. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  124. package/dist/summary/summarizerTypes.d.ts +16 -28
  125. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  126. package/dist/summary/summarizerTypes.js.map +1 -1
  127. package/dist/summary/summaryCollection.d.ts +1 -1
  128. package/dist/summary/summaryCollection.d.ts.map +1 -1
  129. package/dist/summary/summaryCollection.js +2 -2
  130. package/dist/summary/summaryCollection.js.map +1 -1
  131. package/dist/summary/summaryFormat.d.ts +26 -6
  132. package/dist/summary/summaryFormat.d.ts.map +1 -1
  133. package/dist/summary/summaryFormat.js.map +1 -1
  134. package/dist/summary/summaryGenerator.d.ts +7 -8
  135. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  136. package/dist/summary/summaryGenerator.js +30 -25
  137. package/dist/summary/summaryGenerator.js.map +1 -1
  138. package/dist/summary/summaryManager.js +5 -5
  139. package/dist/summary/summaryManager.js.map +1 -1
  140. package/dist/throttler.js.map +1 -1
  141. package/lib/batchTracker.js.map +1 -1
  142. package/lib/blobManager.d.ts +9 -9
  143. package/lib/blobManager.d.ts.map +1 -1
  144. package/lib/blobManager.js +4 -6
  145. package/lib/blobManager.js.map +1 -1
  146. package/lib/channelCollection.d.ts +8 -6
  147. package/lib/channelCollection.d.ts.map +1 -1
  148. package/lib/channelCollection.js +23 -12
  149. package/lib/channelCollection.js.map +1 -1
  150. package/lib/connectionTelemetry.d.ts +1 -1
  151. package/lib/connectionTelemetry.d.ts.map +1 -1
  152. package/lib/connectionTelemetry.js.map +1 -1
  153. package/lib/containerHandleContext.d.ts +2 -1
  154. package/lib/containerHandleContext.d.ts.map +1 -1
  155. package/lib/containerHandleContext.js.map +1 -1
  156. package/lib/containerRuntime.d.ts +14 -24
  157. package/lib/containerRuntime.d.ts.map +1 -1
  158. package/lib/containerRuntime.js +125 -140
  159. package/lib/containerRuntime.js.map +1 -1
  160. package/lib/dataStore.d.ts.map +1 -1
  161. package/lib/dataStore.js.map +1 -1
  162. package/lib/dataStoreContext.d.ts +13 -10
  163. package/lib/dataStoreContext.d.ts.map +1 -1
  164. package/lib/dataStoreContext.js +23 -10
  165. package/lib/dataStoreContext.js.map +1 -1
  166. package/lib/dataStoreContexts.js.map +1 -1
  167. package/lib/dataStoreRegistry.js.map +1 -1
  168. package/lib/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
  169. package/lib/deltaManagerProxies.d.ts.map +1 -0
  170. package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +36 -1
  171. package/lib/deltaManagerProxies.js.map +1 -0
  172. package/lib/deltaScheduler.d.ts +1 -1
  173. package/lib/deltaScheduler.d.ts.map +1 -1
  174. package/lib/deltaScheduler.js.map +1 -1
  175. package/lib/gc/garbageCollection.d.ts +1 -2
  176. package/lib/gc/garbageCollection.d.ts.map +1 -1
  177. package/lib/gc/garbageCollection.js +1 -1
  178. package/lib/gc/garbageCollection.js.map +1 -1
  179. package/lib/gc/gcConfigs.d.ts.map +1 -1
  180. package/lib/gc/gcConfigs.js +15 -20
  181. package/lib/gc/gcConfigs.js.map +1 -1
  182. package/lib/gc/gcDefinitions.d.ts +4 -22
  183. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  184. package/lib/gc/gcDefinitions.js +2 -2
  185. package/lib/gc/gcDefinitions.js.map +1 -1
  186. package/lib/gc/gcHelpers.d.ts +1 -2
  187. package/lib/gc/gcHelpers.d.ts.map +1 -1
  188. package/lib/gc/gcHelpers.js.map +1 -1
  189. package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -1
  190. package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
  191. package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -1
  192. package/lib/gc/gcSummaryDefinitions.js.map +1 -1
  193. package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
  194. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  195. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  196. package/lib/gc/gcTelemetry.d.ts +1 -1
  197. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  198. package/lib/gc/gcTelemetry.js +2 -2
  199. package/lib/gc/gcTelemetry.js.map +1 -1
  200. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  201. package/lib/gc/index.d.ts +1 -1
  202. package/lib/gc/index.d.ts.map +1 -1
  203. package/lib/gc/index.js +1 -1
  204. package/lib/gc/index.js.map +1 -1
  205. package/lib/index.d.ts +1 -1
  206. package/lib/index.d.ts.map +1 -1
  207. package/lib/index.js.map +1 -1
  208. package/lib/legacy.d.ts +6 -1
  209. package/lib/messageTypes.d.ts +5 -2
  210. package/lib/messageTypes.d.ts.map +1 -1
  211. package/lib/messageTypes.js.map +1 -1
  212. package/lib/opLifecycle/batchManager.d.ts +4 -0
  213. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  214. package/lib/opLifecycle/batchManager.js.map +1 -1
  215. package/lib/opLifecycle/opCompressor.js.map +1 -1
  216. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  217. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  218. package/lib/opLifecycle/opSplitter.js.map +1 -1
  219. package/lib/opLifecycle/outbox.d.ts +1 -0
  220. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  221. package/lib/opLifecycle/outbox.js +7 -20
  222. package/lib/opLifecycle/outbox.js.map +1 -1
  223. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  224. package/lib/packageVersion.d.ts +1 -1
  225. package/lib/packageVersion.js +1 -1
  226. package/lib/packageVersion.js.map +1 -1
  227. package/lib/pendingStateManager.d.ts +6 -0
  228. package/lib/pendingStateManager.d.ts.map +1 -1
  229. package/lib/pendingStateManager.js +10 -1
  230. package/lib/pendingStateManager.js.map +1 -1
  231. package/lib/scheduleManager.d.ts +1 -1
  232. package/lib/scheduleManager.d.ts.map +1 -1
  233. package/lib/scheduleManager.js.map +1 -1
  234. package/lib/storageServiceWithAttachBlobs.js.map +1 -1
  235. package/lib/summary/documentSchema.js +2 -2
  236. package/lib/summary/documentSchema.js.map +1 -1
  237. package/lib/summary/index.d.ts +2 -2
  238. package/lib/summary/index.d.ts.map +1 -1
  239. package/lib/summary/index.js.map +1 -1
  240. package/lib/summary/orderedClientElection.d.ts +4 -2
  241. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  242. package/lib/summary/orderedClientElection.js +35 -13
  243. package/lib/summary/orderedClientElection.js.map +1 -1
  244. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  245. package/lib/summary/runningSummarizer.d.ts +0 -5
  246. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  247. package/lib/summary/runningSummarizer.js +21 -106
  248. package/lib/summary/runningSummarizer.js.map +1 -1
  249. package/lib/summary/summarizer.d.ts +1 -1
  250. package/lib/summary/summarizer.d.ts.map +1 -1
  251. package/lib/summary/summarizer.js +4 -1
  252. package/lib/summary/summarizer.js.map +1 -1
  253. package/lib/summary/summarizerClientElection.js.map +1 -1
  254. package/lib/summary/summarizerHeuristics.js.map +1 -1
  255. package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -2
  256. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  257. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  258. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  259. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  260. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  261. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  262. package/lib/summary/summarizerTypes.d.ts +16 -28
  263. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  264. package/lib/summary/summarizerTypes.js.map +1 -1
  265. package/lib/summary/summaryCollection.d.ts +1 -1
  266. package/lib/summary/summaryCollection.d.ts.map +1 -1
  267. package/lib/summary/summaryCollection.js +2 -2
  268. package/lib/summary/summaryCollection.js.map +1 -1
  269. package/lib/summary/summaryFormat.d.ts +26 -6
  270. package/lib/summary/summaryFormat.d.ts.map +1 -1
  271. package/lib/summary/summaryFormat.js +1 -1
  272. package/lib/summary/summaryFormat.js.map +1 -1
  273. package/lib/summary/summaryGenerator.d.ts +7 -8
  274. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  275. package/lib/summary/summaryGenerator.js +24 -19
  276. package/lib/summary/summaryGenerator.js.map +1 -1
  277. package/lib/summary/summaryManager.js +1 -1
  278. package/lib/summary/summaryManager.js.map +1 -1
  279. package/lib/throttler.js.map +1 -1
  280. package/lib/tsdoc-metadata.json +1 -1
  281. package/package.json +65 -26
  282. package/src/blobManager.ts +14 -13
  283. package/src/channelCollection.ts +34 -20
  284. package/src/connectionTelemetry.ts +1 -1
  285. package/src/containerHandleContext.ts +2 -1
  286. package/src/containerRuntime.ts +161 -170
  287. package/src/dataStore.ts +3 -2
  288. package/src/dataStoreContext.ts +62 -23
  289. package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +55 -3
  290. package/src/deltaScheduler.ts +1 -1
  291. package/src/gc/garbageCollection.md +0 -8
  292. package/src/gc/garbageCollection.ts +2 -1
  293. package/src/gc/gcConfigs.ts +12 -19
  294. package/src/gc/gcDefinitions.ts +5 -23
  295. package/src/gc/gcHelpers.ts +1 -1
  296. package/src/gc/gcSummaryDefinitions.ts +1 -1
  297. package/src/gc/gcSummaryStateTracker.ts +1 -1
  298. package/src/gc/gcTelemetry.ts +1 -1
  299. package/src/gc/index.ts +1 -1
  300. package/src/index.ts +6 -1
  301. package/src/messageTypes.ts +4 -2
  302. package/src/opLifecycle/batchManager.ts +5 -0
  303. package/src/opLifecycle/outbox.ts +7 -30
  304. package/src/packageVersion.ts +1 -1
  305. package/src/pendingStateManager.ts +11 -1
  306. package/src/scheduleManager.ts +1 -1
  307. package/src/summary/documentSchema.ts +1 -1
  308. package/src/summary/index.ts +5 -1
  309. package/src/summary/orderedClientElection.ts +83 -12
  310. package/src/summary/runningSummarizer.ts +30 -114
  311. package/src/summary/summarizer.ts +5 -2
  312. package/src/summary/summarizerNode/summarizerNode.ts +0 -2
  313. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -3
  314. package/src/summary/summarizerTypes.ts +22 -29
  315. package/src/summary/summaryCollection.ts +1 -1
  316. package/src/summary/summaryFormat.ts +35 -6
  317. package/src/summary/summaryGenerator.ts +50 -27
  318. package/src/summary/summaryManager.ts +1 -1
  319. package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
  320. package/dist/deltaManagerSummarizerProxy.js.map +0 -1
  321. package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
  322. package/lib/deltaManagerSummarizerProxy.js.map +0 -1
@@ -22,7 +22,7 @@ import { ReportOpPerfTelemetry } from "./connectionTelemetry.js";
22
22
  import { ContainerFluidHandleContext } from "./containerHandleContext.js";
23
23
  import { channelToDataStore } from "./dataStore.js";
24
24
  import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
25
- import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy.js";
25
+ import { DeltaManagerPendingOpsProxy, DeltaManagerSummarizerProxy } from "./deltaManagerProxies.js";
26
26
  import { GCNodeType, GarbageCollector, gcGenerationOptionName, } from "./gc/index.js";
27
27
  import { ContainerMessageType, } from "./messageTypes.js";
28
28
  import { OpCompressor, OpDecompressor, OpGroupingManager, OpSplitter, Outbox, RemoteMessageProcessor, } from "./opLifecycle/index.js";
@@ -49,13 +49,13 @@ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, co
49
49
  export const DefaultSummaryConfiguration = {
50
50
  state: "enabled",
51
51
  minIdleTime: 0,
52
- maxIdleTime: 30 * 1000,
53
- maxTime: 60 * 1000,
54
- maxOps: 100,
52
+ maxIdleTime: 30 * 1000, // 30 secs.
53
+ maxTime: 60 * 1000, // 1 min.
54
+ maxOps: 100, // Summarize if 100 weighted ops received since last snapshot.
55
55
  minOpsForLastSummaryAttempt: 10,
56
- maxAckWaitTime: 3 * 60 * 1000,
56
+ maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
57
57
  maxOpsSinceLastSummary: 7000,
58
- initialSummarizerDelayMs: 5 * 1000,
58
+ initialSummarizerDelayMs: 5 * 1000, // 5 secs.
59
59
  nonRuntimeOpWeight: 0.1,
60
60
  runtimeOpWeight: 1.0,
61
61
  nonRuntimeHeuristicThreshold: 20,
@@ -246,7 +246,7 @@ export class ContainerRuntime extends TypedEventEmitter {
246
246
  },
247
247
  });
248
248
  const mc = loggerToMonitoringContext(logger);
249
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching = false, explicitSchemaControl = false, } = runtimeOptions;
249
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching = true, explicitSchemaControl = false, } = runtimeOptions;
250
250
  const registry = new FluidDataStoreRegistry(registryEntries);
251
251
  const tryFetchBlob = async (blobName) => {
252
252
  const blobId = context.baseSnapshot?.blobs[blobName];
@@ -368,23 +368,20 @@ export class ContainerRuntime extends TypedEventEmitter {
368
368
  return createIdCompressor(compressorLogger);
369
369
  }
370
370
  };
371
- const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
372
371
  const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
373
372
  const compressionLz4 = disableCompression !== true &&
374
373
  compressionOptions.minimumBatchSizeInBytes !== Infinity &&
375
374
  compressionOptions.compressionAlgorithm === "lz4";
376
- const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
377
375
  const documentSchemaController = new DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
378
376
  explicitSchemaControl,
379
377
  compressionLz4,
380
378
  idCompressorMode,
381
- opGroupingEnabled,
379
+ opGroupingEnabled: enableGroupedBatching,
382
380
  disallowedVersions: [],
383
381
  }, (schema) => {
384
382
  runtime.onSchemaChange(schema);
385
383
  });
386
384
  const featureGatesForTelemetry = {
387
- disableGroupedBatching,
388
385
  disableCompression,
389
386
  };
390
387
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
@@ -531,7 +528,9 @@ export class ContainerRuntime extends TypedEventEmitter {
531
528
  return this.garbageCollector.throwOnTombstoneUsage;
532
529
  }
533
530
  /***/
534
- constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, createIdCompressor, documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, summaryConfiguration = {
531
+ constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope,
532
+ // Create a custom ITelemetryBaseLogger to output telemetry events.
533
+ baseLogger, existing, blobManagerSnapshot, _storage, createIdCompressor, documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, summaryConfiguration = {
535
534
  // the defaults
536
535
  ...DefaultSummaryConfiguration,
537
536
  // the runtime configuration overrides
@@ -542,7 +541,7 @@ export class ContainerRuntime extends TypedEventEmitter {
542
541
  this.metadata = metadata;
543
542
  this.runtimeOptions = runtimeOptions;
544
543
  this.containerScope = containerScope;
545
- this.logger = logger;
544
+ this.baseLogger = baseLogger;
546
545
  this._storage = _storage;
547
546
  this.createIdCompressor = createIdCompressor;
548
547
  this.documentsSchemaController = documentsSchemaController;
@@ -573,7 +572,8 @@ export class ContainerRuntime extends TypedEventEmitter {
573
572
  this.snapshotCacheForLoadingGroupIds = new PromiseCache({
574
573
  expiry: { policy: "absolute", durationMs: 60000 },
575
574
  });
576
- const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
575
+ const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, snapshotWithContents, } = context;
576
+ this.logger = createChildLogger({ logger: this.baseLogger });
577
577
  this.mc = createChildMonitoringContext({
578
578
  logger: this.logger,
579
579
  namespace: "ContainerRuntime",
@@ -589,7 +589,6 @@ export class ContainerRuntime extends TypedEventEmitter {
589
589
  compressionAlgorithm: CompressionAlgorithms.lz4,
590
590
  };
591
591
  this.innerDeltaManager = deltaManager;
592
- this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
593
592
  // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
594
593
  // This makes ContainerRuntime the final gatekeeper for outgoing messages.
595
594
  this.submitFn = submitFn;
@@ -663,6 +662,32 @@ export class ContainerRuntime extends TypedEventEmitter {
663
662
  }, this.mc.logger);
664
663
  const opSplitter = new OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
665
664
  this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
665
+ const pendingRuntimeState = pendingLocalState;
666
+ this.pendingStateManager = new PendingStateManager({
667
+ applyStashedOp: this.applyStashedOp.bind(this),
668
+ clientId: () => this.clientId,
669
+ close: this.closeFn,
670
+ connected: () => this.connected,
671
+ reSubmit: (message) => {
672
+ this.reSubmit(message);
673
+ this.flush();
674
+ },
675
+ reSubmitBatch: this.reSubmitBatch.bind(this),
676
+ isActiveConnection: () => this.innerDeltaManager.active,
677
+ isAttached: () => this.attachState !== AttachState.Detached,
678
+ }, pendingRuntimeState?.pending, this.logger);
679
+ let outerDeltaManager;
680
+ const useDeltaManagerOpsProxy = this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
681
+ // The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
682
+ const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
683
+ outerDeltaManager = summarizerDeltaManagerProxy;
684
+ // The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
685
+ // It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
686
+ if (useDeltaManagerOpsProxy) {
687
+ const pendingOpsDeltaManagerProxy = new DeltaManagerPendingOpsProxy(summarizerDeltaManagerProxy, this.pendingStateManager);
688
+ outerDeltaManager = pendingOpsDeltaManagerProxy;
689
+ }
690
+ this.deltaManager = outerDeltaManager;
666
691
  this.handleContext = new ContainerFluidHandleContext("", this);
667
692
  if (this.summaryConfiguration.state === "enabled") {
668
693
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
@@ -682,7 +707,6 @@ export class ContainerRuntime extends TypedEventEmitter {
682
707
  else {
683
708
  this._flushMode = runtimeOptions.flushMode;
684
709
  }
685
- const pendingRuntimeState = pendingLocalState;
686
710
  if (context.attachState === AttachState.Attached) {
687
711
  const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
688
712
  if (maxSnapshotCacheDurationMs !== undefined &&
@@ -738,7 +762,14 @@ export class ContainerRuntime extends TypedEventEmitter {
738
762
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
739
763
  return this.submitSignalFn(envelope2, targetClientId);
740
764
  };
741
- this.channelCollection = new ChannelCollection(getSummaryForDatastores(baseSnapshot, metadata), parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
765
+ let snapshot = getSummaryForDatastores(baseSnapshot, metadata);
766
+ if (snapshot !== undefined && snapshotWithContents !== undefined) {
767
+ snapshot = {
768
+ ...snapshotWithContents,
769
+ snapshotTree: snapshot,
770
+ };
771
+ }
772
+ this.channelCollection = new ChannelCollection(snapshot, parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
742
773
  this.blobManager = new BlobManager({
743
774
  routeContext: this.handleContext,
744
775
  snapshot: blobManagerSnapshot,
@@ -761,19 +792,6 @@ export class ContainerRuntime extends TypedEventEmitter {
761
792
  closeContainer: (error) => this.closeFn(error),
762
793
  });
763
794
  this.scheduleManager = new ScheduleManager(this.innerDeltaManager, this, () => this.clientId, createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }));
764
- this.pendingStateManager = new PendingStateManager({
765
- applyStashedOp: this.applyStashedOp.bind(this),
766
- clientId: () => this.clientId,
767
- close: this.closeFn,
768
- connected: () => this.connected,
769
- reSubmit: (message) => {
770
- this.reSubmit(message);
771
- this.flush();
772
- },
773
- reSubmitBatch: this.reSubmitBatch.bind(this),
774
- isActiveConnection: () => this.innerDeltaManager.active,
775
- isAttached: () => this.attachState !== AttachState.Detached,
776
- }, pendingRuntimeState?.pending, this.logger);
777
795
  const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
778
796
  const legacySendBatchFn = makeLegacySendBatchFn(this.submitFn, this.innerDeltaManager);
779
797
  this.outbox = new Outbox({
@@ -818,7 +836,7 @@ export class ContainerRuntime extends TypedEventEmitter {
818
836
  let oldClientId = this.clientId;
819
837
  this.on("connected", () => {
820
838
  const clientId = this.clientId;
821
- assert(clientId !== undefined, "can't be undefined");
839
+ assert(clientId !== undefined, 0x975 /* can't be undefined */);
822
840
  audience.emit("selfChanged", { clientId: oldClientId }, { clientId, client: audience.getMember(clientId) });
823
841
  oldClientId = clientId;
824
842
  });
@@ -838,7 +856,7 @@ export class ContainerRuntime extends TypedEventEmitter {
838
856
  namespace: "OrderedClientElection",
839
857
  });
840
858
  const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
841
- const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
859
+ const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible, this.mc.config.getBoolean("Fluid.ContainerRuntime.OrderedClientElection.EnablePerformanceEvents"));
842
860
  this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
843
861
  if (this.isSummarizerClient) {
844
862
  this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
@@ -882,7 +900,7 @@ export class ContainerRuntime extends TypedEventEmitter {
882
900
  }
883
901
  }
884
902
  // logging hardware telemetry
885
- logger.sendTelemetryEvent({
903
+ this.logger.sendTelemetryEvent({
886
904
  eventName: "DeviceSpec",
887
905
  ...getDeviceSpec(),
888
906
  });
@@ -1045,7 +1063,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1045
1063
  const props = {
1046
1064
  eventName: "GroupIdSnapshotCatchup",
1047
1065
  loadingGroupIds: sortedLoadingGroupIds.join(","),
1048
- targetSequenceNumber: snapshotSeqNumber,
1066
+ targetSequenceNumber: snapshotSeqNumber, // This is so we reuse some columns in telemetry
1049
1067
  sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
1050
1068
  };
1051
1069
  const event = PerformanceEvent.start(this.mc.logger, {
@@ -1259,6 +1277,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1259
1277
  this.emitDirtyDocumentEvent = false;
1260
1278
  let newState;
1261
1279
  try {
1280
+ this.submitIdAllocationOpIfNeeded(true);
1262
1281
  // replay the ops
1263
1282
  this.pendingStateManager.replayPendingStates();
1264
1283
  }
@@ -1306,8 +1325,6 @@ export class ContainerRuntime extends TypedEventEmitter {
1306
1325
  return;
1307
1326
  case ContainerMessageType.BlobAttach:
1308
1327
  return;
1309
- case ContainerMessageType.ChunkedOp:
1310
- throw new Error("chunkedOp not expected here");
1311
1328
  case ContainerMessageType.Rejoin:
1312
1329
  throw new Error("rejoin not expected here");
1313
1330
  case ContainerMessageType.GC:
@@ -1319,7 +1336,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1319
1336
  // e.g. if an app rolled back its container version
1320
1337
  const compatBehavior = opContents.compatDetails?.behavior;
1321
1338
  if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1322
- const error = DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1339
+ const error = DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
1323
1340
  messageDetails: JSON.stringify({
1324
1341
  type: opContents.type,
1325
1342
  compatBehavior,
@@ -1345,7 +1362,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1345
1362
  for (const range of ops) {
1346
1363
  compressor.finalizeCreationRange(range);
1347
1364
  }
1348
- assert(this.pendingIdCompressorOps.length === 0, "No new ops added");
1365
+ assert(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
1349
1366
  this._idCompressor = compressor;
1350
1367
  })
1351
1368
  .catch((error) => {
@@ -1358,8 +1375,8 @@ export class ContainerRuntime extends TypedEventEmitter {
1358
1375
  setConnectionState(connected, clientId) {
1359
1376
  // Validate we have consistent state
1360
1377
  const currentClientId = this._audience.getSelf()?.clientId;
1361
- assert(clientId === currentClientId, "input clientId does not match Audience");
1362
- assert(this.clientId === currentClientId, "this.clientId does not match Audience");
1378
+ assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
1379
+ assert(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
1363
1380
  if (connected && this.idCompressorMode === "delayed") {
1364
1381
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1365
1382
  this.loadIdCompressor();
@@ -1469,6 +1486,13 @@ export class ContainerRuntime extends TypedEventEmitter {
1469
1486
  */
1470
1487
  processCore(messageWithContext) {
1471
1488
  const { message, local } = messageWithContext;
1489
+ // Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
1490
+ // Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
1491
+ if (this.deltaManager.minimumSequenceNumber <
1492
+ messageWithContext.message.minimumSequenceNumber) {
1493
+ messageWithContext.message.minimumSequenceNumber =
1494
+ this.deltaManager.minimumSequenceNumber;
1495
+ }
1472
1496
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1473
1497
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1474
1498
  // messages once a batch has been fully processed.
@@ -1535,7 +1559,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1535
1559
  this.pendingIdCompressorOps.push(range);
1536
1560
  }
1537
1561
  else {
1538
- assert(this.pendingIdCompressorOps.length === 0, "there should be no pending ops!");
1562
+ assert(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
1539
1563
  this._idCompressor.finalizeCreationRange(range);
1540
1564
  }
1541
1565
  }
@@ -1896,7 +1920,7 @@ export class ContainerRuntime extends TypedEventEmitter {
1896
1920
  return { stats, summary };
1897
1921
  }
1898
1922
  finally {
1899
- this.mc.logger.sendTelemetryEvent({
1923
+ summaryLogger.sendTelemetryEvent({
1900
1924
  eventName: "SummarizeTelemetry",
1901
1925
  details: telemetryContext.serialize(),
1902
1926
  });
@@ -2055,7 +2079,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2055
2079
  * @param options - options controlling how the summary is generated or submitted
2056
2080
  */
2057
2081
  async submitSummary(options) {
2058
- const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger, latestSummaryRefSeqNum, } = options;
2082
+ const { fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
2059
2083
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2060
2084
  // use it for all events logged during this summary.
2061
2085
  const summaryNumber = this.nextSummaryNumber;
@@ -2070,13 +2094,6 @@ export class ContainerRuntime extends TypedEventEmitter {
2070
2094
  },
2071
2095
  });
2072
2096
  assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
2073
- // We close the summarizer and download a new snapshot and reload the container
2074
- if (refreshLatestAck === true) {
2075
- return this.prefetchLatestSummaryThenClose(createChildLogger({
2076
- logger: summaryNumberLogger,
2077
- properties: { all: { safeSummary: true } },
2078
- }));
2079
- }
2080
2097
  // If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
2081
2098
  // and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
2082
2099
  // saved within the timeout, check if it should be failed or can continue.
@@ -2145,7 +2162,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2145
2162
  stage: "base",
2146
2163
  referenceSequenceNumber: summaryRefSeqNum,
2147
2164
  minimumSequenceNumber,
2148
- error: new LoggingError(`Summarizer node state inconsistent with summarizer state.`),
2165
+ error: new RetriableSummaryError(`Summarizer node state inconsistent with summarizer state.`),
2149
2166
  };
2150
2167
  }
2151
2168
  }
@@ -2188,7 +2205,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2188
2205
  stage: "base",
2189
2206
  referenceSequenceNumber: summaryRefSeqNum,
2190
2207
  minimumSequenceNumber,
2191
- error: new LoggingError(continueResult.error),
2208
+ error: new RetriableSummaryError(continueResult.error),
2192
2209
  };
2193
2210
  }
2194
2211
  const trace = Trace.start();
@@ -2209,7 +2226,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2209
2226
  stage: "base",
2210
2227
  referenceSequenceNumber: summaryRefSeqNum,
2211
2228
  minimumSequenceNumber,
2212
- error: wrapError(error, (msg) => new LoggingError(msg)),
2229
+ error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
2213
2230
  };
2214
2231
  }
2215
2232
  // Validate that the summary generated by summarizer nodes is correct before uploading.
@@ -2264,7 +2281,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2264
2281
  return {
2265
2282
  stage: "generate",
2266
2283
  ...generateSummaryData,
2267
- error: new LoggingError(continueResult.error),
2284
+ error: new RetriableSummaryError(continueResult.error),
2268
2285
  };
2269
2286
  }
2270
2287
  const summaryContext = lastAck === undefined
@@ -2286,7 +2303,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2286
2303
  return {
2287
2304
  stage: "generate",
2288
2305
  ...generateSummaryData,
2289
- error: wrapError(error, (msg) => new LoggingError(msg)),
2306
+ error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
2290
2307
  };
2291
2308
  }
2292
2309
  const parent = summaryContext.ackHandle;
@@ -2307,7 +2324,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2307
2324
  return {
2308
2325
  stage: "upload",
2309
2326
  ...uploadData,
2310
- error: new LoggingError(continueResult.error),
2327
+ error: new RetriableSummaryError(continueResult.error),
2311
2328
  };
2312
2329
  }
2313
2330
  let clientSequenceNumber;
@@ -2318,7 +2335,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2318
2335
  return {
2319
2336
  stage: "upload",
2320
2337
  ...uploadData,
2321
- error: wrapError(error, (msg) => new LoggingError(msg)),
2338
+ error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
2322
2339
  };
2323
2340
  }
2324
2341
  const submitData = {
@@ -2334,7 +2351,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2334
2351
  return {
2335
2352
  stage: "upload",
2336
2353
  ...uploadData,
2337
- error: wrapError(error, (msg) => new LoggingError(msg)),
2354
+ error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
2338
2355
  };
2339
2356
  }
2340
2357
  return submitData;
@@ -2424,11 +2441,13 @@ export class ContainerRuntime extends TypedEventEmitter {
2424
2441
  this.verifyNotClosed();
2425
2442
  return this.blobManager.createBlob(blob, signal);
2426
2443
  }
2427
- submitIdAllocationOpIfNeeded() {
2444
+ submitIdAllocationOpIfNeeded(resubmitOutstandingRanges) {
2428
2445
  if (this._idCompressor) {
2429
- const idRange = this._idCompressor.takeNextCreationRange();
2446
+ const idRange = resubmitOutstandingRanges
2447
+ ? this._idCompressor.takeUnfinalizedCreationRange()
2448
+ : this._idCompressor.takeNextCreationRange();
2430
2449
  // Don't include the idRange if there weren't any Ids allocated
2431
- if (idRange?.ids !== undefined) {
2450
+ if (idRange.ids !== undefined) {
2432
2451
  const idAllocationMessage = {
2433
2452
  type: ContainerMessageType.IdAllocation,
2434
2453
  contents: idRange,
@@ -2457,6 +2476,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2457
2476
  });
2458
2477
  }
2459
2478
  const type = containerRuntimeMessage.type;
2479
+ assert(type !== ContainerMessageType.IdAllocation, "IdAllocation should be submitted directly to outbox.");
2460
2480
  const message = {
2461
2481
  contents: serializedContent,
2462
2482
  metadata,
@@ -2464,44 +2484,35 @@ export class ContainerRuntime extends TypedEventEmitter {
2464
2484
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2465
2485
  };
2466
2486
  try {
2467
- // If `message` is an allocation op, then we are in the resubmit path and we must redirect the allocation
2468
- // op into the correct batch to avoid ranges being finalized out of order.
2469
- // Otherwise, submit an IdAllocation op if any IDs have been generated since the last op was submitted, as
2470
- // any of the other op types may contain those IDs and thus depend on the allocation op being sent first.
2471
- if (type === ContainerMessageType.IdAllocation) {
2472
- this.outbox.submitIdAllocation(message);
2487
+ this.submitIdAllocationOpIfNeeded(false);
2488
+ // Allow document schema controller to send a message if it needs to propose change in document schema.
2489
+ // If it needs to send a message, it will call provided callback with payload of such message and rely
2490
+ // on this callback to do actual sending.
2491
+ const contents = this.documentsSchemaController.maybeSendSchemaMessage();
2492
+ if (contents) {
2493
+ this.logger.sendTelemetryEvent({
2494
+ eventName: "SchemaChangeProposal",
2495
+ refSeq: contents.refSeq,
2496
+ version: contents.version,
2497
+ newRuntimeSchema: JSON.stringify(contents.runtime),
2498
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2499
+ oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
2500
+ });
2501
+ const msg = {
2502
+ type: ContainerMessageType.DocumentSchemaChange,
2503
+ contents,
2504
+ };
2505
+ this.outbox.submit({
2506
+ contents: JSON.stringify(msg),
2507
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2508
+ });
2509
+ }
2510
+ if (type === ContainerMessageType.BlobAttach) {
2511
+ // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2512
+ this.outbox.submitBlobAttach(message);
2473
2513
  }
2474
2514
  else {
2475
- this.submitIdAllocationOpIfNeeded();
2476
- // Allow document schema controller to send a message if it needs to propose change in document schema.
2477
- // If it needs to send a message, it will call provided callback with payload of such message and rely
2478
- // on this callback to do actual sending.
2479
- const contents = this.documentsSchemaController.maybeSendSchemaMessage();
2480
- if (contents) {
2481
- this.logger.sendTelemetryEvent({
2482
- eventName: "SchemaChangeProposal",
2483
- refSeq: contents.refSeq,
2484
- version: contents.version,
2485
- newRuntimeSchema: JSON.stringify(contents.runtime),
2486
- sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2487
- oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
2488
- });
2489
- const msg = {
2490
- type: ContainerMessageType.DocumentSchemaChange,
2491
- contents,
2492
- };
2493
- this.outbox.submit({
2494
- contents: JSON.stringify(msg),
2495
- referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2496
- });
2497
- }
2498
- if (type === ContainerMessageType.BlobAttach) {
2499
- // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2500
- this.outbox.submitBlobAttach(message);
2501
- }
2502
- else {
2503
- this.outbox.submit(message);
2504
- }
2515
+ this.outbox.submit(message);
2505
2516
  }
2506
2517
  if (!this.currentlyBatching()) {
2507
2518
  this.flush();
@@ -2601,11 +2612,15 @@ export class ContainerRuntime extends TypedEventEmitter {
2601
2612
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
2602
2613
  break;
2603
2614
  case ContainerMessageType.IdAllocation: {
2604
- this.submit(message, localOpMetadata);
2615
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
2616
+ // avoid being submitted out of order. For example, if the pending state manager contained
2617
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
2618
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
2619
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
2620
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
2621
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
2605
2622
  break;
2606
2623
  }
2607
- case ContainerMessageType.ChunkedOp:
2608
- throw new Error(`chunkedOp not expected here`);
2609
2624
  case ContainerMessageType.BlobAttach:
2610
2625
  this.blobManager.reSubmit(opMetadata);
2611
2626
  break;
@@ -2632,7 +2647,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2632
2647
  });
2633
2648
  }
2634
2649
  else {
2635
- const error = DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2650
+ const error = DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
2636
2651
  messageDetails: JSON.stringify({
2637
2652
  type: message.type,
2638
2653
  compatBehavior,
@@ -2672,51 +2687,23 @@ export class ContainerRuntime extends TypedEventEmitter {
2672
2687
  * and then close as the current main client is likely to be re-elected as the parent summarizer again.
2673
2688
  */
2674
2689
  if (!result.isSummaryTracked && result.isSummaryNewer) {
2675
- await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2690
+ await this.fetchLatestSnapshotAndClose(summaryLogger, {
2676
2691
  eventName: "RefreshLatestSummaryAckFetch",
2677
2692
  ackHandle,
2678
2693
  targetSequenceNumber: summaryRefSeq,
2679
2694
  }, readAndParseBlob);
2680
- await this.closeStaleSummarizer();
2681
2695
  return;
2682
2696
  }
2683
2697
  // Notify the garbage collector so it can update its latest summary state.
2684
2698
  await this.garbageCollector.refreshLatestSummary(result);
2685
2699
  }
2686
2700
  /**
2687
- * Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
2688
- * summarizer to reload from new state.
2689
- * @param summaryLogger - logger to use when fetching snapshot from storage
2690
- * @returns a generic summarization error
2701
+ * Fetches the latest snapshot from storage and closes the container. This is done in cases where
2702
+ * the last known snapshot is older than the latest one. This will ensure that the latest snapshot
2703
+ * is downloaded and we don't end up loading snapshot from cache.
2691
2704
  */
2692
- async prefetchLatestSummaryThenClose(summaryLogger) {
2693
- const readAndParseBlob = async (id) => readAndParse(this.storage, id);
2694
- // This is a performance optimization as the same parent is likely to be elected again, and would use its
2695
- // cache to fetch the snapshot instead of the network.
2696
- await this.fetchLatestSnapshotFromStorage(summaryLogger, {
2697
- eventName: "RefreshLatestSummaryFromServerFetch",
2698
- }, readAndParseBlob);
2699
- await this.closeStaleSummarizer();
2700
- return {
2701
- stage: "base",
2702
- error: new LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
2703
- referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2704
- minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2705
- };
2706
- }
2707
- async closeStaleSummarizer() {
2708
- // Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
2709
- await delay(this.closeSummarizerDelayMs);
2710
- this._summarizer?.stop("latestSummaryStateStale");
2711
- this.disposeFn();
2712
- }
2713
- /**
2714
- * Downloads the latest snapshot from storage.
2715
- * By default, it also closes the container after downloading the snapshot. However, this may be
2716
- * overridden via options.
2717
- */
2718
- async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
2719
- return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2705
+ async fetchLatestSnapshotAndClose(logger, event, readAndParseBlob) {
2706
+ await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
2720
2707
  const stats = {};
2721
2708
  const trace = Trace.start();
2722
2709
  const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose", FetchSource.noCache);
@@ -2729,12 +2716,10 @@ export class ContainerRuntime extends TypedEventEmitter {
2729
2716
  stats.snapshotRefSeq = latestSnapshotRefSeq;
2730
2717
  stats.snapshotVersion = versions[0].id;
2731
2718
  perfEvent.end(stats);
2732
- return {
2733
- snapshotTree: maybeSnapshot,
2734
- versionId: versions[0].id,
2735
- latestSnapshotRefSeq,
2736
- };
2737
2719
  });
2720
+ await delay(this.closeSummarizerDelayMs);
2721
+ this._summarizer?.stop("latestSummaryStateStale");
2722
+ this.disposeFn();
2738
2723
  }
2739
2724
  getPendingLocalState(props) {
2740
2725
  this.verifyNotClosed();