@fluidframework/container-runtime 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531

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 (314) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +69 -0
  3. package/dist/blobManager.d.ts +6 -14
  4. package/dist/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager.js +50 -37
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +47 -4
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +203 -49
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +2 -1
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js +3 -0
  14. package/dist/dataStoreContext.js.map +1 -1
  15. package/dist/dataStores.d.ts +5 -5
  16. package/dist/dataStores.d.ts.map +1 -1
  17. package/dist/dataStores.js +3 -6
  18. package/dist/dataStores.js.map +1 -1
  19. package/dist/gc/garbageCollection.d.ts.map +1 -1
  20. package/dist/gc/garbageCollection.js +5 -5
  21. package/dist/gc/garbageCollection.js.map +1 -1
  22. package/dist/gc/gcConfigs.d.ts.map +1 -1
  23. package/dist/gc/gcConfigs.js +1 -3
  24. package/dist/gc/gcConfigs.js.map +1 -1
  25. package/dist/gc/gcDefinitions.js +1 -1
  26. package/dist/gc/gcDefinitions.js.map +1 -1
  27. package/dist/gc/gcHelpers.d.ts.map +1 -1
  28. package/dist/gc/gcHelpers.js +6 -6
  29. package/dist/gc/gcHelpers.js.map +1 -1
  30. package/dist/id-compressor/appendOnlySortedMap.d.ts +146 -0
  31. package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
  32. package/dist/id-compressor/appendOnlySortedMap.js +360 -0
  33. package/dist/id-compressor/appendOnlySortedMap.js.map +1 -0
  34. package/dist/id-compressor/idCompressor.d.ts +279 -0
  35. package/dist/id-compressor/idCompressor.d.ts.map +1 -0
  36. package/dist/id-compressor/idCompressor.js +1258 -0
  37. package/dist/id-compressor/idCompressor.js.map +1 -0
  38. package/dist/id-compressor/idRange.d.ts +11 -0
  39. package/dist/id-compressor/idRange.d.ts.map +1 -0
  40. package/dist/id-compressor/idRange.js +29 -0
  41. package/dist/id-compressor/idRange.js.map +1 -0
  42. package/dist/id-compressor/index.d.ts +14 -0
  43. package/dist/id-compressor/index.d.ts.map +1 -0
  44. package/dist/id-compressor/index.js +38 -0
  45. package/dist/id-compressor/index.js.map +1 -0
  46. package/dist/id-compressor/numericUuid.d.ts +59 -0
  47. package/dist/id-compressor/numericUuid.d.ts.map +1 -0
  48. package/dist/id-compressor/numericUuid.js +325 -0
  49. package/dist/id-compressor/numericUuid.js.map +1 -0
  50. package/dist/id-compressor/sessionIdNormalizer.d.ts +138 -0
  51. package/dist/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
  52. package/dist/id-compressor/sessionIdNormalizer.js +488 -0
  53. package/dist/id-compressor/sessionIdNormalizer.js.map +1 -0
  54. package/dist/id-compressor/utils.d.ts +57 -0
  55. package/dist/id-compressor/utils.d.ts.map +1 -0
  56. package/dist/id-compressor/utils.js +90 -0
  57. package/dist/id-compressor/utils.js.map +1 -0
  58. package/dist/id-compressor/uuidUtilities.d.ts +30 -0
  59. package/dist/id-compressor/uuidUtilities.d.ts.map +1 -0
  60. package/dist/id-compressor/uuidUtilities.js +106 -0
  61. package/dist/id-compressor/uuidUtilities.js.map +1 -0
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +5 -1
  65. package/dist/index.js.map +1 -1
  66. package/dist/opLifecycle/batchManager.d.ts +9 -2
  67. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  68. package/dist/opLifecycle/batchManager.js +21 -2
  69. package/dist/opLifecycle/batchManager.js.map +1 -1
  70. package/dist/opLifecycle/index.d.ts +2 -1
  71. package/dist/opLifecycle/index.d.ts.map +1 -1
  72. package/dist/opLifecycle/index.js +3 -1
  73. package/dist/opLifecycle/index.js.map +1 -1
  74. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  75. package/dist/opLifecycle/opDecompressor.js +2 -1
  76. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  77. package/dist/opLifecycle/opGroupingManager.d.ts +14 -0
  78. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
  79. package/dist/opLifecycle/opGroupingManager.js +61 -0
  80. package/dist/opLifecycle/opGroupingManager.js.map +1 -0
  81. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  82. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  83. package/dist/opLifecycle/opSplitter.js +5 -6
  84. package/dist/opLifecycle/opSplitter.js.map +1 -1
  85. package/dist/opLifecycle/outbox.d.ts +4 -2
  86. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  87. package/dist/opLifecycle/outbox.js +37 -25
  88. package/dist/opLifecycle/outbox.js.map +1 -1
  89. package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  90. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  91. package/dist/opLifecycle/remoteMessageProcessor.js +30 -20
  92. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  93. package/dist/packageVersion.d.ts +1 -1
  94. package/dist/packageVersion.js +1 -1
  95. package/dist/packageVersion.js.map +1 -1
  96. package/dist/pendingStateManager.d.ts +1 -1
  97. package/dist/pendingStateManager.d.ts.map +1 -1
  98. package/dist/pendingStateManager.js +11 -3
  99. package/dist/pendingStateManager.js.map +1 -1
  100. package/dist/summary/index.d.ts +2 -2
  101. package/dist/summary/index.d.ts.map +1 -1
  102. package/dist/summary/index.js +4 -1
  103. package/dist/summary/index.js.map +1 -1
  104. package/dist/summary/orderedClientElection.d.ts +1 -0
  105. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  106. package/dist/summary/orderedClientElection.js +19 -0
  107. package/dist/summary/orderedClientElection.js.map +1 -1
  108. package/dist/summary/runningSummarizer.d.ts +4 -3
  109. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  110. package/dist/summary/runningSummarizer.js +65 -66
  111. package/dist/summary/runningSummarizer.js.map +1 -1
  112. package/dist/summary/summarizer.d.ts.map +1 -1
  113. package/dist/summary/summarizer.js +1 -5
  114. package/dist/summary/summarizer.js.map +1 -1
  115. package/dist/summary/summarizerHeuristics.d.ts +1 -0
  116. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  117. package/dist/summary/summarizerHeuristics.js +3 -0
  118. package/dist/summary/summarizerHeuristics.js.map +1 -1
  119. package/dist/summary/summarizerNode/summarizerNode.js +1 -1
  120. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  121. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +128 -2
  122. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  123. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +4 -3
  124. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  125. package/dist/summary/summarizerTypes.d.ts +14 -2
  126. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  127. package/dist/summary/summarizerTypes.js.map +1 -1
  128. package/dist/summary/summaryFormat.d.ts +3 -0
  129. package/dist/summary/summaryFormat.d.ts.map +1 -1
  130. package/dist/summary/summaryFormat.js +3 -1
  131. package/dist/summary/summaryFormat.js.map +1 -1
  132. package/dist/summary/summaryGenerator.d.ts +28 -2
  133. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  134. package/dist/summary/summaryGenerator.js +19 -16
  135. package/dist/summary/summaryGenerator.js.map +1 -1
  136. package/dist/summary/summaryManager.d.ts.map +1 -1
  137. package/dist/summary/summaryManager.js +2 -0
  138. package/dist/summary/summaryManager.js.map +1 -1
  139. package/lib/blobManager.d.ts +6 -14
  140. package/lib/blobManager.d.ts.map +1 -1
  141. package/lib/blobManager.js +50 -37
  142. package/lib/blobManager.js.map +1 -1
  143. package/lib/containerRuntime.d.ts +47 -4
  144. package/lib/containerRuntime.d.ts.map +1 -1
  145. package/lib/containerRuntime.js +187 -52
  146. package/lib/containerRuntime.js.map +1 -1
  147. package/lib/dataStoreContext.d.ts +2 -1
  148. package/lib/dataStoreContext.d.ts.map +1 -1
  149. package/lib/dataStoreContext.js +3 -0
  150. package/lib/dataStoreContext.js.map +1 -1
  151. package/lib/dataStores.d.ts +5 -5
  152. package/lib/dataStores.d.ts.map +1 -1
  153. package/lib/dataStores.js +3 -6
  154. package/lib/dataStores.js.map +1 -1
  155. package/lib/gc/garbageCollection.d.ts.map +1 -1
  156. package/lib/gc/garbageCollection.js +5 -5
  157. package/lib/gc/garbageCollection.js.map +1 -1
  158. package/lib/gc/gcConfigs.d.ts.map +1 -1
  159. package/lib/gc/gcConfigs.js +1 -3
  160. package/lib/gc/gcConfigs.js.map +1 -1
  161. package/lib/gc/gcDefinitions.js +1 -1
  162. package/lib/gc/gcDefinitions.js.map +1 -1
  163. package/lib/gc/gcHelpers.d.ts.map +1 -1
  164. package/lib/gc/gcHelpers.js +6 -6
  165. package/lib/gc/gcHelpers.js.map +1 -1
  166. package/lib/id-compressor/appendOnlySortedMap.d.ts +146 -0
  167. package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -0
  168. package/lib/id-compressor/appendOnlySortedMap.js +355 -0
  169. package/lib/id-compressor/appendOnlySortedMap.js.map +1 -0
  170. package/lib/id-compressor/idCompressor.d.ts +279 -0
  171. package/lib/id-compressor/idCompressor.d.ts.map +1 -0
  172. package/lib/id-compressor/idCompressor.js +1248 -0
  173. package/lib/id-compressor/idCompressor.js.map +1 -0
  174. package/lib/id-compressor/idRange.d.ts +11 -0
  175. package/lib/id-compressor/idRange.d.ts.map +1 -0
  176. package/lib/id-compressor/idRange.js +25 -0
  177. package/lib/id-compressor/idRange.js.map +1 -0
  178. package/lib/id-compressor/index.d.ts +14 -0
  179. package/lib/id-compressor/index.d.ts.map +1 -0
  180. package/lib/id-compressor/index.js +14 -0
  181. package/lib/id-compressor/index.js.map +1 -0
  182. package/lib/id-compressor/numericUuid.d.ts +59 -0
  183. package/lib/id-compressor/numericUuid.d.ts.map +1 -0
  184. package/lib/id-compressor/numericUuid.js +315 -0
  185. package/lib/id-compressor/numericUuid.js.map +1 -0
  186. package/lib/id-compressor/sessionIdNormalizer.d.ts +138 -0
  187. package/lib/id-compressor/sessionIdNormalizer.d.ts.map +1 -0
  188. package/lib/id-compressor/sessionIdNormalizer.js +484 -0
  189. package/lib/id-compressor/sessionIdNormalizer.js.map +1 -0
  190. package/lib/id-compressor/utils.d.ts +57 -0
  191. package/lib/id-compressor/utils.d.ts.map +1 -0
  192. package/lib/id-compressor/utils.js +79 -0
  193. package/lib/id-compressor/utils.js.map +1 -0
  194. package/lib/id-compressor/uuidUtilities.d.ts +30 -0
  195. package/lib/id-compressor/uuidUtilities.d.ts.map +1 -0
  196. package/lib/id-compressor/uuidUtilities.js +98 -0
  197. package/lib/id-compressor/uuidUtilities.js.map +1 -0
  198. package/lib/index.d.ts +1 -0
  199. package/lib/index.d.ts.map +1 -1
  200. package/lib/index.js +1 -0
  201. package/lib/index.js.map +1 -1
  202. package/lib/opLifecycle/batchManager.d.ts +9 -2
  203. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  204. package/lib/opLifecycle/batchManager.js +19 -1
  205. package/lib/opLifecycle/batchManager.js.map +1 -1
  206. package/lib/opLifecycle/index.d.ts +2 -1
  207. package/lib/opLifecycle/index.d.ts.map +1 -1
  208. package/lib/opLifecycle/index.js +1 -0
  209. package/lib/opLifecycle/index.js.map +1 -1
  210. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  211. package/lib/opLifecycle/opDecompressor.js +2 -1
  212. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  213. package/lib/opLifecycle/opGroupingManager.d.ts +14 -0
  214. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
  215. package/lib/opLifecycle/opGroupingManager.js +57 -0
  216. package/lib/opLifecycle/opGroupingManager.js.map +1 -0
  217. package/lib/opLifecycle/opSplitter.d.ts +1 -1
  218. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  219. package/lib/opLifecycle/opSplitter.js +5 -6
  220. package/lib/opLifecycle/opSplitter.js.map +1 -1
  221. package/lib/opLifecycle/outbox.d.ts +4 -2
  222. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  223. package/lib/opLifecycle/outbox.js +38 -26
  224. package/lib/opLifecycle/outbox.js.map +1 -1
  225. package/lib/opLifecycle/remoteMessageProcessor.d.ts +4 -2
  226. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  227. package/lib/opLifecycle/remoteMessageProcessor.js +30 -20
  228. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  229. package/lib/packageVersion.d.ts +1 -1
  230. package/lib/packageVersion.js +1 -1
  231. package/lib/packageVersion.js.map +1 -1
  232. package/lib/pendingStateManager.d.ts +1 -1
  233. package/lib/pendingStateManager.d.ts.map +1 -1
  234. package/lib/pendingStateManager.js +11 -3
  235. package/lib/pendingStateManager.js.map +1 -1
  236. package/lib/summary/index.d.ts +2 -2
  237. package/lib/summary/index.d.ts.map +1 -1
  238. package/lib/summary/index.js +2 -1
  239. package/lib/summary/index.js.map +1 -1
  240. package/lib/summary/orderedClientElection.d.ts +1 -0
  241. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  242. package/lib/summary/orderedClientElection.js +19 -0
  243. package/lib/summary/orderedClientElection.js.map +1 -1
  244. package/lib/summary/runningSummarizer.d.ts +4 -3
  245. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  246. package/lib/summary/runningSummarizer.js +65 -66
  247. package/lib/summary/runningSummarizer.js.map +1 -1
  248. package/lib/summary/summarizer.d.ts.map +1 -1
  249. package/lib/summary/summarizer.js +1 -5
  250. package/lib/summary/summarizer.js.map +1 -1
  251. package/lib/summary/summarizerHeuristics.d.ts +1 -0
  252. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  253. package/lib/summary/summarizerHeuristics.js +3 -0
  254. package/lib/summary/summarizerHeuristics.js.map +1 -1
  255. package/lib/summary/summarizerNode/summarizerNode.js +1 -1
  256. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  257. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +128 -2
  258. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  259. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
  260. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  261. package/lib/summary/summarizerTypes.d.ts +14 -2
  262. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  263. package/lib/summary/summarizerTypes.js.map +1 -1
  264. package/lib/summary/summaryFormat.d.ts +3 -0
  265. package/lib/summary/summaryFormat.d.ts.map +1 -1
  266. package/lib/summary/summaryFormat.js +2 -0
  267. package/lib/summary/summaryFormat.js.map +1 -1
  268. package/lib/summary/summaryGenerator.d.ts +28 -2
  269. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  270. package/lib/summary/summaryGenerator.js +17 -15
  271. package/lib/summary/summaryGenerator.js.map +1 -1
  272. package/lib/summary/summaryManager.d.ts.map +1 -1
  273. package/lib/summary/summaryManager.js +2 -0
  274. package/lib/summary/summaryManager.js.map +1 -1
  275. package/package.json +29 -17
  276. package/src/blobManager.ts +64 -41
  277. package/src/containerRuntime.ts +294 -65
  278. package/src/dataStoreContext.ts +6 -0
  279. package/src/dataStores.ts +4 -7
  280. package/src/gc/garbageCollection.ts +7 -6
  281. package/src/gc/gcConfigs.ts +1 -3
  282. package/src/gc/gcDefinitions.ts +1 -1
  283. package/src/gc/gcHelpers.ts +9 -6
  284. package/src/id-compressor/README.md +3 -0
  285. package/src/id-compressor/appendOnlySortedMap.ts +427 -0
  286. package/src/id-compressor/idCompressor.ts +1854 -0
  287. package/src/id-compressor/idRange.ts +35 -0
  288. package/src/id-compressor/index.ts +35 -0
  289. package/src/id-compressor/numericUuid.ts +383 -0
  290. package/src/id-compressor/sessionIdNormalizer.ts +609 -0
  291. package/src/id-compressor/utils.ts +114 -0
  292. package/src/id-compressor/uuidUtilities.ts +123 -0
  293. package/src/index.ts +1 -0
  294. package/src/opLifecycle/README.md +119 -0
  295. package/src/opLifecycle/batchManager.ts +35 -2
  296. package/src/opLifecycle/index.ts +2 -1
  297. package/src/opLifecycle/opDecompressor.ts +1 -0
  298. package/src/opLifecycle/opGroupingManager.ts +82 -0
  299. package/src/opLifecycle/opSplitter.ts +1 -5
  300. package/src/opLifecycle/outbox.ts +64 -26
  301. package/src/opLifecycle/remoteMessageProcessor.ts +38 -22
  302. package/src/packageVersion.ts +1 -1
  303. package/src/pendingStateManager.ts +21 -7
  304. package/src/summary/index.ts +2 -1
  305. package/src/summary/orderedClientElection.ts +17 -1
  306. package/src/summary/runningSummarizer.ts +78 -77
  307. package/src/summary/summarizer.ts +0 -8
  308. package/src/summary/summarizerHeuristics.ts +4 -0
  309. package/src/summary/summarizerNode/summarizerNode.ts +1 -1
  310. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +3 -3
  311. package/src/summary/summarizerTypes.ts +20 -3
  312. package/src/summary/summaryFormat.ts +4 -0
  313. package/src/summary/summaryGenerator.ts +22 -16
  314. package/src/summary/summaryManager.ts +2 -0
