@fluidframework/container-runtime 2.0.0-rc.3.0.2 → 2.0.0-rc.4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/api-report/container-runtime.api.md +72 -34
  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 +6 -4
  11. package/dist/channelCollection.d.ts.map +1 -1
  12. package/dist/channelCollection.js +20 -7
  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 +17 -35
  19. package/dist/containerRuntime.d.ts.map +1 -1
  20. package/dist/containerRuntime.js +182 -160
  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.map +1 -1
  30. package/dist/dataStoreContexts.js.map +1 -1
  31. package/dist/deltaManagerProxies.d.ts +81 -0
  32. package/dist/deltaManagerProxies.d.ts.map +1 -0
  33. package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +75 -20
  34. package/dist/deltaManagerProxies.js.map +1 -0
  35. package/dist/deltaScheduler.d.ts +2 -2
  36. package/dist/deltaScheduler.d.ts.map +1 -1
  37. package/dist/deltaScheduler.js.map +1 -1
  38. package/dist/gc/garbageCollection.d.ts +1 -1
  39. package/dist/gc/garbageCollection.d.ts.map +1 -1
  40. package/dist/gc/garbageCollection.js.map +1 -1
  41. package/dist/gc/gcDefinitions.d.ts +1 -1
  42. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  43. package/dist/gc/gcDefinitions.js.map +1 -1
  44. package/dist/gc/gcTelemetry.d.ts +1 -2
  45. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  46. package/dist/gc/gcTelemetry.js.map +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/legacy.d.ts +6 -1
  51. package/dist/messageTypes.d.ts +5 -2
  52. package/dist/messageTypes.d.ts.map +1 -1
  53. package/dist/messageTypes.js.map +1 -1
  54. package/dist/metadata.d.ts +2 -2
  55. package/dist/metadata.d.ts.map +1 -1
  56. package/dist/metadata.js.map +1 -1
  57. package/dist/opLifecycle/batchManager.d.ts +0 -1
  58. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  59. package/dist/opLifecycle/batchManager.js +0 -10
  60. package/dist/opLifecycle/batchManager.js.map +1 -1
  61. package/dist/opLifecycle/outbox.d.ts +0 -4
  62. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  63. package/dist/opLifecycle/outbox.js +2 -34
  64. package/dist/opLifecycle/outbox.js.map +1 -1
  65. package/dist/packageVersion.d.ts +1 -1
  66. package/dist/packageVersion.js +1 -1
  67. package/dist/packageVersion.js.map +1 -1
  68. package/dist/pendingStateManager.d.ts +9 -2
  69. package/dist/pendingStateManager.d.ts.map +1 -1
  70. package/dist/pendingStateManager.js +26 -10
  71. package/dist/pendingStateManager.js.map +1 -1
  72. package/dist/scheduleManager.d.ts +2 -2
  73. package/dist/scheduleManager.d.ts.map +1 -1
  74. package/dist/scheduleManager.js.map +1 -1
  75. package/dist/summary/documentSchema.d.ts +3 -1
  76. package/dist/summary/documentSchema.d.ts.map +1 -1
  77. package/dist/summary/documentSchema.js +25 -7
  78. package/dist/summary/documentSchema.js.map +1 -1
  79. package/dist/summary/index.d.ts +1 -1
  80. package/dist/summary/index.d.ts.map +1 -1
  81. package/dist/summary/index.js.map +1 -1
  82. package/dist/summary/orderedClientElection.d.ts +2 -2
  83. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  84. package/dist/summary/orderedClientElection.js.map +1 -1
  85. package/dist/summary/runningSummarizer.js +10 -10
  86. package/dist/summary/runningSummarizer.js.map +1 -1
  87. package/dist/summary/summarizer.d.ts +1 -2
  88. package/dist/summary/summarizer.d.ts.map +1 -1
  89. package/dist/summary/summarizer.js.map +1 -1
  90. package/dist/summary/summarizerClientElection.d.ts +1 -1
  91. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  92. package/dist/summary/summarizerClientElection.js.map +1 -1
  93. package/dist/summary/summarizerHeuristics.d.ts +1 -1
  94. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  95. package/dist/summary/summarizerHeuristics.js.map +1 -1
  96. package/dist/summary/summarizerNode/summarizerNode.d.ts +4 -3
  97. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  98. package/dist/summary/summarizerNode/summarizerNode.js +4 -10
  99. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  100. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  101. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  102. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  103. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  104. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  105. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  106. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  107. package/dist/summary/summarizerTypes.d.ts +3 -5
  108. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  109. package/dist/summary/summarizerTypes.js.map +1 -1
  110. package/dist/summary/summaryCollection.d.ts +2 -2
  111. package/dist/summary/summaryCollection.d.ts.map +1 -1
  112. package/dist/summary/summaryCollection.js.map +1 -1
  113. package/dist/summary/summaryFormat.d.ts +25 -5
  114. package/dist/summary/summaryFormat.d.ts.map +1 -1
  115. package/dist/summary/summaryFormat.js.map +1 -1
  116. package/dist/summary/summaryGenerator.d.ts +1 -2
  117. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  118. package/dist/summary/summaryGenerator.js +12 -11
  119. package/dist/summary/summaryGenerator.js.map +1 -1
  120. package/dist/summary/summaryManager.d.ts.map +1 -1
  121. package/dist/summary/summaryManager.js +5 -5
  122. package/dist/summary/summaryManager.js.map +1 -1
  123. package/lib/batchTracker.d.ts +1 -1
  124. package/lib/batchTracker.d.ts.map +1 -1
  125. package/lib/batchTracker.js.map +1 -1
  126. package/lib/blobManager.d.ts +7 -7
  127. package/lib/blobManager.d.ts.map +1 -1
  128. package/lib/blobManager.js +3 -5
  129. package/lib/blobManager.js.map +1 -1
  130. package/lib/channelCollection.d.ts +6 -4
  131. package/lib/channelCollection.d.ts.map +1 -1
  132. package/lib/channelCollection.js +21 -8
  133. package/lib/channelCollection.js.map +1 -1
  134. package/lib/connectionTelemetry.d.ts +2 -2
  135. package/lib/connectionTelemetry.d.ts.map +1 -1
  136. package/lib/connectionTelemetry.js +49 -0
  137. package/lib/connectionTelemetry.js.map +1 -1
  138. package/lib/containerRuntime.d.ts +17 -35
  139. package/lib/containerRuntime.d.ts.map +1 -1
  140. package/lib/containerRuntime.js +183 -161
  141. package/lib/containerRuntime.js.map +1 -1
  142. package/lib/dataStore.d.ts +1 -1
  143. package/lib/dataStore.d.ts.map +1 -1
  144. package/lib/dataStore.js +1 -1
  145. package/lib/dataStore.js.map +1 -1
  146. package/lib/dataStoreContext.d.ts +9 -6
  147. package/lib/dataStoreContext.d.ts.map +1 -1
  148. package/lib/dataStoreContext.js +21 -7
  149. package/lib/dataStoreContext.js.map +1 -1
  150. package/lib/dataStoreContexts.d.ts.map +1 -1
  151. package/lib/dataStoreContexts.js.map +1 -1
  152. package/lib/deltaManagerProxies.d.ts +81 -0
  153. package/lib/deltaManagerProxies.d.ts.map +1 -0
  154. package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +72 -19
  155. package/lib/deltaManagerProxies.js.map +1 -0
  156. package/lib/deltaScheduler.d.ts +2 -2
  157. package/lib/deltaScheduler.d.ts.map +1 -1
  158. package/lib/deltaScheduler.js.map +1 -1
  159. package/lib/gc/garbageCollection.d.ts +1 -1
  160. package/lib/gc/garbageCollection.d.ts.map +1 -1
  161. package/lib/gc/garbageCollection.js.map +1 -1
  162. package/lib/gc/gcDefinitions.d.ts +1 -1
  163. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  164. package/lib/gc/gcDefinitions.js.map +1 -1
  165. package/lib/gc/gcTelemetry.d.ts +1 -2
  166. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  167. package/lib/gc/gcTelemetry.js.map +1 -1
  168. package/lib/index.d.ts +1 -1
  169. package/lib/index.d.ts.map +1 -1
  170. package/lib/index.js.map +1 -1
  171. package/lib/legacy.d.ts +6 -1
  172. package/lib/messageTypes.d.ts +5 -2
  173. package/lib/messageTypes.d.ts.map +1 -1
  174. package/lib/messageTypes.js.map +1 -1
  175. package/lib/metadata.d.ts +2 -2
  176. package/lib/metadata.d.ts.map +1 -1
  177. package/lib/metadata.js.map +1 -1
  178. package/lib/opLifecycle/batchManager.d.ts +0 -1
  179. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  180. package/lib/opLifecycle/batchManager.js +0 -10
  181. package/lib/opLifecycle/batchManager.js.map +1 -1
  182. package/lib/opLifecycle/outbox.d.ts +0 -4
  183. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  184. package/lib/opLifecycle/outbox.js +2 -34
  185. package/lib/opLifecycle/outbox.js.map +1 -1
  186. package/lib/packageVersion.d.ts +1 -1
  187. package/lib/packageVersion.js +1 -1
  188. package/lib/packageVersion.js.map +1 -1
  189. package/lib/pendingStateManager.d.ts +9 -2
  190. package/lib/pendingStateManager.d.ts.map +1 -1
  191. package/lib/pendingStateManager.js +27 -11
  192. package/lib/pendingStateManager.js.map +1 -1
  193. package/lib/scheduleManager.d.ts +2 -2
  194. package/lib/scheduleManager.d.ts.map +1 -1
  195. package/lib/scheduleManager.js.map +1 -1
  196. package/lib/summary/documentSchema.d.ts +3 -1
  197. package/lib/summary/documentSchema.d.ts.map +1 -1
  198. package/lib/summary/documentSchema.js +25 -7
  199. package/lib/summary/documentSchema.js.map +1 -1
  200. package/lib/summary/index.d.ts +1 -1
  201. package/lib/summary/index.d.ts.map +1 -1
  202. package/lib/summary/index.js.map +1 -1
  203. package/lib/summary/orderedClientElection.d.ts +2 -2
  204. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  205. package/lib/summary/orderedClientElection.js +1 -1
  206. package/lib/summary/orderedClientElection.js.map +1 -1
  207. package/lib/summary/runningSummarizer.js +1 -1
  208. package/lib/summary/runningSummarizer.js.map +1 -1
  209. package/lib/summary/summarizer.d.ts +1 -2
  210. package/lib/summary/summarizer.d.ts.map +1 -1
  211. package/lib/summary/summarizer.js.map +1 -1
  212. package/lib/summary/summarizerClientElection.d.ts +1 -1
  213. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  214. package/lib/summary/summarizerClientElection.js.map +1 -1
  215. package/lib/summary/summarizerHeuristics.d.ts +1 -1
  216. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  217. package/lib/summary/summarizerHeuristics.js.map +1 -1
  218. package/lib/summary/summarizerNode/summarizerNode.d.ts +4 -3
  219. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  220. package/lib/summary/summarizerNode/summarizerNode.js +4 -10
  221. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  222. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  223. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  224. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  225. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  226. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  227. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  228. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  229. package/lib/summary/summarizerTypes.d.ts +3 -5
  230. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  231. package/lib/summary/summarizerTypes.js.map +1 -1
  232. package/lib/summary/summaryCollection.d.ts +2 -2
  233. package/lib/summary/summaryCollection.d.ts.map +1 -1
  234. package/lib/summary/summaryCollection.js.map +1 -1
  235. package/lib/summary/summaryFormat.d.ts +25 -5
  236. package/lib/summary/summaryFormat.d.ts.map +1 -1
  237. package/lib/summary/summaryFormat.js.map +1 -1
  238. package/lib/summary/summaryGenerator.d.ts +1 -2
  239. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  240. package/lib/summary/summaryGenerator.js +5 -4
  241. package/lib/summary/summaryGenerator.js.map +1 -1
  242. package/lib/summary/summaryManager.d.ts.map +1 -1
  243. package/lib/summary/summaryManager.js +2 -2
  244. package/lib/summary/summaryManager.js.map +1 -1
  245. package/lib/tsdoc-metadata.json +1 -1
  246. package/package.json +28 -50
  247. package/src/batchTracker.ts +1 -2
  248. package/src/blobManager.ts +11 -10
  249. package/src/channelCollection.ts +30 -12
  250. package/src/connectionTelemetry.ts +59 -4
  251. package/src/containerRuntime.ts +250 -236
  252. package/src/dataStore.ts +7 -4
  253. package/src/dataStoreContext.ts +57 -16
  254. package/src/dataStoreContexts.ts +1 -2
  255. package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +98 -24
  256. package/src/deltaScheduler.ts +2 -3
  257. package/src/gc/garbageCollection.ts +1 -1
  258. package/src/gc/gcDefinitions.ts +1 -1
  259. package/src/gc/gcTelemetry.ts +1 -3
  260. package/src/index.ts +5 -0
  261. package/src/messageTypes.ts +4 -2
  262. package/src/metadata.ts +2 -2
  263. package/src/opLifecycle/README.md +4 -4
  264. package/src/opLifecycle/batchManager.ts +0 -14
  265. package/src/opLifecycle/outbox.ts +2 -49
  266. package/src/packageVersion.ts +1 -1
  267. package/src/pendingStateManager.ts +38 -15
  268. package/src/scheduleManager.ts +2 -2
  269. package/src/summary/documentSchema.ts +37 -12
  270. package/src/summary/index.ts +4 -0
  271. package/src/summary/orderedClientElection.ts +6 -3
  272. package/src/summary/runningSummarizer.ts +1 -1
  273. package/src/summary/summarizer.ts +1 -1
  274. package/src/summary/summarizerClientElection.ts +1 -1
  275. package/src/summary/summarizerHeuristics.ts +1 -1
  276. package/src/summary/summarizerNode/summarizerNode.ts +3 -12
  277. package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -3
  278. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -10
  279. package/src/summary/summarizerTypes.ts +6 -5
  280. package/src/summary/summaryCollection.ts +2 -2
  281. package/src/summary/summaryFormat.ts +30 -4
  282. package/src/summary/summaryGenerator.ts +20 -9
  283. package/src/summary/summaryManager.ts +6 -3
  284. package/dist/deltaManagerSummarizerProxy.d.ts +0 -44
  285. package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
  286. package/dist/deltaManagerSummarizerProxy.js.map +0 -1
  287. package/lib/deltaManagerSummarizerProxy.d.ts +0 -44
  288. package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
  289. package/lib/deltaManagerSummarizerProxy.js.map +0 -1
