@fluidframework/container-runtime 0.59.3003 → 0.59.4000

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 (49) 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.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/summaryFormat.js +1 -1
  20. package/dist/summaryFormat.js.map +1 -1
  21. package/lib/batchTracker.js +1 -1
  22. package/lib/batchTracker.js.map +1 -1
  23. package/lib/containerRuntime.d.ts.map +1 -1
  24. package/lib/containerRuntime.js +12 -9
  25. package/lib/containerRuntime.js.map +1 -1
  26. package/lib/dataStoreContext.js +1 -1
  27. package/lib/dataStoreContext.js.map +1 -1
  28. package/lib/dataStores.js +3 -3
  29. package/lib/dataStores.js.map +1 -1
  30. package/lib/garbageCollection.d.ts +23 -10
  31. package/lib/garbageCollection.d.ts.map +1 -1
  32. package/lib/garbageCollection.js +139 -48
  33. package/lib/garbageCollection.js.map +1 -1
  34. package/lib/opTelemetry.js +2 -2
  35. package/lib/opTelemetry.js.map +1 -1
  36. package/lib/packageVersion.d.ts +1 -1
  37. package/lib/packageVersion.js +1 -1
  38. package/lib/packageVersion.js.map +1 -1
  39. package/lib/summaryFormat.js +1 -1
  40. package/lib/summaryFormat.js.map +1 -1
  41. package/package.json +22 -19
  42. package/src/batchTracker.ts +1 -1
  43. package/src/containerRuntime.ts +21 -8
  44. package/src/dataStoreContext.ts +1 -1
  45. package/src/dataStores.ts +3 -3
  46. package/src/garbageCollection.ts +191 -47
  47. package/src/opTelemetry.ts +2 -2
  48. package/src/packageVersion.ts +1 -1
  49. 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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"}
@@ -3,16 +3,38 @@
3
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
4
  * Licensed under the MIT License.
5
5
  */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
6
25
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.GarbageCollector = exports.GCNodeType = exports.defaultSessionExpiryDurationMs = exports.gcBlobPrefix = exports.gcTreeKey = void 0;
26
+ exports.GarbageCollector = exports.GCNodeType = exports.defaultSessionExpiryDurationMs = exports.trackGCStateMinimumVersionKey = exports.trackGCStateKey = exports.logUnknownOutboundReferencesKey = exports.disableSessionExpiryKey = exports.runSessionExpiryKey = exports.gcBlobPrefix = exports.gcTreeKey = void 0;
8
27
  const common_utils_1 = require("@fluidframework/common-utils");
9
28
  const container_utils_1 = require("@fluidframework/container-utils");
10
29
  const garbage_collector_1 = require("@fluidframework/garbage-collector");
30
+ const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
11
31
  const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
12
32
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
13
33
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
34
+ const semver = __importStar(require("semver"));
14
35
  const containerRuntime_1 = require("./containerRuntime");
15
36
  const dataStores_1 = require("./dataStores");
37
+ const packageVersion_1 = require("./packageVersion");
16
38
  const summaryFormat_1 = require("./summaryFormat");
17
39
  /** This is the current version of garbage collection. */
18
40
  const GCVersion = 1;
@@ -29,12 +51,16 @@ const runSweepKey = "Fluid.GarbageCollection.RunSweep";
29
51
  // Feature gate key to write GC data at the root of the summary tree.
30
52
  const writeAtRootKey = "Fluid.GarbageCollection.WriteDataAtRoot";
31
53
  // Feature gate key to expire a session after a set period of time.
32
- const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
54
+ exports.runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
33
55
  // Feature gate key to disable expiring session after a set period of time, even if expiry value is present
34
- const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
56
+ exports.disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
35
57
  // Feature gate key to log error messages if GC reference validation fails.
36
- const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
37
- const defaultDeleteTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
58
+ exports.logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
59
+ // Feature gate key to write the gc blob as a handle if the data is the same.
60
+ exports.trackGCStateKey = "Fluid.GarbageCollection.TrackGCState";
61
+ // Feature gate key to limit which versions can write the gc blob as a handle if the data is the same.
62
+ exports.trackGCStateMinimumVersionKey = "Fluid.GarbageCollection.TrackGCState.MinVersion";
63
+ const defaultInactiveTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
38
64
  exports.defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days
39
65
  /** The types of GC nodes in the GC reference graph. */
