@fluidframework/container-runtime 2.0.0-dev-rc.3.0.0.254674 → 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
@@ -5,15 +5,14 @@
5
5
 
6
6
  import { IGarbageCollectionData } from "@fluidframework/runtime-definitions";
7
7
  import {
8
- type ITelemetryGenericEventExt,
9
8
  ITelemetryLoggerExt,
10
- } from "@fluidframework/telemetry-utils";
11
- import {
12
9
  MonitoringContext,
13
10
  generateStack,
14
11
  tagCodeArtifacts,
12
+ type ITelemetryGenericEventExt,
15
13
  } from "@fluidframework/telemetry-utils/internal";
16
14
 
15
+ import type { Tagged } from "@fluidframework/core-interfaces";
17
16
  import { RuntimeHeaderData } from "../containerRuntime.js";
18
17
  import { ICreateContainerMetadata } from "../summary/index.js";
19
18
 
@@ -43,11 +42,12 @@ interface ICommonProps {
43
42
 
44
43
  /** The event that is logged when unreferenced node is used after a certain time. */
45
44
  interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps {
45
+ /** The id that GC uses to track the node. May or may not match id */
46
+ trackedId: string;
46
47
  state: UnreferencedState;
47
- id: {
48
- value: string;
49
- tag: string;
50
- };
48
+ /** The full path (in GC Path format) to the node in question */
49
+ id: Tagged<string>;
50
+ fromId?: Tagged<string>;
51
51
  type: GCNodeType;
52
52
  unrefTime: number;
53
53
  age: number;
@@ -56,19 +56,24 @@ interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps
56
56
  [K in keyof GCFeatureMatrix]: GCFeatureMatrix[K];
57
57
  };
58
58
  timeout?: number;
59
- fromId?: {
60
- value: string;
61
- tag: string;
62
- };
63
59
  }
64
60
 
65
61
  /** Properties passed to nodeUsed function when a node is used. */
66
62
  interface INodeUsageProps extends ICommonProps {
63
+ /** The full path (in GC Path format) to the node in question */
67
64
  id: string;
65
+ /** Latest timestamp received from the server, as a baseline for computing GC state/age */
68
66
  currentReferenceTimestampMs: number | undefined;
67
+ /** The package path of the node. This may not be available if the node hasn't been loaded yet */
69
68
  packagePath: readonly string[] | undefined;
69
+ /** In case of Revived - what node added the reference? */
70
70
  fromId?: string;
71
+ /** In case of Revived - was it revived due to autorecovery? */
71
72
  autorecovery?: true;
73
+ /** URL (including query string) if this usage came from a request */
74
+ requestUrl?: string;
75
+ /** Original request headers if this usage came from a request or handle.get */
76
+ requestHeaders?: string;
72
77
  }
73
78
 
74
79
  /**
@@ -143,18 +148,34 @@ export class GCTelemetryTracker {
143
148
  }
144
149
 
145
150
  /**
146
- * Called when a node is used. If the node is not active or tombstoned, log telemetry indicating object is used
151
+ * Called when a node is used. If the node is inactive or tombstoned, log telemetry indicating object is used
147
152
  * when it should not have been.
153
+ * @param trackedId - The id that GC uses to track the node. For SubDataStore nodes, this should be the DataStore ID.
154
+ * @param INodeUsageProps - All kind of details about this event to be logged
148
155
  */
