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

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 (293) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/api-report/container-runtime.api.md +33 -19
  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/channelCollection.d.ts +5 -3
  7. package/dist/channelCollection.d.ts.map +1 -1
  8. package/dist/channelCollection.js +67 -15
  9. package/dist/channelCollection.js.map +1 -1
  10. package/dist/connectionTelemetry.d.ts +1 -1
  11. package/dist/connectionTelemetry.d.ts.map +1 -1
  12. package/dist/connectionTelemetry.js +54 -5
  13. package/dist/connectionTelemetry.js.map +1 -1
  14. package/dist/containerRuntime.d.ts +17 -27
  15. package/dist/containerRuntime.d.ts.map +1 -1
  16. package/dist/containerRuntime.js +174 -143
  17. package/dist/containerRuntime.js.map +1 -1
  18. package/dist/dataStore.d.ts +1 -1
  19. package/dist/dataStore.d.ts.map +1 -1
  20. package/dist/dataStore.js.map +1 -1
  21. package/dist/dataStoreContext.d.ts.map +1 -1
  22. package/dist/dataStoreContext.js +1 -0
  23. package/dist/dataStoreContext.js.map +1 -1
  24. package/dist/dataStoreContexts.d.ts +2 -0
  25. package/dist/dataStoreContexts.d.ts.map +1 -1
  26. package/dist/dataStoreContexts.js +7 -0
  27. package/dist/dataStoreContexts.js.map +1 -1
  28. package/dist/deltaManagerSummarizerProxy.d.ts +18 -6
  29. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  30. package/dist/deltaManagerSummarizerProxy.js +38 -19
  31. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  32. package/dist/deltaScheduler.d.ts +1 -1
  33. package/dist/deltaScheduler.d.ts.map +1 -1
  34. package/dist/deltaScheduler.js.map +1 -1
  35. package/dist/gc/garbageCollection.d.ts +5 -12
  36. package/dist/gc/garbageCollection.d.ts.map +1 -1
  37. package/dist/gc/garbageCollection.js +45 -29
  38. package/dist/gc/garbageCollection.js.map +1 -1
  39. package/dist/gc/gcDefinitions.d.ts +27 -6
  40. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  41. package/dist/gc/gcDefinitions.js.map +1 -1
  42. package/dist/gc/gcHelpers.d.ts +5 -4
  43. package/dist/gc/gcHelpers.d.ts.map +1 -1
  44. package/dist/gc/gcHelpers.js +14 -2
  45. package/dist/gc/gcHelpers.js.map +1 -1
  46. package/dist/gc/gcTelemetry.d.ts +14 -4
  47. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  48. package/dist/gc/gcTelemetry.js +24 -21
  49. package/dist/gc/gcTelemetry.js.map +1 -1
  50. package/dist/gc/index.d.ts +2 -2
  51. package/dist/gc/index.d.ts.map +1 -1
  52. package/dist/gc/index.js +2 -2
  53. package/dist/gc/index.js.map +1 -1
  54. package/dist/index.d.ts +2 -2
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +2 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/{alpha.d.ts → legacy.d.ts} +3 -1
  59. package/dist/metadata.d.ts +2 -2
  60. package/dist/metadata.d.ts.map +1 -1
  61. package/dist/metadata.js.map +1 -1
  62. package/dist/opLifecycle/batchManager.d.ts +0 -1
  63. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  64. package/dist/opLifecycle/batchManager.js +0 -10
  65. package/dist/opLifecycle/batchManager.js.map +1 -1
  66. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  67. package/dist/opLifecycle/opDecompressor.js +6 -6
  68. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  69. package/dist/opLifecycle/opGroupingManager.js +2 -2
  70. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  71. package/dist/opLifecycle/opSplitter.js +1 -1
  72. package/dist/opLifecycle/opSplitter.js.map +1 -1
  73. package/dist/opLifecycle/outbox.d.ts +0 -4
  74. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  75. package/dist/opLifecycle/outbox.js +2 -34
  76. package/dist/opLifecycle/outbox.js.map +1 -1
  77. package/dist/packageVersion.d.ts +1 -1
  78. package/dist/packageVersion.js +1 -1
  79. package/dist/packageVersion.js.map +1 -1
  80. package/dist/pendingStateManager.d.ts +3 -2
  81. package/dist/pendingStateManager.d.ts.map +1 -1
  82. package/dist/pendingStateManager.js +17 -10
  83. package/dist/pendingStateManager.js.map +1 -1
  84. package/dist/public.d.ts +3 -0
  85. package/dist/scheduleManager.d.ts +1 -1
  86. package/dist/scheduleManager.d.ts.map +1 -1
  87. package/dist/scheduleManager.js.map +1 -1
  88. package/dist/summary/documentSchema.d.ts +3 -1
  89. package/dist/summary/documentSchema.d.ts.map +1 -1
  90. package/dist/summary/documentSchema.js +34 -16
  91. package/dist/summary/documentSchema.js.map +1 -1
  92. package/dist/summary/orderedClientElection.d.ts +1 -1
  93. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  94. package/dist/summary/orderedClientElection.js.map +1 -1
  95. package/dist/summary/summarizer.d.ts +1 -2
  96. package/dist/summary/summarizer.d.ts.map +1 -1
  97. package/dist/summary/summarizer.js.map +1 -1
  98. package/dist/summary/summarizerClientElection.d.ts +1 -1
  99. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  100. package/dist/summary/summarizerClientElection.js.map +1 -1
  101. package/dist/summary/summarizerHeuristics.d.ts +1 -1
  102. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  103. package/dist/summary/summarizerHeuristics.js.map +1 -1
  104. package/dist/summary/summarizerNode/summarizerNode.d.ts +4 -3
  105. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  106. package/dist/summary/summarizerNode/summarizerNode.js +4 -10
  107. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  108. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  109. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  110. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  111. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  112. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  113. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  114. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  115. package/dist/summary/summarizerTypes.d.ts +2 -3
  116. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  117. package/dist/summary/summarizerTypes.js.map +1 -1
  118. package/dist/summary/summaryCollection.d.ts +1 -1
  119. package/dist/summary/summaryCollection.d.ts.map +1 -1
  120. package/dist/summary/summaryCollection.js.map +1 -1
  121. package/dist/summary/summaryGenerator.d.ts +1 -2
  122. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  123. package/dist/summary/summaryGenerator.js +3 -2
  124. package/dist/summary/summaryGenerator.js.map +1 -1
  125. package/dist/summary/summaryManager.d.ts.map +1 -1
  126. package/dist/summary/summaryManager.js.map +1 -1
  127. package/{dist/beta.d.ts → internal.d.ts} +2 -0
  128. package/{lib/beta.d.ts → legacy.d.ts} +2 -0
  129. package/lib/batchTracker.d.ts +1 -1
  130. package/lib/batchTracker.d.ts.map +1 -1
  131. package/lib/batchTracker.js.map +1 -1
  132. package/lib/channelCollection.d.ts +5 -3
  133. package/lib/channelCollection.d.ts.map +1 -1
  134. package/lib/channelCollection.js +69 -17
  135. package/lib/channelCollection.js.map +1 -1
  136. package/lib/connectionTelemetry.d.ts +1 -1
  137. package/lib/connectionTelemetry.d.ts.map +1 -1
  138. package/lib/connectionTelemetry.js +49 -0
  139. package/lib/connectionTelemetry.js.map +1 -1
  140. package/lib/containerRuntime.d.ts +17 -27
  141. package/lib/containerRuntime.d.ts.map +1 -1
  142. package/lib/containerRuntime.js +174 -143
  143. package/lib/containerRuntime.js.map +1 -1
  144. package/lib/dataStore.d.ts +1 -1
  145. package/lib/dataStore.d.ts.map +1 -1
  146. package/lib/dataStore.js +1 -1
  147. package/lib/dataStore.js.map +1 -1
  148. package/lib/dataStoreContext.d.ts.map +1 -1
  149. package/lib/dataStoreContext.js +1 -0
  150. package/lib/dataStoreContext.js.map +1 -1
  151. package/lib/dataStoreContexts.d.ts +2 -0
  152. package/lib/dataStoreContexts.d.ts.map +1 -1
  153. package/lib/dataStoreContexts.js +7 -0
  154. package/lib/dataStoreContexts.js.map +1 -1
  155. package/lib/deltaManagerSummarizerProxy.d.ts +18 -6
  156. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  157. package/lib/deltaManagerSummarizerProxy.js +36 -18
  158. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  159. package/lib/deltaScheduler.d.ts +1 -1
  160. package/lib/deltaScheduler.d.ts.map +1 -1
  161. package/lib/deltaScheduler.js.map +1 -1
  162. package/lib/gc/garbageCollection.d.ts +5 -12
  163. package/lib/gc/garbageCollection.d.ts.map +1 -1
  164. package/lib/gc/garbageCollection.js +47 -31
  165. package/lib/gc/garbageCollection.js.map +1 -1
  166. package/lib/gc/gcDefinitions.d.ts +27 -6
  167. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  168. package/lib/gc/gcDefinitions.js.map +1 -1
  169. package/lib/gc/gcHelpers.d.ts +5 -4
  170. package/lib/gc/gcHelpers.d.ts.map +1 -1
  171. package/lib/gc/gcHelpers.js +12 -1
  172. package/lib/gc/gcHelpers.js.map +1 -1
  173. package/lib/gc/gcTelemetry.d.ts +14 -4
  174. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  175. package/lib/gc/gcTelemetry.js +24 -21
  176. package/lib/gc/gcTelemetry.js.map +1 -1
  177. package/lib/gc/index.d.ts +2 -2
  178. package/lib/gc/index.d.ts.map +1 -1
  179. package/lib/gc/index.js +1 -1
  180. package/lib/gc/index.js.map +1 -1
  181. package/lib/index.d.ts +2 -2
  182. package/lib/index.d.ts.map +1 -1
  183. package/lib/index.js +1 -1
  184. package/lib/index.js.map +1 -1
  185. package/lib/{alpha.d.ts → legacy.d.ts} +3 -1
  186. package/lib/metadata.d.ts +2 -2
  187. package/lib/metadata.d.ts.map +1 -1
  188. package/lib/metadata.js.map +1 -1
  189. package/lib/opLifecycle/batchManager.d.ts +0 -1
  190. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  191. package/lib/opLifecycle/batchManager.js +0 -10
  192. package/lib/opLifecycle/batchManager.js.map +1 -1
  193. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  194. package/lib/opLifecycle/opDecompressor.js +6 -6
  195. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  196. package/lib/opLifecycle/opGroupingManager.js +2 -2
  197. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  198. package/lib/opLifecycle/opSplitter.js +1 -1
  199. package/lib/opLifecycle/opSplitter.js.map +1 -1
  200. package/lib/opLifecycle/outbox.d.ts +0 -4
  201. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  202. package/lib/opLifecycle/outbox.js +2 -34
  203. package/lib/opLifecycle/outbox.js.map +1 -1
  204. package/lib/packageVersion.d.ts +1 -1
  205. package/lib/packageVersion.js +1 -1
  206. package/lib/packageVersion.js.map +1 -1
  207. package/lib/pendingStateManager.d.ts +3 -2
  208. package/lib/pendingStateManager.d.ts.map +1 -1
  209. package/lib/pendingStateManager.js +18 -11
  210. package/lib/pendingStateManager.js.map +1 -1
  211. package/lib/public.d.ts +3 -0
  212. package/lib/scheduleManager.d.ts +1 -1
  213. package/lib/scheduleManager.d.ts.map +1 -1
  214. package/lib/scheduleManager.js.map +1 -1
  215. package/lib/summary/documentSchema.d.ts +3 -1
  216. package/lib/summary/documentSchema.d.ts.map +1 -1
  217. package/lib/summary/documentSchema.js +34 -16
  218. package/lib/summary/documentSchema.js.map +1 -1
  219. package/lib/summary/orderedClientElection.d.ts +1 -1
  220. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  221. package/lib/summary/orderedClientElection.js +1 -1
  222. package/lib/summary/orderedClientElection.js.map +1 -1
  223. package/lib/summary/summarizer.d.ts +1 -2
  224. package/lib/summary/summarizer.d.ts.map +1 -1
  225. package/lib/summary/summarizer.js.map +1 -1
  226. package/lib/summary/summarizerClientElection.d.ts +1 -1
  227. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  228. package/lib/summary/summarizerClientElection.js.map +1 -1
  229. package/lib/summary/summarizerHeuristics.d.ts +1 -1
  230. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  231. package/lib/summary/summarizerHeuristics.js.map +1 -1
  232. package/lib/summary/summarizerNode/summarizerNode.d.ts +4 -3
  233. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  234. package/lib/summary/summarizerNode/summarizerNode.js +4 -10
  235. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  236. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
  237. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  238. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  239. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
  240. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  241. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +2 -9
  242. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  243. package/lib/summary/summarizerTypes.d.ts +2 -3
  244. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  245. package/lib/summary/summarizerTypes.js.map +1 -1
  246. package/lib/summary/summaryCollection.d.ts +1 -1
  247. package/lib/summary/summaryCollection.d.ts.map +1 -1
  248. package/lib/summary/summaryCollection.js.map +1 -1
  249. package/lib/summary/summaryGenerator.d.ts +1 -2
  250. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  251. package/lib/summary/summaryGenerator.js +4 -3
  252. package/lib/summary/summaryGenerator.js.map +1 -1
  253. package/lib/summary/summaryManager.d.ts.map +1 -1
  254. package/lib/summary/summaryManager.js +1 -1
  255. package/lib/summary/summaryManager.js.map +1 -1
  256. package/package.json +33 -57
  257. package/src/batchTracker.ts +1 -2
  258. package/src/channelCollection.ts +87 -35
  259. package/src/connectionTelemetry.ts +58 -3
  260. package/src/containerRuntime.ts +214 -222
  261. package/src/dataStore.ts +5 -2
  262. package/src/dataStoreContext.ts +1 -0
  263. package/src/dataStoreContexts.ts +13 -2
  264. package/src/deltaManagerSummarizerProxy.ts +43 -21
  265. package/src/deltaScheduler.ts +1 -2
  266. package/src/gc/garbageCollection.ts +64 -42
  267. package/src/gc/gcDefinitions.ts +22 -10
  268. package/src/gc/gcHelpers.ts +14 -1
  269. package/src/gc/gcTelemetry.ts +57 -50
  270. package/src/gc/index.ts +2 -1
  271. package/src/index.ts +2 -0
  272. package/src/metadata.ts +2 -2
  273. package/src/opLifecycle/README.md +4 -4
  274. package/src/opLifecycle/batchManager.ts +0 -14
  275. package/src/opLifecycle/opDecompressor.ts +12 -6
  276. package/src/opLifecycle/opGroupingManager.ts +2 -2
  277. package/src/opLifecycle/opSplitter.ts +1 -1
  278. package/src/opLifecycle/outbox.ts +2 -49
  279. package/src/packageVersion.ts +1 -1
  280. package/src/pendingStateManager.ts +28 -15
  281. package/src/scheduleManager.ts +1 -1
  282. package/src/summary/documentSchema.ts +52 -18
  283. package/src/summary/orderedClientElection.ts +5 -2
  284. package/src/summary/summarizer.ts +1 -1
  285. package/src/summary/summarizerClientElection.ts +1 -1
  286. package/src/summary/summarizerHeuristics.ts +1 -1
  287. package/src/summary/summarizerNode/summarizerNode.ts +3 -12
  288. package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -3
  289. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -10
  290. package/src/summary/summarizerTypes.ts +5 -3
  291. package/src/summary/summaryCollection.ts +1 -1
  292. package/src/summary/summaryGenerator.ts +19 -8
  293. package/src/summary/summaryManager.ts +5 -2
