@fluidframework/container-runtime 0.59.3003 → 0.59.4000-71128
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.
- package/dist/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +10 -7
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.js +1 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.js +3 -3
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +23 -10
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +161 -51
- package/dist/garbageCollection.js.map +1 -1
- package/dist/opTelemetry.js +2 -2
- package/dist/opTelemetry.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summaryFormat.js +1 -1
- package/dist/summaryFormat.js.map +1 -1
- package/lib/batchTracker.js +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +12 -9
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.js +1 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.js +3 -3
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +23 -10
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +139 -48
- package/lib/garbageCollection.js.map +1 -1
- package/lib/opTelemetry.js +2 -2
- package/lib/opTelemetry.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summaryFormat.js +1 -1
- package/lib/summaryFormat.js.map +1 -1
- package/package.json +22 -19
- package/src/batchTracker.ts +1 -1
- package/src/containerRuntime.ts +21 -8
- package/src/dataStoreContext.ts +1 -1
- package/src/dataStores.ts +3 -3
- package/src/garbageCollection.ts +191 -47
- package/src/opTelemetry.ts +2 -2
- package/src/packageVersion.ts +1 -1
- 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,
|
|
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():
|
|
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
|
-
|
|
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
|
|
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?:
|
|
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():
|
|
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":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAA8B,MAAM,oCAAoC,CAAC;AAElG,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAEhF,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AASjE,OAAO,EAAE,aAAa,
|
|
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
|
-
|
|
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
|
-
|
|
56
|
+
exports.disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
|
|
35
57
|
// Feature gate key to log error messages if GC reference validation fails.
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
152
|
-
this.
|
|
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 = (
|
|
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 = (
|
|
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 && ((
|
|
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 = (
|
|
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 = (
|
|
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
|
-
|
|
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 /*
|
|
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.
|
|
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
|
-
//
|
|
332
|
-
//
|
|
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 {
|
|
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`,
|
|
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
|
|
455
|
-
// that is now the latest summary.
|
|
456
|
-
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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
|