@@ -31,6 +31,7 @@ import {
31
31
  } from "@fluidframework/container-runtime-definitions";
32
32
  import {
33
33
  assert,
34
+ delay,
34
35
  LazyPromise,
35
36
  Trace,
36
37
  TypedEventEmitter,
@@ -88,9 +89,14 @@ import {
88
89
  CreateChildSummarizerNodeParam,
89
90
  SummarizeInternalFn,
90
91
  channelsTreeName,
91
- IAttachMessage,
92
92
  IDataStore,
93
93
  ITelemetryContext,
94
+ SerializedIdCompressorWithNoSession,
95
+ IIdCompressor,
96
+ IIdCompressorCore,
97
+ IdCreationRange,
98
+ IdCreationRangeWithStashedState,
99
+ IAttachMessage,
94
100
  } from "@fluidframework/runtime-definitions";
95
101
  import {
96
102
  addBlobToSummary,
@@ -123,6 +129,7 @@ import {
123
129
  extractSummaryMetadataMessage,
124
130
  IContainerRuntimeMetadata,
125
131
  ICreateContainerMetadata,
132
+ idCompressorBlobName,
126
133
  IFetchSnapshotResult,
127
134
  IRootSummarizerNodeWithGC,
128
135
  ISummaryMetadataMessage,
@@ -168,6 +175,7 @@ import {
168
175
  Outbox,
169
176
  OpSplitter,
170
177
  RemoteMessageProcessor,
178
+ OpGroupingManager,
171
179
  } from "./opLifecycle";
172
180
  import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
173
181
 
@@ -189,6 +197,13 @@ export enum ContainerMessageType {
189
197
 
190
198
  // Sets the alias of a root data store
191
199
  Alias = "alias",
200
+
201
+ /**
202
+ * An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
203
+ * the last allocation op was sent.
204
+ * See the [IdCompressor README](./id-compressor/README.md) for more details.
205
+ */
206
+ IdAllocation = "idAllocation",
192
207
  }
193
208
 
194
209
  export interface ContainerRuntimeMessage {
@@ -205,7 +220,7 @@ export interface ISummaryBaseConfiguration {
205
220
  /**
206
221
  * Defines the maximum allowed time to wait for a pending summary ack.
207
222
  * The maximum amount of time client will wait for a summarize is the minimum of
208
- * maxSummarizeAckWaitTime (currently 10 * 60 * 1000) and maxAckWaitTime.
223
+ * maxSummarizeAckWaitTime (currently 3 * 60 * 1000) and maxAckWaitTime.
209
224
  */
210
225
  maxAckWaitTime: number;
211
226
  /**
@@ -301,7 +316,7 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
301
316
 
302
317
  minOpsForLastSummaryAttempt: 10,
303
318
 
304
- maxAckWaitTime: 10 * 60 * 1000, // 10 mins.
319
+ maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
305
320
 
306
321
  maxOpsSinceLastSummary: 7000,
307
322
 
@@ -392,6 +407,13 @@ export interface IContainerRuntimeOptions {
392
407
  * @experimental Not ready for use.
393
408
  */
394
409
  readonly chunkSizeInBytes?: number;
410
+
411
+ /**
412
+ * Enable the IdCompressor in the runtime.
413
+ * @experimental Not ready for use.
414
+ */
415
+ readonly enableRuntimeIdCompressor?: boolean;
416
+
395
417
  /**
396
418
  * If enabled, the runtime will block all attempts to send an op inside the
397
419
  * {@link ContainerRuntime#ensureNoDataModelChanges} callback. The callback is used by
@@ -402,6 +424,17 @@ export interface IContainerRuntimeOptions {
402
424
  * can be used to disable it at runtime.
403
425
  */
404
426
  readonly enableOpReentryCheck?: boolean;
427
+ /**
428
+ * If enabled, the runtime will group messages within a batch into a single
429
+ * message to be sent to the service.
430
+ * The grouping an ungrouping of such messages is handled by the "OpGroupingManager".
431
+ *
432
+ * By default, the feature is disabled. If enabled from options, the `Fluid.ContainerRuntime.DisableGroupedBatching`
433
+ * flag can be used to disable it at runtime.
434
+ *
435
+ * @experimental Not ready for use.
436
+ */
437
+ readonly enableGroupedBatching?: boolean;
405
438
  }
406
439
 
407
440
  /**
@@ -496,6 +529,13 @@ const defaultCompressionConfig = {
496
529
 
497
530
  const defaultChunkSizeInBytes = 204800;
498
531
 
532
+ /**
533
+ * Instead of refreshing from latest because we do not have 100% confidence in the state
534
+ * of the current system, we should close the summarizer and let it recover.
535
+ * This delay's goal is to prevent tight restart loops
536
+ */
537
+ const defaultCloseSummarizerDelayMs = 10000; // 10 seconds
538
+
499
539
  /**
500
540
  * @deprecated - use ContainerRuntimeMessage instead
501
541
  */
@@ -641,8 +681,10 @@ export class ContainerRuntime
641
681
  flushMode = defaultFlushMode,
642
682
  compressionOptions = defaultCompressionConfig,
643
683
  maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
684
+ enableRuntimeIdCompressor = false,
644
685
  chunkSizeInBytes = defaultChunkSizeInBytes,
645
686
  enableOpReentryCheck = false,
687
+ enableGroupedBatching = false,
646
688
  } = runtimeOptions;
647
689
 
648
690
  const registry = new FluidDataStoreRegistry(registryEntries);
@@ -660,12 +702,14 @@ export class ContainerRuntime
660
702
  }
661
703
  };
662
704
 
663
- const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
664
- tryFetchBlob<[string, string[]][]>(chunksBlobName),
665
- tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
666
- tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
667
- tryFetchBlob<[string, string][]>(aliasBlobName),
668
- ]);
705
+ const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] =
706
+ await Promise.all([
707
+ tryFetchBlob<[string, string[]][]>(chunksBlobName),
708
+ tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
709
+ tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
710
+ tryFetchBlob<[string, string][]>(aliasBlobName),
711
+ tryFetchBlob<SerializedIdCompressorWithNoSession>(idCompressorBlobName),
712
+ ]);
669
713
 
