@fluidframework/container-runtime 0.59.3002 → 0.59.4000-71130

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 (51) hide show
  1. package/dist/batchTracker.js +1 -1
  2. package/dist/batchTracker.js.map +1 -1
  3. package/dist/containerRuntime.d.ts.map +1 -1
  4. package/dist/containerRuntime.js +10 -7
  5. package/dist/containerRuntime.js.map +1 -1
  6. package/dist/dataStoreContext.js +1 -1
  7. package/dist/dataStoreContext.js.map +1 -1
  8. package/dist/dataStores.js +3 -3
  9. package/dist/dataStores.js.map +1 -1
  10. package/dist/garbageCollection.d.ts +23 -10
  11. package/dist/garbageCollection.d.ts.map +1 -1
  12. package/dist/garbageCollection.js +161 -51
  13. package/dist/garbageCollection.js.map +1 -1
  14. package/dist/opTelemetry.js +2 -2
  15. package/dist/opTelemetry.js.map +1 -1
  16. package/dist/packageVersion.d.ts +1 -1
  17. package/dist/packageVersion.d.ts.map +1 -1
  18. package/dist/packageVersion.js +1 -1
  19. package/dist/packageVersion.js.map +1 -1
  20. package/dist/summaryFormat.js +1 -1
  21. package/dist/summaryFormat.js.map +1 -1
  22. package/lib/batchTracker.js +1 -1
  23. package/lib/batchTracker.js.map +1 -1
  24. package/lib/containerRuntime.d.ts.map +1 -1
  25. package/lib/containerRuntime.js +12 -9
  26. package/lib/containerRuntime.js.map +1 -1
  27. package/lib/dataStoreContext.js +1 -1
  28. package/lib/dataStoreContext.js.map +1 -1
  29. package/lib/dataStores.js +3 -3
  30. package/lib/dataStores.js.map +1 -1
  31. package/lib/garbageCollection.d.ts +23 -10
  32. package/lib/garbageCollection.d.ts.map +1 -1
  33. package/lib/garbageCollection.js +139 -48
  34. package/lib/garbageCollection.js.map +1 -1
  35. package/lib/opTelemetry.js +2 -2
  36. package/lib/opTelemetry.js.map +1 -1
  37. package/lib/packageVersion.d.ts +1 -1
  38. package/lib/packageVersion.d.ts.map +1 -1
  39. package/lib/packageVersion.js +1 -1
  40. package/lib/packageVersion.js.map +1 -1
  41. package/lib/summaryFormat.js +1 -1
  42. package/lib/summaryFormat.js.map +1 -1
  43. package/package.json +22 -19
  44. package/src/batchTracker.ts +1 -1
  45. package/src/containerRuntime.ts +21 -8
  46. package/src/dataStoreContext.ts +1 -1
  47. package/src/dataStores.ts +3 -3
  48. package/src/garbageCollection.ts +191 -47
  49. package/src/opTelemetry.ts +2 -2
  50. package/src/packageVersion.ts +1 -1
  51. package/src/summaryFormat.ts +1 -1
@@ -6,12 +6,17 @@ import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
6
  import { ICriticalContainerError } from "@fluidframework/container-definitions";
7
7
  import { IRequestHeader } from "@fluidframework/core-interfaces";
8
8
  import { ISnapshotTree } from "@fluidframework/protocol-definitions";
