@fluidframework/container-runtime 2.0.0-dev-rc.3.0.0.254866 → 2.0.0-dev-rc.5.0.0.263932

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 (338) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/api-report/container-runtime.api.md +93 -39
  3. package/dist/batchTracker.d.ts +1 -1
  4. package/dist/batchTracker.d.ts.map +1 -1
  5. package/dist/batchTracker.js.map +1 -1
  6. package/dist/blobManager.d.ts +7 -7
  7. package/dist/blobManager.d.ts.map +1 -1
  8. package/dist/blobManager.js +2 -4
  9. package/dist/blobManager.js.map +1 -1
  10. package/dist/channelCollection.d.ts +10 -6
  11. package/dist/channelCollection.d.ts.map +1 -1
  12. package/dist/channelCollection.js +85 -22
  13. package/dist/channelCollection.js.map +1 -1
  14. package/dist/connectionTelemetry.d.ts +2 -2
  15. package/dist/connectionTelemetry.d.ts.map +1 -1
  16. package/dist/connectionTelemetry.js +54 -5
  17. package/dist/connectionTelemetry.js.map +1 -1
  18. package/dist/containerRuntime.d.ts +22 -35
  19. package/dist/containerRuntime.d.ts.map +1 -1
  20. package/dist/containerRuntime.js +232 -174
  21. package/dist/containerRuntime.js.map +1 -1
  22. package/dist/dataStore.d.ts +1 -1
  23. package/dist/dataStore.d.ts.map +1 -1
  24. package/dist/dataStore.js.map +1 -1
  25. package/dist/dataStoreContext.d.ts +9 -6
  26. package/dist/dataStoreContext.d.ts.map +1 -1
  27. package/dist/dataStoreContext.js +19 -5
  28. package/dist/dataStoreContext.js.map +1 -1
  29. package/dist/dataStoreContexts.d.ts +2 -0
  30. package/dist/dataStoreContexts.d.ts.map +1 -1
  31. package/dist/dataStoreContexts.js +7 -0
  32. package/dist/dataStoreContexts.js.map +1 -1
  33. package/dist/deltaManagerProxies.d.ts +81 -0
  34. package/dist/deltaManagerProxies.d.ts.map +1 -0
  35. package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +75 -20
  36. package/dist/deltaManagerProxies.js.map +1 -0
  37. package/dist/deltaScheduler.d.ts +2 -2
  38. package/dist/deltaScheduler.d.ts.map +1 -1
  39. package/dist/deltaScheduler.js.map +1 -1
  40. package/dist/gc/garbageCollection.d.ts +5 -12
  41. package/dist/gc/garbageCollection.d.ts.map +1 -1
  42. package/dist/gc/garbageCollection.js +45 -29
  43. package/dist/gc/garbageCollection.js.map +1 -1
  44. package/dist/gc/gcDefinitions.d.ts +27 -6
  45. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  46. package/dist/gc/gcDefinitions.js.map +1 -1
  47. package/dist/gc/gcHelpers.d.ts +5 -4
  48. package/dist/gc/gcHelpers.d.ts.map +1 -1
  49. package/dist/gc/gcHelpers.js +14 -2
  50. package/dist/gc/gcHelpers.js.map +1 -1
  51. package/dist/gc/gcTelemetry.d.ts +14 -4
  52. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  53. package/dist/gc/gcTelemetry.js +24 -21
  54. package/dist/gc/gcTelemetry.js.map +1 -1
  55. package/dist/gc/index.d.ts +2 -2
  56. package/dist/gc/index.d.ts.map +1 -1
  57. package/dist/gc/index.js +2 -2
  58. package/dist/gc/index.js.map +1 -1
  59. package/dist/index.d.ts +3 -3
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +2 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/{alpha.d.ts → legacy.d.ts} +8 -1
  64. package/dist/messageTypes.d.ts +5 -2
  65. package/dist/messageTypes.d.ts.map +1 -1
  66. package/dist/messageTypes.js.map +1 -1
  67. package/dist/metadata.d.ts +2 -2
  68. package/dist/metadata.d.ts.map +1 -1
  69. package/dist/metadata.js.map +1 -1
  70. package/dist/opLifecycle/batchManager.d.ts +4 -1
  71. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  72. package/dist/opLifecycle/batchManager.js +0 -10
  73. package/dist/opLifecycle/batchManager.js.map +1 -1
  74. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  75. package/dist/opLifecycle/opDecompressor.js +6 -6
  76. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  77. package/dist/opLifecycle/opGroupingManager.js +2 -2
  78. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  79. package/dist/opLifecycle/opSplitter.js +1 -1
  80. package/dist/opLifecycle/opSplitter.js.map +1 -1
  81. package/dist/opLifecycle/outbox.d.ts +0 -4
  82. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  83. package/dist/opLifecycle/outbox.js +7 -38
  84. package/dist/opLifecycle/outbox.js.map +1 -1
  85. package/dist/packageVersion.d.ts +1 -1
  86. package/dist/packageVersion.js +1 -1
  87. package/dist/packageVersion.js.map +1 -1
  88. package/dist/pendingStateManager.d.ts +9 -2
  89. package/dist/pendingStateManager.d.ts.map +1 -1
  90. package/dist/pendingStateManager.js +26 -10
  91. package/dist/pendingStateManager.js.map +1 -1
  92. package/dist/public.d.ts +3 -0
  93. package/dist/scheduleManager.d.ts +2 -2
  94. package/dist/scheduleManager.d.ts.map +1 -1
  95. package/dist/scheduleManager.js.map +1 -1
  96. package/dist/summary/documentSchema.d.ts +3 -1
  97. package/dist/summary/documentSchema.d.ts.map +1 -1
  98. package/dist/summary/documentSchema.js +34 -16
  99. package/dist/summary/documentSchema.js.map +1 -1
  100. package/dist/summary/index.d.ts +1 -1
  101. package/dist/summary/index.d.ts.map +1 -1
  102. package/dist/summary/index.js.map +1 -1
  103. package/dist/summary/orderedClientElection.d.ts +2 -2
  104. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  105. package/dist/summary/orderedClientElection.js.map +1 -1
  106. package/dist/summary/runningSummarizer.js +10 -10
  107. package/dist/summary/runningSummarizer.js.map +1 -1
  108. package/dist/summary/summarizer.d.ts +1 -2
  109. package/dist/summary/summarizer.d.ts.map +1 -1
  110. package/dist/summary/summarizer.js.map +1 -1
  111. package/dist/summary/summarizerClientElection.d.ts +1 -1
  112. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  113. package/dist/summary/summarizerClientElection.js.map +1 -1
  114. package/dist/summary/summarizerHeuristics.d.ts +1 -1
  115. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  116. package/dist/summary/summarizerHeuristics.js.map +1 -1
  117. package/dist/summary/summarizerNode/summarizerNode.d.ts +4 -3
  118. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  119. package/dist/summary/summarizerNode/summarizerNode.js +4 -10
  120. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  121. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  122. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  123. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  124. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  125. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  126. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  127. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  128. package/dist/summary/summarizerTypes.d.ts +3 -5
  129. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  130. package/dist/summary/summarizerTypes.js.map +1 -1
  131. package/dist/summary/summaryCollection.d.ts +2 -2
  132. package/dist/summary/summaryCollection.d.ts.map +1 -1
  133. package/dist/summary/summaryCollection.js.map +1 -1
  134. package/dist/summary/summaryFormat.d.ts +25 -5
  135. package/dist/summary/summaryFormat.d.ts.map +1 -1
  136. package/dist/summary/summaryFormat.js.map +1 -1
  137. package/dist/summary/summaryGenerator.d.ts +1 -2
  138. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  139. package/dist/summary/summaryGenerator.js +12 -11
  140. package/dist/summary/summaryGenerator.js.map +1 -1
  141. package/dist/summary/summaryManager.d.ts.map +1 -1
  142. package/dist/summary/summaryManager.js +5 -5
  143. package/dist/summary/summaryManager.js.map +1 -1
  144. package/{lib/beta.d.ts → internal.d.ts} +2 -0
  145. package/{dist/beta.d.ts → legacy.d.ts} +2 -0
  146. package/lib/batchTracker.d.ts +1 -1
  147. package/lib/batchTracker.d.ts.map +1 -1
  148. package/lib/batchTracker.js.map +1 -1
  149. package/lib/blobManager.d.ts +7 -7
  150. package/lib/blobManager.d.ts.map +1 -1
  151. package/lib/blobManager.js +3 -5
  152. package/lib/blobManager.js.map +1 -1
  153. package/lib/channelCollection.d.ts +10 -6
  154. package/lib/channelCollection.d.ts.map +1 -1
  155. package/lib/channelCollection.js +88 -25
  156. package/lib/channelCollection.js.map +1 -1
  157. package/lib/connectionTelemetry.d.ts +2 -2
  158. package/lib/connectionTelemetry.d.ts.map +1 -1
  159. package/lib/connectionTelemetry.js +49 -0
  160. package/lib/connectionTelemetry.js.map +1 -1
  161. package/lib/containerRuntime.d.ts +22 -35
  162. package/lib/containerRuntime.d.ts.map +1 -1
  163. package/lib/containerRuntime.js +232 -174
  164. package/lib/containerRuntime.js.map +1 -1
  165. package/lib/dataStore.d.ts +1 -1
  166. package/lib/dataStore.d.ts.map +1 -1
  167. package/lib/dataStore.js +1 -1
  168. package/lib/dataStore.js.map +1 -1
  169. package/lib/dataStoreContext.d.ts +9 -6
  170. package/lib/dataStoreContext.d.ts.map +1 -1
  171. package/lib/dataStoreContext.js +21 -7
  172. package/lib/dataStoreContext.js.map +1 -1
  173. package/lib/dataStoreContexts.d.ts +2 -0
  174. package/lib/dataStoreContexts.d.ts.map +1 -1
  175. package/lib/dataStoreContexts.js +7 -0
  176. package/lib/dataStoreContexts.js.map +1 -1
  177. package/lib/deltaManagerProxies.d.ts +81 -0
  178. package/lib/deltaManagerProxies.d.ts.map +1 -0
  179. package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +72 -19
  180. package/lib/deltaManagerProxies.js.map +1 -0
  181. package/lib/deltaScheduler.d.ts +2 -2
  182. package/lib/deltaScheduler.d.ts.map +1 -1
  183. package/lib/deltaScheduler.js.map +1 -1
  184. package/lib/gc/garbageCollection.d.ts +5 -12
  185. package/lib/gc/garbageCollection.d.ts.map +1 -1
  186. package/lib/gc/garbageCollection.js +47 -31
  187. package/lib/gc/garbageCollection.js.map +1 -1
  188. package/lib/gc/gcDefinitions.d.ts +27 -6
  189. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  190. package/lib/gc/gcDefinitions.js.map +1 -1
  191. package/lib/gc/gcHelpers.d.ts +5 -4
  192. package/lib/gc/gcHelpers.d.ts.map +1 -1
  193. package/lib/gc/gcHelpers.js +12 -1
  194. package/lib/gc/gcHelpers.js.map +1 -1
  195. package/lib/gc/gcTelemetry.d.ts +14 -4
  196. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  197. package/lib/gc/gcTelemetry.js +24 -21
  198. package/lib/gc/gcTelemetry.js.map +1 -1
  199. package/lib/gc/index.d.ts +2 -2
  200. package/lib/gc/index.d.ts.map +1 -1
  201. package/lib/gc/index.js +1 -1
  202. package/lib/gc/index.js.map +1 -1
  203. package/lib/index.d.ts +3 -3
  204. package/lib/index.d.ts.map +1 -1
  205. package/lib/index.js +1 -1
  206. package/lib/index.js.map +1 -1
  207. package/lib/{alpha.d.ts → legacy.d.ts} +8 -1
  208. package/lib/messageTypes.d.ts +5 -2
  209. package/lib/messageTypes.d.ts.map +1 -1
  210. package/lib/messageTypes.js.map +1 -1
  211. package/lib/metadata.d.ts +2 -2
  212. package/lib/metadata.d.ts.map +1 -1
  213. package/lib/metadata.js.map +1 -1
  214. package/lib/opLifecycle/batchManager.d.ts +4 -1
  215. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  216. package/lib/opLifecycle/batchManager.js +0 -10
  217. package/lib/opLifecycle/batchManager.js.map +1 -1
  218. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  219. package/lib/opLifecycle/opDecompressor.js +6 -6
  220. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  221. package/lib/opLifecycle/opGroupingManager.js +2 -2
  222. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  223. package/lib/opLifecycle/opSplitter.js +1 -1
  224. package/lib/opLifecycle/opSplitter.js.map +1 -1
  225. package/lib/opLifecycle/outbox.d.ts +0 -4
  226. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  227. package/lib/opLifecycle/outbox.js +7 -38
  228. package/lib/opLifecycle/outbox.js.map +1 -1
  229. package/lib/packageVersion.d.ts +1 -1
  230. package/lib/packageVersion.js +1 -1
  231. package/lib/packageVersion.js.map +1 -1
  232. package/lib/pendingStateManager.d.ts +9 -2
  233. package/lib/pendingStateManager.d.ts.map +1 -1
  234. package/lib/pendingStateManager.js +27 -11
  235. package/lib/pendingStateManager.js.map +1 -1
  236. package/lib/public.d.ts +3 -0
  237. package/lib/scheduleManager.d.ts +2 -2
  238. package/lib/scheduleManager.d.ts.map +1 -1
  239. package/lib/scheduleManager.js.map +1 -1
  240. package/lib/summary/documentSchema.d.ts +3 -1
  241. package/lib/summary/documentSchema.d.ts.map +1 -1
  242. package/lib/summary/documentSchema.js +34 -16
  243. package/lib/summary/documentSchema.js.map +1 -1
  244. package/lib/summary/index.d.ts +1 -1
  245. package/lib/summary/index.d.ts.map +1 -1
  246. package/lib/summary/index.js.map +1 -1
  247. package/lib/summary/orderedClientElection.d.ts +2 -2
  248. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  249. package/lib/summary/orderedClientElection.js +1 -1
  250. package/lib/summary/orderedClientElection.js.map +1 -1
  251. package/lib/summary/runningSummarizer.js +1 -1
  252. package/lib/summary/runningSummarizer.js.map +1 -1
  253. package/lib/summary/summarizer.d.ts +1 -2
  254. package/lib/summary/summarizer.d.ts.map +1 -1
  255. package/lib/summary/summarizer.js.map +1 -1
  256. package/lib/summary/summarizerClientElection.d.ts +1 -1
  257. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  258. package/lib/summary/summarizerClientElection.js.map +1 -1
  259. package/lib/summary/summarizerHeuristics.d.ts +1 -1
  260. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  261. package/lib/summary/summarizerHeuristics.js.map +1 -1
  262. package/lib/summary/summarizerNode/summarizerNode.d.ts +4 -3
  263. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  264. package/lib/summary/summarizerNode/summarizerNode.js +4 -10
  265. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  266. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  267. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  268. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  269. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  270. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  271. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  272. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  273. package/lib/summary/summarizerTypes.d.ts +3 -5
  274. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  275. package/lib/summary/summarizerTypes.js.map +1 -1
  276. package/lib/summary/summaryCollection.d.ts +2 -2
  277. package/lib/summary/summaryCollection.d.ts.map +1 -1
  278. package/lib/summary/summaryCollection.js.map +1 -1
  279. package/lib/summary/summaryFormat.d.ts +25 -5
  280. package/lib/summary/summaryFormat.d.ts.map +1 -1
  281. package/lib/summary/summaryFormat.js.map +1 -1
  282. package/lib/summary/summaryGenerator.d.ts +1 -2
  283. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  284. package/lib/summary/summaryGenerator.js +5 -4
  285. package/lib/summary/summaryGenerator.js.map +1 -1
  286. package/lib/summary/summaryManager.d.ts.map +1 -1
  287. package/lib/summary/summaryManager.js +2 -2
  288. package/lib/summary/summaryManager.js.map +1 -1
  289. package/lib/tsdoc-metadata.json +1 -1
  290. package/package.json +37 -59
  291. package/src/batchTracker.ts +1 -2
  292. package/src/blobManager.ts +11 -10
  293. package/src/channelCollection.ts +115 -47
  294. package/src/connectionTelemetry.ts +59 -4
  295. package/src/containerRuntime.ts +302 -270
  296. package/src/dataStore.ts +7 -4
  297. package/src/dataStoreContext.ts +57 -16
  298. package/src/dataStoreContexts.ts +13 -2
  299. package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +98 -24
  300. package/src/deltaScheduler.ts +2 -3
  301. package/src/gc/garbageCollection.ts +64 -42
  302. package/src/gc/gcDefinitions.ts +22 -10
  303. package/src/gc/gcHelpers.ts +14 -1
  304. package/src/gc/gcTelemetry.ts +57 -50
  305. package/src/gc/index.ts +2 -1
  306. package/src/index.ts +7 -0
  307. package/src/messageTypes.ts +4 -2
  308. package/src/metadata.ts +2 -2
  309. package/src/opLifecycle/README.md +4 -4
  310. package/src/opLifecycle/batchManager.ts +5 -14
  311. package/src/opLifecycle/opDecompressor.ts +12 -6
  312. package/src/opLifecycle/opGroupingManager.ts +2 -2
  313. package/src/opLifecycle/opSplitter.ts +1 -1
  314. package/src/opLifecycle/outbox.ts +7 -53
  315. package/src/packageVersion.ts +1 -1
  316. package/src/pendingStateManager.ts +38 -15
  317. package/src/scheduleManager.ts +2 -2
  318. package/src/summary/documentSchema.ts +52 -18
  319. package/src/summary/index.ts +4 -0
  320. package/src/summary/orderedClientElection.ts +6 -3
  321. package/src/summary/runningSummarizer.ts +1 -1
  322. package/src/summary/summarizer.ts +1 -1
  323. package/src/summary/summarizerClientElection.ts +1 -1
  324. package/src/summary/summarizerHeuristics.ts +1 -1
  325. package/src/summary/summarizerNode/summarizerNode.ts +3 -12
  326. package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -3
  327. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -10
  328. package/src/summary/summarizerTypes.ts +6 -5
  329. package/src/summary/summaryCollection.ts +2 -2
  330. package/src/summary/summaryFormat.ts +30 -4
  331. package/src/summary/summaryGenerator.ts +20 -9
  332. package/src/summary/summaryManager.ts +6 -3
  333. package/dist/deltaManagerSummarizerProxy.d.ts +0 -44
  334. package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
  335. package/dist/deltaManagerSummarizerProxy.js.map +0 -1
  336. package/lib/deltaManagerSummarizerProxy.d.ts +0 -44
  337. package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
  338. package/lib/deltaManagerSummarizerProxy.js.map +0 -1
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
7
+ exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DeletedResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
8
8
  const client_utils_1 = require("@fluid-internal/client-utils");