670
714
  const loadExisting = existing === true || context.existing === true;
671
715
 
@@ -710,6 +754,17 @@ export class ContainerRuntime
710
754
  }
711
755
  }
712
756
 
757
+ const idCompressorEnabled =
758
+ metadata?.idCompressorEnabled ?? runtimeOptions.enableRuntimeIdCompressor ?? false;
759
+ let idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
760
+ if (idCompressorEnabled) {
761
+ const { IdCompressor, createSessionId } = await import("./id-compressor");
762
+ idCompressor =
763
+ serializedIdCompressor !== undefined
764
+ ? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
765
+ : new IdCompressor(createSessionId(), logger);
766
+ }
767
+
713
768
  const runtime = new containerRuntimeCtor(
714
769
  context,
715
770
  registry,
@@ -725,13 +780,16 @@ export class ContainerRuntime
725
780
  compressionOptions,
726
781
  maxBatchSizeInBytes,
727
782
  chunkSizeInBytes,
783
+ enableRuntimeIdCompressor,
728
784
  enableOpReentryCheck,
785
+ enableGroupedBatching,
729
786
  },
730
787
  containerScope,
731
788
  logger,
732
789
  loadExisting,
733
790
  blobManagerSnapshot,
734
791
  context.storage,
792
+ idCompressor,
735
793
  requestHandler,
