@fluidframework/container-runtime 2.0.0-rc.2.0.3 → 2.0.0-rc.2.0.5

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 (118) hide show
  1. package/api-report/container-runtime.api.md +32 -4
  2. package/dist/channelCollection.d.ts +7 -3
  3. package/dist/channelCollection.d.ts.map +1 -1
  4. package/dist/channelCollection.js +80 -22
  5. package/dist/channelCollection.js.map +1 -1
  6. package/dist/container-runtime-alpha.d.ts +14 -4
  7. package/dist/container-runtime-beta.d.ts +6 -0
  8. package/dist/container-runtime-public.d.ts +6 -0
  9. package/dist/container-runtime-untrimmed.d.ts +43 -4
  10. package/dist/containerRuntime.d.ts +6 -0
  11. package/dist/containerRuntime.d.ts.map +1 -1
  12. package/dist/containerRuntime.js +16 -4
  13. package/dist/containerRuntime.js.map +1 -1
  14. package/dist/dataStoreContext.d.ts +1 -1
  15. package/dist/dataStoreContext.d.ts.map +1 -1
  16. package/dist/dataStoreContext.js +12 -2
  17. package/dist/dataStoreContext.js.map +1 -1
  18. package/dist/dataStoreContexts.d.ts +2 -0
  19. package/dist/dataStoreContexts.d.ts.map +1 -1
  20. package/dist/dataStoreContexts.js +7 -0
  21. package/dist/dataStoreContexts.js.map +1 -1
  22. package/dist/gc/garbageCollection.d.ts +4 -11
  23. package/dist/gc/garbageCollection.d.ts.map +1 -1
  24. package/dist/gc/garbageCollection.js +45 -29
  25. package/dist/gc/garbageCollection.js.map +1 -1
  26. package/dist/gc/gcDefinitions.d.ts +26 -5
  27. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  28. package/dist/gc/gcDefinitions.js.map +1 -1
  29. package/dist/gc/gcHelpers.d.ts +5 -4
  30. package/dist/gc/gcHelpers.d.ts.map +1 -1
  31. package/dist/gc/gcHelpers.js +14 -2
  32. package/dist/gc/gcHelpers.js.map +1 -1
  33. package/dist/gc/gcTelemetry.d.ts +13 -2
  34. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  35. package/dist/gc/gcTelemetry.js +24 -21
  36. package/dist/gc/gcTelemetry.js.map +1 -1
  37. package/dist/gc/index.d.ts +2 -2
  38. package/dist/gc/index.d.ts.map +1 -1
  39. package/dist/gc/index.js +2 -2
  40. package/dist/gc/index.js.map +1 -1
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +2 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  46. package/dist/opLifecycle/outbox.js +8 -5
  47. package/dist/opLifecycle/outbox.js.map +1 -1
  48. package/dist/packageVersion.d.ts +1 -1
  49. package/dist/packageVersion.js +1 -1
  50. package/dist/packageVersion.js.map +1 -1
  51. package/lib/channelCollection.d.ts +7 -3
  52. package/lib/channelCollection.d.ts.map +1 -1
  53. package/lib/channelCollection.js +82 -24
  54. package/lib/channelCollection.js.map +1 -1
  55. package/lib/container-runtime-alpha.d.ts +14 -4
  56. package/lib/container-runtime-beta.d.ts +6 -0
  57. package/lib/container-runtime-public.d.ts +6 -0
  58. package/lib/container-runtime-untrimmed.d.ts +43 -4
  59. package/lib/containerRuntime.d.ts +6 -0
  60. package/lib/containerRuntime.d.ts.map +1 -1
  61. package/lib/containerRuntime.js +15 -3
  62. package/lib/containerRuntime.js.map +1 -1
  63. package/lib/dataStoreContext.d.ts +1 -1
  64. package/lib/dataStoreContext.d.ts.map +1 -1
  65. package/lib/dataStoreContext.js +12 -2
  66. package/lib/dataStoreContext.js.map +1 -1
  67. package/lib/dataStoreContexts.d.ts +2 -0
  68. package/lib/dataStoreContexts.d.ts.map +1 -1
  69. package/lib/dataStoreContexts.js +7 -0
  70. package/lib/dataStoreContexts.js.map +1 -1
  71. package/lib/gc/garbageCollection.d.ts +4 -11
  72. package/lib/gc/garbageCollection.d.ts.map +1 -1
  73. package/lib/gc/garbageCollection.js +47 -31
  74. package/lib/gc/garbageCollection.js.map +1 -1
  75. package/lib/gc/gcDefinitions.d.ts +26 -5
  76. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  77. package/lib/gc/gcDefinitions.js.map +1 -1
  78. package/lib/gc/gcHelpers.d.ts +5 -4
  79. package/lib/gc/gcHelpers.d.ts.map +1 -1
  80. package/lib/gc/gcHelpers.js +12 -1
  81. package/lib/gc/gcHelpers.js.map +1 -1
  82. package/lib/gc/gcTelemetry.d.ts +13 -2
  83. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  84. package/lib/gc/gcTelemetry.js +24 -21
  85. package/lib/gc/gcTelemetry.js.map +1 -1
  86. package/lib/gc/index.d.ts +2 -2
  87. package/lib/gc/index.d.ts.map +1 -1
  88. package/lib/gc/index.js +1 -1
  89. package/lib/gc/index.js.map +1 -1
  90. package/lib/index.d.ts +2 -2
  91. package/lib/index.d.ts.map +1 -1
  92. package/lib/index.js +1 -1
  93. package/lib/index.js.map +1 -1
  94. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  95. package/lib/opLifecycle/outbox.js +8 -5
  96. package/lib/opLifecycle/outbox.js.map +1 -1
  97. package/lib/packageVersion.d.ts +1 -1
  98. package/lib/packageVersion.js +1 -1
  99. package/lib/packageVersion.js.map +1 -1
  100. package/lib/test/gc/garbageCollection.spec.js +23 -14
  101. package/lib/test/gc/garbageCollection.spec.js.map +1 -1
  102. package/lib/test/gc/gcHelpers.spec.js +69 -1
  103. package/lib/test/gc/gcHelpers.spec.js.map +1 -1
  104. package/lib/test/gc/gcTelemetry.spec.js +31 -3
  105. package/lib/test/gc/gcTelemetry.spec.js.map +1 -1
  106. package/package.json +16 -16
  107. package/src/channelCollection.ts +107 -43
  108. package/src/containerRuntime.ts +17 -23
  109. package/src/dataStoreContext.ts +14 -2
  110. package/src/dataStoreContexts.ts +12 -0
  111. package/src/gc/garbageCollection.ts +63 -41
  112. package/src/gc/gcDefinitions.ts +21 -9
  113. package/src/gc/gcHelpers.ts +14 -1
  114. package/src/gc/gcTelemetry.ts +56 -47
  115. package/src/gc/index.ts +2 -1
  116. package/src/index.ts +3 -0
  117. package/src/opLifecycle/outbox.ts +8 -6
  118. package/src/packageVersion.ts +1 -1