9
- import { IGarbageCollectionData, IGarbageCollectionDetailsBase, ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
9
+ import { IGarbageCollectionData, IGarbageCollectionDetailsBase, ISummarizeResult } from "@fluidframework/runtime-definitions";
10
10
  import { ReadAndParseBlob, RefreshSummaryResult } from "@fluidframework/runtime-utils";
11
11
  import { IGCRuntimeOptions } from "./containerRuntime";
12
12
  import { IContainerRuntimeMetadata, IGCMetadata } from "./summaryFormat";
13
13
  export declare const gcTreeKey = "gc";
14
14
  export declare const gcBlobPrefix = "__gc";
15
+ export declare const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
16
+ export declare const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
17
+ export declare const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
18
+ export declare const trackGCStateKey = "Fluid.GarbageCollection.TrackGCState";
19
+ export declare const trackGCStateMinimumVersionKey = "Fluid.GarbageCollection.TrackGCState.MinVersion";
15
20
  export declare const defaultSessionExpiryDurationMs: number;
16
21
  /** The statistics of the system state after a garbage collection run. */
17
22
  export interface IGCStats {
@@ -67,6 +72,7 @@ export interface IGarbageCollector {
67
72
  readonly summaryStateNeedsReset: boolean;
68
73
  /** Tells whether GC data should be written to the root of the summary tree. */
69
74
  readonly writeDataAtRoot: boolean;
75
+ readonly trackGCState: boolean;
70
76
  /** Run garbage collection and update the reference / used state of the system. */
71
77
  collectGarbage(options: {
72
78
  logger?: ITelemetryLogger;
@@ -75,7 +81,7 @@ export interface IGarbageCollector {
75
81
  fullGC?: boolean;
76
82
  }): Promise<IGCStats>;
77
83
  /** Summarizes the GC data and returns it as a summary tree. */
78
- summarize(): ISummaryTreeWithStats | undefined;
84
+ summarize(fullTree: boolean, trackState: boolean): ISummarizeResult | undefined;
79
85
  /** Returns the garbage collector specific metadata to be written into the summary. */
80
86
  getMetadata(): IGCMetadata;
81
87
  /** Returns a map of each node id to its base GC details in the base summary. */
@@ -112,7 +118,8 @@ export declare class GarbageCollector implements IGarbageCollector {
112
118
  private readonly getNodePackagePath;
113
119
  /** Returns the timestamp of the last summary generated for this container. */
114
120
  private readonly getLastSummaryTimestampMs;
115
- static create(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions, getNodePackagePath: (nodePath: string) => readonly string[] | undefined, getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata): IGarbageCollector;
121
+ private readonly isSummarizerClient;
122
+ static create(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions, getNodePackagePath: (nodePath: string) => readonly string[] | undefined, getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata: IContainerRuntimeMetadata | undefined, isSummarizerClient: boolean): IGarbageCollector;
116
123
  /**
117
124
  * The time in ms to expire a session for a client for gc.
118
125
  */
@@ -146,6 +153,7 @@ export declare class GarbageCollector implements IGarbageCollector {
146
153
  * can be explicitly disabled via feature flags. It also won't run if session expiry is not enabled.
147
154
  */
148
155
  private readonly shouldRunSweep;
156
+ readonly trackGCState: boolean;
149
157
  private readonly testMode;
150
158
  private readonly mc;
151
159
  /**
@@ -167,19 +175,28 @@ export declare class GarbageCollector implements IGarbageCollector {
167
175
  private readonly currentGCVersion;
168
176
  private latestSummaryGCVersion;
169
177
  private previousGCDataFromLastRun;
178
+ /**
179
+ * Keeps track of the serialized GC blob from the latest summary successfully submitted to the server.
180
+ */
181
+ private latestSerializedSummaryState;
182
+ /**
183
+ * Keeps track of the serialized GC blob from the last GC run of the client.
184
+ */
185
+ private pendingSerializedSummaryState;
170
186
  private readonly newReferencesSinceLastRun;
171
187
  private readonly initializeBaseStateP;
172
188
  private readonly baseGCDetailsP;
173
- private readonly deleteTimeoutMs;
189
+ private readonly inactiveTimeoutMs;
174
190
  private readonly unreferencedNodesState;
175
191
  private sessionExpiryTimer?;
176
192
  private readonly loggedUnreferencedEvents;
177
193
  private readonly pendingEventsQueue;
194
+ private completedRuns;
178
195
  protected constructor(runtime: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions,
179
196
  /** For a given node path, returns the node's package path. */
180
197
  getNodePackagePath: (nodePath: string) => readonly string[] | undefined,
181
198
  /** Returns the timestamp of the last summary generated for this container. */
182
- getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata);
199
+ getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata: IContainerRuntimeMetadata | undefined, isSummarizerClient?: boolean);
183
200
  /**
184
201
  * Runs garbage collection and updates the reference / used state of the nodes in the container.
185
202
  * @returns the number of data stores that have been marked as unreferenced.
@@ -197,7 +214,7 @@ export declare class GarbageCollector implements IGarbageCollector {
197
214
  * We current write the entire GC state in a single blob. This can be modified later to write multiple
198
215
  * blobs. All the blob keys should start with `gcBlobPrefix`.
199
216
  */
200
- summarize(): ISummaryTreeWithStats | undefined;
217
+ summarize(fullTree: boolean, trackState: boolean): ISummarizeResult | undefined;
201
218
  getMetadata(): IGCMetadata;
202
219
  /**
203
220
  * Returns a map of node ids to their base GC details generated from the base summary. This is used by the caller
@@ -227,10 +244,6 @@ export declare class GarbageCollector implements IGarbageCollector {
227
244
  */
228
245
  addedOutboundReference(fromNodePath: string, toNodePath: string): void;
229
246
  dispose(): void;
230
- /**
231
- * Update the latest summary GC version from the metadata blob in the given snapshot.
232
- */
233
- private updateSummaryGCVersionFromSnapshot;
234
247
  /**
235
248
  * Updates the state of the system as per the current GC run. It does the following:
236
249
  * 1. Sets up the current GC state as per the gcData.
@@ -1 +1 @@
1
- {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"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"}
@@ -5,11 +5,14 @@
5
5
  import { assert, LazyPromise, Timer } from "@fluidframework/common-utils";
6
6
  import { ClientSessionExpiredError, DataProcessingError, UsageError } from "@fluidframework/container-utils";
7
7
  import { cloneGCData, concatGarbageCollectionStates, concatGarbageCollectionData, runGarbageCollection, unpackChildNodesGCDetails, } from "@fluidframework/garbage-collector";
8
+ import { SummaryType } from "@fluidframework/protocol-definitions";
8
9
  import { gcBlobKey, } from "@fluidframework/runtime-definitions";
9
- import { SummaryTreeBuilder, } from "@fluidframework/runtime-utils";
10
+ import { mergeStats, SummaryTreeBuilder, } from "@fluidframework/runtime-utils";
10
11
  import { ChildLogger, loggerToMonitoringContext, PerformanceEvent, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
12
+ import * as semver from "semver";
11
13
  import { RuntimeHeaders } from "./containerRuntime";
12
14
  import { getSummaryForDatastores } from "./dataStores";
15
+ import { pkgVersion } from "./packageVersion";
13
16
  import { getGCVersion, metadataBlobName, dataStoreAttributesBlobName, } from "./summaryFormat";
14
17
  /** This is the current version of garbage collection. */
15
18
  const GCVersion = 1;
@@ -26,12 +29,16 @@ const runSweepKey = "Fluid.GarbageCollection.RunSweep";
26
29
  // Feature gate key to write GC data at the root of the summary tree.
27
30
  const writeAtRootKey = "Fluid.GarbageCollection.WriteDataAtRoot";
28
31
  // Feature gate key to expire a session after a set period of time.
29
- const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
32
+ export const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
30
33
  // Feature gate key to disable expiring session after a set period of time, even if expiry value is present
31
- const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
34
+ export const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
32
35
  // Feature gate key to log error messages if GC reference validation fails.
33
- const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
34
- const defaultDeleteTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
36
+ export const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
37
+ // Feature gate key to write the gc blob as a handle if the data is the same.
38
+ export const trackGCStateKey = "Fluid.GarbageCollection.TrackGCState";
39
+ // Feature gate key to limit which versions can write the gc blob as a handle if the data is the same.
40
+ export const trackGCStateMinimumVersionKey = "Fluid.GarbageCollection.TrackGCState.MinVersion";
41
+ const defaultInactiveTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
35
42
  export const defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days
36
43
  /** The types of GC nodes in the GC reference graph. */
37
44
  export const GCNodeType = {
@@ -112,12 +119,13 @@ export class GarbageCollector {
112
119
  /** For a given node path, returns the node's package path. */
113
120
  getNodePackagePath,
114
121
  /** Returns the timestamp of the last summary generated for this container. */
115
- getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
116
- var _a, _b, _c, _d, _e, _f;
122
+ getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient = true) {
123
+ var _a, _b, _c, _d, _e, _f, _g;
117
124
  this.runtime = runtime;
118
125
  this.gcOptions = gcOptions;
119
126
  this.getNodePackagePath = getNodePackagePath;
120
127
  this.getLastSummaryTimestampMs = getLastSummaryTimestampMs;
128
+ this.isSummarizerClient = isSummarizerClient;
121
129
  /**
122
130
  * Tells whether the GC data should be written to the root of the summary tree.
123
131
  */
@@ -145,8 +153,9 @@ export class GarbageCollector {
145
153
  this.loggedUnreferencedEvents = new Set();
146
154
  // Queue for unreferenced events that should be logged the next time GC runs.
147
155
  this.pendingEventsQueue = [];
148
- this.mc = loggerToMonitoringContext(ChildLogger.create(baseLogger, "GarbageCollector"));
149
- this.deleteTimeoutMs = (_a = this.gcOptions.deleteTimeoutMs) !== null && _a !== void 0 ? _a : defaultDeleteTimeoutMs;
156
+ // The number of times GC has successfully completed on this instance of GarbageCollector.
157
+ this.completedRuns = 0;
158
+ this.mc = loggerToMonitoringContext(ChildLogger.create(baseLogger, "GarbageCollector", { all: { completedGCRuns: () => this.completedRuns } }));
150
159
  let prevSummaryGCVersion;
151
160
  /**
152
161
  * The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
@@ -160,7 +169,7 @@ export class GarbageCollector {
160
169
  // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
161
170
  // other existing documents, GC is enabled.
162
171
  this.gcEnabled = prevSummaryGCVersion > 0;
163
- this.sweepEnabled = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.sweepEnabled) !== null && _b !== void 0 ? _b : false;
172
+ this.sweepEnabled = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.sweepEnabled) !== null && _a !== void 0 ? _a : false;
164
173
  this.sessionExpiryTimeoutMs = metadata === null || metadata === void 0 ? void 0 : metadata.sessionExpiryTimeoutMs;
165
174
  }
166
175
  else {
@@ -201,20 +210,26 @@ export class GarbageCollector {
201
210
  * 2. GC should not be disabled via disableGC GC option.
202
211
  * These conditions can be overridden via runGCKey feature flag.
203
212
  */
204
- this.shouldRunGC = (_c = this.mc.config.getBoolean(runGCKey)) !== null && _c !== void 0 ? _c : (
213
+ this.shouldRunGC = (_b = this.mc.config.getBoolean(runGCKey)) !== null && _b !== void 0 ? _b : (
205
214
  // GC must be enabled for the document.
206
215
  this.gcEnabled
207
216
  // GC must not be disabled via GC options.
208
217
  && !gcOptions.disableGC);
218
+ const minimumVersion = this.mc.config.getString(trackGCStateMinimumVersionKey);
219
+ const shouldTrackStateForVersion = meetsMinimumVersionRequirement(pkgVersion, minimumVersion);
220
+ this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true && shouldTrackStateForVersion;
209
221
  /**
210
222
  * Whether sweep should run or not. The following conditions have to be met to run sweep:
211
223
  * 1. Overall GC or mark phase must be enabled (this.shouldRunGC).
212
224
  * 2. Session expiry and sweep should be enabled for this container. Without session expiry we cannot safely
213
225
  * delete unreferenced objects. This condition (#2) can be overridden via runSweepKey feature flag.
214
226
  */
215
- this.shouldRunSweep = this.shouldRunGC && ((_d = this.mc.config.getBoolean(runSweepKey)) !== null && _d !== void 0 ? _d : (this.sessionExpiryTimeoutMs !== undefined && this.sweepEnabled));
227
+ this.shouldRunSweep = this.shouldRunGC && ((_c = this.mc.config.getBoolean(runSweepKey)) !== null && _c !== void 0 ? _c : (this.sessionExpiryTimeoutMs !== undefined && this.sweepEnabled));
228
+ // Override inactive timeout if test config or gc options to override it is set.
229
+ this.inactiveTimeoutMs =
230
+ (_e = (_d = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _d !== void 0 ? _d : this.gcOptions.inactiveTimeoutMs) !== null && _e !== void 0 ? _e : defaultInactiveTimeoutMs;
216
231
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
217
- this.testMode = (_e = this.mc.config.getBoolean(gcTestModeKey)) !== null && _e !== void 0 ? _e : gcOptions.runGCInTestMode === true;
232
+ this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : gcOptions.runGCInTestMode === true;
218
233
  /**
219
234
  * Enable resetting initial state once the following issue is resolved:
220
235
  * https://github.com/microsoft/FluidFramework/issues/8878.
@@ -226,7 +241,7 @@ export class GarbageCollector {
226
241
  // this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;
227
242
  // If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that
228
243
  // the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.
229
- this._writeDataAtRoot = (_f = this.mc.config.getBoolean(writeAtRootKey)) !== null && _f !== void 0 ? _f : this.gcOptions.writeDataAtRoot === true;
244
+ this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : this.gcOptions.writeDataAtRoot === true;
230
245
  // Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do
231
246
  // this once since it involves fetching blobs from storage which is expensive.
232
247
  const baseSummaryStateP = new LazyPromise(async () => {
@@ -239,7 +254,11 @@ export class GarbageCollector {
239
254
  if (gcSnapshotTree !== undefined) {
240
255
  // If the GC tree is written at root, we should also do the same.
241
256
  this._writeDataAtRoot = true;
242
- return getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
257
+ const baseGCState = await getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
258
+ if (this.trackGCState) {
259
+ this.latestSerializedSummaryState = JSON.stringify(generateSortedGCState(baseGCState));
260
+ }
261
+ return baseGCState;
243
262
  }
244
263
  // back-compat - Older documents will have the GC blobs in each data store's summary tree. Get them and
245
264
  // consolidate into IGarbageCollectionState format.
@@ -270,7 +289,7 @@ export class GarbageCollector {
270
289
  const rootId = id === "/" ? dsRootId : `${dsRootId}${id}`;
271
290
  gcState.gcNodes[rootId] = { outboundRoutes: Array.from(outboundRoutes) };
272
291
  }
273
- assert(gcState.gcNodes[dsRootId] !== undefined, 0x2a9 /* `GC nodes for data store ${dsId} not in GC blob` */);
292
+ assert(gcState.gcNodes[dsRootId] !== undefined, 0x2a9 /* GC nodes for data store not in GC blob */);
274
293
  gcState.gcNodes[dsRootId].unreferencedTimestampMs = gcSummaryDetails.unrefTimestamp;
275
294
  }
276
295
  // If there is only one node (root node just added above), either GC is disabled or we are loading from the
@@ -291,7 +310,7 @@ export class GarbageCollector {
291
310
  const gcNodes = {};
292
311
  for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {
293
312
  if (nodeData.unreferencedTimestampMs !== undefined) {
294
- this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
313
+ this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.inactiveTimeoutMs, currentReferenceTimestampMs));
295
314
  }
296
315
  gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
297
316
  }
@@ -325,24 +344,26 @@ export class GarbageCollector {
325
344
  }
326
345
  return baseGCDetailsMap;
327
346
  });
328
- // Initialize the base state. The base GC data is used to detect and log when inactive / deleted objects are
329
- // used in the container.
347
+ // Log all the GC options and the state determined by the garbage collector. This is interesting only for the
348
+ // summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.
349
+ const gcConfigProps = JSON.stringify(Object.assign({ gcEnabled: this.gcEnabled, sweepEnabled: this.sweepEnabled, runGC: this.shouldRunGC, runSweep: this.shouldRunSweep, writeAtRoot: this._writeDataAtRoot, testMode: this.testMode, sessionExpiry: this.sessionExpiryTimeoutMs, inactiveTimeout: this.inactiveTimeoutMs, existing }, this.gcOptions));
350
+ if (this.isSummarizerClient) {
351
+ this.mc.logger.sendTelemetryEvent({
352
+ eventName: "GarbageCollectorLoaded",
353
+ gcConfigs: gcConfigProps,
354
+ });
355
+ }
356
+ // Initialize the base state that is used to detect when inactive objects are used.
330
357
  if (this.shouldRunGC) {
331
358
  this.initializeBaseStateP.catch((error) => {
332
359
  const dpe = DataProcessingError.wrapIfUnrecognized(error, "FailedToInitializeGC");
333
- dpe.addTelemetryProperties({
334
- gcEnabled: this.gcEnabled,
335
- runSweep: this.shouldRunSweep,
336
- writeAtRoot: this._writeDataAtRoot,
337
- testMode: this.testMode,
338
- sessionExpiry: this.sessionExpiryTimeoutMs,
339
- });
360
+ dpe.addTelemetryProperties({ gcConfigs: gcConfigProps });
340
361
  throw dpe;
341
362
  });
342
363
  }
343
364
  }
344
- static create(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
345
- return new GarbageCollector(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata);
365
+ static create(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient) {
366
+ return new GarbageCollector(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient);
346
367
  }
347
368
  /**
348
369
  * Tells whether the GC state needs to be reset in the next summary. We need to do this if:
@@ -364,7 +385,10 @@ export class GarbageCollector {
364
385
  * @returns the number of data stores that have been marked as unreferenced.
365
386
  */
366
387
  async collectGarbage(options) {
367
- const { logger = this.mc.logger, runSweep = this.shouldRunSweep, fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset, } = options;
388
+ const { runSweep = this.shouldRunSweep, fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset, } = options;
389
+ const logger = options.logger
390
+ ? ChildLogger.create(options.logger, undefined, { all: { completedGCRuns: () => this.completedRuns } })
391
+ : this.mc.logger;
368
392
  return PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
369
393
  await this.initializeBaseStateP;
370
394
  // Let the runtime update its pending state before GC runs.
@@ -389,6 +413,7 @@ export class GarbageCollector {
389
413
  this.runtime.deleteUnusedRoutes(gcResult.deletedNodeIds);
390
414
  }
391
415
  event.end(Object.assign({}, gcStats));
416
+ this.completedRuns++;
392
417
  return gcStats;
393
418
  }, { end: true, cancel: "error" });
394
419
  }
@@ -397,7 +422,7 @@ export class GarbageCollector {
397
422
  * We current write the entire GC state in a single blob. This can be modified later to write multiple
398
423
  * blobs. All the blob keys should start with `gcBlobPrefix`.
399
424
  */
400
- summarize() {
425
+ summarize(fullTree, trackState) {
401
426
  var _a;
402
427
  if (!this.shouldRunGC || this.previousGCDataFromLastRun === undefined) {
403
428
  return;
@@ -409,8 +434,31 @@ export class GarbageCollector {
409
434
  unreferencedTimestampMs: (_a = this.unreferencedNodesState.get(nodeId)) === null || _a === void 0 ? void 0 : _a.unreferencedTimestampMs,
410
435
  };
411
436
  }
437
+ const newSerializedSummaryState = JSON.stringify(generateSortedGCState(gcState));
438
+ /**
439
+ * As an optimization if the GC tree hasn't changed and we're tracking the gc state, return a tree handle
440
+ * instead of returning the whole GC tree. If there are changes, then we want to return the whole tree.
441
+ */
442
+ if (this.trackGCState) {
443
+ this.pendingSerializedSummaryState = newSerializedSummaryState;
444
+ if (this.latestSerializedSummaryState !== undefined &&
445
+ this.latestSerializedSummaryState === newSerializedSummaryState &&
446
+ !fullTree &&
447
+ trackState) {
448
+ const stats = mergeStats();
449
+ stats.handleNodeCount++;
450
+ return {
451
+ summary: {
452
+ type: SummaryType.Handle,
453
+ handle: `/${gcTreeKey}`,
454
+ handleType: SummaryType.Tree,
455
+ },
456
+ stats,
457
+ };
458
+ }
459
+ }
412
460
  const builder = new SummaryTreeBuilder();
413
- builder.addBlob(`${gcBlobPrefix}_root`, JSON.stringify(gcState));
461
+ builder.addBlob(`${gcBlobPrefix}_root`, newSerializedSummaryState);
414
462
  return builder.getSummaryTree();
415
463
  }
416
464
  getMetadata() {
@@ -446,11 +494,29 @@ export class GarbageCollector {
446
494
  // Basically, it was written in the current GC version.
447
495
  if (result.wasSummaryTracked) {
448
496
  this.latestSummaryGCVersion = this.currentGCVersion;
497
+ if (this.trackGCState) {
498
+ this.latestSerializedSummaryState = this.pendingSerializedSummaryState;
499
+ this.pendingSerializedSummaryState = undefined;
500
+ }
449
501
  return;
450
502
  }
451
- // If the summary was not tracked by this client, update latest GC version from the snapshot in the result as
452
- // that is now the latest summary.
453
- await this.updateSummaryGCVersionFromSnapshot(result.snapshot, readAndParseBlob);
503
+ // If the summary was not tracked by this client, update latest GC version and blob from the snapshot in the
504
+ // result as that is now the latest summary.
505
+ const snapshot = result.snapshot;
506
+ const metadataBlobId = snapshot.blobs[metadataBlobName];
507
+ if (metadataBlobId) {
508
+ const metadata = await readAndParseBlob(metadataBlobId);
509
+ this.latestSummaryGCVersion = getGCVersion(metadata);
510
+ }
511
+ const gcSnapshotTree = snapshot.trees[gcTreeKey];
512
+ if (gcSnapshotTree !== undefined && this.trackGCState) {
513
+ const latestGCState = await getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
514
+ this.latestSerializedSummaryState = JSON.stringify(generateSortedGCState(latestGCState));
515
+ }
516
+ else {
517
+ this.latestSerializedSummaryState = undefined;
518
+ }
519
+ this.pendingSerializedSummaryState = undefined;
454
520
  }
455
521
  /**
456
522
  * Called when a node with the given id is updated. If the node is inactive, log an error.
@@ -490,16 +556,6 @@ export class GarbageCollector {
490
556
  this.sessionExpiryTimer = undefined;
491
557
  }
492
558
  }
493
- /**
494
- * Update the latest summary GC version from the metadata blob in the given snapshot.
495
- */
496
- async updateSummaryGCVersionFromSnapshot(snapshot, readAndParseBlob) {
497
- const metadataBlobId = snapshot.blobs[metadataBlobName];
498
- if (metadataBlobId) {
499
- const metadata = await readAndParseBlob(metadataBlobId);
500
- this.latestSummaryGCVersion = getGCVersion(metadata);
501
- }
502
- }
503
559
  /**
504
560
  * Updates the state of the system as per the current GC run. It does the following:
505
561
  * 1. Sets up the current GC state as per the gcData.
@@ -538,7 +594,7 @@ export class GarbageCollector {
538
594
  for (const nodeId of gcResult.deletedNodeIds) {
539
595
  const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
540
596
  if (nodeStateTracker === undefined) {
541
- this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(currentReferenceTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
597
+ this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(currentReferenceTimestampMs, this.inactiveTimeoutMs, currentReferenceTimestampMs));
542
598
  }
543
599
  else {
544
600
  nodeStateTracker.updateTracking(currentReferenceTimestampMs);
@@ -728,23 +784,37 @@ export class GarbageCollector {
728
784
  /**
729
785
  * Logs an event if a node is inactive and is used.
730
786
  */
731
- logIfInactive(eventSuffix, nodeId, currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(), packagePath, requestHeaders) {
787
+ logIfInactive(eventType, nodeId, currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(), packagePath, requestHeaders) {
732
788
  // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
733
789
  // logging as nothing interesting would have happened worth logging.
734
790
  if (currentReferenceTimestampMs === undefined) {
735
791
  return;
736
792
  }
737
- const eventName = `inactiveObject_${eventSuffix}`;
793
+ // We only care about data stores and attachment blobs for this telemetry since GC only marks these objects
794
+ // as unreferenced. Also, if an inactive DDS is used, the corresponding data store store will also be used.
795
+ const nodeType = this.runtime.getNodeType(nodeId);
796
+ if (nodeType !== GCNodeType.DataStore && nodeType !== GCNodeType.Blob) {
797
+ return;
798
+ }
799
+ // For non-summarizer clients, only log "Loaded" type events since these objects may not be loaded in the
800
+ // summarizer clients if they are based off of user actions (such as scrolling to content for these objects).
801
+ if (!this.isSummarizerClient && eventType !== "Loaded") {
802
+ return;
803
+ }
804
+ const eventName = `inactiveObject_${eventType}`;
738
805
  // We log a particular event for a given node only once so that it is not too noisy.
739
806
  const uniqueEventId = `${nodeId}-${eventName}`;
740
807
  const nodeState = this.unreferencedNodesState.get(nodeId);
741
808
  if ((nodeState === null || nodeState === void 0 ? void 0 : nodeState.inactive) && !this.loggedUnreferencedEvents.has(uniqueEventId)) {
742
809
  this.loggedUnreferencedEvents.add(uniqueEventId);
810
+ // Save all the properties at this point in time so that if we log this later, these values are preserved.
743
811
  const event = {
744
812
  eventName,
745
813
  id: nodeId,
814
+ type: nodeType,
746
815
  age: currentReferenceTimestampMs - nodeState.unreferencedTimestampMs,
747
- timeout: this.deleteTimeoutMs,
816
+ timeout: this.inactiveTimeoutMs,
817
+ completedGCRuns: this.completedRuns,
748
818
  lastSummaryTime: this.getLastSummaryTimestampMs(),
749
819
  externalRequest: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[RuntimeHeaders.externalRequest],
750
820
  viaHandle: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[RuntimeHeaders.viaHandle],
@@ -783,6 +853,16 @@ async function getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob) {
783
853
  }
784
854
  return rootGCState;
785
855
  }
856
+ function generateSortedGCState(gcState) {
857
+ const sortableArray = Object.entries(gcState.gcNodes);
858
+ sortableArray.sort(([a], [b]) => a.localeCompare(b));
859
+ const sortedGCState = { gcNodes: {} };
860
+ for (const [nodeId, nodeData] of sortableArray) {
861
+ nodeData.outboundRoutes.sort();
862
+ sortedGCState.gcNodes[nodeId] = nodeData;
863
+ }
864
+ return sortedGCState;
865
+ }
786
866
  /**
787
867
  * setLongTimeout is used for timeouts longer than setTimeout's ~24.8 day max
788
868
  * @param timeoutMs - the total time the timeout needs to last in ms
@@ -802,4 +882,15 @@ function setLongTimeout(timeoutMs, timeoutFn, setTimerFn) {
802
882
  }
803
883
  setTimerFn(timer);
804
884
  }
885
+ /**
886
+ * meetsMinimumVersionRequirement is used determining if a feature version should be run. This is similar to feature
887
+ * flags. The advantage of this is that if we ship a bug in version 0.1.1 and fix it in version 0.2.1. We can keep this
888
+ * feature disabled for version 0.1.1 and enabled for 0.2.1. Older versions will run without the feature and new
889
+ * versions will run with the feature.
890
+ * @param currentVersion - the total time the timeout needs to last in ms
891
+ * @param minimumVersion - the function to execute when the timer ends
892
+ */
893
+ function meetsMinimumVersionRequirement(currentVersion, minimumVersion) {
894
+ return minimumVersion === undefined || semver.compare(currentVersion, minimumVersion) >= 0;
895
+ }
805
896
  //# sourceMappingURL=garbageCollection.js.map