@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.
- 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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"}
|
package/lib/garbageCollection.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
149
|
-
this.
|
|
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 = (
|
|
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 = (
|
|
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 && ((
|
|
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 = (
|
|
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 = (
|
|
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
|
-
|
|
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 /*
|
|
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.
|
|
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
|
-
//
|
|
329
|
-
//
|
|
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 {
|
|
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`,
|
|
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
|
|
452
|
-
// that is now the latest summary.
|
|
453
|
-
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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
|