@fluidframework/container-runtime 2.0.0-dev.7.2.0.204906 → 2.0.0-dev.7.3.0.206769

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 (84) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/container-runtime.api.md +4 -7
  3. package/dist/blobManager.d.ts +5 -5
  4. package/dist/blobManager.d.ts.map +1 -1
  5. package/dist/blobManager.js +36 -43
  6. package/dist/blobManager.js.map +1 -1
  7. package/dist/containerRuntime.d.ts +12 -8
  8. package/dist/containerRuntime.d.ts.map +1 -1
  9. package/dist/containerRuntime.js +24 -12
  10. package/dist/containerRuntime.js.map +1 -1
  11. package/dist/dataStoreContext.d.ts +8 -1
  12. package/dist/dataStoreContext.d.ts.map +1 -1
  13. package/dist/dataStoreContext.js +46 -31
  14. package/dist/dataStoreContext.js.map +1 -1
  15. package/dist/dataStores.d.ts +0 -14
  16. package/dist/dataStores.d.ts.map +1 -1
  17. package/dist/dataStores.js +0 -43
  18. package/dist/dataStores.js.map +1 -1
  19. package/dist/deltaManagerProxyBase.d.ts +1 -1
  20. package/dist/deltaManagerProxyBase.d.ts.map +1 -1
  21. package/dist/deltaManagerProxyBase.js +2 -2
  22. package/dist/deltaManagerProxyBase.js.map +1 -1
  23. package/dist/gc/garbageCollection.d.ts +6 -3
  24. package/dist/gc/garbageCollection.d.ts.map +1 -1
  25. package/dist/gc/garbageCollection.js +27 -17
  26. package/dist/gc/garbageCollection.js.map +1 -1
  27. package/dist/gc/gcDefinitions.d.ts +7 -3
  28. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  29. package/dist/gc/gcDefinitions.js.map +1 -1
  30. package/dist/gc/gcTelemetry.d.ts +11 -4
  31. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  32. package/dist/gc/gcTelemetry.js +72 -39
  33. package/dist/gc/gcTelemetry.js.map +1 -1
  34. package/dist/packageVersion.d.ts +1 -1
  35. package/dist/packageVersion.js +1 -1
  36. package/dist/packageVersion.js.map +1 -1
  37. package/lib/blobManager.d.ts +5 -5
  38. package/lib/blobManager.d.ts.map +1 -1
  39. package/lib/blobManager.js +37 -44
  40. package/lib/blobManager.js.map +1 -1
  41. package/lib/containerRuntime.d.ts +12 -8
  42. package/lib/containerRuntime.d.ts.map +1 -1
  43. package/lib/containerRuntime.js +24 -12
  44. package/lib/containerRuntime.js.map +1 -1
  45. package/lib/dataStoreContext.d.ts +8 -1
  46. package/lib/dataStoreContext.d.ts.map +1 -1
  47. package/lib/dataStoreContext.js +46 -31
  48. package/lib/dataStoreContext.js.map +1 -1
  49. package/lib/dataStores.d.ts +0 -14
  50. package/lib/dataStores.d.ts.map +1 -1
  51. package/lib/dataStores.js +1 -44
  52. package/lib/dataStores.js.map +1 -1
  53. package/lib/deltaManagerProxyBase.d.ts +1 -1
  54. package/lib/deltaManagerProxyBase.d.ts.map +1 -1
  55. package/lib/deltaManagerProxyBase.js +2 -2
  56. package/lib/deltaManagerProxyBase.js.map +1 -1
  57. package/lib/gc/garbageCollection.d.ts +6 -3
  58. package/lib/gc/garbageCollection.d.ts.map +1 -1
  59. package/lib/gc/garbageCollection.js +28 -18
  60. package/lib/gc/garbageCollection.js.map +1 -1
  61. package/lib/gc/gcDefinitions.d.ts +7 -3
  62. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  63. package/lib/gc/gcDefinitions.js.map +1 -1
  64. package/lib/gc/gcTelemetry.d.ts +11 -4
  65. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  66. package/lib/gc/gcTelemetry.js +72 -39
  67. package/lib/gc/gcTelemetry.js.map +1 -1
  68. package/lib/packageVersion.d.ts +1 -1
  69. package/lib/packageVersion.js +1 -1
  70. package/lib/packageVersion.js.map +1 -1
  71. package/package.json +19 -19
  72. package/src/blobManager.ts +43 -53
  73. package/src/containerRuntime.ts +41 -19
  74. package/src/dataStoreContext.ts +23 -4
  75. package/src/dataStores.ts +1 -67
  76. package/src/deltaManagerProxyBase.ts +2 -2
  77. package/src/gc/garbageCollection.ts +39 -25
  78. package/src/gc/gcDefinitions.ts +8 -3
  79. package/src/gc/gcTelemetry.ts +102 -54
  80. package/src/packageVersion.ts +1 -1
  81. package/dist/container-runtime-alpha.d.ts +0 -1744
  82. package/dist/container-runtime-beta.d.ts +0 -1744
  83. package/dist/container-runtime-public.d.ts +0 -1744
  84. package/dist/container-runtime-untrimmed.d.ts +0 -1805