736
794
  undefined, // summaryConfiguration
737
795
  initializeEntryPoint,
@@ -802,6 +860,8 @@ export class ContainerRuntime
802
860
  return this.context.attachState;
803
861
  }
804
862
 
863
+ public idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
864
+
805
865
  public get IFluidHandleContext(): IFluidHandleContext {
806
866
  return this.handleContext;
807
867
  }
@@ -896,6 +956,8 @@ export class ContainerRuntime
896
956
  private emitDirtyDocumentEvent = true;
897
957
  private readonly enableOpReentryCheck: boolean;
898
958
  private readonly disableAttachReorder: boolean | undefined;
959
+ private readonly summaryStateUpdateMethod: string | undefined;
960
+ private readonly closeSummarizerDelayMs: number;
899
961
 
900
962
  private readonly defaultTelemetrySignalSampleCount = 100;
901
963
  private _perfSignalData: IPerfSignalReport = {
@@ -975,6 +1037,11 @@ export class ContainerRuntime
975
1037
  */
976
1038
  private readonly telemetryDocumentId: string;
977
1039
 
1040
+ /**
1041
+ * If true, the runtime has access to an IdCompressor
1042
+ */
1043
+ private readonly idCompressorEnabled: boolean;
1044
+
978
1045
  /**
979
1046
  * @internal
980
1047
  */
@@ -991,6 +1058,7 @@ export class ContainerRuntime
991
1058
  existing: boolean,
992
1059
  blobManagerSnapshot: IBlobManagerLoadInfo,
993
1060
  private readonly _storage: IDocumentStorageService,
1061
+ idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
994
1062
  private readonly requestHandler?: (
995
1063
  request: IRequest,
996
1064
  runtime: IContainerRuntime,
@@ -1008,6 +1076,8 @@ export class ContainerRuntime
1008
1076
  this.innerDeltaManager = context.deltaManager;
1009
1077
  this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
1010
1078
 
1079
+ this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
1080
+
1011
1081
  let loadSummaryNumber: number;
1012
1082
  // Get the container creation metadata. For new container, we initialize these. For existing containers,
1013
1083
  // get the values from the metadata blob.
@@ -1019,12 +1089,20 @@ export class ContainerRuntime
1019
1089
  // summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
1020
1090
  // the count is reset to 0.
1021
1091
  loadSummaryNumber = metadata?.summaryNumber ?? 0;
1092
+
1093
+ // Enabling the IdCompressor is a one-way operation and we only want to
1094
+ // allow new containers to turn it on
1095
+ this.idCompressorEnabled = metadata?.idCompressorEnabled ?? false;
1022
1096
  } else {
1023
1097
  this.createContainerMetadata = {
1024
1098
  createContainerRuntimeVersion: pkgVersion,
1025
1099
  createContainerTimestamp: Date.now(),
1026
1100
  };
1027
1101
  loadSummaryNumber = 0;
1102
+
1103
+ this.idCompressorEnabled =
1104
+ this.mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled") ??
1105
+ idCompressor !== undefined;
1028
1106
  }
1029
1107
  this.nextSummaryNumber = loadSummaryNumber + 1;
1030
1108
 
@@ -1037,8 +1115,6 @@ export class ContainerRuntime
1037
1115
  this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */,
1038
1116
  );