@@ -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");
@@ -250,7 +250,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
250
250
  },
251
251
  });
252
252
  const mc = (0, internal_7.loggerToMonitoringContext)(logger);
253
- 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;
254
254
  const registry = new dataStoreRegistry_js_1.FluidDataStoreRegistry(registryEntries);
255
255
  const tryFetchBlob = async (blobName) => {
256
256
  const blobId = context.baseSnapshot?.blobs[blobName];
@@ -278,9 +278,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
278
278
  const messageAtLastSummary = lastMessageFromMetadata(metadata);
279
279
  // Verify summary runtime sequence number matches protocol sequence number.
280
280
  const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
281
+ const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
281
282
  // When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
282
283
  if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
283
- const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
284
284
  // Unless bypass is explicitly set, then take action when sequence numbers mismatch.
285
285
  if (loadSequenceNumberVerification !== "bypass" &&
286
286
  runtimeSequenceNumber !== protocolSequenceNumber) {
@@ -372,23 +372,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
372
372
  return createIdCompressor(compressorLogger);
373
373
  }
374
374
  };
375
- const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
376
375
  const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
377
376
  const compressionLz4 = disableCompression !== true &&
378
377
  compressionOptions.minimumBatchSizeInBytes !== Infinity &&
379
378
  compressionOptions.compressionAlgorithm === "lz4";