9
9
  const container_definitions_1 = require("@fluidframework/container-definitions");
10
10
  const internal_1 = require("@fluidframework/container-definitions/internal");
@@ -23,7 +23,7 @@ const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
23
23
  const containerHandleContext_js_1 = require("./containerHandleContext.js");
24
24
  const dataStore_js_1 = require("./dataStore.js");
25
25
  const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
26
- const deltaManagerSummarizerProxy_js_1 = require("./deltaManagerSummarizerProxy.js");
26
+ const deltaManagerProxies_js_1 = require("./deltaManagerProxies.js");
27
27
  const index_js_1 = require("./gc/index.js");
28
28
  const messageTypes_js_1 = require("./messageTypes.js");
29
29
  const index_js_2 = require("./opLifecycle/index.js");
@@ -61,6 +61,11 @@ exports.DefaultSummaryConfiguration = {
61
61
  runtimeOpWeight: 1.0,
62
62
  nonRuntimeHeuristicThreshold: 20,
63
63
  };
64
+ /**
65
+ * Error responses when requesting a deleted object will have this header set to true
66
+ * @alpha
67
+ */
68
+ exports.DeletedResponseHeaderKey = "wasDeleted";
64
69
  /**
65
70
  * Tombstone error responses will have this header set to true
66
71
  * @alpha
@@ -245,7 +250,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
245
250
  },
246
251
  });
247
252
  const mc = (0, internal_7.loggerToMonitoringContext)(logger);
248
- const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, explicitSchemaControl = false, } = runtimeOptions;
253
+ const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching = true, explicitSchemaControl = false, } = runtimeOptions;
249
254
  const registry = new dataStoreRegistry_js_1.FluidDataStoreRegistry(registryEntries);
250
255
  const tryFetchBlob = async (blobName) => {
251
256
  const blobId = context.baseSnapshot?.blobs[blobName];
@@ -273,9 +278,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
273
278
  const messageAtLastSummary = lastMessageFromMetadata(metadata);
274
279
  // Verify summary runtime sequence number matches protocol sequence number.
275
280
  const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
281
+ const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
276
282
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
277
283
  if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
278
- const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
279
284
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
280
285
  if (loadSequenceNumberVerification !== "bypass" &&
281
286
  runtimeSequenceNumber !== protocolSequenceNumber) {
@@ -327,7 +332,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
327
332
  ?.idCompressorMode;
328
333
  // This is the only exception to the rule above - we have proper plumbing to load ID compressor on schema change
329
334
  // event. It is loaded async (relative to op processing), so this conversion is only safe for off -> delayed conversion!
330
- if (idCompressorMode === undefined && desiredIdCompressorMode === "delayed") {
335
+ // Clients do not expect ID compressor ops unless ID compressor is On for them, and that could be achieved only through
336
+ // explicit schema change, i.e. only if explicitSchemaControl is on.
337
+ // Note: it would be better if we throw on combination of options (explicitSchemaControl = off, desiredIdCompressorMode === "delayed")
338
+ // that is not supported. But our service tests are oblivious to these problems and throwing here will cause a ton of failures
339
+ // We ignored incompatible ID compressor changes from the start (they were sticky), so that's not a new problem being introduced...
340
+ if (idCompressorMode === undefined &&
341
+ desiredIdCompressorMode === "delayed" &&
342
+ explicitSchemaControl) {
331
343
  idCompressorMode = desiredIdCompressorMode;
332
344
  }
333
345
  }
@@ -360,23 +372,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
360
372
  return createIdCompressor(compressorLogger);
361
373
  }
362
374
  };
363
- const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
364
375
  const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
365
376
  const compressionLz4 = disableCompression !== true &&
366
377
  compressionOptions.minimumBatchSizeInBytes !== Infinity &&
367
378
  compressionOptions.compressionAlgorithm === "lz4";
368
- const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
369
- const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, metadata?.documentSchema, {
379
+ const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
370
380
  explicitSchemaControl,
371
381
  compressionLz4,
372
382
  idCompressorMode,
373
- opGroupingEnabled,
383
+ opGroupingEnabled: enableGroupedBatching,
374
384
  disallowedVersions: [],
375
385
  }, (schema) => {
376
386
  runtime.onSchemaChange(schema);
377
387
  });
378
388
  const featureGatesForTelemetry = {
379
- disableGroupedBatching,
380
389
  disableCompression,
381
390
  };
382
391
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
@@ -389,7 +398,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
389
398
  chunkSizeInBytes,
390
399
  // Requires<> drops undefined from IdCompressorType
391
400
  enableRuntimeIdCompressor: enableRuntimeIdCompressor,
392
- enableOpReentryCheck,
393
401
  enableGroupedBatching,
394
402
  explicitSchemaControl,
395
403
  }, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, undefined);
@@ -428,11 +436,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
428
436
  get attachState() {
429
437
  return this._getAttachState();
430
438
  }
431
- get documentSchema() {
439
+ /**
440
+ * Current session schema - defines what options are on & off.
441
+ * It's overlap of document schema (controlled by summary & ops) and options controlling this session.
442
+ * For example, document schema might have compression ON, but feature gates / runtime options turn it Off.
443
+ * In such case it will be off in session schema (i.e. this session should not use compression), but this client
444
+ * has to deal with compressed ops as other clients might send them.
445
+ * And in reverse, session schema can have compression Off, but feature gates / runtime options want it On.
446
+ * In such case it will be off in session schema, however this client will propose change to schema, and once / if
447
+ * this op rountrips, compression will be On. Client can't send compressed ops until it's change in schema.
448
+ */
449
+ get sessionSchema() {
432
450
  return this.documentsSchemaController.sessionSchema.runtime;
433
451
  }