149
- public nodeUsed(nodeUsageProps: INodeUsageProps) {
156
+ public nodeUsed(
157
+ trackedId: string,
158
+ {
159
+ usageType,
160
+ currentReferenceTimestampMs,
161
+ packagePath,
162
+ id: untaggedId,
163
+ fromId: untaggedFromId,
164
+ isTombstoned,
165
+ ...otherNodeUsageProps
166
+ }: INodeUsageProps,
167
+ ) {
150
168
  // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
151
169
  // logging as nothing interesting would have happened worth logging.
152
- if (nodeUsageProps.currentReferenceTimestampMs === undefined) {
170
+ if (currentReferenceTimestampMs === undefined) {
153
171
  return;
154
172
  }
155
173
 
156
- const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
157
- const nodeType = this.getNodeType(nodeUsageProps.id);
174
+ // Note: For SubDataStore Load usage, trackedId will be the DataStore's id, not the full path in question.
175
+ // This is necessary because the SubDataStore path may be unrecognized by GC (if suited for a custom request handler)
176
+ const nodeStateTracker = this.getNodeStateTracker(trackedId);
177
+ const nodeType = this.getNodeType(untaggedId);
178
+
158
179
  const timeout = (() => {
159
180
  switch (nodeStateTracker?.state) {
160
181
  case UnreferencedState.Inactive:
@@ -170,33 +191,27 @@ export class GCTelemetryTracker {
170
191
  return undefined;
171
192
  }
172
193
  })();
173
- const {
174
- usageType,
175
- currentReferenceTimestampMs,
176
- packagePath,
177
- id: untaggedId,
178
- fromId: untaggedFromId,
179
- ...propsToLog
180
- } = nodeUsageProps;
181
194
  const { persistedGcFeatureMatrix, ...configs } = this.configs;
182
- const unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType"> = {
195
+ const unrefEventProps = {
196
+ trackedId,
183
197
  type: nodeType,
184
198
  unrefTime: nodeStateTracker?.unreferencedTimestampMs ?? -1,
185
199
  age:
186
200
  nodeStateTracker !== undefined
187
- ? nodeUsageProps.currentReferenceTimestampMs -
188
- nodeStateTracker.unreferencedTimestampMs
201
+ ? currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs
189
202
  : -1,
190
203
  timeout,
204
+ isTombstoned,
191
205
  ...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
192
- ...propsToLog,
206
+ ...otherNodeUsageProps,
193
207
  ...this.createContainerMetadata,
194
208
  gcConfigs: { ...configs, ...persistedGcFeatureMatrix },
195
- };
209
+ } satisfies Omit<IUnreferencedEventProps, "state" | "usageType"> &
210
+ typeof otherNodeUsageProps;
196
211
 
197
212
  // If the node that is used is tombstoned, log a tombstone telemetry.
198
- if (nodeUsageProps.isTombstoned) {
199
- this.logTombstoneUsageTelemetry(nodeUsageProps, unrefEventProps, nodeType, usageType);
213
+ if (isTombstoned) {
214
+ this.logTombstoneUsageTelemetry(unrefEventProps, nodeType, usageType, packagePath);
200
215
  }
201
216
 
202
217
  // After logging tombstone telemetry, if the node's unreferenced state is not tracked, there is nothing
@@ -206,16 +221,9 @@ export class GCTelemetryTracker {
206
221
  }
207
222
 
208
223
  const state = nodeStateTracker.state;
209
- const uniqueEventId = `${state}-${nodeUsageProps.id}-${nodeUsageProps.usageType}`;
224
+ const uniqueEventId = `${state}-${untaggedId}-${usageType}`;
210
225
 
211
- if (
212
- !this.shouldLogNonActiveEvent(
213
- nodeType,
214
- nodeUsageProps.usageType,
215
- nodeStateTracker,
216
- uniqueEventId,
217
- )
218
- ) {
226
+ if (!this.shouldLogNonActiveEvent(nodeType, usageType, nodeStateTracker, uniqueEventId)) {
219
227
  return;
220
228
  }
221
229
 
@@ -229,8 +237,8 @@ export class GCTelemetryTracker {
229
237
  // SweepReady errors are usages of Objects that will be deleted by GC Sweep!
230
238
  if (this.isSummarizerClient) {
231
239
  this.pendingEventsQueue.push({
232
- ...unrefEventProps,
233
- usageType: nodeUsageProps.usageType,
240
+ ...unrefEventProps, // Note: Contains some properties from INodeUsageProps as well
241
+ usageType,
234
242
  state,
235
243
  });
236
244
  } else {
@@ -238,11 +246,11 @@ export class GCTelemetryTracker {
238
246
  // summarizer clients if they are based off of user actions (such as scrolling to content for these objects)
239
247
  // Events generated:
240
248
  // InactiveObject_Loaded, SweepReadyObject_Loaded
241
- if (nodeUsageProps.usageType === "Loaded") {
249
+ if (usageType === "Loaded") {
242
250
  const { id, fromId, headers, gcConfigs, ...detailedProps } = unrefEventProps;
243
251
  const event = {
244
- eventName: `${state}Object_${nodeUsageProps.usageType}`,
245
- ...tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }),
252
+ eventName: `${state}Object_${usageType}`,
253
+ ...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
246
254
  stack: generateStack(),
247
255
  id,
248
256
  fromId,
@@ -262,10 +270,10 @@ export class GCTelemetryTracker {
262
270
  * Logs telemetry when a tombstoned object is changed, revived or loaded.
263
271
  */
264
272
  private logTombstoneUsageTelemetry(
265
- nodeUsageProps: INodeUsageProps,
266
273
  unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType">,
267
274
  nodeType: GCNodeType,
268
275
  usageType: NodeUsageType,
276
+ packagePath?: readonly string[],
269
277
  ) {
270
278
  // This will log the following events:
271
279
  // GC_Tombstone_DataStore_Requested, GC_Tombstone_DataStore_Changed, GC_Tombstone_DataStore_Revived
@@ -275,12 +283,12 @@ export class GCTelemetryTracker {
275
283
  const eventUsageName = usageType === "Loaded" ? "Requested" : usageType;
276
284
  const event = {
277
285
  eventName: `GC_Tombstone_${nodeType}_${eventUsageName}`,
278
- pkg: tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }).pkg,
286
+ ...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
279
287
  stack: generateStack(),
280
288
  id,
281
289
  fromId,
282
290
  headers: { ...headers },
283
- details: detailedProps,
291
+ details: detailedProps, // Also includes some properties from INodeUsageProps type
284
292
  gcConfigs,
285
293
  tombstoneFlags: {
286
294
  DisableTombstone: this.mc.config.getBoolean(disableTombstoneKey),
@@ -372,7 +380,6 @@ export class GCTelemetryTracker {
372
380
  // InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
373
381
  // SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
374
382
  for (const eventProps of this.pendingEventsQueue) {
375
- // const { usageType, state, id, fromId, ...propsToLog } = eventProps;
376
383
  const { usageType, state, id, fromId, headers, gcConfigs, ...detailedProps } =
377
384
  eventProps;
378
385
  /**
@@ -381,7 +388,7 @@ export class GCTelemetryTracker {
381
388
  * Loaded and Changed events are logged only if the node is not active. If the node is active, it was
382
389
  * revived and a Revived event will be logged for it.
383
390
  */
384
- const nodeStateTracker = this.getNodeStateTracker(eventProps.id.value);
391
+ const nodeStateTracker = this.getNodeStateTracker(detailedProps.trackedId); // Note: This is never SubDataStore path
385
392
  const active =
386
393
  nodeStateTracker === undefined ||
387
394
  nodeStateTracker.state === UnreferencedState.Active;
package/src/gc/index.ts CHANGED
@@ -23,6 +23,7 @@ export {
23
23
  IGarbageCollectorCreateParams,
24
24
  IGCMetadata,
25
25
  IGCMetadata_Deprecated,
26
+ IGCNodeUpdatedProps,
26
27
  IGCResult,
27
28
  IGCRuntimeOptions,
28
29
  IMarkPhaseStats,
@@ -46,8 +47,8 @@ export {
46
47
  cloneGCData,
47
48
  concatGarbageCollectionStates,
48
49
  getGCVersionInEffect,
49
- trimLeadingAndTrailingSlashes,
50
50
  unpackChildNodesGCDetails,
51
+ urlToGCNodePath,
51
52
  } from "./gcHelpers.js";
52
53
  export { runGarbageCollection } from "./gcReferenceGraphAlgorithm.js";
53
54
  export {
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ export {
13
13
  isRuntimeMessage,
14
14
  agentSchedulerId,
15
15
  ContainerRuntime,
16
+ DeletedResponseHeaderKey,
16
17
  TombstoneResponseHeaderKey,
17
18
  InactiveResponseHeaderKey,
18
19
  ISummaryConfiguration,
@@ -47,6 +48,7 @@ export {
47
48
  IGCRuntimeOptions,
48
49
  IMarkPhaseStats,
49
50
  ISweepPhaseStats,
51
+ IGCNodeUpdatedProps,
50
52
  IGCStats,
51
53
  } from "./gc/index.js";
52
54
  export {
package/src/metadata.ts CHANGED
@@ -19,8 +19,8 @@ export interface IBlobMetadata {
19
19
  }
20
20
 
21
21
  /**
22
- * The IdCompressor needs to know if this is a replayed savedOp as those need to be skipped in stashed ops scenarios.
22
+ * ContainerRuntime needs to know if this is a replayed savedOp as those need to be skipped in stashed ops scenarios.
23
23
  */
24
- export interface IIdAllocationMetadata {
24
+ export interface ISavedOpMetadata {
25
25
  savedOp?: boolean;
26
26
  }
@@ -339,19 +339,19 @@ stateDiagram-v2
339
339
  state "Store original (uncompressed, unchunked, ungrouped) batch locally" as store
340
340
  state if_compression <<choice>>
341
341
  [*] --> ContainerRuntime.submit
342
- ContainerRuntime.submit --> outbox.submitAttach
342
+ ContainerRuntime.submit --> outbox.submitIdAllocation
343
343
  ContainerRuntime.submit --> outbox.submitBlobAttach
344
344
  ContainerRuntime.submit --> outbox.submit
345
345
  outbox.submit --> scheduleFlush
346
- outbox.submitAttach --> scheduleFlush
346
+ outbox.submitIdAllocation --> scheduleFlush
347
347
  outbox.submitBlobAttach --> scheduleFlush
348
348
  scheduleFlush --> jsTurn
349
349
  jsTurn --> flush
350
350
  flush --> outbox.flushInternalMain
351
- flush --> outbox.flushInternalAttach
351
+ flush --> outbox.flushInternalIdAllocation
352
352
  flush --> outbox.flushInternalBlobAttach
353
353
  outbox.flushInternalMain --> flushInternal
354
- outbox.flushInternalAttach --> flushInternal
354
+ outbox.flushInternalIdAllocation --> flushInternal
355
355
  outbox.flushInternalBlobAttach --> flushInternal
356
356
  flushInternal --> ContainerRuntime.reSubmit: if batch has reentrant ops and should group
357
357
  ContainerRuntime.reSubmit --> flushInternal
@@ -9,7 +9,6 @@ import { BatchMessage, IBatch, IBatchCheckpoint } from "./definitions.js";
9
9
 
10
10
  export interface IBatchManagerOptions {
11
11
  readonly hardLimit: number;
12
- readonly softLimit?: number;
13
12
  readonly compressionOptions?: ICompressionRuntimeOptions;
14
13
  }
15
14
 
@@ -72,19 +71,6 @@ export class BatchManager {
72
71
  // initially stored as base64, and that requires only 2 extra escape characters.
73
72
  const socketMessageSize = contentSize + opOverhead * opCount;
74
73
 
75
- // If we were provided soft limit, check for exceeding it.
76
- // But only if we have any ops, as the intention here is to flush existing ops (on exceeding this limit)
77
- // and start over. That's not an option if we have no ops.
78
- // If compression is enabled, the soft and hard limit are ignored and the message will be pushed anyways.
79
- // Cases where the message is still too large will be handled by the maxConsecutiveReconnects path.
80
- if (
81
- this.options.softLimit !== undefined &&
82
- this.length > 0 &&
83
- socketMessageSize >= this.options.softLimit
84
- ) {
85
- return false;
86
- }
87
-
88
74
  if (socketMessageSize >= this.options.hardLimit) {
89
75
  return false;
90
76
  }
@@ -98,7 +98,10 @@ export class OpDecompressor {
98
98
  message.compression === undefined || message.compression === CompressionAlgorithms.lz4,
99
99
  0x511 /* Only lz4 compression is supported */,
100
100
  );
101
- assert(this.isCompressedMessage(message), "provided message should be compressed");
101
+ assert(
102
+ this.isCompressedMessage(message),
103
+ 0x940 /* provided message should be compressed */,
104
+ );
102
105
 
103
106
  assert(this.activeBatch === false, 0x4b8 /* shouldn't have multiple active batches */);
104
107
  this.activeBatch = true;
@@ -107,7 +110,7 @@ export class OpDecompressor {
107
110
  if (batchMetadata === undefined) {
108
111
  this.isSingleMessageBatch = true;
109
112
  } else {
110
- assert(batchMetadata === true, "invalid batch metadata");
113
+ assert(batchMetadata === true, 0x941 /* invalid batch metadata */);
111
114
  }
112
115
 
113
116
  const contents = IsoBuffer.from(
@@ -125,9 +128,12 @@ export class OpDecompressor {
125
128
  * @returns the unrolled `ISequencedDocumentMessage`
126
129
  */
127
130
  public unroll(message: ISequencedDocumentMessage): ISequencedDocumentMessage {
128
- assert(this.currentlyUnrolling, "not currently unrolling");
129
- assert(this.rootMessageContents !== undefined, "missing rootMessageContents");
130
- assert(this.rootMessageContents.length > this.processedCount, "no more content to unroll");
131
+ assert(this.currentlyUnrolling, 0x942 /* not currently unrolling */);
132
+ assert(this.rootMessageContents !== undefined, 0x943 /* missing rootMessageContents */);
133
+ assert(
134
+ this.rootMessageContents.length > this.processedCount,
135
+ 0x944 /* no more content to unroll */,
136
+ );
131
137
 
132
138
  const batchMetadata = (message.metadata as IBatchMetadata | undefined)?.batch;
133
139
 
@@ -149,7 +155,7 @@ export class OpDecompressor {
149
155
  return newMessage(message, this.rootMessageContents[this.processedCount++]);
150
156
  }
151
157
 
152
- assert(batchMetadata === undefined, "invalid batch metadata");
158
+ assert(batchMetadata === undefined, 0x945 /* invalid batch metadata */);
153
159
  assert(message.contents === undefined, 0x512 /* Expecting empty message */);
154
160
 
155
161
  // Continuation of compressed batch
@@ -50,7 +50,7 @@ export class OpGroupingManager {
50
50
  }
51
51
 
52
52
  public groupBatch(batch: IBatch): IBatch {
53
- assert(this.shouldGroup(batch), "cannot group the provided batch");
53
+ assert(this.shouldGroup(batch), 0x946 /* cannot group the provided batch */);
54
54
 
55
55
  if (batch.content.length >= 1000) {
56
56
  this.logger.sendTelemetryEvent({
@@ -96,7 +96,7 @@ export class OpGroupingManager {
96
96
  }
97
97
 
98
98
  public ungroupOp(op: ISequencedDocumentMessage): ISequencedDocumentMessage[] {
99
- assert(isGroupContents(op.contents), "can only ungroup a grouped batch");
99
+ assert(isGroupContents(op.contents), 0x947 /* can only ungroup a grouped batch */);
100
100
  const contents: IGroupedBatchMessageContents = op.contents;
101
101
 
102
102
  let fakeCsn = 1;
@@ -182,7 +182,7 @@ export class OpSplitter {
182
182
  }
183
183
 
184
184
  public processChunk(message: ISequencedDocumentMessage): ProcessChunkResult {
185
- assert(isChunkedContents(message.contents), "message not of type ChunkedOp");
185
+ assert(isChunkedContents(message.contents), 0x948 /* message not of type ChunkedOp */);
186
186
  const contents: IChunkedContents = message.contents;
187
187
 
188
188
  // TODO: Verify whether this should be able to handle server-generated ops (with null clientId)
@@ -89,11 +89,9 @@ export function getLongStack<T>(action: () => T, length: number = 50): T {
89
89
 
90
90
  export class Outbox {
91
91
  private readonly mc: MonitoringContext;
92
- private readonly attachFlowBatch: BatchManager;
93
92
  private readonly mainBatch: BatchManager;
94
93
  private readonly blobAttachBatch: BatchManager;
95
94
  private readonly idAllocationBatch: BatchManager;
96
- private readonly defaultAttachFlowSoftLimitInBytes = 320 * 1024;
97
95
  private batchRebasesToReport = 5;
98
96
  private rebasing = false;
99
97
 
@@ -113,21 +111,14 @@ export class Outbox {
113
111
  Number.POSITIVE_INFINITY;
114
112
  // We need to allow infinite size batches if we enable compression
115
113
  const hardLimit = isCompressionEnabled ? Infinity : this.params.config.maxBatchSizeInBytes;
116
- const softLimit = isCompressionEnabled ? Infinity : this.defaultAttachFlowSoftLimitInBytes;
117
114
 
118
- this.attachFlowBatch = new BatchManager({ hardLimit, softLimit });
119
115
  this.mainBatch = new BatchManager({ hardLimit });
120
116
  this.blobAttachBatch = new BatchManager({ hardLimit });
121
117
  this.idAllocationBatch = new BatchManager({ hardLimit });
122
118
  }
123
119
 
124
120
  public get messageCount(): number {
125
- return (
126
- this.attachFlowBatch.length +
127
- this.mainBatch.length +
128
- this.blobAttachBatch.length +
129
- this.idAllocationBatch.length
130
- );
121
+ return this.mainBatch.length + this.blobAttachBatch.length + this.idAllocationBatch.length;
131
122
  }
132
123
 
133
124
  public get isEmpty(): boolean {
@@ -142,13 +133,11 @@ export class Outbox {
142
133
  */
143
134
  private maybeFlushPartialBatch() {
144
135
  const mainBatchSeqNums = this.mainBatch.sequenceNumbers;
145
- const attachFlowBatchSeqNums = this.attachFlowBatch.sequenceNumbers;
146
136
  const blobAttachSeqNums = this.blobAttachBatch.sequenceNumbers;
147
137
  const idAllocSeqNums = this.idAllocationBatch.sequenceNumbers;
148
138
  assert(
149
139
  this.params.config.disablePartialFlush ||
150
- (sequenceNumbersMatch(mainBatchSeqNums, attachFlowBatchSeqNums) &&
151
- sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
140
+ (sequenceNumbersMatch(mainBatchSeqNums, blobAttachSeqNums) &&
152
141
  sequenceNumbersMatch(mainBatchSeqNums, idAllocSeqNums)),
153
142
  0x58d /* Reference sequence numbers from both batches must be in sync */,
154
143
  );
@@ -157,7 +146,6 @@ export class Outbox {
157
146
 
158
147
  if (
159
148
  sequenceNumbersMatch(mainBatchSeqNums, currentSequenceNumbers) &&
160
- sequenceNumbersMatch(attachFlowBatchSeqNums, currentSequenceNumbers) &&
161
149
  sequenceNumbersMatch(blobAttachSeqNums, currentSequenceNumbers) &&
162
150
  sequenceNumbersMatch(idAllocSeqNums, currentSequenceNumbers)
163
151
  ) {
@@ -172,8 +160,6 @@ export class Outbox {
172
160
  eventName: "ReferenceSequenceNumberMismatch",
173
161
  mainReferenceSequenceNumber: mainBatchSeqNums.referenceSequenceNumber,
174
162
  mainClientSequenceNumber: mainBatchSeqNums.clientSequenceNumber,
175
- attachReferenceSequenceNumber: attachFlowBatchSeqNums.referenceSequenceNumber,
176
- attachClientSequenceNumber: attachFlowBatchSeqNums.clientSequenceNumber,
177
163
  blobAttachReferenceSequenceNumber: blobAttachSeqNums.referenceSequenceNumber,
178
164
  blobAttachClientSequenceNumber: blobAttachSeqNums.clientSequenceNumber,
179
165
  currentReferenceSequenceNumber: currentSequenceNumbers.referenceSequenceNumber,
@@ -194,37 +180,6 @@ export class Outbox {
194
180
  this.addMessageToBatchManager(this.mainBatch, message);
195
181
  }
196
182
 
197
- public submitAttach(message: BatchMessage) {
198
- this.maybeFlushPartialBatch();
199
-
200
- if (
201
- !this.attachFlowBatch.push(
202
- message,
203
- this.isContextReentrant(),
204
- this.params.getCurrentSequenceNumbers().clientSequenceNumber,
205
- )
206
- ) {
207
- // BatchManager has two limits - soft limit & hard limit. Soft limit is only engaged
208
- // when queue is not empty.
209
- // Flush queue & retry. Failure on retry would mean - single message is bigger than hard limit
210
- this.flushInternal(this.attachFlowBatch);
211
-
212
- this.addMessageToBatchManager(this.attachFlowBatch, message);
213
- }
214
-
215
- // If compression is enabled, we will always successfully receive
216
- // attach ops and compress then send them at the next JS turn, regardless
217
- // of the overall size of the accumulated ops in the batch.
218
- // However, it is more efficient to flush these ops faster, preferably
219
- // after they reach a size which would benefit from compression.
220
- if (
221
- this.attachFlowBatch.contentSizeInBytes >=
222
- this.params.config.compressionOptions.minimumBatchSizeInBytes
223
- ) {
224
- this.flushInternal(this.attachFlowBatch);
225
- }
226
- }
227
-
228
183
  public submitBlobAttach(message: BatchMessage) {
229
184
  this.maybeFlushPartialBatch();
230
185
 
@@ -303,7 +258,6 @@ export class Outbox {
303
258
 
304
259
  private flushAll() {
305
260
  this.flushInternal(this.idAllocationBatch);
306
- this.flushInternal(this.attachFlowBatch);
307
261
  this.flushInternal(this.blobAttachBatch, true /* disableGroupedBatching */);
308
262
  this.flushInternal(this.mainBatch);
309
263
  }
@@ -479,7 +433,6 @@ export class Outbox {
479
433
  const mainBatch: IBatchCheckpoint = this.mainBatch.checkpoint();
480
434
  return {
481
435
  mainBatch,
482
- attachFlowBatch: this.attachFlowBatch.checkpoint(),
483
436
  blobAttachBatch: this.blobAttachBatch.checkpoint(),
484
437
  };
485
438
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-dev-rc.3.0.0.254674";
9
+ export const pkgVersion = "2.0.0-dev-rc.4.0.0.261659";
@@ -7,8 +7,11 @@ import { ICriticalContainerError } from "@fluidframework/container-definitions";
7
7
  import { IDisposable } from "@fluidframework/core-interfaces";
8
8
  import { assert, Lazy } from "@fluidframework/core-utils/internal";
9
9
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
10
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
11
- import { DataProcessingError } from "@fluidframework/telemetry-utils/internal";
10
+ import {
11
+ ITelemetryLoggerExt,
12
+ DataProcessingError,
13
+ LoggingError,
14
+ } from "@fluidframework/telemetry-utils/internal";
12
15
  import Deque from "double-ended-queue";
13
16
 
14
17
  import { InboundSequencedContainerRuntimeMessage } from "./messageTypes.js";
@@ -25,6 +28,7 @@ export interface IPendingMessage {
25
28
  content: string;
26
29
  localOpMetadata: unknown;
27
30
  opMetadata: Record<string, unknown> | undefined;
31
+ sequenceNumber?: number;
28
32
  }
29
33
 
30
34
  export interface IPendingLocalState {
@@ -119,22 +123,31 @@ export class PendingStateManager implements IDisposable {
119
123
  return this.pendingMessagesCount !== 0;
120
124
  }
121
125
 
122
- public getLocalState(): IPendingLocalState | undefined {
126
+ public getLocalState(snapshotSequenceNumber?: number): IPendingLocalState {
123
127
  assert(
124
128
  this.initialMessages.isEmpty(),
125
129
  0x2e9 /* "Must call getLocalState() after applying initial states" */,
126
130
  );
127
- if (!this.pendingMessages.isEmpty()) {
128
- return {
129
- pendingStates: [...this.savedOps, ...this.pendingMessages.toArray()].map(
130
- (message) => {
131
- // delete localOpMetadata since it may not be serializable
132
- // and will be regenerated by applyStashedOp()
133
- return { ...message, localOpMetadata: undefined };
134
- },
135
- ),
136
- };
137
- }
131
+ const newSavedOps = [...this.savedOps].filter((message) => {
132
+ assert(
133
+ message.sequenceNumber !== undefined,
134
+ "saved op should already have a sequence number",
135
+ );
136
+ return message.sequenceNumber >= (snapshotSequenceNumber ?? 0);
137
+ });
138
+ this.pendingMessages.toArray().forEach((message) => {
139
+ if (
140
+ snapshotSequenceNumber !== undefined &&
141
+ message.referenceSequenceNumber < snapshotSequenceNumber
142
+ ) {
143
+ throw new LoggingError("trying to stash ops older than our latest snapshot");
144
+ }
145
+ });
146
+ return {
147
+ pendingStates: [...newSavedOps, ...this.pendingMessages.toArray()].map((message) => {
148
+ return { ...message, localOpMetadata: undefined };
149
+ }),
150
+ };
138
151
  }
139
152
 
140
153
  constructor(
@@ -221,13 +234,13 @@ export class PendingStateManager implements IDisposable {
221
234
  public processPendingLocalMessage(message: InboundSequencedContainerRuntimeMessage): unknown {
222
235
  // Pre-processing part - This may be the start of a batch.
223
236
  this.maybeProcessBatchBegin(message);
224
-
225
237
  // Get the next message from the pending queue. Verify a message exists.
226
238
  const pendingMessage = this.pendingMessages.peekFront();
227
239
  assert(
228
240
  pendingMessage !== undefined,
229
241
  0x169 /* "No pending message found for this remote message" */,
230
242
  );
243
+ pendingMessage.sequenceNumber = message.sequenceNumber;
231
244
  this.savedOps.push(pendingMessage);
232
245
 
233
246
  this.pendingMessages.shift();
@@ -9,8 +9,8 @@ import { IDeltaManager } from "@fluidframework/container-definitions";
9
9
  import { assert } from "@fluidframework/core-utils/internal";
10
10
  import { isRuntimeMessage } from "@fluidframework/driver-utils/internal";
11
11
  import { IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
12
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
13
12
  import {
13
+ ITelemetryLoggerExt,
14
14
  DataCorruptionError,
15
15
  DataProcessingError,
16
16
  createChildLogger,