1039
1117
 
1040
- this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
1041
-
1042
1118
  this.mc.logger.sendTelemetryEvent({
1043
1119
  eventName: "GCFeatureMatrix",
1044
1120
  metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
@@ -1056,6 +1132,9 @@ export class ContainerRuntime
1056
1132
  const disableChunking = this.mc.config.getBoolean(
1057
1133
  "Fluid.ContainerRuntime.CompressionChunkingDisabled",
1058
1134
  );
1135
+
1136
+ const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
1137
+
1059
1138
  const opSplitter = new OpSplitter(
1060
1139
  chunks,
1061
1140
  this.context.submitBatchFn,
@@ -1063,9 +1142,11 @@ export class ContainerRuntime
1063
1142
  runtimeOptions.maxBatchSizeInBytes,
1064
1143
  this.mc.logger,
1065
1144
  );
1145
+
1066
1146
  this.remoteMessageProcessor = new RemoteMessageProcessor(
1067
1147
  opSplitter,
1068
1148
  new OpDecompressor(this.mc.logger),
1149
+ opGroupingManager,
1069
1150
  );
1070
1151
 
1071
1152
  this.handleContext = new ContainerFluidHandleContext("", this);
@@ -1087,6 +1168,10 @@ export class ContainerRuntime
1087
1168
  this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
1088
1169
  this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
1089
1170
 
1171
+ if (this.idCompressorEnabled) {
1172
+ this.idCompressor = idCompressor;
1173
+ }
1174
+
1090
1175
  this.maxConsecutiveReconnects =
1091
1176
  this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
1092
1177
  this.defaultMaxConsecutiveReconnects;
@@ -1203,7 +1288,7 @@ export class ContainerRuntime
1203
1288
  (blobPath: string) => this.garbageCollector.isNodeDeleted(blobPath),
1204
1289
  this,
1205
1290
  pendingRuntimeState?.pendingAttachmentBlobs,
1206
- () => this.getCurrentReferenceTimestampMs(),
1291
+ (error?: ICriticalContainerError) => this.closeFn(error),
1207
1292
  );
1208
1293
 
1209
1294
  this.scheduleManager = new ScheduleManager(
@@ -1252,12 +1337,25 @@ export class ContainerRuntime
1252
1337
  disablePartialFlush: disablePartialFlush === true,
1253
1338
  },
1254
1339
  logger: this.mc.logger,
1340
+ groupingManager: opGroupingManager,
1341
+ getCurrentSequenceNumbers: () => ({
1342
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
1343
+ clientSequenceNumber: this._processedClientSequenceNumber,
1344
+ }),
1255
1345
  });