434
452
  get idCompressorMode() {
435
- return this.documentSchema.idCompressorMode;
453
+ return this.sessionSchema.idCompressorMode;
436
454
  }
437
455
  /**
438
456
  * See IContainerRuntimeBase.idCompressor() for details.
@@ -540,13 +558,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
540
558
  this.flushTaskExists = false;
541
559
  this.consecutiveReconnects = 0;
542
560
  this.ensureNoDataModelChangesCalls = 0;
543
- /**
544
- * Tracks the number of detected reentrant ops to report,
545
- * in order to self-throttle the telemetry events.
546
- *
547
- * This should be removed as part of ADO:2322
548
- */
549
- this.opReentryCallsToReport = 5;
550
561
  this._disposed = false;
551
562
  this.emitDirtyDocumentEvent = true;
552
563
  this.defaultTelemetrySignalSampleCount = 100;
@@ -563,7 +574,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
563
574
  this.snapshotCacheForLoadingGroupIds = new internal_2.PromiseCache({
564
575
  expiry: { policy: "absolute", durationMs: 60000 },
565
576
  });
566
- const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
577
+ const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, snapshotWithContents, } = context;
567
578
  this.mc = (0, internal_7.createChildMonitoringContext)({
568
579
  logger: this.logger,
569
580
  namespace: "ContainerRuntime",
@@ -573,13 +584,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
573
584
  // If it's not in the list, then we will need to either use no compression, or fallback to some other (supported by format)
574
585
  // compression.
575
586
  const compressionOptions = {
576
- minimumBatchSizeInBytes: this.documentSchema.compressionLz4
587
+ minimumBatchSizeInBytes: this.sessionSchema.compressionLz4
577
588
  ? runtimeOptions.compressionOptions.minimumBatchSizeInBytes
578
589
  : Number.POSITIVE_INFINITY,
579
590
  compressionAlgorithm: CompressionAlgorithms.lz4,
580
591
  };
581
592
  this.innerDeltaManager = deltaManager;
582
- this.deltaManager = new deltaManagerSummarizerProxy_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
583
593
  // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
584
594
  // This makes ContainerRuntime the final gatekeeper for outgoing messages.
585
595
  this.submitFn = submitFn;
@@ -653,15 +663,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
653
663
  }, this.mc.logger);