380
- const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
381
- const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, metadata?.documentSchema, {
379
+ const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
382
380
  explicitSchemaControl,
383
381
  compressionLz4,
384
382
  idCompressorMode,
385
- opGroupingEnabled,
383
+ opGroupingEnabled: enableGroupedBatching,
386
384
  disallowedVersions: [],
387
385
  }, (schema) => {
388
386
  runtime.onSchemaChange(schema);
389
387
  });
390
388
  const featureGatesForTelemetry = {
391
- disableGroupedBatching,
392
389
  disableCompression,
393
390
  };
394
391
  const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
@@ -401,7 +398,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
401
398
  chunkSizeInBytes,
402
399
  // Requires<> drops undefined from IdCompressorType
403
400
  enableRuntimeIdCompressor: enableRuntimeIdCompressor,
404
- enableOpReentryCheck,
405
401
  enableGroupedBatching,
406
402
  explicitSchemaControl,
407
403
  }, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, undefined);
@@ -440,11 +436,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
440
436
  get attachState() {
441
437
  return this._getAttachState();
442
438
  }
443
- 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() {
444
450
  return this.documentsSchemaController.sessionSchema.runtime;
445
451
  }
446
452
  get idCompressorMode() {
447
- return this.documentSchema.idCompressorMode;
453
+ return this.sessionSchema.idCompressorMode;
448
454
  }