@@ -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");
@@ -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 = false, 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
  }
@@ -366,7 +378,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
366
378
  compressionOptions.minimumBatchSizeInBytes !== Infinity &&
367
379
  compressionOptions.compressionAlgorithm === "lz4";
368
380
  const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
369
- const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, metadata?.documentSchema, {
381
+ const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
370
382
  explicitSchemaControl,
371
383
  compressionLz4,
372
384
  idCompressorMode,
@@ -389,7 +401,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
389
401
  chunkSizeInBytes,
390
402
  // Requires<> drops undefined from IdCompressorType
391
403
  enableRuntimeIdCompressor: enableRuntimeIdCompressor,
392
- enableOpReentryCheck,
393
404
  enableGroupedBatching,
394
405
  explicitSchemaControl,
395
406
  }, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, undefined);
@@ -428,11 +439,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
428
439
  get attachState() {
429
440
  return this._getAttachState();
430
441
  }
431
- get documentSchema() {
442
+ /**
443
+ * Current session schema - defines what options are on & off.
444
+ * It's overlap of document schema (controlled by summary & ops) and options controlling this session.
445
+ * For example, document schema might have compression ON, but feature gates / runtime options turn it Off.
446
+ * In such case it will be off in session schema (i.e. this session should not use compression), but this client
447
+ * has to deal with compressed ops as other clients might send them.
448
+ * And in reverse, session schema can have compression Off, but feature gates / runtime options want it On.
449
+ * In such case it will be off in session schema, however this client will propose change to schema, and once / if
450
+ * this op rountrips, compression will be On. Client can't send compressed ops until it's change in schema.
451
+ */
452
+ get sessionSchema() {
432
453
  return this.documentsSchemaController.sessionSchema.runtime;
433
454
  }
434
455
  get idCompressorMode() {
435
- return this.documentSchema.idCompressorMode;
456
+ return this.sessionSchema.idCompressorMode;
436
457
  }
437
458
  /**
438
459
  * See IContainerRuntimeBase.idCompressor() for details.
@@ -540,13 +561,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
540
561
  this.flushTaskExists = false;
541
562
  this.consecutiveReconnects = 0;
542
563
  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
564
  this._disposed = false;
551
565
  this.emitDirtyDocumentEvent = true;
552
566
  this.defaultTelemetrySignalSampleCount = 100;
@@ -573,7 +587,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
573
587
  // 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
588
  // compression.
575
589
  const compressionOptions = {
576
- minimumBatchSizeInBytes: this.documentSchema.compressionLz4
590
+ minimumBatchSizeInBytes: this.sessionSchema.compressionLz4
577
591
  ? runtimeOptions.compressionOptions.minimumBatchSizeInBytes
578
592
  : Number.POSITIVE_INFINITY,
579
593
  compressionAlgorithm: CompressionAlgorithms.lz4,
@@ -657,11 +671,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
657
671
  if (this.summaryConfiguration.state === "enabled") {
658
672
  this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
659
673
  }
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
674
  this.summariesDisabled = this.isSummariesDisabled();
666
675
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
667
676
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
@@ -733,7 +742,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
733
742
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
734
743
  return this.submitSignalFn(envelope2, targetClientId);
735
744
  };
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);
745
+ 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);
737
746
  this.blobManager = new blobManager_js_1.BlobManager({
738
747
  routeContext: this.handleContext,
739
748
  snapshot: blobManagerSnapshot,
@@ -746,7 +755,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
746
755
  });
747
756
  }
748
757
  },
749
- blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
758
+ blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
759
+ node: { type: "Blob", path: blobPath },
760
+ reason: "Loaded",
761
+ }),
750
762
  isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
751
763
  runtime: this,
752
764
  stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
@@ -794,12 +806,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
794
806
  this._quorum.on("removeMember", (clientId) => {
795
807
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
796
808
  });
797
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
798
809
  this._audience = audience;
810
+ if (audience.getSelf === undefined) {
811
+ // back-compat, added in 2.0 RC3.
812
+ // Purpose: deal with cases when we run against old loader that does not have newly added capabilities
813
+ audience.getSelf = () => {
814
+ const clientId = this._getClientId();
815
+ return clientId === undefined
816
+ ? undefined
817
+ : ({
818
+ clientId,
819
+ client: audience.getMember(clientId),
820
+ });
821
+ };
822
+ let oldClientId = this.clientId;
823
+ this.on("connected", () => {
824
+ const clientId = this.clientId;
825
+ (0, internal_2.assert)(clientId !== undefined, "can't be undefined");
826
+ audience.emit("selfChanged", { clientId: oldClientId }, { clientId, client: audience.getMember(clientId) });
827
+ oldClientId = clientId;
828
+ });
829
+ }
799
830
  const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
800
831
  this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
801
- this.validateSummaryBeforeUpload =
802
- this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
803
832
  this.summaryCollection = new index_js_3.SummaryCollection(this.deltaManager, this.logger);
804
833
  this.dirtyContainer =
805
834
  this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
@@ -872,9 +901,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
872
901
  options: JSON.stringify(runtimeOptions),
873
902
  idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
874
903
  idCompressorMode: this.idCompressorMode,
904
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
875
905
  featureGates: JSON.stringify({
876
906
  ...featureGatesForTelemetry,
877
- disableOpReentryCheck,
878
907
  disableChunking,
879
908
  disableAttachReorder: this.disableAttachReorder,
880
909
  disablePartialFlush,
@@ -882,6 +911,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
882
911
  }),
883
912
  telemetryDocumentId: this.telemetryDocumentId,
884
913
  groupedBatchingEnabled: this.groupedBatchingEnabled,
914
+ initialSequenceNumber: this.deltaManager.initialSequenceNumber,
885
915
  });
886
916
  (0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
887
917
  (0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
@@ -897,6 +927,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
897
927
  this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
898
928
  }
899
929
  onSchemaChange(schema) {
930
+ this.logger.sendTelemetryEvent({
931
+ eventName: "SchemaChangeAccept",
932
+ sessionRuntimeSchema: JSON.stringify(schema),
933
+ });
900
934
  // Most of the settings will be picked up only by new sessions (i.e. after reload).
901
935
  // We can make it better in the future (i.e. start to use op compression right away), but for simplicity
902
936
  // this is not done.
@@ -929,9 +963,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
929
963
  async initializeBaseState() {
930
964
  if (this.idCompressorMode === "on" ||
931
965
  (this.idCompressorMode === "delayed" && this.connected)) {
966
+ this._idCompressor = await this.createIdCompressor();
932
967
  // This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
933
968
  (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
934
- this._idCompressor = await this.createIdCompressor();
935
969
  }
936
970
  await this.garbageCollector.initializeBaseState();
937
971
  }
@@ -1309,12 +1343,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1309
1343
  this._loadIdCompressor === undefined) {
1310
1344
  this._loadIdCompressor = this.createIdCompressor()
1311
1345
  .then((compressor) => {
1312
- this._idCompressor = compressor;
1313
1346
  // Finalize any ranges we received while the compressor was turned off.
1314
- for (const range of this.pendingIdCompressorOps) {
1315
- this._idCompressor.finalizeCreationRange(range);
1316
- }
1347
+ const ops = this.pendingIdCompressorOps;
1317
1348
  this.pendingIdCompressorOps = [];
1349
+ for (const range of ops) {
1350
+ compressor.finalizeCreationRange(range);
1351
+ }
1352
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, "No new ops added");
1353
+ this._idCompressor = compressor;
1318
1354
  })
1319
1355
  .catch((error) => {
1320
1356
  this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
@@ -1324,6 +1360,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1324
1360
  return this._loadIdCompressor;
1325
1361
  }
1326
1362
  setConnectionState(connected, clientId) {
1363
+ // Validate we have consistent state
1364
+ const currentClientId = this._audience.getSelf()?.clientId;
1365
+ (0, internal_2.assert)(clientId === currentClientId, "input clientId does not match Audience");
1366
+ (0, internal_2.assert)(this.clientId === currentClientId, "this.clientId does not match Audience");
1327
1367
  if (connected && this.idCompressorMode === "delayed") {
1328
1368
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
1329
1369
  this.loadIdCompressor();
@@ -1405,9 +1445,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1405
1445
  // We do not need to make a deep copy. Each layer will just replace message.contents itself,
1406
1446
  // but will not modify the contents object (likely it will replace it on the message).
1407
1447
  const messageCopy = { ...messageArg };
1448
+ const savedOp = messageCopy.metadata?.savedOp;
1408
1449
  for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1409
- if (modernRuntimeMessage) {
1410
- this.processCore({
1450
+ const msg = modernRuntimeMessage
1451
+ ? {
1411
1452
  // Cast it since we expect it to be this based on modernRuntimeMessage computation above.
1412
1453
  // There is nothing really ensuring that anytime original message.type is Operation that
1413
1454
  // the result messages will be so. In the end modern bool being true only directs to
@@ -1415,12 +1456,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1415
1456
  message: message,
1416
1457
  local,
1417
1458
  modernRuntimeMessage,
1418
- });
1419
- }
1420
- else {
1421
- // Unrecognized message will be ignored.
1422
- this.processCore({ message, local, modernRuntimeMessage });
1423
- }
1459
+ }
1460
+ : // Unrecognized message will be ignored.
1461
+ {
1462
+ message,
1463
+ local,
1464
+ modernRuntimeMessage,
1465
+ };
1466
+ msg.savedOp = savedOp;
1467
+ // ensure that we observe any re-entrancy, and if needed, rebase ops
1468
+ this.ensureNoDataModelChanges(() => this.processCore(msg));
1424
1469
  }
1425
1470
  }
1426
1471
  /**
@@ -1438,7 +1483,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1438
1483
  // These calls should be made for all but chunked ops:
1439
1484
  // 1) this.pendingStateManager.processPendingLocalMessage() below
1440
1485
  // 2) this.resetReconnectCount() below
1441
- (0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, "we should never get here with chunked ops");
1486
+ (0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, 0x93b /* we should never get here with chunked ops */);
1442
1487
  let localOpMetadata;