40
66
  exports.GCNodeType = {
@@ -115,12 +141,13 @@ class GarbageCollector {
115
141
  /** For a given node path, returns the node's package path. */
116
142
  getNodePackagePath,
117
143
  /** Returns the timestamp of the last summary generated for this container. */
118
- getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
119
- var _a, _b, _c, _d, _e, _f;
144
+ getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient = true) {
145
+ var _a, _b, _c, _d, _e, _f, _g;
120
146
  this.runtime = runtime;
121
147
  this.gcOptions = gcOptions;
122
148
  this.getNodePackagePath = getNodePackagePath;
123
149
  this.getLastSummaryTimestampMs = getLastSummaryTimestampMs;
150
+ this.isSummarizerClient = isSummarizerClient;
124
151
  /**
125
152
  * Tells whether the GC data should be written to the root of the summary tree.
126
153
  */
@@ -148,8 +175,9 @@ class GarbageCollector {
148
175
  this.loggedUnreferencedEvents = new Set();
149
176
  // Queue for unreferenced events that should be logged the next time GC runs.
150
177
  this.pendingEventsQueue = [];
151
- this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(baseLogger, "GarbageCollector"));
152
- this.deleteTimeoutMs = (_a = this.gcOptions.deleteTimeoutMs) !== null && _a !== void 0 ? _a : defaultDeleteTimeoutMs;
178
+ // The number of times GC has successfully completed on this instance of GarbageCollector.
179
+ this.completedRuns = 0;
180
+ this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(baseLogger, "GarbageCollector", { all: { completedGCRuns: () => this.completedRuns } }));
153
181
  let prevSummaryGCVersion;
154
182
  /**
155
183
  * The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
@@ -163,7 +191,7 @@ class GarbageCollector {
163
191
  // Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
164
192
  // other existing documents, GC is enabled.
165
193
  this.gcEnabled = prevSummaryGCVersion > 0;
166
- this.sweepEnabled = (_b = metadata === null || metadata === void 0 ? void 0 : metadata.sweepEnabled) !== null && _b !== void 0 ? _b : false;
194
+ this.sweepEnabled = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.sweepEnabled) !== null && _a !== void 0 ? _a : false;
167
195
  this.sessionExpiryTimeoutMs = metadata === null || metadata === void 0 ? void 0 : metadata.sessionExpiryTimeoutMs;
168
196
  }
169
197
  else {
@@ -176,13 +204,13 @@ class GarbageCollector {
176
204
  this.gcEnabled = gcOptions.gcAllowed === true;
177
205
  this.sweepEnabled = gcOptions.sweepAllowed === true;
178
206
  // Set the Session Expiry only if the flag is enabled or the test option is set.
179
- if (this.mc.config.getBoolean(runSessionExpiryKey) && this.gcEnabled) {
207
+ if (this.mc.config.getBoolean(exports.runSessionExpiryKey) && this.gcEnabled) {
180
208
  this.sessionExpiryTimeoutMs = exports.defaultSessionExpiryDurationMs;
181
209
  }
182
210
  }
183
211
  // If session expiry is enabled, we need to close the container when the timeout expires
184
212
  if (this.sessionExpiryTimeoutMs !== undefined
185
- && this.mc.config.getBoolean(disableSessionExpiryKey) !== true) {
213
+ && this.mc.config.getBoolean(exports.disableSessionExpiryKey) !== true) {
186
214
  // If Test Override config is set, override Session Expiry timeout
187
215
  const overrideSessionExpiryTimeoutMs = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.SessionExpiryMs");
188
216
  if (overrideSessionExpiryTimeoutMs !== undefined) {
@@ -204,20 +232,26 @@ class GarbageCollector {
204
232
  * 2. GC should not be disabled via disableGC GC option.
205
233
  * These conditions can be overridden via runGCKey feature flag.
206
234
  */
207
- this.shouldRunGC = (_c = this.mc.config.getBoolean(runGCKey)) !== null && _c !== void 0 ? _c : (
235
+ this.shouldRunGC = (_b = this.mc.config.getBoolean(runGCKey)) !== null && _b !== void 0 ? _b : (
208
236
  // GC must be enabled for the document.
209
237
  this.gcEnabled
210
238
  // GC must not be disabled via GC options.
211
239
  && !gcOptions.disableGC);
240
+ const minimumVersion = this.mc.config.getString(exports.trackGCStateMinimumVersionKey);
241
+ const shouldTrackStateForVersion = meetsMinimumVersionRequirement(packageVersion_1.pkgVersion, minimumVersion);
242
+ this.trackGCState = this.mc.config.getBoolean(exports.trackGCStateKey) === true && shouldTrackStateForVersion;
212
243
  /**
213
244
  * Whether sweep should run or not. The following conditions have to be met to run sweep:
214
245
  * 1. Overall GC or mark phase must be enabled (this.shouldRunGC).
215
246
  * 2. Session expiry and sweep should be enabled for this container. Without session expiry we cannot safely
216
247
  * delete unreferenced objects. This condition (#2) can be overridden via runSweepKey feature flag.
217
248
  */
218
- this.shouldRunSweep = this.shouldRunGC && ((_d = this.mc.config.getBoolean(runSweepKey)) !== null && _d !== void 0 ? _d : (this.sessionExpiryTimeoutMs !== undefined && this.sweepEnabled));
249
+ this.shouldRunSweep = this.shouldRunGC && ((_c = this.mc.config.getBoolean(runSweepKey)) !== null && _c !== void 0 ? _c : (this.sessionExpiryTimeoutMs !== undefined && this.sweepEnabled));
250
+ // Override inactive timeout if test config or gc options to override it is set.
251
+ this.inactiveTimeoutMs =
252
+ (_e = (_d = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _d !== void 0 ? _d : this.gcOptions.inactiveTimeoutMs) !== null && _e !== void 0 ? _e : defaultInactiveTimeoutMs;
219
253
  // Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
220
- this.testMode = (_e = this.mc.config.getBoolean(gcTestModeKey)) !== null && _e !== void 0 ? _e : gcOptions.runGCInTestMode === true;
254
+ this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : gcOptions.runGCInTestMode === true;
221
255
  /**
222
256
  * Enable resetting initial state once the following issue is resolved:
223
257
  * https://github.com/microsoft/FluidFramework/issues/8878.
@@ -229,7 +263,7 @@ class GarbageCollector {
229
263
  // this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;
230
264
  // If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that
231
265
  // the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.
232
- this._writeDataAtRoot = (_f = this.mc.config.getBoolean(writeAtRootKey)) !== null && _f !== void 0 ? _f : this.gcOptions.writeDataAtRoot === true;
266
+ this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : this.gcOptions.writeDataAtRoot === true;
233
267
  // Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do
234
268
  // this once since it involves fetching blobs from storage which is expensive.
235
269
  const baseSummaryStateP = new common_utils_1.LazyPromise(async () => {
@@ -242,7 +276,11 @@ class GarbageCollector {
242
276
  if (gcSnapshotTree !== undefined) {
243
277
  // If the GC tree is written at root, we should also do the same.
244
278
  this._writeDataAtRoot = true;
245
- return getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
279
+ const baseGCState = await getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
280
+ if (this.trackGCState) {
281
+ this.latestSerializedSummaryState = JSON.stringify(generateSortedGCState(baseGCState));
282
+ }
283
+ return baseGCState;
246
284
  }
247
285
  // back-compat - Older documents will have the GC blobs in each data store's summary tree. Get them and
248
286
  // consolidate into IGarbageCollectionState format.
@@ -273,7 +311,7 @@ class GarbageCollector {
273
311
  const rootId = id === "/" ? dsRootId : `${dsRootId}${id}`;
274
312
  gcState.gcNodes[rootId] = { outboundRoutes: Array.from(outboundRoutes) };
275
313
  }
276
- (0, common_utils_1.assert)(gcState.gcNodes[dsRootId] !== undefined, 0x2a9 /* `GC nodes for data store ${dsId} not in GC blob` */);
314
+ (0, common_utils_1.assert)(gcState.gcNodes[dsRootId] !== undefined, 0x2a9 /* GC nodes for data store not in GC blob */);
277
315
  gcState.gcNodes[dsRootId].unreferencedTimestampMs = gcSummaryDetails.unrefTimestamp;
278
316
  }
279
317
  // If there is only one node (root node just added above), either GC is disabled or we are loading from the
@@ -294,7 +332,7 @@ class GarbageCollector {
294
332
  const gcNodes = {};
295
333
  for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {
296
334
  if (nodeData.unreferencedTimestampMs !== undefined) {
297
- this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
335
+ this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.inactiveTimeoutMs, currentReferenceTimestampMs));
298
336
  }
299
337
  gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
300
338
  }