449
455
  /**
450
456
  * See IContainerRuntimeBase.idCompressor() for details.
@@ -552,13 +558,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
552
558
  this.flushTaskExists = false;
553
559
  this.consecutiveReconnects = 0;
554
560
  this.ensureNoDataModelChangesCalls = 0;
555
- /**
556
- * Tracks the number of detected reentrant ops to report,
557
- * in order to self-throttle the telemetry events.
558
- *
559
- * This should be removed as part of ADO:2322
560
- */
561
- this.opReentryCallsToReport = 5;
562
561
  this._disposed = false;
563
562
  this.emitDirtyDocumentEvent = true;
564
563
  this.defaultTelemetrySignalSampleCount = 100;
@@ -575,7 +574,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
575
574
  this.snapshotCacheForLoadingGroupIds = new internal_2.PromiseCache({
576
575
  expiry: { policy: "absolute", durationMs: 60000 },
577
576
  });
578
- 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;
579
578
  this.mc = (0, internal_7.createChildMonitoringContext)({
580
579
  logger: this.logger,
581
580
  namespace: "ContainerRuntime",
@@ -585,13 +584,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
585
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)
586
585
  // compression.
587
586
  const compressionOptions = {
588
- minimumBatchSizeInBytes: this.documentSchema.compressionLz4
587
+ minimumBatchSizeInBytes: this.sessionSchema.compressionLz4
589
588
  ? runtimeOptions.compressionOptions.minimumBatchSizeInBytes
590
589
  : Number.POSITIVE_INFINITY,
591
590
  compressionAlgorithm: CompressionAlgorithms.lz4,
592
591
  };
593
592
  this.innerDeltaManager = deltaManager;
594
- this.deltaManager = new deltaManagerSummarizerProxy_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
595
593
  // Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
596
594
  // This makes ContainerRuntime the final gatekeeper for outgoing messages.
597
595
  this.submitFn = submitFn;
@@ -665,15 +663,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
665
663
  }, this.mc.logger);
666
664
  const opSplitter = new index_js_2.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
667
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;
668
692
  this.handleContext = new containerHandleContext_js_1.ContainerFluidHandleContext("", this);
669
693
  if (this.summaryConfiguration.state === "enabled") {
670
694
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
671
695
  }
672
- const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
673
- this.enableOpReentryCheck =
674
- runtimeOptions.enableOpReentryCheck === true &&
675
- // Allow for a break-glass config to override the options
676
- disableOpReentryCheck !== true;
677
696
  this.summariesDisabled = this.isSummariesDisabled();
678
697
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
679
698
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
@@ -689,7 +708,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
689
708
  else {
690
709
  this._flushMode = runtimeOptions.flushMode;
691
710
  }