654
664
  const opSplitter = new index_js_2.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
655
665
  this.remoteMessageProcessor = new index_js_2.RemoteMessageProcessor(opSplitter, new index_js_2.OpDecompressor(this.mc.logger), opGroupingManager);
666
+ const pendingRuntimeState = pendingLocalState;
667
+ this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
668
+ applyStashedOp: this.applyStashedOp.bind(this),
669
+ clientId: () => this.clientId,
670
+ close: this.closeFn,
671
+ connected: () => this.connected,
672
+ reSubmit: (message) => {
673
+ this.reSubmit(message);
674
+ this.flush();
675
+ },
676
+ reSubmitBatch: this.reSubmitBatch.bind(this),
677
+ isActiveConnection: () => this.innerDeltaManager.active,
678
+ isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
679
+ }, pendingRuntimeState?.pending, this.logger);
680
+ let outerDeltaManager;
681
+ const useDeltaManagerOpsProxy = this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
682
+ // The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
683
+ const summarizerDeltaManagerProxy = new deltaManagerProxies_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
684
+ outerDeltaManager = summarizerDeltaManagerProxy;
685
+ // The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
686
+ // It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
687
+ if (useDeltaManagerOpsProxy) {
688
+ const pendingOpsDeltaManagerProxy = new deltaManagerProxies_js_1.DeltaManagerPendingOpsProxy(summarizerDeltaManagerProxy, this.pendingStateManager);
689
+ outerDeltaManager = pendingOpsDeltaManagerProxy;
690
+ }
691
+ this.deltaManager = outerDeltaManager;
656
692
  this.handleContext = new containerHandleContext_js_1.ContainerFluidHandleContext("", this);