1443
1488
  if (local && messageWithContext.modernRuntimeMessage) {
1444
1489
  localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
@@ -1485,17 +1530,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1485
1530
  // stashed ops flow. The compressor is stashed with these ops already processed.
1486
1531
  // That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
1487
1532
  // thus we need to process all the ops.
1488
- if (!(this.skipSavedCompressorOps &&
1489
- messageWithContext.message.metadata?.savedOp ===
1490
- true)) {
1533
+ if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
1491
1534
  const range = messageWithContext.message.contents;
1492
1535
  // Some other client turned on the id compressor. If we have not turned it on,
1493
1536
  // put it in a pending queue and delay finalization.
1494
1537
  if (this._idCompressor === undefined) {
1495
- (0, internal_2.assert)(this.idCompressorMode !== undefined, "id compressor should be enabled");
1538
+ (0, internal_2.assert)(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
1496
1539
  this.pendingIdCompressorOps.push(range);
1497
1540
  }
1498
1541
  else {
1542
+ (0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, "there should be no pending ops!");
1499
1543
  this._idCompressor.finalizeCreationRange(range);
1500
1544
  }
1501
1545
  }
@@ -1506,7 +1550,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1506
1550
  case messageTypes_js_1.ContainerMessageType.ChunkedOp:
1507
1551
  // From observability POV, we should not exppse the rest of the system (including "op" events on object) to these messages.
1508
1552
  // 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");
1553
+ (0, internal_2.assert)(false, 0x93d /* should not even get here */);
1510
1554
  case messageTypes_js_1.ContainerMessageType.Rejoin:
1511
1555
  break;
1512
1556
  case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
@@ -1616,9 +1660,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1616
1660
  let checkpoint;
1617
1661
  let result;
1618
1662
  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.
1663
+ // Note: we are not touching any batches other than mainBatch here, for two reasons:
1664
+ // 1. It would not help, as other batches are flushed independently from main batch.
1665
+ // 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
1666
  checkpoint = this.outbox.checkpoint().mainBatch;
1623
1667
  }
1624
1668
  try {
@@ -1681,7 +1725,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1681
1725
  if (channel.entryPoint === undefined) {
1682
1726
  throw new internal_7.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
1683
1727
  }
1684
- this.garbageCollector.nodeUpdated(`/${internalId}`, "Loaded", undefined /* timestampMs */, context.packagePath);
1728
+ this.garbageCollector.nodeUpdated({
1729
+ node: { type: "DataStore", path: `/${internalId}` },
1730
+ reason: "Loaded",
1731
+ packagePath: context.packagePath,
1732
+ });
1685
1733
  return channel.entryPoint;
1686
1734
  }
1687
1735
  createDetachedDataStore(pkg, loadingGroupId) {
@@ -1805,7 +1853,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
1805
1853
  // We can finalize any allocated IDs since we're the only client
1806
1854
  const idRange = this._idCompressor?.takeNextCreationRange();
1807
1855
  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.");
1856
+ (0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1, 0x93e /* No other ranges should be taken while container is detached. */);
1809
1857
  this._idCompressor?.finalizeCreationRange(idRange);
1810
1858
  }
1811
1859
  const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
@@ -2015,10 +2063,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2015
2063
  // The summary number for this summary. This will be updated during the summary process, so get it now and
2016
2064
  // use it for all events logged during this summary.
2017
2065
  const summaryNumber = this.nextSummaryNumber;
2066
+ let summaryRefSeqNum;
2018
2067
  const summaryNumberLogger = (0, internal_7.createChildLogger)({
2019
2068
  logger: summaryLogger,
2020
2069
  properties: {
2021
- all: { summaryNumber },
2070
+ all: {
2071
+ summaryNumber,
2072
+ referenceSequenceNumber: () => summaryRefSeqNum,
2073
+ },
2022
2074
  },
2023
2075
  });
2024
2076
  (0, internal_2.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
@@ -2032,7 +2084,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2032
2084
  // If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
2033
2085
  // and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
2034
2086
  // saved within the timeout, check if it should be failed or can continue.
2035
- if (this.validateSummaryBeforeUpload && this.isDirty) {
2087
+ if (this.isDirty) {
2036
2088
  const countBefore = this.pendingMessagesCount;
2037
2089
  // The timeout for waiting for pending ops can be overridden via configurations.
2038
2090
  const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
@@ -2065,7 +2117,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2065
2117
  }
2066
2118
  const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
2067
2119
  const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
2068
- let summaryRefSeqNum;
2069
2120
  try {
2070
2121
  await this.deltaManager.inbound.pause();
2071
2122
  if (shouldPauseInboundSignal) {
@@ -2076,9 +2127,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2076
2127
  const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
2077
2128
  const lastAck = this.summaryCollection.latestAck;
2078
2129
  const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
2130
+ /**
2131
+ * This was added to validate that the summarizer node tree has the same reference sequence number from the
2132
+ * top running summarizer down to the lowest summarizer node.
2133
+ *
2134
+ * The order of mismatch numbers goes (validate sequence number)-(node sequence number).
2135
+ * Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
2136
+ * summarizer nodes.
2137
+ */
2079
2138
  if (startSummaryResult.invalidNodes > 0 ||
2080
2139
  startSummaryResult.mismatchNumbers.size > 0) {
2081
- summaryLogger.sendErrorEvent({
2140
+ summaryLogger.sendTelemetryEvent({
2082
2141
  eventName: "LatestSummaryRefSeqNumMismatch",
2083
2142
  details: {
2084
2143
  ...startSummaryResult,
@@ -2090,7 +2149,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2090
2149
  stage: "base",
2091
2150
  referenceSequenceNumber: summaryRefSeqNum,
2092
2151
  minimumSequenceNumber,
2093
- error: `Summarizer node state inconsistent with summarizer state.`,
2152
+ error: new internal_7.LoggingError(`Summarizer node state inconsistent with summarizer state.`),
2094
2153
  };
2095
2154
  }
2096
2155
  }
@@ -2133,7 +2192,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2133
2192
  stage: "base",
2134
2193
  referenceSequenceNumber: summaryRefSeqNum,
2135
2194
  minimumSequenceNumber,
2136
- error: continueResult.error,
2195
+ error: new internal_7.LoggingError(continueResult.error),
2137
2196
  };
2138
2197
  }
2139
2198
  const trace = client_utils_1.Trace.start();
@@ -2150,6 +2209,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2150
2209
  });
2151
2210
  }
2152
2211
  catch (error) {
2212
+ return {
2213
+ stage: "base",
2214
+ referenceSequenceNumber: summaryRefSeqNum,
2215
+ minimumSequenceNumber,
2216
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2217
+ };
2218
+ }
2219
+ // Validate that the summary generated by summarizer nodes is correct before uploading.
2220
+ const validateResult = this.summarizerNode.validateSummary();
2221
+ if (!validateResult.success) {
2222
+ const { success, ...loggingProps } = validateResult;
2223
+ const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
2153
2224
  return {
2154
2225
  stage: "base",
2155
2226
  referenceSequenceNumber: summaryRefSeqNum,
@@ -2157,24 +2228,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2157
2228
  error,
2158
2229
  };
2159
2230
  }
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
- }
2231
+ // If there are pending unacked ops, this summary attempt may fail as the uploaded
2232
+ // summary would be eventually inconsistent.
2233
+ const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
2234
+ if (pendingMessagesFailResult !== undefined) {
2235
+ return pendingMessagesFailResult;
2178
2236
  }
2179
2237
  const { summary: summaryTree, stats: partialStats } = summarizeResult;
2180
2238
  // Now that we have generated the summary, update the message at last summary to the last message processed.
@@ -2207,7 +2265,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2207
2265
  };
2208
2266
  continueResult = checkContinue();
2209
2267
  if (!continueResult.continue) {
2210
- return { stage: "generate", ...generateSummaryData, error: continueResult.error };
2268
+ return {
2269
+ stage: "generate",
2270
+ ...generateSummaryData,
2271
+ error: new internal_7.LoggingError(continueResult.error),
2272
+ };
2211
2273
  }
2212
2274
  const summaryContext = lastAck === undefined
2213
2275
  ? {
@@ -2225,7 +2287,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2225
2287
  handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
2226
2288
  }
2227
2289
  catch (error) {
2228
- return { stage: "generate", ...generateSummaryData, error };
2290
+ return {
2291
+ stage: "generate",
2292
+ ...generateSummaryData,
2293
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2294
+ };
2229
2295
  }
2230
2296
  const parent = summaryContext.ackHandle;
2231
2297
  const summaryMessage = {
@@ -2242,14 +2308,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2242
2308
  };
2243
2309
  continueResult = checkContinue();
2244
2310
  if (!continueResult.continue) {
2245
- return { stage: "upload", ...uploadData, error: continueResult.error };
2311
+ return {
2312
+ stage: "upload",
2313
+ ...uploadData,
2314
+ error: new internal_7.LoggingError(continueResult.error),
2315
+ };
2246
2316
  }
2247
2317
  let clientSequenceNumber;
2248
2318
  try {
2249
2319
  clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
2250
2320
  }
2251
2321
  catch (error) {
2252
- return { stage: "upload", ...uploadData, error };
2322
+ return {
2323
+ stage: "upload",
2324
+ ...uploadData,
2325
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2326
+ };
2253
2327
  }
2254
2328
  const submitData = {
2255
2329
  stage: "submit",
@@ -2258,11 +2332,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2258
2332
  submitOpDuration: trace.trace().duration,
2259
2333
  };
2260
2334
  try {
2261
- // If validateSummaryBeforeUpload is false, the summary should be validated in this step.
2262
- this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
2335
+ this.summarizerNode.completeSummary(handle);
2263
2336
  }
2264
2337
  catch (error) {
2265
- return { stage: "upload", ...uploadData, error };
2338
+ return {
2339
+ stage: "upload",
2340
+ ...uploadData,
2341
+ error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
2342
+ };
2266
2343
  }
2267
2344
  return submitData;
2268
2345
  }