692
- const pendingRuntimeState = pendingLocalState;
693
711
  if (context.attachState === container_definitions_1.AttachState.Attached) {
694
712
  const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
695
713
  if (maxSnapshotCacheDurationMs !== undefined &&
@@ -745,7 +763,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
745
763
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
746
764
  return this.submitSignalFn(envelope2, targetClientId);
747
765
  };
748
- this.channelCollection = new channelCollection_js_1.ChannelCollection((0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata), parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (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);
749
774
  this.blobManager = new blobManager_js_1.BlobManager({
750
775
  routeContext: this.handleContext,
751
776
  snapshot: blobManagerSnapshot,
@@ -768,19 +793,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
768
793
  closeContainer: (error) => this.closeFn(error),
769
794
  });
770
795
  this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, internal_7.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
771
- this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
772
- applyStashedOp: this.applyStashedOp.bind(this),
773
- clientId: () => this.clientId,
774
- close: this.closeFn,
775
- connected: () => this.connected,
776
- reSubmit: (message) => {
777
- this.reSubmit(message);
778
- this.flush();
779
- },
780
- reSubmitBatch: this.reSubmitBatch.bind(this),
781
- isActiveConnection: () => this.innerDeltaManager.active,
782
- isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
783
- }, pendingRuntimeState?.pending, this.logger);
784
796
  const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
785
797
  const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
786
798
  this.outbox = new index_js_2.Outbox({
@@ -809,12 +821,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
809
821
  this._quorum.on("removeMember", (clientId) => {
810
822
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
811
823
  });
812
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
813
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
+ }
814
845
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
815
846
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
816
- this.validateSummaryBeforeUpload =
817
- this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
818
847
  this.summaryCollection = new index_js_3.SummaryCollection(this.deltaManager, this.logger);
819
848
  this.dirtyContainer =
820
849
  this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
@@ -887,9 +916,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
887
916
  options: JSON.stringify(runtimeOptions),
888
917
  idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
889
918
  idCompressorMode: this.idCompressorMode,
919
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
890
920
  featureGates: JSON.stringify({
891
921
  ...featureGatesForTelemetry,
892
- disableOpReentryCheck,
893
922
  disableChunking,
894
923
  disableAttachReorder: this.disableAttachReorder,
895
924
  disablePartialFlush,
@@ -897,6 +926,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
897
926
  }),
898
927
  telemetryDocumentId: this.telemetryDocumentId,
899
928
  groupedBatchingEnabled: this.groupedBatchingEnabled,
929
+ initialSequenceNumber: this.deltaManager.initialSequenceNumber,
900
930
  });