657
693
  if (this.summaryConfiguration.state === "enabled") {
658
694
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
659
695
  }
660
- const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
661
- this.enableOpReentryCheck =
662
- runtimeOptions.enableOpReentryCheck === true &&
663
- // Allow for a break-glass config to override the options
664
- disableOpReentryCheck !== true;
665
696
  this.summariesDisabled = this.isSummariesDisabled();
666
697
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
667
698
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
@@ -677,7 +708,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
677
708
  else {
678
709
  this._flushMode = runtimeOptions.flushMode;
679
710
  }
680
- const pendingRuntimeState = pendingLocalState;
681
711
  if (context.attachState === container_definitions_1.AttachState.Attached) {
682
712
  const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
683
713
  if (maxSnapshotCacheDurationMs !== undefined &&
@@ -733,7 +763,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
733
763
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
734
764
  return this.submitSignalFn(envelope2, targetClientId);
735
765
  };
736
- this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (path, reason, timestampMs, packagePath, request, headerData) => this.garbageCollector.nodeUpdated(path, reason, timestampMs, packagePath, request, headerData), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
766
+ let snapshot = (0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata);
767
+ if (snapshot !== undefined && snapshotWithContents !== undefined) {
768
+ snapshot = {
769
+ ...snapshotWithContents,
770
+ snapshotTree: snapshot,
771
+ };
772
+ }
773
+ this.channelCollection = new channelCollection_js_1.ChannelCollection(snapshot, parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
737
774
  this.blobManager = new blobManager_js_1.BlobManager({
738
775
  routeContext: this.handleContext,
739
776
  snapshot: blobManagerSnapshot,
@@ -746,26 +783,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
746
783
  });
747
784
  }
748
785
  },
749
- blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
786
+ blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
787
+ node: { type: "Blob", path: blobPath },
788
+ reason: "Loaded",
789
+ }),
750
790
  isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
751
791
  runtime: this,
752
792
  stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
753
793
  closeContainer: (error) => this.closeFn(error),
754
794
  });
755
795
  this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, internal_7.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
756
- this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
757
- applyStashedOp: this.applyStashedOp.bind(this),
758
- clientId: () => this.clientId,
759
- close: this.closeFn,
760
- connected: () => this.connected,
761
- reSubmit: (message) => {
762
- this.reSubmit(message);
763
- this.flush();
764
- },
765
- reSubmitBatch: this.reSubmitBatch.bind(this),
766
- isActiveConnection: () => this.innerDeltaManager.active,
767
- isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
768
- }, pendingRuntimeState?.pending, this.logger);
769
796
  const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
770
797
  const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
771
798
  this.outbox = new index_js_2.Outbox({
@@ -794,12 +821,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
794
821
  this._quorum.on("removeMember", (clientId) => {
795
822
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
796
823
  });
797
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
798
824
  this._audience = audience;
825
+ if (audience.getSelf === undefined) {
826
+ // back-compat, added in 2.0 RC3.
827
+ // Purpose: deal with cases when we run against old loader that does not have newly added capabilities
828
+ audience.getSelf = () => {
829
+ const clientId = this._getClientId();
830
+ return clientId === undefined
831
+ ? undefined
832
+ : ({
833
+ clientId,
834
+ client: audience.getMember(clientId),
835
+ });
836
+ };
837
+ let oldClientId = this.clientId;
838
+ this.on("connected", () => {
839
+ const clientId = this.clientId;
840
+ (0, internal_2.assert)(clientId !== undefined, 0x975 /* can't be undefined */);
841
+ audience.emit("selfChanged", { clientId: oldClientId }, { clientId, client: audience.getMember(clientId) });
842
+ oldClientId = clientId;
843
+ });
844
+ }
799
845
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
800
846
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
801
- this.validateSummaryBeforeUpload =
802
- this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
803
847
  this.summaryCollection = new index_js_3.SummaryCollection(this.deltaManager, this.logger);
804
848
  this.dirtyContainer =
805
849
  this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
@@ -872,9 +916,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
872
916
  options: JSON.stringify(runtimeOptions),
873
917
  idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
874
918
  idCompressorMode: this.idCompressorMode,
919
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
875
920
  featureGates: JSON.stringify({
876
921
  ...featureGatesForTelemetry,
877
- disableOpReentryCheck,
878
922
  disableChunking,
879
923
  disableAttachReorder: this.disableAttachReorder,
880
924
  disablePartialFlush,
@@ -882,6 +926,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
882
926
  }),
883
927
  telemetryDocumentId: this.telemetryDocumentId,
884
928
  groupedBatchingEnabled: this.groupedBatchingEnabled,
929
+ initialSequenceNumber: this.deltaManager.initialSequenceNumber,
885
930
  });