@@ -328,24 +366,26 @@ class GarbageCollector {
328
366
  }
329
367
  return baseGCDetailsMap;
330
368
  });
331
- // Initialize the base state. The base GC data is used to detect and log when inactive / deleted objects are
332
- // used in the container.
369
+ // Log all the GC options and the state determined by the garbage collector. This is interesting only for the
370
+ // summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.
371
+ 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));
372
+ if (this.isSummarizerClient) {
373
+ this.mc.logger.sendTelemetryEvent({
374
+ eventName: "GarbageCollectorLoaded",
375
+ gcConfigs: gcConfigProps,
376
+ });
377
+ }
378
+ // Initialize the base state that is used to detect when inactive objects are used.
333
379
  if (this.shouldRunGC) {
334
380
  this.initializeBaseStateP.catch((error) => {
335
381
  const dpe = container_utils_1.DataProcessingError.wrapIfUnrecognized(error, "FailedToInitializeGC");
336
- dpe.addTelemetryProperties({
337
- gcEnabled: this.gcEnabled,
338
- runSweep: this.shouldRunSweep,
339
- writeAtRoot: this._writeDataAtRoot,
340
- testMode: this.testMode,
341
- sessionExpiry: this.sessionExpiryTimeoutMs,
342
- });
382
+ dpe.addTelemetryProperties({ gcConfigs: gcConfigProps });
343
383
  throw dpe;
344
384
  });
345
385
  }