901
931
  (0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
902
932
  (0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
@@ -912,6 +942,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
912
942
  this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
913
943
  }
914
944
  onSchemaChange(schema) {
945
+ this.logger.sendTelemetryEvent({
946
+ eventName: "SchemaChangeAccept",
947
+ sessionRuntimeSchema: JSON.stringify(schema),
948
+ });
915
949
  // Most of the settings will be picked up only by new sessions (i.e. after reload).
916
950
  // We can make it better in the future (i.e. start to use op compression right away), but for simplicity
917
951
  // this is not done.
@@ -944,9 +978,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
944
978
  async initializeBaseState() {
945
979
  if (this.idCompressorMode === "on" ||
946
980
  (this.idCompressorMode === "delayed" && this.connected)) {
981
+ this._idCompressor = await this.createIdCompressor();
947
982
  // This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
948
983
  (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
949
- this._idCompressor = await this.createIdCompressor();
950
984
  }
951
985
  await this.garbageCollector.initializeBaseState();
952
986
  }
@@ -1291,8 +1325,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1291
1325
  return;
1292
1326
  case messageTypes_js_1.ContainerMessageType.BlobAttach:
1293
1327
  return;
1294
- case messageTypes_js_1.ContainerMessageType.ChunkedOp:
1295
- throw new Error("chunkedOp not expected here");
1296
1328
  case messageTypes_js_1.ContainerMessageType.Rejoin:
1297
1329
  throw new Error("rejoin not expected here");
1298
1330
  case messageTypes_js_1.ContainerMessageType.GC:
@@ -1304,7 +1336,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1304
1336
  // e.g. if an app rolled back its container version
1305
1337
  const compatBehavior = opContents.compatDetails?.behavior;
1306
1338
  if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1307
- const error = internal_7.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
1339
+ const error = internal_7.DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
1308
1340
  messageDetails: JSON.stringify({
1309
1341
  type: opContents.type,
1310
1342
  compatBehavior,
@@ -1324,12 +1356,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1324
1356
  this._loadIdCompressor === undefined) {
1325
1357
  this._loadIdCompressor = this.createIdCompressor()
1326
1358
  .then((compressor) => {
1327
- this._idCompressor = compressor;
1328
1359
  // Finalize any ranges we received while the compressor was turned off.
1329
- for (const range of this.pendingIdCompressorOps) {
1330
- this._idCompressor.finalizeCreationRange(range);
1331
- }
1360
+ const ops = this.pendingIdCompressorOps;
1332
1361
  this.pendingIdCompressorOps = [];
1362
+ for (const range of ops) {
1363
+ compressor.finalizeCreationRange(range);
1364
+ }
1365
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
1366
+ this._idCompressor = compressor;
1333
1367
  })
1334
1368
  .catch((error) => {
1335
1369
  this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
@@ -1339,6 +1373,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1339
1373
  return this._loadIdCompressor;
1340
1374
  }
1341
1375
  setConnectionState(connected, clientId) {
1376
+ // Validate we have consistent state
1377
+ const currentClientId = this._audience.getSelf()?.clientId;
1378
+ (0, internal_2.assert)(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
1379
+ (0, internal_2.assert)(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
1342
1380
  if (connected && this.idCompressorMode === "delayed") {
1343
1381
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1344
1382
  this.loadIdCompressor();
@@ -1420,9 +1458,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1420
1458
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1421
1459
  // but will not modify the contents object (likely it will replace it on the message).
1422
1460
  const messageCopy = { ...messageArg };
1461
+ const savedOp = messageCopy.metadata?.savedOp;
1423
1462
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1424
- if (modernRuntimeMessage) {
1425
- this.processCore({
1463
+ const msg = modernRuntimeMessage
1464
+ ? {
1426
1465
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1427
1466
  // There is nothing really ensuring that anytime original message.type is Operation that
1428
1467
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1430,12 +1469,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1430
1469
  message: message,
1431
1470
  local,
1432
1471
  modernRuntimeMessage,
1433
- });
1434
- }
1435
- else {
1436
- // Unrecognized message will be ignored.
1437
- this.processCore({ message, local, modernRuntimeMessage });
1438
- }
1472
+ }
1473
+ : // Unrecognized message will be ignored.
1474
+ {
1475
+ message,
1476
+ local,
1477
+ modernRuntimeMessage,
1478
+ };
1479
+ msg.savedOp = savedOp;
1480
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1481
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1439
1482
  }
1440
1483
  }
1441
1484
  /**
@@ -1443,6 +1486,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1443
1486
  */
1444
1487
  processCore(messageWithContext) {
1445
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
+ }
1446
1496
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1447
1497
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1448
1498
  // messages once a batch has been fully processed.
@@ -1500,9 +1550,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1500
1550
  // stashed ops flow. The compressor is stashed with these ops already processed.
1501
1551
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1502
1552
  // thus we need to process all the ops.
1503
- if (!(this.skipSavedCompressorOps &&
1504
- messageWithContext.message.metadata?.savedOp ===
1505
- true)) {
1553
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1506
1554
  const range = messageWithContext.message.contents;
1507
1555
  // Some other client turned on the id compressor. If we have not turned it on,
1508
1556
  // put it in a pending queue and delay finalization.
@@ -1511,6 +1559,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1511
1559
  this.pendingIdCompressorOps.push(range);
1512
1560
  }
1513
1561
  else {
1562
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
1514
1563
  this._idCompressor.finalizeCreationRange(range);
1515
1564
  }
1516
1565
  }
@@ -1631,9 +1680,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1631
1680
  let checkpoint;
1632
1681
  let result;
1633
1682
  if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
1634
- // Note: we are not touching this.pendingAttachBatch here, for two reasons:
1635
- // 1. It would not help, as we flush attach ops as they become available.
1636
- // 2. There is no way to undo process of data store creation.
1683
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1684
+ // 1. It would not help, as other batches are flushed independently from main batch.
1685
+ // 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
1637
1686
  checkpoint = this.outbox.checkpoint().mainBatch;
1638
1687
  }
1639
1688
  try {
@@ -2034,10 +2083,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2034
2083
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2035
2084
  // use it for all events logged during this summary.
2036
2085
  const summaryNumber = this.nextSummaryNumber;
2086
+ let summaryRefSeqNum;
2037
2087
  const summaryNumberLogger = (0, internal_7.createChildLogger)({
2038
2088
  logger: summaryLogger,
2039
2089
  properties: {
2040
- all: { summaryNumber },
2090
+ all: {
2091
+ summaryNumber,
2092
+ referenceSequenceNumber: () => summaryRefSeqNum,
2093
+ },
2041
2094
  },
2042
2095
  });
2043
2096
  (0, internal_2.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
@@ -2051,7 +2104,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2051
2104
  // If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
2052
2105
  // and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
2053
2106
  // saved within the timeout, check if it should be failed or can continue.
2054
- if (this.validateSummaryBeforeUpload && this.isDirty) {
2107
+ if (this.isDirty) {
2055
2108
  const countBefore = this.pendingMessagesCount;
2056
2109
  // The timeout for waiting for pending ops can be overridden via configurations.
2057
2110
  const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
@@ -2084,7 +2137,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2084
2137
  }
2085
2138
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
2086
2139
  const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
2087
- let summaryRefSeqNum;
2088
2140
  try {
2089
2141
  await this.deltaManager.inbound.pause();
2090
2142
  if (shouldPauseInboundSignal) {
@@ -2117,7 +2169,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2117
2169
  stage: "base",
2118
2170
  referenceSequenceNumber: summaryRefSeqNum,
2119
2171
  minimumSequenceNumber,
2120
- error: `Summarizer node state inconsistent with summarizer state.`,
2172
+ error: new internal_7.LoggingError(`Summarizer node state inconsistent with summarizer state.`),
2121
2173
  };
2122
2174
  }
2123
2175
  }
@@ -2160,7 +2212,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2160
2212
  stage: "base",
2161
2213
  referenceSequenceNumber: summaryRefSeqNum,
2162
2214
  minimumSequenceNumber,
2163
- error: continueResult.error,
2215
+ error: new internal_7.LoggingError(continueResult.error),
2164
2216
  };
2165
2217
  }
2166
2218
  const trace = client_utils_1.Trace.start();
@@ -2177,6 +2229,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2177
2229
  });
2178
2230
  }
2179
2231
  catch (error) {
2232
+ return {
2233
+ stage: "base",
2234
+ referenceSequenceNumber: summaryRefSeqNum,
2235
+ minimumSequenceNumber,
2236
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2237
+ };
2238
+ }
2239
+ // Validate that the summary generated by summarizer nodes is correct before uploading.
2240
+ const validateResult = this.summarizerNode.validateSummary();
2241
+ if (!validateResult.success) {
2242
+ const { success, ...loggingProps } = validateResult;
2243
+ const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
2180
2244
  return {
2181
2245
  stage: "base",
2182
2246
  referenceSequenceNumber: summaryRefSeqNum,
@@ -2184,24 +2248,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2184
2248
  error,
2185
2249
  };
2186
2250
  }
2187
- // If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
2188
- if (this.validateSummaryBeforeUpload) {
2189
- // Validate that the summaries generated by summarize nodes is correct.
2190
- const validateResult = this.summarizerNode.validateSummary();
2191
- if (!validateResult.success) {
2192
- const { success, ...loggingProps } = validateResult;
2193
- const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
2194
- return {
2195
- stage: "base",
2196
- referenceSequenceNumber: summaryRefSeqNum,
2197
- minimumSequenceNumber,
2198
- error,
2199
- };
2200
- }
2201
- const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
2202
- if (pendingMessagesFailResult !== undefined) {
2203
- return pendingMessagesFailResult;
2204
- }
2251
+ // If there are pending unacked ops, this summary attempt may fail as the uploaded
2252
+ // summary would be eventually inconsistent.
2253
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
2254
+ if (pendingMessagesFailResult !== undefined) {
2255
+ return pendingMessagesFailResult;
2205
2256
  }
2206
2257
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
2207
2258
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -2234,7 +2285,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2234
2285
  };
2235
2286
  continueResult = checkContinue();
2236
2287
  if (!continueResult.continue) {
2237
- return { stage: "generate", ...generateSummaryData, error: continueResult.error };
2288
+ return {
2289
+ stage: "generate",
2290
+ ...generateSummaryData,
2291
+ error: new internal_7.LoggingError(continueResult.error),
2292
+ };
2238
2293
  }
2239
2294
  const summaryContext = lastAck === undefined
2240
2295
  ? {
@@ -2252,7 +2307,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2252
2307
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
2253
2308
  }
2254
2309
  catch (error) {
2255
- return { stage: "generate", ...generateSummaryData, error };
2310
+ return {
2311
+ stage: "generate",
2312
+ ...generateSummaryData,
2313
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2314
+ };
2256
2315
  }
2257
2316
  const parent = summaryContext.ackHandle;
2258
2317
  const summaryMessage = {
@@ -2269,14 +2328,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2269
2328
  };
2270
2329
  continueResult = checkContinue();
2271
2330
  if (!continueResult.continue) {
2272
- return { stage: "upload", ...uploadData, error: continueResult.error };
2331
+ return {
2332
+ stage: "upload",
2333
+ ...uploadData,
2334
+ error: new internal_7.LoggingError(continueResult.error),
2335
+ };
2273
2336
  }
2274
2337
  let clientSequenceNumber;
2275
2338
  try {
2276
2339
  clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
2277
2340
  }
2278
2341
  catch (error) {
2279
- return { stage: "upload", ...uploadData, error };
2342
+ return {
2343
+ stage: "upload",
2344
+ ...uploadData,
2345
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2346
+ };
2280
2347
  }
2281
2348
  const submitData = {
2282
2349
  stage: "submit",
@@ -2285,11 +2352,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2285
2352
  submitOpDuration: trace.trace().duration,
2286
2353
  };
2287
2354
  try {
2288
- // If validateSummaryBeforeUpload is false, the summary should be validated in this step.
2289
- this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
2355
+ this.summarizerNode.completeSummary(handle);
2290
2356
  }
2291
2357
  catch (error) {
2292
- return { stage: "upload", ...uploadData, error };
2358
+ return {
2359
+ stage: "upload",
2360
+ ...uploadData,
2361
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2362
+ };
2293
2363
  }
2294
2364
  return submitData;
2295
2365
  }
@@ -2397,7 +2467,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2397
2467
  }
2398
2468
  submit(containerRuntimeMessage, localOpMetadata = undefined, metadata) {
2399
2469
  this.verifyNotClosed();
2400
- this.verifyCanSubmitOps();
2401
2470
  // There should be no ops in detached container state!
2402
2471
  (0, internal_2.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2403
2472
  (0, internal_2.assert)(metadata === undefined ||
@@ -2433,6 +2502,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2433
2502
  // on this callback to do actual sending.
2434
2503
  const contents = this.documentsSchemaController.maybeSendSchemaMessage();
2435
2504
  if (contents) {
2505
+ this.logger.sendTelemetryEvent({
2506
+ eventName: "SchemaChangeProposal",
2507
+ refSeq: contents.refSeq,
2508
+ version: contents.version,
2509
+ newRuntimeSchema: JSON.stringify(contents.runtime),
2510
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2511
+ oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
2512
+ });
2436
2513
  const msg = {
2437
2514
  type: messageTypes_js_1.ContainerMessageType.DocumentSchemaChange,
2438
2515
  contents,
@@ -2442,32 +2519,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2442
2519
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2443
2520
  });
2444
2521
  }
2445
- // If this is attach message for new data store, and we are in a batch, send this op out of order
2446
- // Is it safe:
2447
- // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
2448
- // They become visible only when aliased, or handle to some sub-element of newly created datastore
2449
- // is stored in some DDS, i.e. only after some other op.
2450
- // Why:
2451
- // Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
2452
- // stores are created, causing issues like relay service throttling (too many ops) and catastrophic
2453
- // failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
2454
- // these issues.
2455
- // Cons:
2456
- // 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
2457
- // This change creates new possibility of a lot of newly created data stores never being referenced
2458
- // because client died before it had a change to submit the rest of the ops. This will create more
2459
- // garbage that needs to be collected leveraging GC (Garbage Collection) feature.
2460
- // 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
2461
- // today as rollback can't undo creation of data store. To some extent not sending them is a bigger
2462
- // issue than sending.
2463
- // Please note that this does not change file format, so it can be disabled in the future if this
2464
- // optimization no longer makes sense (for example, batch compression may make it less appealing).
2465
- if (this.currentlyBatching() &&
2466
- type === messageTypes_js_1.ContainerMessageType.Attach &&
2467
- this.disableAttachReorder !== true) {
2468
- this.outbox.submitAttach(message);
2469
- }
2470
- else if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2522
+ if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2471
2523
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2472
2524
  this.outbox.submitBlobAttach(message);
2473
2525
  }
@@ -2542,32 +2594,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2542
2594
  throw new Error("Runtime is closed");
2543
2595
  }
2544
2596
  }