1256
1346
 
1257
1347
  this.context.quorum.on("removeMember", (clientId: string) => {
1258
1348
  this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
1259
1349
  });
1260
1350
 
1351
+ this.summaryStateUpdateMethod = this.mc.config.getString(
1352
+ "Fluid.ContainerRuntime.Test.SummaryStateUpdateMethod",
1353
+ );
1354
+ const closeSummarizerDelayOverride = this.mc.config.getNumber(
1355
+ "Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
1356
+ );
1357
+ this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
1358
+
1261
1359
  this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
1262
1360
 
1263
1361
  this.dirtyContainer =
@@ -1398,8 +1496,12 @@ export class ContainerRuntime
1398
1496
  disableChunking,
1399
1497
  disableAttachReorder: this.disableAttachReorder,
1400
1498
  disablePartialFlush,
1499
+ idCompressorEnabled: this.idCompressorEnabled,
1500
+ summaryStateUpdateMethod: this.summaryStateUpdateMethod,
1501
+ closeSummarizerDelayOverride,
1401
1502
  }),
1402
1503
  telemetryDocumentId: this.telemetryDocumentId,
1504
+ groupedBatchingEnabled: this.groupedBatchingEnabled,
1403
1505
  });
1404
1506
 
1405
1507
  ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
@@ -1576,6 +1678,7 @@ export class ContainerRuntime
1576
1678
  extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
1577
1679
  this.messageAtLastSummary,
1578
1680
  telemetryDocumentId: this.telemetryDocumentId,
1681
+ idCompressorEnabled: this.idCompressorEnabled ? true : undefined,
1579
1682
  };
1580
1683
  addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
1581
1684
  }