346
386
  }
347
- static create(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
348
- return new GarbageCollector(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata);
387
+ static create(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient) {
388
+ return new GarbageCollector(provider, gcOptions, getNodePackagePath, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient);
349
389
  }
350
390
  /**
351
391
  * Tells whether the GC state needs to be reset in the next summary. We need to do this if:
@@ -367,7 +407,10 @@ class GarbageCollector {
367
407
  * @returns the number of data stores that have been marked as unreferenced.
368
408
  */
369
409
  async collectGarbage(options) {
370
- const { logger = this.mc.logger, runSweep = this.shouldRunSweep, fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset, } = options;
410
+ const { runSweep = this.shouldRunSweep, fullGC = this.gcOptions.runFullGC === true || this.summaryStateNeedsReset, } = options;
411
+ const logger = options.logger
412
+ ? telemetry_utils_1.ChildLogger.create(options.logger, undefined, { all: { completedGCRuns: () => this.completedRuns } })
413
+ : this.mc.logger;
371
414
  return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
372
415
  await this.initializeBaseStateP;
373
416
  // Let the runtime update its pending state before GC runs.
@@ -392,6 +435,7 @@ class GarbageCollector {
392
435
  this.runtime.deleteUnusedRoutes(gcResult.deletedNodeIds);
393
436
  }
394
437
  event.end(Object.assign({}, gcStats));
438
+ this.completedRuns++;
395
439
  return gcStats;
396
440
  }, { end: true, cancel: "error" });
397
441
  }