2545
- verifyCanSubmitOps() {
2546
- if (this.ensureNoDataModelChangesCalls > 0) {
2547
- const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
2548
- if (this.opReentryCallsToReport > 0) {
2549
- this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
2550
- // We need to capture the call stack in order to inspect the source of this usage pattern
2551
- (0, index_js_2.getLongStack)(() => new internal_7.UsageError(errorMessage)));
2552
- this.opReentryCallsToReport--;
2553
- }
2554
- // Creating ops while processing ops can lead
2555
- // to undefined behavior and events observed in the wrong order.
2556
- // For example, we have two callbacks registered for a DDS, A and B.
2557
- // Then if on change #1 callback A creates change #2, the invocation flow will be:
2558
- //
2559
- // A because of #1
2560
- // A because of #2
2561
- // B because of #2
2562
- // B because of #1
2563
- //
2564
- // The runtime must enforce op coherence by not allowing ops to be submitted
2565
- // while ops are being processed.
2566
- if (this.enableOpReentryCheck) {
2567
- throw new internal_7.UsageError(errorMessage);
2568
- }
2569
- }
2570
- }
2571
2597
  reSubmitBatch(batch) {
2572
2598
  this.orderSequentially(() => {
2573
2599
  for (const message of batch) {
@@ -2602,8 +2628,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2602
2628
  this.submit(message, localOpMetadata);
2603
2629
  break;
2604
2630
  }
2605
- case messageTypes_js_1.ContainerMessageType.ChunkedOp:
2606
- throw new Error(`chunkedOp not expected here`);
2607
2631
  case messageTypes_js_1.ContainerMessageType.BlobAttach:
2608
2632
  this.blobManager.reSubmit(opMetadata);
2609
2633
  break;
@@ -2630,7 +2654,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2630
2654
  });
2631
2655
  }