@@ -1588,6 +1691,15 @@ export class ContainerRuntime
1588
1691
  ) {
1589
1692
  this.addMetadataToSummary(summaryTree);
1590
1693
 
1694
+ if (this.idCompressorEnabled) {
1695
+ assert(
1696
+ this.idCompressor !== undefined,
1697
+ 0x67a /* IdCompressor should be defined if enabled */,
1698
+ );
1699
+ const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
1700
+ addBlobToSummary(summaryTree, idCompressorBlobName, idCompressorState);
1701
+ }
1702
+
1591
1703
  if (this.remoteMessageProcessor.partialMessages.size > 0) {
1592
1704
  const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
1593
1705
  addBlobToSummary(summaryTree, chunksBlobName, content);
@@ -1686,15 +1798,32 @@ export class ContainerRuntime
1686
1798
  this.updateDocumentDirtyState(newState);
1687
1799
  }
1688
1800
 
1689
- private async applyStashedOp(
1690
- type: ContainerMessageType,
1691
- op: ISequencedDocumentMessage,
1692
- ): Promise<unknown> {
1801
+ /**
1802
+ * Updates the runtime's IdCompressor with the stashed state present in the given op. This is a bit of a
1803
+ * hack and is unnecessarily expensive. As it stands, every locally stashed op (all ops that get stored in
1804
+ * the PendingStateManager) will store their serialized representation locally until ack'd. Upon receiving
1805
+ * this stashed state, the IdCompressor blindly deserializes to the stashed state and assumes the session.
1806
+ * Technically only the last stashed state is needed to do this correctly, but we would have to write some
1807
+ * more hacky code to modify the batch before it gets sent out.
1808
+ * @param content - An IdAllocationOp with "stashedState", which is a representation of un-ack'd local state.
1809
+ */
1810
+ private async applyStashedIdAllocationOp(op: IdCreationRangeWithStashedState) {
1811
+ const { IdCompressor } = await import("./id-compressor");
1812
+ this.idCompressor = IdCompressor.deserialize(op.stashedState);
1813
+ }
1814
+
1815
+ private async applyStashedOp(type: ContainerMessageType, contents: unknown): Promise<unknown> {
1693
1816
  switch (type) {
1694
1817
  case ContainerMessageType.FluidDataStoreOp:
1695
- return this.dataStores.applyStashedOp(op);
1818
+ return this.dataStores.applyStashedOp(contents as IEnvelope);
1696
1819
  case ContainerMessageType.Attach:
1697
- return this.dataStores.applyStashedAttachOp(op as unknown as IAttachMessage);
1820
+ return this.dataStores.applyStashedAttachOp(contents as IAttachMessage);
1821
+ case ContainerMessageType.IdAllocation:
1822
+ assert(
1823
+ this.idCompressor !== undefined,
1824
+ 0x67b /* IdCompressor should be defined if enabled */,
1825
+ );
1826
+ return this.applyStashedIdAllocationOp(contents as IdCreationRangeWithStashedState);
1698
1827
  case ContainerMessageType.Alias:
1699
1828
  case ContainerMessageType.BlobAttach:
1700
1829
  return;
@@ -1814,13 +1943,25 @@ export class ContainerRuntime
1814
1943
 
1815
1944
  // Do shallow copy of message, as the processing flow will modify it.
1816
1945
  const messageCopy = { ...messageArg };
1817
- const message = this.remoteMessageProcessor.process(messageCopy);
1946
+ for (const message of this.remoteMessageProcessor.process(messageCopy)) {
1947
+ this.processCore(message, local, runtimeMessage);
1948
+ }
1949
+ }
1950
+
1951
+ private _processedClientSequenceNumber: number | undefined;
1818
1952
 
1953
+ private processCore(
1954
+ message: ISequencedDocumentMessage,
1955
+ local: boolean,
1956
+ runtimeMessage: boolean,
1957
+ ) {
1819
1958
  // Surround the actual processing of the operation with messages to the schedule manager indicating
1820
1959
  // the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
1821
1960
  // messages once a batch has been fully processed.
1822
1961
  this.scheduleManager.beforeOpProcessing(message);
1823
1962
 
1963
+ this._processedClientSequenceNumber = message.clientSequenceNumber;
1964
+
1824
1965
  try {
1825
1966
  let localOpMetadata: unknown;
1826
1967
  if (local && runtimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
@@ -1847,6 +1988,13 @@ export class ContainerRuntime
1847
1988
  case ContainerMessageType.BlobAttach:
1848
1989
  this.blobManager.processBlobAttachOp(message, local);
1849
1990
  break;
1991
+ case ContainerMessageType.IdAllocation:
1992
+ assert(
1993
+ this.idCompressor !== undefined,
1994
+ 0x67c /* IdCompressor should be defined if enabled */,
1995
+ );
1996
+ this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
1997
+ break;
1850
1998
  case ContainerMessageType.ChunkedOp:
1851
1999
  case ContainerMessageType.Rejoin:
1852
2000
  break;
@@ -1870,8 +2018,7 @@ export class ContainerRuntime
1870
2018
  }
1871
2019
  }
1872
2020
 
1873
- // For back-compat, notify only about runtime messages for now.
1874
- if (runtimeMessage) {
2021
+ if (runtimeMessage || this.groupedBatchingEnabled) {
1875
2022
  this.emit("op", message, runtimeMessage);
1876
2023
  }
1877
2024
 
@@ -2291,31 +2438,33 @@ export class ContainerRuntime
2291
2438
  runSweep,
2292
2439
  });
2293
2440
 
2294
- let gcStats: IGCStats | undefined;
2295
- if (runGC) {
2296
- gcStats = await this.collectGarbage(
2297
- { logger: summaryLogger, runSweep, fullGC },
2441
+ try {
2442
+ let gcStats: IGCStats | undefined;
2443
+ if (runGC) {
2444
+ gcStats = await this.collectGarbage(
2445
+ { logger: summaryLogger, runSweep, fullGC },
2446
+ telemetryContext,
2447
+ );
2448
+ }
2449
+
2450
+ const { stats, summary } = await this.summarizerNode.summarize(
2451
+ fullTree,
2452
+ trackState,
2298
2453
  telemetryContext,
2299
2454
  );
2300
- }
2301
2455
 
2302
- const { stats, summary } = await this.summarizerNode.summarize(
2303
- fullTree,
2304
- trackState,
2305
- telemetryContext,
2306
- );
2307
-
2308
- this.logger.sendTelemetryEvent({
2309
- eventName: "SummarizeTelemetry",
2310
- details: telemetryContext.serialize(),
2311
- });
2312
-
2313
- assert(
2314
- summary.type === SummaryType.Tree,
2315
- 0x12f /* "Container Runtime's summarize should always return a tree" */,
2316
- );
2456
+ assert(
2457
+ summary.type === SummaryType.Tree,
2458
+ 0x12f /* "Container Runtime's summarize should always return a tree" */,
2459
+ );
2317
2460
 
2318
- return { stats, summary, gcStats };
2461
+ return { stats, summary, gcStats };
2462
+ } finally {
2463
+ this.logger.sendTelemetryEvent({
2464
+ eventName: "SummarizeTelemetry",
2465
+ details: telemetryContext.serialize(),
2466
+ });
2467
+ }
2319
2468
  }
2320
2469
 
2321
2470
  /**
@@ -2797,6 +2946,40 @@ export class ContainerRuntime
2797
2946
  return this.blobManager.createBlob(blob);
2798
2947
  }
2799
2948
 
2949
+ private maybeSubmitIdAllocationOp(type: ContainerMessageType) {
2950
+ if (type !== ContainerMessageType.IdAllocation) {
2951
+ let idAllocationBatchMessage: BatchMessage | undefined;
2952
+ let idRange: IdCreationRange | undefined;
2953
+ if (this.idCompressorEnabled) {
2954
+ assert(
2955
+ this.idCompressor !== undefined,
2956
+ 0x67d /* IdCompressor should be defined if enabled */,
2957
+ );
2958
+ idRange = this.idCompressor.takeNextCreationRange();
2959
+ // Don't include the idRange if there weren't any Ids allocated
2960
+ idRange = idRange?.ids?.first !== undefined ? idRange : undefined;
2961
+ }
2962
+
2963
+ if (idRange !== undefined) {
2964
+ const idAllocationMessage: ContainerRuntimeMessage = {
2965
+ type: ContainerMessageType.IdAllocation,
2966
+ contents: idRange,
2967
+ };
2968
+ idAllocationBatchMessage = {
2969
+ contents: JSON.stringify(idAllocationMessage),
2970
+ deserializedContent: idAllocationMessage,
2971
+ referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
2972
+ metadata: undefined,
2973
+ localOpMetadata: this.idCompressor?.serialize(true),
2974
+ };
2975
+ }
2976
+
2977
+ if (idAllocationBatchMessage !== undefined) {
2978
+ this.outbox.submit(idAllocationBatchMessage);
2979
+ }
2980
+ }
2981
+ }
2982
+
2800
2983
  private submit(
2801
2984
  type: ContainerMessageType,
2802
2985
  contents: any,
@@ -2832,6 +3015,12 @@ export class ContainerRuntime
2832
3015
  };
2833
3016
 