@@ -2370,11 +2447,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2370
2447
  }
2371
2448
  submit(containerRuntimeMessage, localOpMetadata = undefined, metadata) {
2372
2449
  this.verifyNotClosed();
2373
- this.verifyCanSubmitOps();
2374
2450
  // There should be no ops in detached container state!
2375
2451
  (0, internal_2.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
2376
2452
  (0, internal_2.assert)(metadata === undefined ||
2377
- containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, "metadata");
2453
+ containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, 0x93f /* metadata */);
2378
2454
  const serializedContent = JSON.stringify(containerRuntimeMessage);
2379
2455
  // Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
2380
2456
  // container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
@@ -2406,6 +2482,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2406
2482
  // on this callback to do actual sending.
2407
2483
  const contents = this.documentsSchemaController.maybeSendSchemaMessage();
2408
2484
  if (contents) {
2485
+ this.logger.sendTelemetryEvent({
2486
+ eventName: "SchemaChangeProposal",
2487
+ refSeq: contents.refSeq,
2488
+ version: contents.version,
2489
+ newRuntimeSchema: JSON.stringify(contents.runtime),
2490
+ sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
2491
+ oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
2492
+ });
2409
2493
  const msg = {
2410
2494
  type: messageTypes_js_1.ContainerMessageType.DocumentSchemaChange,
2411
2495
  contents,
@@ -2415,32 +2499,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2415
2499
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2416
2500
  });
2417
2501
  }
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) {
2502
+ if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
2444
2503
  // BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
2445
2504
  this.outbox.submitBlobAttach(message);
2446
2505
  }