@@ -11,6 +11,7 @@ import {
11
11
  MonitoringContext,
12
12
  tagCodeArtifacts,
13
13
  } from "@fluidframework/telemetry-utils";
14
+ import { RuntimeHeaderData } from "../containerRuntime";
14
15
  import { ICreateContainerMetadata } from "../summary";
15
16
  import {
16
17
  disableSweepLogKey,
@@ -32,7 +33,7 @@ interface ICommonProps {
32
33
  completedGCRuns: number;
33
34
  isTombstoned: boolean;
34
35
  lastSummaryTime?: number;
35
- viaHandle?: boolean;
36
+ headers?: RuntimeHeaderData;
36
37
  }
37
38
 
38
39
  /** The event that is logged when unreferenced node is used after a certain time. */
@@ -80,7 +81,11 @@ export class GCTelemetryTracker {
80
81
  private readonly mc: MonitoringContext,
81
82
  private readonly configs: Pick<
82
83
  IGarbageCollectorConfigs,
83
- "inactiveTimeoutMs" | "sweepTimeoutMs" | "tombstoneEnforcementAllowed"
84
+ | "inactiveTimeoutMs"
85
+ | "sweepTimeoutMs"
86
+ | "tombstoneEnforcementAllowed"
87
+ | "throwOnTombstoneLoad"
88
+ | "throwOnTombstoneUsage"
84
89
  >,
85
90
  private readonly isSummarizerClient: boolean,
86
91
  private readonly createContainerMetadata: ICreateContainerMetadata,
@@ -94,12 +99,12 @@ export class GCTelemetryTracker {
94
99
  ) {}
95
100
 
96
101
  /**
97
- * Returns whether an event should be logged for a node that isn't active anymore. Some scenarios where we won't log:
102
+ * Returns whether an event should be logged for a node that isn't active anymore. This does not apply to
103
+ * tombstoned nodes for which an event is always logged. Some scenarios where we won't log:
98
104
  * 1. When a DDS is changed. The corresponding data store's event will be logged instead.
99
105
  * 2. An event is logged only once per container instance per event per node.
100
106
  */
101
107
  private shouldLogNonActiveEvent(
102
- nodeId: string,
103
108
  nodeType: GCNodeType,
104
109
  usageType: NodeUsageType,
105
110
  nodeStateTracker: UnreferencedStateTracker,
@@ -119,6 +124,8 @@ export class GCTelemetryTracker {
119
124
  return false;
120
125
  }
121
126
 
127
+ // Non-tombstone events are logged once per event per node. A unique id is generated by joining
128
+ // node state (inactive / sweep ready), node's id and usage (loaded / changed / revived).
122
129
  if (this.loggedUnreferencedEvents.has(uniqueEventId)) {
123
130
  return false;
124
131
  }
@@ -126,24 +133,61 @@ export class GCTelemetryTracker {
126
133
  }
127
134
 
128
135
  /**
129
- * Called when a node is used. If the node is not active, log an event indicating object is used when its not active.
136
+ * Called when a node is used. If the node is not active or tombstoned, log telemetry indicating object is used
137
+ * when it should not have been.
130
138
  */
131
139
  public nodeUsed(nodeUsageProps: INodeUsageProps) {
132
140
  // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
133
141
  // logging as nothing interesting would have happened worth logging.
134
- // If the node is not unreferenced, skip logging.
135
- const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
136
- if (!nodeStateTracker || nodeUsageProps.currentReferenceTimestampMs === undefined) {
142
+ if (nodeUsageProps.currentReferenceTimestampMs === undefined) {
137
143
  return;
138
144
  }
139
145
 
140
- // We log these events once per event per node. A unique id is generated by joining node state (inactive / sweep ready),
141
- // node's id and usage (loaded / changed / revived).
142
- const uniqueEventId = `${nodeStateTracker.state}-${nodeUsageProps.id}-${nodeUsageProps.usageType}`;
146
+ const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
143
147
  const nodeType = this.getNodeType(nodeUsageProps.id);
148
+ const {
149
+ usageType,
150
+ currentReferenceTimestampMs,
151
+ packagePath,
152
+ id: untaggedId,
153
+ fromId: untaggedFromId,
154
+ ...propsToLog
155
+ } = nodeUsageProps;
156
+ const unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType"> = {
157
+ type: nodeType,
158
+ unrefTime: nodeStateTracker?.unreferencedTimestampMs ?? -1,
159
+ age:
160
+ nodeStateTracker !== undefined
161
+ ? nodeUsageProps.currentReferenceTimestampMs -
162
+ nodeStateTracker.unreferencedTimestampMs
163
+ : -1,
164
+ timeout:
165
+ nodeStateTracker?.state === UnreferencedState.Inactive
166
+ ? this.configs.inactiveTimeoutMs
167
+ : this.configs.sweepTimeoutMs,
168
+ ...tagCodeArtifacts({ id: untaggedId, fromId: untaggedFromId }),
169
+ ...propsToLog,
170
+ ...this.createContainerMetadata,
171
+ };
172
+
173
+ // If the node that is used is tombstoned, log a tombstone telemetry.
174
+ // Note that this is done before checking if "nodeStateTracker" is undefined below because unreferenced
175
+ // tracking may not have yet been enabled. That happens only after the client transitions to write mode.
176
+ if (nodeUsageProps.isTombstoned) {
177
+ this.logTombstoneUsageTelemetry(nodeUsageProps, unrefEventProps, nodeType, usageType);
178
+ }
179
+
180
+ // After logging tombstone telemetry, if the node's unreferenced state is not tracked, there is nothing
181
+ // else to log.
182
+ if (nodeStateTracker === undefined) {
183
+ return;
184
+ }
185
+
186
+ const state = nodeStateTracker.state;
187
+ const uniqueEventId = `${state}-${nodeUsageProps.id}-${nodeUsageProps.usageType}`;
188
+
144
189
  if (
145
190
  !this.shouldLogNonActiveEvent(
146
- nodeUsageProps.id,
147
191
  nodeType,
148
192
  nodeUsageProps.usageType,
149
193
  nodeStateTracker,
@@ -153,42 +197,9 @@ export class GCTelemetryTracker {
153
197
  return;
154
198
  }
155
199
 
156
- // Add the unique event id so that we don't generate a log for this event again in this session..
200
+ // Add the unique event id so that we don't generate a log for this event again in this session.
157
201
  this.loggedUnreferencedEvents.add(uniqueEventId);
158
202
 
159
- const state = nodeStateTracker.state;
160
- const { usageType, currentReferenceTimestampMs, packagePath, id, fromId, ...propsToLog } =
161
- nodeUsageProps;
162
- const eventProps: Omit<IUnreferencedEventProps, "state" | "usageType"> = {
163
- type: nodeType,
164
- unrefTime: nodeStateTracker.unreferencedTimestampMs,
165
- age:
166
- nodeUsageProps.currentReferenceTimestampMs -
167
- nodeStateTracker.unreferencedTimestampMs,
168
- timeout:
169
- state === UnreferencedState.Inactive
170
- ? this.configs.inactiveTimeoutMs
171
- : this.configs.sweepTimeoutMs,
172
- ...tagCodeArtifacts({ id, fromId }),
173
- ...propsToLog,
174
- ...this.createContainerMetadata,
175
- };
176
-
177
- // This will log the following events:
178
- // GC_Tombstone_DataStore_Revived, GC_Tombstone_SubDataStore_Revived, GC_Tombstone_Blob_Revived
179
- if (nodeUsageProps.usageType === "Revived" && nodeUsageProps.isTombstoned) {
180
- sendGCUnexpectedUsageEvent(
181
- this.mc,
182
- {
183
- eventName: `GC_Tombstone_${nodeType}_Revived`,
184
- category: "generic",
185
- ...tagCodeArtifacts({ url: id }),
186
- gcTombstoneEnforcementAllowed: this.configs.tombstoneEnforcementAllowed,
187
- },
188
- undefined /* packagePath */,
189
- );
190
- }
191
-
192
203
  // For summarizer client, queue the event so it is logged the next time GC runs if the event is still valid.
193
204
  // For non-summarizer client, log the event now since GC won't run on it. This may result in false positives
194
205
  // but it's a good signal nonetheless and we can consume it with a grain of salt.
@@ -196,7 +207,7 @@ export class GCTelemetryTracker {
196
207
  // SweepReady errors are usages of Objects that will be deleted by GC Sweep!
197
208
  if (this.isSummarizerClient) {
198
209
  this.pendingEventsQueue.push({
199
- ...eventProps,
210
+ ...unrefEventProps,
200
211
  usageType: nodeUsageProps.usageType,
201
212
  state,
202
213
  });
@@ -206,16 +217,15 @@ export class GCTelemetryTracker {
206
217
  // Events generated:
207
218
  // InactiveObject_Loaded, SweepReadyObject_Loaded
208
219
  if (nodeUsageProps.usageType === "Loaded") {
209
- const { id: taggedId, fromId: taggedFromId, ...otherProps } = eventProps;
220
+ const { id, fromId, headers, ...detailedProps } = unrefEventProps;
210
221
  const event = {
211
222
  eventName: `${state}Object_${nodeUsageProps.usageType}`,
212
- pkg: tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }).pkg,
223
+ ...tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }),
213
224
  stack: generateStack(),
214
- id: taggedId,
215
- fromId: taggedFromId,
216
- details: JSON.stringify({
217
- ...otherProps,
218
- }),
225
+ id,
226
+ fromId,
227
+ headers: { ...headers },
228
+ details: detailedProps,
219
229
  };
220
230
 
221
231
  // Do not log the inactive object x events as error events as they are not the best signal for
@@ -229,6 +239,44 @@ export class GCTelemetryTracker {
229
239
  }
230
240
  }
231
241
 
242
+ /**
243
+ * Logs telemetry when a tombstoned object is changed, revived or loaded.
244
+ */
245
+ private logTombstoneUsageTelemetry(
246
+ nodeUsageProps: INodeUsageProps,
247
+ unrefEventProps: Omit<IUnreferencedEventProps, "state" | "usageType">,
248
+ nodeType: GCNodeType,
249
+ usageType: NodeUsageType,
250
+ ) {
251
+ // This will log the following events:
252
+ // GC_Tombstone_DataStore_Requested, GC_Tombstone_DataStore_Changed, GC_Tombstone_DataStore_Revived
253
+ // GC_Tombstone_SubDataStore_Requested, GC_Tombstone_SubDataStore_Changed, GC_Tombstone_SubDataStore_Revived
254
+ // GC_Tombstone_Blob_Requested, GC_Tombstone_Blob_Changed, GC_Tombstone_Blob_Revived
255
+ const { id, fromId, headers, ...detailedProps } = unrefEventProps;
256
+ const eventUsageName = usageType === "Loaded" ? "Requested" : usageType;
257
+ const event = {
258
+ eventName: `GC_Tombstone_${nodeType}_${eventUsageName}`,
259
+ pkg: tagCodeArtifacts({ pkg: nodeUsageProps.packagePath?.join("/") }).pkg,
260
+ stack: generateStack(),
261
+ id,
262
+ fromId,
263
+ headers: { ...headers },
264
+ details: detailedProps,
265
+ gcTombstoneEnforcementAllowed: this.configs.tombstoneEnforcementAllowed,
266
+ };
267
+
268
+ if (
269
+ (usageType === "Loaded" &&
270
+ this.configs.throwOnTombstoneLoad &&
271
+ !headers?.allowTombstone) ||
272
+ (usageType === "Changed" && this.configs.throwOnTombstoneUsage)
273
+ ) {
274
+ this.mc.logger.sendErrorEvent(event);
275
+ } else {
276
+ this.mc.logger.sendTelemetryEvent(event);
277
+ }
278
+ }
279
+
232
280
  /**
233
281
  * Log all new references or outbound routes in the current graph that haven't been explicitly notified to GC.
234
282
  * The principle is that every new reference or outbound route must be notified to GC via the
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "2.0.0-dev.7.2.0.204906";
9
+ export const pkgVersion = "2.0.0-dev.7.3.0.206769";