2834
3017
  try {
3018
+ // Submit an IdAllocation op if any Ids have been generated since
3019
+ // the last op was submitted. Don't submit another if it's an IdAllocation
3020
+ // op as that means we're in resubmission flow and we don't want to send
3021
+ // IdRanges out of order.
3022
+ this.maybeSubmitIdAllocationOp(type);
3023
+
2835
3024
  // If this is attach message for new data store, and we are in a batch, send this op out of order
2836
3025
  // Is it safe:
2837
3026
  // Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
@@ -2994,6 +3183,7 @@ export class ContainerRuntime
2994
3183
  break;
2995
3184
  case ContainerMessageType.Attach:
2996
3185
  case ContainerMessageType.Alias:
3186
+ case ContainerMessageType.IdAllocation:
2997
3187
  this.submit(type, content, localOpMetadata);
2998
3188
  break;
2999
3189
  case ContainerMessageType.ChunkedOp:
@@ -3059,6 +3249,25 @@ export class ContainerRuntime
3059
3249
  readAndParseBlob,
3060
3250
  );
3061
3251
 
3252
+ /**
3253
+ * back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
3254
+ * getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
3255
+ * these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
3256
+ * change that started fetching latest snapshot always.
3257
+ */
3258
+ if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3259
+ fetchResult = await this.fetchSnapshotFromStorage(
3260
+ summaryLogger,
3261
+ {
3262
+ eventName: "RefreshLatestSummaryAckFetchBackCompat",
3263
+ ackHandle,
3264
+ targetSequenceNumber: summaryRefSeq,
3265
+ },
3266
+ readAndParseBlob,
3267
+ ackHandle,
3268
+ );
3269
+ }
3270
+
3062
3271
  /**
3063
3272
  * If the fetched snapshot is older than the one for which the ack was received, close the container.
3064
3273
  * This should never happen because an ack should be sent after the latest summary is updated in the server.
@@ -3070,32 +3279,18 @@ export class ContainerRuntime
3070
3279
  * state.
3071
3280
  */
3072
3281
  if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3073
- /* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
3074
- fetchResult = await this.fetchSnapshotFromStorage(
3075
- summaryLogger,
3282
+ const error = DataProcessingError.create(
3283
+ "Fetched snapshot is older than the received ack",
3284
+ "RefreshLatestSummaryAck",
3285
+ undefined /* sequencedMessage */,
3076
3286
  {
3077
- eventName: "RefreshLatestSummaryAckFetch",
3078
3287
  ackHandle,
3079
- targetSequenceNumber: summaryRefSeq,
3288
+ summaryRefSeq,
3289
+ fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3080
3290
  },
3081
- readAndParseBlob,
3082
- ackHandle,
3083
3291
  );
3084
-
3085
- if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
3086
- const error = DataProcessingError.create(
3087
- "Fetched snapshot is older than the received ack",
3088
- "RefreshLatestSummaryAck",
3089
- undefined /* sequencedMessage */,
3090
- {
3091
- ackHandle,
3092
- summaryRefSeq,
3093
- fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
3094
- },
3095
- );
3096
- this.closeFn(error);
3097
- throw error;
3098
- }
3292
+ this.closeFn(error);
3293
+ throw error;
3099
3294
  }
3100
3295
 
3101
3296
  // In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
@@ -3177,7 +3372,7 @@ export class ContainerRuntime
3177
3372
  readAndParseBlob: ReadAndParseBlob,
3178
3373
  versionId: string | null,
3179
3374
  ): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
3180
- return PerformanceEvent.timedExecAsync(
3375
+ const snapshotResults = await PerformanceEvent.timedExecAsync(
3181
3376
  logger,
3182
3377
  event,
3183
3378
  async (perfEvent: {
@@ -3223,6 +3418,33 @@ export class ContainerRuntime
3223
3418
  };
3224
3419
  },
3225
3420
  );
3421
+
3422
+ // We choose to close the summarizer after the snapshot cache is updated to avoid
3423
+ // situations which the main client (which is likely to be re-elected as the leader again)
3424
+ // loads the summarizer from cache.
3425
+ if (this.summaryStateUpdateMethod === "restart") {
3426
+ const error = new GenericError("Restarting summarizer instead of refreshing");
3427
+
3428
+ this.mc.logger.sendTelemetryEvent(
3429
+ {
3430
+ ...event,
3431
+ eventName: "ClosingSummarizerOnSummaryStale",
3432
+ codePath: event.eventName,
3433
+ message: "Stopping fetch from storage",
3434
+ versionId: versionId != null ? versionId : undefined,
3435
+ closeSummarizerDelayMs: this.closeSummarizerDelayMs,
3436
+ },
3437
+ error,
3438
+ );
3439
+
3440
+ // Delay 10 seconds before restarting summarizer to prevent the summarizer from restarting too frequently.
3441
+ await delay(this.closeSummarizerDelayMs);
3442
+ this._summarizer?.stop("latestSummaryStateStale");
3443
+ this.closeFn();
3444
+ throw error;
3445
+ }
3446
+
3447
+ return snapshotResults;
3226
3448
  }
3227
3449
 
3228
3450
  public notifyAttaching() {} // do nothing (deprecated method)
@@ -3316,6 +3538,13 @@ export class ContainerRuntime
3316
3538
  );
3317
3539
  }
3318
3540
  }
3541
+
3542
+ private get groupedBatchingEnabled(): boolean {
3543
+ const killSwitch = this.mc.config.getBoolean(
3544
+ "Fluid.ContainerRuntime.DisableGroupedBatching",
3545
+ );
3546
+ return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
3547
+ }
3319
3548
  }
3320
3549
 
3321
3550
  /**
@@ -48,6 +48,8 @@ import {
48
48
  ISummarizerNodeWithGC,
49
49
  SummarizeInternalFn,
50
50
  ITelemetryContext,
51
+ IIdCompressor,
52
+ IIdCompressorCore,
51
53
  VisibilityState,
52
54
  } from "@fluidframework/runtime-definitions";
53
55
  import {
@@ -193,6 +195,10 @@ export abstract class FluidDataStoreContext
193
195
  return this._baseSnapshot;
194
196
  }
195
197
 
198
+ public get idCompressor(): (IIdCompressorCore & IIdCompressor) | undefined {
199
+ return this._containerRuntime.idCompressor;
200
+ }
201
+
196
202
  private _disposed = false;
197
203
  public get disposed() {
198
204
  return this._disposed;