@@ -2515,32 +2574,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2515
2574
  throw new Error("Runtime is closed");
2516
2575
  }
2517
2576
  }
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
2577
  reSubmitBatch(batch) {
2545
2578
  this.orderSequentially(() => {
2546
2579
  for (const message of batch) {
@@ -2670,7 +2703,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2670
2703
  await this.closeStaleSummarizer();
2671
2704
  return {
2672
2705
  stage: "base",
2673
- error: "summary state stale - Unsupported option 'refreshLatestAck'",
2706
+ error: new internal_7.LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
2674
2707
  referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2675
2708
  minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
2676
2709
  };
@@ -2714,16 +2747,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2714
2747
  }
2715
2748
  this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
2716
2749
  const getSyncState = (pendingAttachmentBlobs) => {
2717
- const pending = this.pendingStateManager.getLocalState();
2718
- if (pendingAttachmentBlobs === undefined && !this.hasPendingMessages()) {
2719
- return; // no pending state to save
2720
- }
2750
+ const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
2751
+ const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
2721
2752
  const pendingIdCompressorState = this._idCompressor?.serialize(true);
2722
2753
  return {
2723
2754
  pending,
2724
2755
  pendingIdCompressorState,
2725
2756
  pendingAttachmentBlobs,
2726
- sessionExpiryTimerStarted: this.garbageCollector.sessionExpiryTimerStarted,
2757
+ sessionExpiryTimerStarted,
2727
2758
  };
2728
2759
  };
2729
2760
  const perfEvent = {
@@ -2793,7 +2824,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
2793
2824
  }
2794
2825
  }
2795
2826
  get groupedBatchingEnabled() {
2796
- return this.documentSchema.opGroupingEnabled === true;
2827
+ return this.sessionSchema.opGroupingEnabled === true;
2797
2828
  }
2798
2829
  }
2799
2830
  exports.ContainerRuntime = ContainerRuntime;