2632
2656
  else {
2633
- const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
2657
+ const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
2634
2658
  messageDetails: JSON.stringify({
2635
2659
  type: message.type,
2636
2660
  compatBehavior,
@@ -2697,7 +2721,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2697
2721
  await this.closeStaleSummarizer();
2698
2722
  return {
2699
2723
  stage: "base",
2700
- error: "summary state stale - Unsupported option 'refreshLatestAck'",
2724
+ error: new internal_7.LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
2701
2725
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2702
2726
  minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2703
2727
  };
@@ -2741,16 +2765,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2741
2765
  }
2742
2766
  this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
2743
2767
  const getSyncState = (pendingAttachmentBlobs) => {
2744
- const pending = this.pendingStateManager.getLocalState();
2745
- if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
2746
- return; // no pending state to save
2747
- }
2768
+ const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
2769
+ const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
2748
2770
  const pendingIdCompressorState = this._idCompressor?.serialize(true);
2749
2771
  return {
2750
2772
  pending,
2751
2773
  pendingIdCompressorState,
2752
2774
  pendingAttachmentBlobs,
2753
- sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
2775
+ sessionExpiryTimerStarted,
2754
2776
  };
2755
2777
  };
2756
2778
  const perfEvent = {
@@ -2820,7 +2842,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2820
2842
  }
2821
2843
  }
2822
2844
  get groupedBatchingEnabled() {
2823
- return this.documentSchema.opGroupingEnabled === true;
2845
+ return this.sessionSchema.opGroupingEnabled === true;
2824
2846
  }
2825
2847
  }
2826
2848
  exports.ContainerRuntime = ContainerRuntime;