@@ -11,6 +11,7 @@ import {
11
11
  tagCodeArtifacts,
12
12
  type ITelemetryGenericEventExt,
13
13
  } from "@fluidframework/telemetry-utils";
14
+ import type { Tagged } from "@fluidframework/core-interfaces";
14
15
  import { RuntimeHeaderData } from "../containerRuntime.js";
15
16
  import { ICreateContainerMetadata } from "../summary/index.js";
16
17
  import {
@@ -38,11 +39,12 @@ interface ICommonProps {
38
39
 
39
40
  /** The event that is logged when unreferenced node is used after a certain time. */
40
41
  interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps {
42
+ /** The id that GC uses to track the node. May or may not match id */
43
+ trackedId: string;
41
44
  state: UnreferencedState;
42
- id: {
43
- value: string;
44
- tag: string;
45
- };
45
+ /** The full path (in GC Path format) to the node in question */
46
+ id: Tagged<string>;
47
+ fromId?: Tagged<string>;
46
48
  type: GCNodeType;
47
49
  unrefTime: number;
48
50
  age: number;
@@ -51,19 +53,24 @@ interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps
51
53
  [K in keyof GCFeatureMatrix]: GCFeatureMatrix[K];
52
54
  };
53
55
  timeout?: number;
54
- fromId?: {
55
- value: string;
56
- tag: string;
57
- };
58
56
  }
59
57
 
60
58
  /** Properties passed to nodeUsed function when a node is used. */
61
59
  interface INodeUsageProps extends ICommonProps {
60
+ /** The full path (in GC Path format) to the node in question */
62
61
  id: string;
62
+ /** Latest timestamp received from the server, as a baseline for computing GC state/age */
63
63
  currentReferenceTimestampMs: number | undefined;
64
+ /** The package path of the node. This may not be available if the node hasn't been loaded yet */
64
65
  packagePath: readonly string[] | undefined;
66
+ /** In case of Revived - what node added the reference? */
65
67
  fromId?: string;
68
+ /** In case of Revived - was it revived due to autorecovery? */
66
69
  autorecovery?: true;
70
+ /** URL (including query string) if this usage came from a request */
71
+ requestUrl?: string;
72
+ /** Original request headers if this usage came from a request or handle.get */
73
+ requestHeaders?: string;
67
74
  }
68
75
 
69
76
  /**
@@ -138,18 +145,34 @@ export class GCTelemetryTracker {
138
145
  }
139
146
 
140
147
  /**
141
- * Called when a node is used. If the node is not active or tombstoned, log telemetry indicating object is used
148
+ * Called when a node is used. If the node is inactive or tombstoned, log telemetry indicating object is used
142
149
  * when it should not have been.
150
+ * @param trackedId - The id that GC uses to track the node. For SubDataStore nodes, this should be the DataStore ID.
151
+ * @param INodeUsageProps - All kind of details about this event to be logged
143
152
  */
144
- public nodeUsed(nodeUsageProps: INodeUsageProps) {
153
+ public nodeUsed(
154
+ trackedId: string,
155
+ {
156
+ usageType,
157
+ currentReferenceTimestampMs,
158
+ packagePath,
159
+ id: untaggedId,
160
+ fromId: untaggedFromId,
161
+ isTombstoned,
162
+ ...otherNodeUsageProps
163
+ }: INodeUsageProps,
164
+ ) {
145
165
  // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
146
166
  // logging as nothing interesting would have happened worth logging.
147
- if (nodeUsageProps.currentReferenceTimestampMs === undefined) {
167
+ if (currentReferenceTimestampMs === undefined) {
148
168
  return;
149
169
  }
150
170
 
151
- const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
152
- const nodeType = this.getNodeType(nodeUsageProps.id);
171
+ // Note: For SubDataStore Load usage, trackedId will be the DataStore's id, not the full path in question.
172
+ // This is necessary because the SubDataStore path may be unrecognized by GC (if suited for a custom request handler)
173
+ const nodeStateTracker = this.getNodeStateTracker(trackedId);
174
+ const nodeType = this.getNodeType(untaggedId);
175
+
153
176
  const timeout = (() => {
154
177
  switch (nodeStateTracker?.state) {
155
178
  case UnreferencedState.Inactive:
@@ -165,33 +188,27 @@ export class GCTelemetryTracker {
165
188
  return undefined;
166
189
  }
167
190
  })();
168
- const {
169
- usageType,
170
- currentReferenceTimestampMs,
171
- packagePath,
172
- id: untaggedId,
173
- fromId: untaggedFromId,
174
- ...propsToLog
175
- } = nodeUsageProps;
176
191
  const { persistedGcFeatureMatrix, ...configs } = this.configs;
177
- const unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType"> = {
192
+ const unrefEventProps = {
193
+ trackedId,
178
194
  type: nodeType,
179
195
  unrefTime: nodeStateTracker?.unreferencedTimestampMs ?? -1,
180
196
  age:
181
197
  nodeStateTracker !== undefined
182
- ? nodeUsageProps.currentReferenceTimestampMs -
183
- nodeStateTracker.unreferencedTimestampMs
198
+ ? currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs
184
199
  : -1,
185
200
  timeout,
201
+ isTombstoned,
186
202
  ...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
187
- ...propsToLog,
203
+ ...otherNodeUsageProps,
188
204
  ...this.createContainerMetadata,
189
205
  gcConfigs: { ...configs, ...persistedGcFeatureMatrix },
190
- };
206
+ } satisfies Omit<IUnreferencedEventProps, "state" | "usageType"> &
207
+ typeof otherNodeUsageProps;
191
208
 
192
209
  // If the node that is used is tombstoned, log a tombstone telemetry.
193
- if (nodeUsageProps.isTombstoned) {
194
- this.logTombstoneUsageTelemetry(nodeUsageProps, unrefEventProps, nodeType, usageType);
210
+ if (isTombstoned) {
211
+ this.logTombstoneUsageTelemetry(unrefEventProps, nodeType, usageType, packagePath);
195
212
  }
196
213
 
197
214
  // After logging tombstone telemetry, if the node's unreferenced state is not tracked, there is nothing
@@ -201,16 +218,9 @@ export class GCTelemetryTracker {
201
218
  }
202
219
 
203
220
  const state = nodeStateTracker.state;
204
- const uniqueEventId = `${state}-${nodeUsageProps.id}-${nodeUsageProps.usageType}`;
221
+ const uniqueEventId = `${state}-${untaggedId}-${usageType}`;
205
222
 
206
- if (
207
- !this.shouldLogNonActiveEvent(
208
- nodeType,
209
- nodeUsageProps.usageType,
210
- nodeStateTracker,
211
- uniqueEventId,
212
- )
213
- ) {
223
+ if (!this.shouldLogNonActiveEvent(nodeType, usageType, nodeStateTracker, uniqueEventId)) {
214
224
  return;
215
225
  }
216
226
 
@@ -224,8 +234,8 @@ export class GCTelemetryTracker {
224
234
  // SweepReady errors are usages of Objects that will be deleted by GC Sweep!
225
235
  if (this.isSummarizerClient) {
226
236
  this.pendingEventsQueue.push({
227
- ...unrefEventProps,
228
- usageType: nodeUsageProps.usageType,
237
+ ...unrefEventProps, // Note: Contains some properties from INodeUsageProps as well
238
+ usageType,
229
239
  state,
230
240
  });
231
241
  } else {
@@ -233,11 +243,11 @@ export class GCTelemetryTracker {
233
243
  // summarizer clients if they are based off of user actions (such as scrolling to content for these objects)
234
244
  // Events generated:
235
245
  // InactiveObject_Loaded, SweepReadyObject_Loaded
236
- if (nodeUsageProps.usageType === "Loaded") {
246
+ if (usageType === "Loaded") {
237
247
  const { id, fromId, headers, gcConfigs, ...detailedProps } = unrefEventProps;
238
248
  const event = {
239
- eventName: `${state}Object_${nodeUsageProps.usageType}`,
240
- ...tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }),
249
+ eventName: `${state}Object_${usageType}`,
250
+ ...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
241
251
  stack: generateStack(),
242
252
  id,
243
253
  fromId,
@@ -257,10 +267,10 @@ export class GCTelemetryTracker {
257
267
  * Logs telemetry when a tombstoned object is changed, revived or loaded.
258
268
  */
259
269
  private logTombstoneUsageTelemetry(
260
- nodeUsageProps: INodeUsageProps,
261
270
  unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType">,
262
271
  nodeType: GCNodeType,
263
272
  usageType: NodeUsageType,
273
+ packagePath?: readonly string[],
264
274
  ) {
265
275
  // This will log the following events:
266
276
  // GC_Tombstone_DataStore_Requested, GC_Tombstone_DataStore_Changed, GC_Tombstone_DataStore_Revived
@@ -270,12 +280,12 @@ export class GCTelemetryTracker {
270
280
  const eventUsageName = usageType === "Loaded" ? "Requested" : usageType;
271
281
  const event = {
272
282
  eventName: `GC_Tombstone_${nodeType}_${eventUsageName}`,
273
- pkg: tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }).pkg,
283
+ ...tagCodeArtifacts({ pkg: packagePath?.join("/") }),
274
284
  stack: generateStack(),
275
285
  id,
276
286
  fromId,
277
287
  headers: { ...headers },
278
- details: detailedProps,
288
+ details: detailedProps, // Also includes some properties from INodeUsageProps type
279
289
  gcConfigs,
280
290
  tombstoneFlags: {
281
291
  DisableTombstone: this.mc.config.getBoolean(disableTombstoneKey),
@@ -367,7 +377,6 @@ export class GCTelemetryTracker {
367
377
  // InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
368
378
  // SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
369
379
  for (const eventProps of this.pendingEventsQueue) {
370
- // const { usageType, state, id, fromId, ...propsToLog } = eventProps;
371
380
  const { usageType, state, id, fromId, headers, gcConfigs, ...detailedProps } =
372
381
  eventProps;
373
382
  /**
@@ -376,7 +385,7 @@ export class GCTelemetryTracker {
376
385
  * Loaded and Changed events are logged only if the node is not active. If the node is active, it was
377
386
  * revived and a Revived event will be logged for it.
378
387
  */
379
- const nodeStateTracker = this.getNodeStateTracker(eventProps.id.value);
388
+ const nodeStateTracker = this.getNodeStateTracker(detailedProps.trackedId); // Note: This is never SubDataStore path
380
389
  const active =
381
390
  nodeStateTracker === undefined ||
382
391
  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,
@@ -45,8 +46,8 @@ export {
45
46
  export {
46
47
  cloneGCData,
47
48
  concatGarbageCollectionStates,
48
- trimLeadingAndTrailingSlashes,
49
49
  unpackChildNodesGCDetails,
50
+ urlToGCNodePath,
50
51
  } from "./gcHelpers.js";
51
52
  export { runGarbageCollection } from "./gcReferenceGraphAlgorithm.js";
52
53
  export {
package/src/index.ts CHANGED
@@ -14,12 +14,14 @@ export {
14
14
  RuntimeMessage,
15
15
  agentSchedulerId,
16
16
  ContainerRuntime,
17
+ DeletedResponseHeaderKey,
17
18
  TombstoneResponseHeaderKey,
18
19
  InactiveResponseHeaderKey,
19
20
  ISummaryConfiguration,
20
21
  DefaultSummaryConfiguration,
21
22
  ICompressionRuntimeOptions,
22
23
  CompressionAlgorithms,
24
+ RuntimeHeaderData,
23
25
  } from "./containerRuntime.js";
24
26
  export {
25
27
  ContainerMessageType,
@@ -46,6 +48,7 @@ export {
46
48
  IGCRuntimeOptions,
47
49
  IMarkPhaseStats,
48
50
  ISweepPhaseStats,
51
+ IGCNodeUpdatedProps,
49
52
  IGCStats,
50
53
  } from "./gc/index.js";
51
54
  export {
@@ -335,8 +335,13 @@ export class Outbox {
335
335
  return;
336
336
  }
337
337
 
338
- const processedBatch = this.compressBatch(rawBatch, disableGroupedBatching);
339
- this.sendBatch(processedBatch);
338
+ // Did we disconnect?
339
+ // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
340
+ // Because flush() is a task that executes async (on clean stack), we can get here in disconnected state.
341
+ if (this.params.shouldSend()) {
342
+ const processedBatch = this.compressBatch(rawBatch, disableGroupedBatching);
343
+ this.sendBatch(processedBatch);
344
+ }
340
345
 
341
346
  this.persistBatch(rawBatch.content);
342
347
  }
@@ -424,10 +429,7 @@ export class Outbox {
424
429
  */
425
430
  private sendBatch(batch: IBatch) {
426
431
  const length = batch.content.length;
427
-
428
- // Did we disconnect in the middle of turn-based batch?
429
- // If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
430
- if (length === 0 || !this.params.shouldSend()) {
432
+ if (length === 0) {
431
433
  return;
432
434
  }
433
435
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-rc.2.0.3";
9
+ export const pkgVersion = "2.0.0-rc.2.0.5";