886
931
  (0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
887
932
  (0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
@@ -897,6 +942,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
897
942
  this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
898
943
  }
899
944
  onSchemaChange(schema) {
945
+ this.logger.sendTelemetryEvent({
946
+ eventName: "SchemaChangeAccept",
947
+ sessionRuntimeSchema: JSON.stringify(schema),
948
+ });
900
949
  // Most of the settings will be picked up only by new sessions (i.e. after reload).
901
950
  // We can make it better in the future (i.e. start to use op compression right away), but for simplicity
902
951
  // this is not done.
@@ -929,9 +978,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
929
978
  async initializeBaseState() {
930
979
  if (this.idCompressorMode === "on" ||
931
980
  (this.idCompressorMode === "delayed" && this.connected)) {
981
+ this._idCompressor = await this.createIdCompressor();
932
982
  // This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
933
983
  (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
934
- this._idCompressor = await this.createIdCompressor();
935
984
  }
936
985
  await this.garbageCollector.initializeBaseState();
937
986
  }
@@ -1229,6 +1278,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1229
1278
  this.emitDirtyDocumentEvent = false;
1230
1279
  let newState;
1231
1280
  try {
1281
+ this.submitIdAllocationOpIfNeeded(true);
1232
1282
  // replay the ops
1233
1283
  this.pendingStateManager.replayPendingStates();
1234
1284
  }
@@ -1276,8 +1326,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1276
1326
  return;
1277
1327
  case messageTypes_js_1.ContainerMessageType.BlobAttach:
1278
1328
  return;
1279
- case messageTypes_js_1.ContainerMessageType.ChunkedOp:
1280
- throw new Error("chunkedOp not expected here");
1281
1329
  case messageTypes_js_1.ContainerMessageType.Rejoin:
1282
1330
  throw new Error("rejoin not expected here");
1283
1331
  case messageTypes_js_1.ContainerMessageType.GC:
@@ -1289,7 +1337,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1289
1337
  // e.g. if an app rolled back its container version
1290
1338
  const compatBehavior = opContents.compatDetails?.behavior;
1291
1339
  if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1292
- const error = internal_7.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1340
+ const error = internal_7.DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
1293
1341
  messageDetails: JSON.stringify({
1294
1342
  type: opContents.type,
1295
1343
  compatBehavior,
@@ -1309,12 +1357,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1309
1357
  this._loadIdCompressor === undefined) {
1310
1358
  this._loadIdCompressor = this.createIdCompressor()
1311
1359
  .then((compressor) => {
1312
- this._idCompressor = compressor;
1313
1360
  // Finalize any ranges we received while the compressor was turned off.
1314
- for (const range of this.pendingIdCompressorOps) {
1315
- this._idCompressor.finalizeCreationRange(range);
1316
- }
1361
+ const ops = this.pendingIdCompressorOps;
1317
1362
  this.pendingIdCompressorOps = [];
1363
+ for (const range of ops) {
1364
+ compressor.finalizeCreationRange(range);
1365
+ }
1366
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
1367
+ this._idCompressor = compressor;
1318
1368
  })
1319
1369
  .catch((error) => {
1320
1370
  this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
@@ -1324,6 +1374,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1324
1374
  return this._loadIdCompressor;
1325
1375
  }
1326
1376
  setConnectionState(connected, clientId) {
1377
+ // Validate we have consistent state
1378
+ const currentClientId = this._audience.getSelf()?.clientId;
1379
+ (0, internal_2.assert)(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
1380
+ (0, internal_2.assert)(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
1327
1381
  if (connected && this.idCompressorMode === "delayed") {
1328
1382
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1329
1383
  this.loadIdCompressor();
@@ -1405,9 +1459,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1405
1459
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1406
1460
  // but will not modify the contents object (likely it will replace it on the message).
1407
1461
  const messageCopy = { ...messageArg };
1462
+ const savedOp = messageCopy.metadata?.savedOp;
1408
1463
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1409
- if (modernRuntimeMessage) {
1410
- this.processCore({
1464
+ const msg = modernRuntimeMessage
1465
+ ? {
1411
1466
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1412
1467
  // There is nothing really ensuring that anytime original message.type is Operation that
1413
1468
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1415,12 +1470,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1415
1470
  message: message,
1416
1471
  local,
1417
1472
  modernRuntimeMessage,
1418
- });
1419
- }
1420
- else {
1421
- // Unrecognized message will be ignored.
1422
- this.processCore({ message, local, modernRuntimeMessage });
1423
- }
1473
+ }
1474
+ : // Unrecognized message will be ignored.
1475
+ {
1476
+ message,
1477
+ local,
1478
+ modernRuntimeMessage,
1479
+ };
1480
+ msg.savedOp = savedOp;
1481
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1482
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1424
1483
  }
1425
1484
  }
1426
1485
  /**
@@ -1428,6 +1487,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1428
1487
  */
1429
1488
  processCore(messageWithContext) {
1430
1489
  const { message, local } = messageWithContext;
1490
+ // Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
1491
+ // Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
1492
+ if (this.deltaManager.minimumSequenceNumber <
1493
+ messageWithContext.message.minimumSequenceNumber) {
1494
+ messageWithContext.message.minimumSequenceNumber =
1495
+ this.deltaManager.minimumSequenceNumber;
1496
+ }
1431
1497
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1432
1498
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1433
1499
  // messages once a batch has been fully processed.
@@ -1438,7 +1504,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1438
1504
  // These calls should be made for all but chunked ops:
1439
1505
  // 1) this.pendingStateManager.processPendingLocalMessage() below
1440
1506
  // 2) this.resetReconnectCount() below
1441
- (0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, "we should never get here with chunked ops");
1507
+ (0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, 0x93b /* we should never get here with chunked ops */);
1442
1508
  let localOpMetadata;
1443
1509
  if (local && messageWithContext.modernRuntimeMessage) {
1444
1510
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
@@ -1485,17 +1551,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1485
1551
  // stashed ops flow. The compressor is stashed with these ops already processed.
1486
1552
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1487
1553
  // thus we need to process all the ops.
1488
- if (!(this.skipSavedCompressorOps &&
1489
- messageWithContext.message.metadata?.savedOp ===
1490
- true)) {
1554
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1491
1555
  const range = messageWithContext.message.contents;
1492
1556
  // Some other client turned on the id compressor. If we have not turned it on,
1493
1557
  // put it in a pending queue and delay finalization.
1494
1558
  if (this._idCompressor === undefined) {
1495
- (0, internal_2.assert)(this.idCompressorMode !== undefined, "id compressor should be enabled");
1559
+ (0, internal_2.assert)(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
1496
1560
  this.pendingIdCompressorOps.push(range);
1497
1561
  }
1498
1562
  else {
1563
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
1499
1564
  this._idCompressor.finalizeCreationRange(range);
1500
1565
  }
1501
1566
  }
@@ -1506,7 +1571,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1506
1571
  case messageTypes_js_1.ContainerMessageType.ChunkedOp:
1507
1572
  // From observability POV, we should not exppse the rest of the system (including "op" events on object) to these messages.
1508
1573
  // Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
1509
- (0, internal_2.assert)(false, "should not even get here");
1574
+ (0, internal_2.assert)(false, 0x93d /* should not even get here */);
1510
1575
  case messageTypes_js_1.ContainerMessageType.Rejoin:
1511
1576
  break;
1512
1577
  case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
@@ -1616,9 +1681,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1616
1681
  let checkpoint;
1617
1682
  let result;
1618
1683
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1619
- // Note: we are not touching this.pendingAttachBatch here, for two reasons:
1620
- // 1. It would not help, as we flush attach ops as they become available.
1621
- // 2. There is no way to undo process of data store creation.
1684
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1685
+ // 1. It would not help, as other batches are flushed independently from main batch.
1686
+ // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
1622
1687
  checkpoint = this.outbox.checkpoint().mainBatch;
1623
1688
  }
1624
1689
  try {
@@ -1681,7 +1746,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1681
1746
  if (channel.entryPoint === undefined) {
1682
1747
  throw new internal_7.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1683
1748
  }
1684
- this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
1749
+ this.garbageCollector.nodeUpdated({
1750
+ node: { type: "DataStore", path: `/${internalId}` },
1751
+ reason: "Loaded",
1752
+ packagePath: context.packagePath,
1753
+ });
1685
1754
  return channel.entryPoint;
1686
1755
  }
1687
1756
  createDetachedDataStore(pkg, loadingGroupId) {
@@ -1805,7 +1874,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1805
1874
  // We can finalize any allocated IDs since we're the only client
1806
1875
  const idRange = this._idCompressor?.takeNextCreationRange();
1807
1876
  if (idRange !== undefined) {
1808
- (0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1, "No other ranges should be taken while container is detached.");
1877
+ (0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1, 0x93e /* No other ranges should be taken while container is detached. */);
1809
1878
  this._idCompressor?.finalizeCreationRange(idRange);
1810
1879
  }
1811
1880
  const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
@@ -1852,7 +1921,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1852
1921
  return { stats, summary };
1853
1922
  }
1854
1923
  finally {
1855
- this.mc.logger.sendTelemetryEvent({
1924
+ summaryLogger.sendTelemetryEvent({
1856
1925
  eventName: "SummarizeTelemetry",
1857
1926
  details: telemetryContext.serialize(),
1858
1927
  });
@@ -2015,10 +2084,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2015
2084
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2016
2085
  // use it for all events logged during this summary.
2017
2086
  const summaryNumber = this.nextSummaryNumber;
2087
+ let summaryRefSeqNum;
2018
2088
  const summaryNumberLogger = (0, internal_7.createChildLogger)({
2019
2089
  logger: summaryLogger,
2020
2090
  properties: {
2021
- all: { summaryNumber },
2091
+ all: {
2092
+ summaryNumber,
2093
+ referenceSequenceNumber: () => summaryRefSeqNum,
2094
+ },
2022
2095
  },
2023
2096
  });
2024
2097
  (0, internal_2.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
@@ -2032,7 +2105,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2032
2105
  // If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
2033
2106
  // and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
2034
2107
  // saved within the timeout, check if it should be failed or can continue.
2035
- if (this.validateSummaryBeforeUpload && this.isDirty) {
2108
+ if (this.isDirty) {
2036
2109
  const countBefore = this.pendingMessagesCount;
2037
2110
  // The timeout for waiting for pending ops can be overridden via configurations.
2038
2111
  const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
@@ -2065,7 +2138,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2065
2138
  }
2066
2139
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
2067
2140
  const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
2068
- let summaryRefSeqNum;
2069
2141
  try {
2070
2142
  await this.deltaManager.inbound.pause();
2071
2143
  if (shouldPauseInboundSignal) {
@@ -2076,9 +2148,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2076
2148
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
2077
2149
  const lastAck = this.summaryCollection.latestAck;
2078
2150
  const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
2151
+ /**
2152
+ * This was added to validate that the summarizer node tree has the same reference sequence number from the
2153
+ * top running summarizer down to the lowest summarizer node.
2154
+ *
2155
+ * The order of mismatch numbers goes (validate sequence number)-(node sequence number).
2156
+ * Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
2157
+ * summarizer nodes.
2158
+ */
2079
2159
  if (startSummaryResult.invalidNodes > 0 ||
2080
2160
  startSummaryResult.mismatchNumbers.size > 0) {
2081
- summaryLogger.sendErrorEvent({
2161
+ summaryLogger.sendTelemetryEvent({
2082
2162
  eventName: "LatestSummaryRefSeqNumMismatch",
2083
2163
  details: {
2084
2164
  ...startSummaryResult,
@@ -2090,7 +2170,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2090
2170
  stage: "base",
2091
2171
  referenceSequenceNumber: summaryRefSeqNum,
2092
2172
  minimumSequenceNumber,
2093
- error: `Summarizer node state inconsistent with summarizer state.`,
2173
+ error: new internal_7.LoggingError(`Summarizer node state inconsistent with summarizer state.`),
2094
2174
  };
2095
2175
  }
2096
2176
  }
@@ -2133,7 +2213,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2133
2213
  stage: "base",
2134
2214
  referenceSequenceNumber: summaryRefSeqNum,
2135
2215
  minimumSequenceNumber,
2136
- error: continueResult.error,
2216
+ error: new internal_7.LoggingError(continueResult.error),
2137
2217
  };
2138
2218
  }
2139
2219
  const trace = client_utils_1.Trace.start();
@@ -2150,6 +2230,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2150
2230
  });
2151
2231
  }
2152
2232
  catch (error) {
2233
+ return {
2234
+ stage: "base",
2235
+ referenceSequenceNumber: summaryRefSeqNum,
2236
+ minimumSequenceNumber,
2237
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2238
+ };
2239
+ }
2240
+ // Validate that the summary generated by summarizer nodes is correct before uploading.
2241
+ const validateResult = this.summarizerNode.validateSummary();
2242
+ if (!validateResult.success) {
2243
+ const { success, ...loggingProps } = validateResult;
2244
+ const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
2153
2245
  return {
2154
2246
  stage: "base",
2155
2247
  referenceSequenceNumber: summaryRefSeqNum,
@@ -2157,24 +2249,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2157
2249
  error,
2158
2250
  };
2159
2251
  }
2160
- // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
2161
- if (this.validateSummaryBeforeUpload) {
2162
- // Validate that the summaries generated by summarize nodes is correct.
2163
- const validateResult = this.summarizerNode.validateSummary();
2164
- if (!validateResult.success) {
2165
- const { success, ...loggingProps } = validateResult;
2166
- const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
2167
- return {
2168
- stage: "base",
2169
- referenceSequenceNumber: summaryRefSeqNum,
2170
- minimumSequenceNumber,
2171
- error,
2172
- };
2173
- }
2174
- const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
2175
- if (pendingMessagesFailResult !== undefined) {
2176
- return pendingMessagesFailResult;
2177
- }
2252
+ // If there are pending unacked ops, this summary attempt may fail as the uploaded
2253
+ // summary would be eventually inconsistent.
2254
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
2255
+ if (pendingMessagesFailResult !== undefined) {
2256
+ return pendingMessagesFailResult;
2178
2257
  }
2179
2258
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
2180
2259
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -2207,7 +2286,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2207
2286
  };
2208
2287
  continueResult = checkContinue();
2209
2288
  if (!continueResult.continue) {
2210
- return { stage: "generate", ...generateSummaryData, error: continueResult.error };
2289
+ return {
2290
+ stage: "generate",
2291
+ ...generateSummaryData,
2292
+ error: new internal_7.LoggingError(continueResult.error),
2293
+ };
2211
2294
  }
2212
2295
  const summaryContext = lastAck === undefined
2213
2296
  ? {
@@ -2225,7 +2308,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2225
2308
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
2226
2309
  }
2227
2310
  catch (error) {
2228
- return { stage: "generate", ...generateSummaryData, error };
2311
+ return {
2312
+ stage: "generate",
2313
+ ...generateSummaryData,
2314
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2315
+ };
2229
2316
  }
2230
2317
  const parent = summaryContext.ackHandle;
2231
2318
  const summaryMessage = {
@@ -2242,14 +2329,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2242
2329
  };
2243
2330
  continueResult = checkContinue();
2244
2331
  if (!continueResult.continue) {
2245
- return { stage: "upload", ...uploadData, error: continueResult.error };
2332
+ return {
2333
+ stage: "upload",
2334
+ ...uploadData,
2335
+ error: new internal_7.LoggingError(continueResult.error),
2336
+ };
2246
2337
  }
2247
2338
  let clientSequenceNumber;
2248
2339
  try {
2249
2340
  clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
2250
2341
  }
2251
2342
  catch (error) {
2252
- return { stage: "upload", ...uploadData, error };
2343
+ return {
2344
+ stage: "upload",
2345
+ ...uploadData,
2346
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2347
+ };
2253
2348
  }
2254
2349
  const submitData = {
2255
2350
  stage: "submit",
@@ -2258,11 +2353,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2258
2353
  submitOpDuration: trace.trace().duration,
2259
2354
  };
2260
2355
  try {
2261
- // If validateSummaryBeforeUpload is false, the summary should be validated in this step.
2262
- this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
2356
+ this.summarizerNode.completeSummary(handle);
2263
2357
  }
2264
2358
  catch (error) {
2265
- return { stage: "upload", ...uploadData, error };
2359
+ return {
2360
+ stage: "upload",
2361
+ ...uploadData,
2362
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2363
+ };
2266
2364
  }
2267
2365
  return submitData;
2268
2366
  }
@@ -2351,9 +2449,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2351
2449
  this.verifyNotClosed();
2352
2450
  return this.blobManager.createBlob(blob, signal);
2353
2451
  }
2354
- submitIdAllocationOpIfNeeded() {
2452
+ submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
2355
2453
  if (this._idCompressor) {
2356
- const idRange = this._idCompressor.takeNextCreationRange();
2454
+ const idRange = resubmitOutstandingRanges
2455
+ ? this.idCompressor?.takeUnfinalizedCreationRange()
2456
+ : this._idCompressor.takeNextCreationRange();
2357
2457
  // Don't include the idRange if there weren't any Ids allocated
2358
2458
  if (idRange?.ids !== undefined) {
2359
2459
  const idAllocationMessage = {
@@ -2370,11 +2470,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2370
2470
  }
2371
2471
  submit(containerRuntimeMessage, localOpMetadata = undefined, metadata) {
2372
2472
  this.verifyNotClosed();
2373
- this.verifyCanSubmitOps();
2374
2473
  // There should be no ops in detached container state!
2375
2474
  (0, internal_2.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2376
2475
  (0, internal_2.assert)(metadata === undefined ||
2377
- containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, "metadata");
2476
+ containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, 0x93f /* metadata */);
2378
2477
  const serializedContent = JSON.stringify(containerRuntimeMessage);
2379
2478
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2380
2479
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
@@ -2406,6 +2505,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2406
2505
  // on this callback to do actual sending.
2407
2506
  const contents = this.documentsSchemaController.maybeSendSchemaMessage();
2408
2507
  if (contents) {
2508
+ this.logger.sendTelemetryEvent({
2509
+ eventName: "SchemaChangeProposal",
2510
+ refSeq: contents.refSeq,
2511
+ version: contents.version,
2512
+ newRuntimeSchema: JSON.stringify(contents.runtime),
2513
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2514
+ oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
2515
+ });
2409
2516
  const msg = {
2410
2517
  type: messageTypes_js_1.ContainerMessageType.DocumentSchemaChange,
2411
2518
  contents,
@@ -2415,32 +2522,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2415
2522
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2416
2523
  });
2417
2524
  }
2418
- // If this is attach message for new data store, and we are in a batch, send this op out of order
2419
- // Is it safe:
2420
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
2421
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
2422
- // is stored in some DDS, i.e. only after some other op.
2423
- // Why:
2424
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
2425
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
2426
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
2427
- // these issues.
2428
- // Cons:
2429
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
2430
- // This change creates new possibility of a lot of newly created data stores never being referenced
2431
- // because client died before it had a change to submit the rest of the ops. This will create more
2432
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
2433
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
2434
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
2435
- // issue than sending.
2436
- // Please note that this does not change file format, so it can be disabled in the future if this
2437
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
2438
- if (this.currentlyBatching() &&
2439
- type === messageTypes_js_1.ContainerMessageType.Attach &&
2440
- this.disableAttachReorder !== true) {
2441
- this.outbox.submitAttach(message);
2442
- }
2443
- else if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2525
+ if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2444
2526
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2445
2527
  this.outbox.submitBlobAttach(message);
2446
2528
  }
@@ -2515,32 +2597,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2515
2597
  throw new Error("Runtime is closed");
2516
2598
  }
2517
2599
  }
2518
- verifyCanSubmitOps() {
2519
- if (this.ensureNoDataModelChangesCalls > 0) {
2520
- const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
2521
- if (this.opReentryCallsToReport > 0) {
2522
- this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
2523
- // We need to capture the call stack in order to inspect the source of this usage pattern
2524
- (0, index_js_2.getLongStack)(() => new internal_7.UsageError(errorMessage)));
2525
- this.opReentryCallsToReport--;
2526
- }
2527
- // Creating ops while processing ops can lead
2528
- // to undefined behavior and events observed in the wrong order.
2529
- // For example, we have two callbacks registered for a DDS, A and B.
2530
- // Then if on change #1 callback A creates change #2, the invocation flow will be:
2531
- //
2532
- // A because of #1
2533
- // A because of #2
2534
- // B because of #2
2535
- // B because of #1
2536
- //
2537
- // The runtime must enforce op coherence by not allowing ops to be submitted
2538
- // while ops are being processed.
2539
- if (this.enableOpReentryCheck) {
2540
- throw new internal_7.UsageError(errorMessage);
2541
- }
2542
- }
2543
- }
2544
2600
  reSubmitBatch(batch) {
2545
2601
  this.orderSequentially(() => {
2546
2602
  for (const message of batch) {
@@ -2572,11 +2628,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2572
2628
  this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
2573
2629
  break;
2574
2630
  case messageTypes_js_1.ContainerMessageType.IdAllocation: {
2575
- this.submit(message, localOpMetadata);
2631
+ // Allocation ops are never resubmitted/rebased. This is because they require special handling to
2632
+ // avoid being submitted out of order. For example, if the pending state manager contained
2633
+ // [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
2634
+ // placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
2635
+ // To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
2636
+ // manager to replay pending ops, the runtime will always submit a new allocation range that includes
2637
+ // all pending IDs. The resubmitted allocation ops are then ignored here.
2576
2638
  break;
2577
2639
  }
2578
- case messageTypes_js_1.ContainerMessageType.ChunkedOp:
2579
- throw new Error(`chunkedOp not expected here`);
2580
2640
  case messageTypes_js_1.ContainerMessageType.BlobAttach:
2581
2641
  this.blobManager.reSubmit(opMetadata);
2582
2642
  break;
@@ -2603,7 +2663,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2603
2663
  });
2604
2664
  }
2605
2665
  else {
2606
- const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2666
+ const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
2607
2667
  messageDetails: JSON.stringify({
2608
2668
  type: message.type,
2609
2669
  compatBehavior,
@@ -2670,7 +2730,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2670
2730
  await this.closeStaleSummarizer();
2671
2731
  return {
2672
2732
  stage: "base",
2673
- error: "summary state stale - Unsupported option 'refreshLatestAck'",
2733
+ error: new internal_7.LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
2674
2734
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2675
2735
  minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2676
2736
  };
@@ -2714,16 +2774,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2714
2774
  }
2715
2775
  this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
2716
2776
  const getSyncState = (pendingAttachmentBlobs) => {
2717
- const pending = this.pendingStateManager.getLocalState();
2718
- if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
2719
- return; // no pending state to save
2720
- }
2777
+ const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
2778
+ const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
2721
2779
  const pendingIdCompressorState = this._idCompressor?.serialize(true);
2722
2780
  return {
2723
2781
  pending,
2724
2782
  pendingIdCompressorState,
2725
2783
  pendingAttachmentBlobs,
2726
- sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
2784
+ sessionExpiryTimerStarted,
2727
2785
  };
2728
2786
  };
2729
2787
  const perfEvent = {
@@ -2793,7 +2851,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2793
2851
  }
2794
2852
  }
2795
2853
  get groupedBatchingEnabled() {
2796
- return this.documentSchema.opGroupingEnabled === true;
2854
+ return this.sessionSchema.opGroupingEnabled === true;
2797
2855
  }
2798
2856
  }
2799
2857
  exports.ContainerRuntime = ContainerRuntime;