@@ -400,7 +444,7 @@ class GarbageCollector {
400
444
  * We current write the entire GC state in a single blob. This can be modified later to write multiple
401
445
  * blobs. All the blob keys should start with `gcBlobPrefix`.
402
446
  */
403
- summarize() {
447
+ summarize(fullTree, trackState) {
404
448
  var _a;
405
449
  if (!this.shouldRunGC || this.previousGCDataFromLastRun === undefined) {
406
450
  return;
@@ -412,8 +456,31 @@ class GarbageCollector {
412
456
  unreferencedTimestampMs: (_a = this.unreferencedNodesState.get(nodeId)) === null || _a === void 0 ? void 0 : _a.unreferencedTimestampMs,
413
457
  };
414
458
  }
459
+ const newSerializedSummaryState = JSON.stringify(generateSortedGCState(gcState));
460
+ /**
461
+ * As an optimization if the GC tree hasn't changed and we're tracking the gc state, return a tree handle
462
+ * instead of returning the whole GC tree. If there are changes, then we want to return the whole tree.
463
+ */
464
+ if (this.trackGCState) {
465
+ this.pendingSerializedSummaryState = newSerializedSummaryState;
466
+ if (this.latestSerializedSummaryState !== undefined &&
467
+ this.latestSerializedSummaryState === newSerializedSummaryState &&
468
+ !fullTree &&
469
+ trackState) {
470
+ const stats = (0, runtime_utils_1.mergeStats)();
471
+ stats.handleNodeCount++;
472
+ return {
473
+ summary: {
474
+ type: protocol_definitions_1.SummaryType.Handle,
475
+ handle: `/${exports.gcTreeKey}`,
476
+ handleType: protocol_definitions_1.SummaryType.Tree,
477
+ },
478
+ stats,
479
+ };
480
+ }
481
+ }
415
482
  const builder = new runtime_utils_1.SummaryTreeBuilder();
416
- builder.addBlob(`${exports.gcBlobPrefix}_root`, JSON.stringify(gcState));
483
+ builder.addBlob(`${exports.gcBlobPrefix}_root`, newSerializedSummaryState);
417
484
  return builder.getSummaryTree();
418
485
  }
419
486
  getMetadata() {
@@ -449,11 +516,29 @@ class GarbageCollector {
449
516
  // Basically, it was written in the current GC version.
450
517
  if (result.wasSummaryTracked) {
451
518
  this.latestSummaryGCVersion = this.currentGCVersion;
519
+ if (this.trackGCState) {
520
+ this.latestSerializedSummaryState = this.pendingSerializedSummaryState;
521
+ this.pendingSerializedSummaryState = undefined;
522
+ }
452
523
  return;
453
524
  }
454
- // If the summary was not tracked by this client, update latest GC version from the snapshot in the result as
455
- // that is now the latest summary.
456
- await this.updateSummaryGCVersionFromSnapshot(result.snapshot, readAndParseBlob);
525
+ // If the summary was not tracked by this client, update latest GC version and blob from the snapshot in the
526
+ // result as that is now the latest summary.
527
+ const snapshot = result.snapshot;
528
+ const metadataBlobId = snapshot.blobs[summaryFormat_1.metadataBlobName];
529
+ if (metadataBlobId) {
530
+ const metadata = await readAndParseBlob(metadataBlobId);
531
+ this.latestSummaryGCVersion = (0, summaryFormat_1.getGCVersion)(metadata);
532
+ }
533
+ const gcSnapshotTree = snapshot.trees[exports.gcTreeKey];
534
+ if (gcSnapshotTree !== undefined && this.trackGCState) {
535
+ const latestGCState = await getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob);
536
+ this.latestSerializedSummaryState = JSON.stringify(generateSortedGCState(latestGCState));
537
+ }
538
+ else {
539
+ this.latestSerializedSummaryState = undefined;
540
+ }
541
+ this.pendingSerializedSummaryState = undefined;
457
542
  }
458
543
  /**
459
544
  * Called when a node with the given id is updated. If the node is inactive, log an error.
@@ -493,16 +578,6 @@ class GarbageCollector {
493
578
  this.sessionExpiryTimer = undefined;
494
579
  }
495
580
  }
496
- /**
497
- * Update the latest summary GC version from the metadata blob in the given snapshot.
498
- */
499
- async updateSummaryGCVersionFromSnapshot(snapshot, readAndParseBlob) {
500
- const metadataBlobId = snapshot.blobs[summaryFormat_1.metadataBlobName];
501
- if (metadataBlobId) {
502
- const metadata = await readAndParseBlob(metadataBlobId);
503
- this.latestSummaryGCVersion = (0, summaryFormat_1.getGCVersion)(metadata);
504
- }
505
- }
506
581
  /**
507
582
  * Updates the state of the system as per the current GC run. It does the following:
508
583
  * 1. Sets up the current GC state as per the gcData.
@@ -541,7 +616,7 @@ class GarbageCollector {
541
616
  for (const nodeId of gcResult.deletedNodeIds) {
542
617
  const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
543
618
  if (nodeStateTracker === undefined) {
544
- this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(currentReferenceTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
619
+ this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(currentReferenceTimestampMs, this.inactiveTimeoutMs, currentReferenceTimestampMs));
545
620
  }
546
621
  else {
547
622
  nodeStateTracker.updateTracking(currentReferenceTimestampMs);
@@ -565,7 +640,7 @@ class GarbageCollector {
565
640
  const missingExplicitReferences = this.findMissingExplicitReferences(currentGCData, this.previousGCDataFromLastRun, this.newReferencesSinceLastRun);
566
641
  // The following log will be enabled once this issue is resolved:
567
642
  // https://github.com/microsoft/FluidFramework/issues/8878.
568
- if (this.mc.config.getBoolean(logUnknownOutboundReferencesKey) === true
643
+ if (this.mc.config.getBoolean(exports.logUnknownOutboundReferencesKey) === true
569
644
  && missingExplicitReferences.length > 0) {
570
645
  missingExplicitReferences.forEach((missingExplicitReference) => {
571
646
  const event = {
@@ -731,23 +806,37 @@ class GarbageCollector {
731
806
  /**
732
807
  * Logs an event if a node is inactive and is used.
733
808
  */
734
- logIfInactive(eventSuffix, nodeId, currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(), packagePath, requestHeaders) {
809
+ logIfInactive(eventType, nodeId, currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs(), packagePath, requestHeaders) {
735
810
  // If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
736
811
  // logging as nothing interesting would have happened worth logging.
737
812
  if (currentReferenceTimestampMs === undefined) {
738
813
  return;
739
814
  }
740
- const eventName = `inactiveObject_${eventSuffix}`;
815
+ // We only care about data stores and attachment blobs for this telemetry since GC only marks these objects
816
+ // as unreferenced. Also, if an inactive DDS is used, the corresponding data store store will also be used.
817
+ const nodeType = this.runtime.getNodeType(nodeId);
818
+ if (nodeType !== exports.GCNodeType.DataStore && nodeType !== exports.GCNodeType.Blob) {
819
+ return;
820
+ }
821
+ // For non-summarizer clients, only log "Loaded" type events since these objects may not be loaded in the
822
+ // summarizer clients if they are based off of user actions (such as scrolling to content for these objects).
823
+ if (!this.isSummarizerClient && eventType !== "Loaded") {
824
+ return;
825
+ }
826
+ const eventName = `inactiveObject_${eventType}`;
741
827
  // We log a particular event for a given node only once so that it is not too noisy.
742
828
  const uniqueEventId = `${nodeId}-${eventName}`;
743
829
  const nodeState = this.unreferencedNodesState.get(nodeId);
744
830
  if ((nodeState === null || nodeState === void 0 ? void 0 : nodeState.inactive) && !this.loggedUnreferencedEvents.has(uniqueEventId)) {
745
831
  this.loggedUnreferencedEvents.add(uniqueEventId);
832
+ // Save all the properties at this point in time so that if we log this later, these values are preserved.
746
833
  const event = {
747
834
  eventName,
748
835
  id: nodeId,
836
+ type: nodeType,
749
837
  age: currentReferenceTimestampMs - nodeState.unreferencedTimestampMs,
750
- timeout: this.deleteTimeoutMs,
838
+ timeout: this.inactiveTimeoutMs,
839
+ completedGCRuns: this.completedRuns,
751
840
  lastSummaryTime: this.getLastSummaryTimestampMs(),
752
841
  externalRequest: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[containerRuntime_1.RuntimeHeaders.externalRequest],
753
842
  viaHandle: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[containerRuntime_1.RuntimeHeaders.viaHandle],
@@ -787,6 +876,16 @@ async function getGCStateFromSnapshot(gcSnapshotTree, readAndParseBlob) {
787
876
  }
788
877
  return rootGCState;
789
878
  }
879
+ function generateSortedGCState(gcState) {
880
+ const sortableArray = Object.entries(gcState.gcNodes);
881
+ sortableArray.sort(([a], [b]) => a.localeCompare(b));
882
+ const sortedGCState = { gcNodes: {} };
883
+ for (const [nodeId, nodeData] of sortableArray) {
884
+ nodeData.outboundRoutes.sort();
885
+ sortedGCState.gcNodes[nodeId] = nodeData;
886
+ }
887
+ return sortedGCState;
888
+ }
790
889
  /**
791
890
  * setLongTimeout is used for timeouts longer than setTimeout's ~24.8 day max
792
891
  * @param timeoutMs - the total time the timeout needs to last in ms
@@ -806,4 +905,15 @@ function setLongTimeout(timeoutMs, timeoutFn, setTimerFn) {
806
905
  }
807
906
  setTimerFn(timer);
808
907
  }
908
+ /**
909
+ * meetsMinimumVersionRequirement is used determining if a feature version should be run. This is similar to feature
910
+ * 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
911
+ * feature disabled for version 0.1.1 and enabled for 0.2.1. Older versions will run without the feature and new
912
+ * versions will run with the feature.
913
+ * @param currentVersion - the total time the timeout needs to last in ms
914
+ * @param minimumVersion - the function to execute when the timer ends
915
+ */
916
+ function meetsMinimumVersionRequirement(currentVersion, minimumVersion) {
917
+ return minimumVersion === undefined || semver.compare(currentVersion, minimumVersion) >= 0;
918
+ }
809
919
  //# sourceMappingURL=garbageCollection.js.map