@fluidframework/container-runtime 0.57.0-51086 → 0.58.0-55561
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.d.ts +26 -0
- package/dist/batchTracker.d.ts.map +1 -0
- package/dist/batchTracker.js +59 -0
- package/dist/batchTracker.js.map +1 -0
- package/dist/containerRuntime.d.ts +12 -7
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +125 -55
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +1 -36
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +5 -27
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +5 -7
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +12 -7
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +1 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +3 -3
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +25 -11
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +100 -57
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +1 -6
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runningSummarizer.d.ts +1 -1
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +1 -1
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summarizer.d.ts +3 -4
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +8 -9
- package/dist/summarizer.js.map +1 -1
- package/dist/summaryGenerator.d.ts +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +1 -1
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts +2 -6
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +4 -10
- package/dist/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +26 -0
- package/lib/batchTracker.d.ts.map +1 -0
- package/lib/batchTracker.js +54 -0
- package/lib/batchTracker.js.map +1 -0
- package/lib/containerRuntime.d.ts +12 -7
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +126 -56
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +1 -36
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +4 -26
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +5 -7
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +13 -8
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +1 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +3 -3
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +25 -11
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +98 -55
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +1 -6
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runningSummarizer.d.ts +1 -1
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +1 -1
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summarizer.d.ts +3 -4
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +8 -9
- package/lib/summarizer.js.map +1 -1
- package/lib/summaryGenerator.d.ts +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +1 -1
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts +2 -6
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +5 -11
- package/lib/summaryManager.js.map +1 -1
- package/package.json +12 -12
- package/src/batchTracker.ts +80 -0
- package/src/containerRuntime.ts +180 -63
- package/src/dataStore.ts +6 -42
- package/src/dataStoreContext.ts +17 -15
- package/src/dataStores.ts +9 -4
- package/src/garbageCollection.ts +125 -67
- package/src/index.ts +0 -1
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +4 -8
- package/src/runningSummarizer.ts +3 -3
- package/src/summarizer.ts +8 -8
- package/src/summaryGenerator.ts +2 -2
- package/src/summaryManager.ts +5 -20
|
@@ -12,6 +12,7 @@ import { IGCRuntimeOptions } from "./containerRuntime";
|
|
|
12
12
|
import { IContainerRuntimeMetadata } from "./summaryFormat";
|
|
13
13
|
export declare const gcTreeKey = "gc";
|
|
14
14
|
export declare const gcBlobPrefix = "__gc";
|
|
15
|
+
export declare const defaultSessionExpiryDurationMs: number;
|
|
15
16
|
/** The statistics of the system state after a garbage collection run. */
|
|
16
17
|
export interface IGCStats {
|
|
17
18
|
/** The number of nodes in the container. */
|
|
@@ -35,6 +36,8 @@ export interface IGarbageCollectionRuntime {
|
|
|
35
36
|
getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
|
|
36
37
|
/** After GC has run, called to notify the runtime of routes that are used in it. */
|
|
37
38
|
updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): void;
|
|
39
|
+
/** Called when the runtime should close because of an error. */
|
|
40
|
+
closeFn(error?: ICriticalContainerError): void;
|
|
38
41
|
}
|
|
39
42
|
/** Defines the contract for the garbage collector. */
|
|
40
43
|
export interface IGarbageCollector {
|
|
@@ -66,7 +69,7 @@ export interface IGarbageCollector {
|
|
|
66
69
|
/** Called when the latest summary of the system has been refreshed. */
|
|
67
70
|
latestSummaryStateRefreshed(result: RefreshSummaryResult, readAndParseBlob: ReadAndParseBlob): Promise<void>;
|
|
68
71
|
/** Called when a node is updated. Used to detect and log when an inactive node is changed or loaded. */
|
|
69
|
-
nodeUpdated(nodePath: string, reason: "Loaded" | "Changed", packagePath?: readonly string[], requestHeaders?: IRequestHeader): void;
|
|
72
|
+
nodeUpdated(nodePath: string, reason: "Loaded" | "Changed", timestampMs?: number, packagePath?: readonly string[], requestHeaders?: IRequestHeader): void;
|
|
70
73
|
/** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */
|
|
71
74
|
addedOutboundReference(fromNodePath: string, toNodePath: string): void;
|
|
72
75
|
dispose(): void;
|
|
@@ -82,10 +85,15 @@ export declare class GarbageCollector implements IGarbageCollector {
|
|
|
82
85
|
private readonly deleteUnusedRoutes;
|
|
83
86
|
/** For a given node path, returns the node's package path. */
|
|
84
87
|
private readonly getNodePackagePath;
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Returns a referenced timestamp to be used to track unreferenced nodes. This is a server generated timestamp
|
|
90
|
+
* and may not be available if there aren't any ops processed yet. If so, we skip tracking unreferenced state
|
|
91
|
+
* such as time when node becomes unreferenced or inactive.
|
|
92
|
+
*/
|
|
93
|
+
private readonly getCurrentReferenceTimestampMs;
|
|
94
|
+
/** Returns the timestamp of the last summary generated for this container. */
|
|
95
|
+
private readonly getLastSummaryTimestampMs;
|
|
96
|
+
static create(provider: IGarbageCollectionRuntime, gcOptions: IGCRuntimeOptions, deleteUnusedRoutes: (unusedRoutes: string[]) => void, getNodePackagePath: (nodeId: string) => readonly string[] | undefined, getCurrentReferenceTimestampMs: () => number | undefined, getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata): IGarbageCollector;
|
|
89
97
|
/**
|
|
90
98
|
* Tells whether GC should be run based on the GC options and local storage flags.
|
|
91
99
|
*/
|
|
@@ -149,8 +157,14 @@ export declare class GarbageCollector implements IGarbageCollector {
|
|
|
149
157
|
deleteUnusedRoutes: (unusedRoutes: string[]) => void,
|
|
150
158
|
/** For a given node path, returns the node's package path. */
|
|
151
159
|
getNodePackagePath: (nodePath: string) => readonly string[] | undefined,
|
|
152
|
-
/**
|
|
153
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Returns a referenced timestamp to be used to track unreferenced nodes. This is a server generated timestamp
|
|
162
|
+
* and may not be available if there aren't any ops processed yet. If so, we skip tracking unreferenced state
|
|
163
|
+
* such as time when node becomes unreferenced or inactive.
|
|
164
|
+
*/
|
|
165
|
+
getCurrentReferenceTimestampMs: () => number | undefined,
|
|
166
|
+
/** Returns the timestamp of the last summary generated for this container. */
|
|
167
|
+
getLastSummaryTimestampMs: () => number | undefined, baseSnapshot: ISnapshotTree | undefined, readAndParseBlob: ReadAndParseBlob, baseLogger: ITelemetryLogger, existing: boolean, metadata?: IContainerRuntimeMetadata);
|
|
154
168
|
/**
|
|
155
169
|
* Runs garbage collection and udpates the reference / used state of the nodes in the container.
|
|
156
170
|
* @returns the number of data stores that have been marked as unreferenced.
|
|
@@ -183,10 +197,11 @@ export declare class GarbageCollector implements IGarbageCollector {
|
|
|
183
197
|
* Called when a node with the given id is updated. If the node is inactive, log an error.
|
|
184
198
|
* @param nodePath - The id of the node that changed.
|
|
185
199
|
* @param reason - Whether the node was loaded or changed.
|
|
200
|
+
* @param timestampMs - The timestamp when the node changed.
|
|
186
201
|
* @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.
|
|
187
202
|
* @param requestHeaders - If the node was loaded via request path, the headers in the request.
|
|
188
203
|
*/
|
|
189
|
-
nodeUpdated(nodePath: string, reason: "Loaded" | "Changed", packagePath?: readonly string[], requestHeaders?: IRequestHeader): void;
|
|
204
|
+
nodeUpdated(nodePath: string, reason: "Loaded" | "Changed", timestampMs?: number, packagePath?: readonly string[], requestHeaders?: IRequestHeader): void;
|
|
190
205
|
/**
|
|
191
206
|
* Called when an outbound reference is added to a node. This is used to identify all nodes that have been
|
|
192
207
|
* referenced between summaries so that their unreferenced timestamp can be reset.
|
|
@@ -207,7 +222,7 @@ export declare class GarbageCollector implements IGarbageCollector {
|
|
|
207
222
|
* 3. Clears tracking for nodes that were unreferenced but became referenced in this run.
|
|
208
223
|
* @param gcData - The data representing the reference graph on which GC is run.
|
|
209
224
|
* @param gcResult - The result of the GC run on the gcData.
|
|
210
|
-
* @param
|
|
225
|
+
* @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.
|
|
211
226
|
*/
|
|
212
227
|
private updateCurrentState;
|
|
213
228
|
/**
|
|
@@ -236,8 +251,7 @@ export declare class GarbageCollector implements IGarbageCollector {
|
|
|
236
251
|
*/
|
|
237
252
|
private generateStatsAndLogEvents;
|
|
238
253
|
/**
|
|
239
|
-
* Logs an event if a node is inactive and is used.
|
|
240
|
-
* queue it and it will be logged the next time GC runs as the package data should be available then.
|
|
254
|
+
* Logs an event if a node is inactive and is used.
|
|
241
255
|
*/
|
|
242
256
|
private logIfInactive;
|
|
243
257
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAEhF,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AASjE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAEH,sBAAsB,EAEtB,6BAA6B,EAC7B,qBAAqB,EACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACH,gBAAgB,EAChB,oBAAoB,EAEvB,MAAM,+BAA+B,CAAC;AAUvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAGH,yBAAyB,EAI5B,MAAM,iBAAiB,CAAC;AAMzB,eAAO,MAAM,SAAS,OAAO,CAAC;AAE9B,eAAO,MAAM,YAAY,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"garbageCollection.d.ts","sourceRoot":"","sources":["../src/garbageCollection.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.GarbageCollector = exports.gcBlobPrefix = exports.gcTreeKey = void 0;
|
|
7
|
+
exports.GarbageCollector = exports.defaultSessionExpiryDurationMs = exports.gcBlobPrefix = exports.gcTreeKey = void 0;
|
|
8
8
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
9
9
|
const container_utils_1 = require("@fluidframework/container-utils");
|
|
10
10
|
const garbage_collector_1 = require("@fluidframework/garbage-collector");
|
|
@@ -31,30 +31,48 @@ const writeAtRootKey = "Fluid.GarbageCollection.WriteDataAtRoot";
|
|
|
31
31
|
// Feature gate key to expire a session after a set period of time.
|
|
32
32
|
const runSessionExpiry = "Fluid.GarbageCollection.RunSessionExpiry";
|
|
33
33
|
const defaultDeleteTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
34
|
-
|
|
34
|
+
exports.defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
35
35
|
;
|
|
36
36
|
/**
|
|
37
37
|
* Helper class that tracks the state of an unreferenced node such as the time it was unreferenced. It also sets
|
|
38
38
|
* the node's state to inactive if it remains unreferenced for a given amount of time (inactiveTimeoutMs).
|
|
39
39
|
*/
|
|
40
40
|
class UnreferencedStateTracker {
|
|
41
|
-
constructor(unreferencedTimestampMs, inactiveTimeoutMs) {
|
|
41
|
+
constructor(unreferencedTimestampMs, inactiveTimeoutMs, currentReferenceTimestampMs) {
|
|
42
42
|
this.unreferencedTimestampMs = unreferencedTimestampMs;
|
|
43
|
+
this.inactiveTimeoutMs = inactiveTimeoutMs;
|
|
43
44
|
this._inactive = false;
|
|
44
|
-
// If
|
|
45
|
-
//
|
|
46
|
-
if (
|
|
47
|
-
this.
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
this.timer = new common_utils_1.Timer(inactiveTimeoutMs, () => { this._inactive = true; });
|
|
51
|
-
this.timer.start();
|
|
45
|
+
// If there is no current reference timestamp, don't track the node's inactive state. This will happen later
|
|
46
|
+
// when updateTracking is called with a reference timestamp.
|
|
47
|
+
if (currentReferenceTimestampMs !== undefined) {
|
|
48
|
+
this.updateTracking(currentReferenceTimestampMs);
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
get inactive() {
|
|
55
52
|
return this._inactive;
|
|
56
53
|
}
|
|
57
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Updates the tracking state based on the provided timestamp.
|
|
56
|
+
*/
|
|
57
|
+
updateTracking(currentReferenceTimestampMs) {
|
|
58
|
+
var _a;
|
|
59
|
+
const unreferencedDurationMs = currentReferenceTimestampMs - this.unreferencedTimestampMs;
|
|
60
|
+
// If the timeout has already expired, the node has become inactive.
|
|
61
|
+
if (unreferencedDurationMs > this.inactiveTimeoutMs) {
|
|
62
|
+
this._inactive = true;
|
|
63
|
+
(_a = this.timer) === null || _a === void 0 ? void 0 : _a.clear();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// The node isn't inactive yet. Restart a timer for the duration remaining for it to become inactive.
|
|
67
|
+
const remainingDurationMs = this.inactiveTimeoutMs - unreferencedDurationMs;
|
|
68
|
+
if (this.timer === undefined) {
|
|
69
|
+
this.timer = new common_utils_1.Timer(remainingDurationMs, () => { this._inactive = true; });
|
|
70
|
+
}
|
|
71
|
+
this.timer.restart(remainingDurationMs);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop tracking this node. Reset the unreferenced timer, if any, and reset inactive state.
|
|
75
|
+
*/
|
|
58
76
|
stopTracking() {
|
|
59
77
|
var _a;
|
|
60
78
|
(_a = this.timer) === null || _a === void 0 ? void 0 : _a.clear();
|
|
@@ -71,15 +89,21 @@ class GarbageCollector {
|
|
|
71
89
|
deleteUnusedRoutes,
|
|
72
90
|
/** For a given node path, returns the node's package path. */
|
|
73
91
|
getNodePackagePath,
|
|
74
|
-
/**
|
|
75
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Returns a referenced timestamp to be used to track unreferenced nodes. This is a server generated timestamp
|
|
94
|
+
* and may not be available if there aren't any ops processed yet. If so, we skip tracking unreferenced state
|
|
95
|
+
* such as time when node becomes unreferenced or inactive.
|
|
96
|
+
*/
|
|
97
|
+
getCurrentReferenceTimestampMs,
|
|
98
|
+
/** Returns the timestamp of the last summary generated for this container. */
|
|
99
|
+
getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
|
|
76
100
|
var _a, _b, _c, _d, _e;
|
|
77
101
|
this.provider = provider;
|
|
78
102
|
this.gcOptions = gcOptions;
|
|
79
103
|
this.deleteUnusedRoutes = deleteUnusedRoutes;
|
|
80
104
|
this.getNodePackagePath = getNodePackagePath;
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
105
|
+
this.getCurrentReferenceTimestampMs = getCurrentReferenceTimestampMs;
|
|
106
|
+
this.getLastSummaryTimestampMs = getLastSummaryTimestampMs;
|
|
83
107
|
/**
|
|
84
108
|
* Tells whether the GC data should be written to the root of the summary tree.
|
|
85
109
|
*/
|
|
@@ -125,14 +149,14 @@ class GarbageCollector {
|
|
|
125
149
|
this.gcEnabled = gcOptions.gcAllowed === true;
|
|
126
150
|
// Set the Session Expiry only if the flag is enabled or the test option is set.
|
|
127
151
|
if (this.mc.config.getBoolean(runSessionExpiry) && this.gcEnabled) {
|
|
128
|
-
this.sessionExpiryTimeoutMs = defaultSessionExpiryDurationMs;
|
|
152
|
+
this.sessionExpiryTimeoutMs = exports.defaultSessionExpiryDurationMs;
|
|
129
153
|
}
|
|
130
154
|
}
|
|
131
155
|
// If session expiry is enabled, we need to close the container when the timeout expires
|
|
132
156
|
if (this.sessionExpiryTimeoutMs !== undefined) {
|
|
133
157
|
const timeoutMs = this.sessionExpiryTimeoutMs;
|
|
134
158
|
setLongTimeout(timeoutMs, () => {
|
|
135
|
-
this.closeFn(new container_utils_1.ClientSessionExpiredError(`Client session expired.`, timeoutMs));
|
|
159
|
+
this.provider.closeFn(new container_utils_1.ClientSessionExpiredError(`Client session expired.`, timeoutMs));
|
|
136
160
|
}, (timer) => {
|
|
137
161
|
this.sessionExpiryTimer = timer;
|
|
138
162
|
});
|
|
@@ -215,22 +239,21 @@ class GarbageCollector {
|
|
|
215
239
|
// very first summary generated by detached container. In both cases, GC was not run - return undefined.
|
|
216
240
|
return Object.keys(gcState.gcNodes).length === 1 ? undefined : gcState;
|
|
217
241
|
});
|
|
218
|
-
|
|
219
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Set up the initializer which initializes the base GC state from the base snapshot. Note that the reference
|
|
244
|
+
* timestamp maybe from old ops which were not summarized and stored in the file. So, the unreferenced state
|
|
245
|
+
* may be out of date. This is fine because the state is updated every time GC runs based on the time then.
|
|
246
|
+
*/
|
|
220
247
|
this.initializeBaseStateP = new common_utils_1.LazyPromise(async () => {
|
|
221
|
-
const
|
|
248
|
+
const currentReferenceTimestampMs = this.getCurrentReferenceTimestampMs();
|
|
222
249
|
const baseState = await baseSummaryStateP;
|
|
223
250
|
if (baseState === undefined) {
|
|
224
251
|
return;
|
|
225
252
|
}
|
|
226
253
|
const gcNodes = {};
|
|
227
254
|
for (const [nodeId, nodeData] of Object.entries(baseState.gcNodes)) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// Get how long it has been since the node was unreferenced. Start a timeout for the remaining time
|
|
231
|
-
// left for it to be eligible for deletion.
|
|
232
|
-
const unreferencedDurationMs = currentTimestampMs - unreferencedTimestampMs;
|
|
233
|
-
this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(unreferencedTimestampMs, this.deleteTimeoutMs - unreferencedDurationMs));
|
|
255
|
+
if (nodeData.unreferencedTimestampMs !== undefined) {
|
|
256
|
+
this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(nodeData.unreferencedTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
|
|
234
257
|
}
|
|
235
258
|
gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
|
|
236
259
|
}
|
|
@@ -268,18 +291,20 @@ class GarbageCollector {
|
|
|
268
291
|
// used in the container.
|
|
269
292
|
if (this.shouldRunGC) {
|
|
270
293
|
this.initializeBaseStateP.catch((error) => {
|
|
271
|
-
|
|
294
|
+
const dpe = container_utils_1.DataProcessingError.wrapIfUnrecognized(error, "FailedToInitializeGC");
|
|
295
|
+
dpe.addTelemetryProperties({
|
|
272
296
|
gcEnabled: this.gcEnabled,
|
|
273
297
|
runSweep: this.shouldRunSweep,
|
|
274
298
|
writeAtRoot: this._writeDataAtRoot,
|
|
275
299
|
testMode: this.testMode,
|
|
276
300
|
sessionExpiry: this.sessionExpiryTimeoutMs,
|
|
277
301
|
});
|
|
302
|
+
throw dpe;
|
|
278
303
|
});
|
|
279
304
|
}
|
|
280
305
|
}
|
|
281
|
-
static create(provider, gcOptions, deleteUnusedRoutes, getNodePackagePath,
|
|
282
|
-
return new GarbageCollector(provider, gcOptions, deleteUnusedRoutes, getNodePackagePath,
|
|
306
|
+
static create(provider, gcOptions, deleteUnusedRoutes, getNodePackagePath, getCurrentReferenceTimestampMs, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata) {
|
|
307
|
+
return new GarbageCollector(provider, gcOptions, deleteUnusedRoutes, getNodePackagePath, getCurrentReferenceTimestampMs, getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata);
|
|
283
308
|
}
|
|
284
309
|
/**
|
|
285
310
|
* This tracks two things:
|
|
@@ -322,9 +347,9 @@ class GarbageCollector {
|
|
|
322
347
|
// the current run. We need to identify than and update their unreferenced state if needed.
|
|
323
348
|
this.updateStateSinceLastRun(gcData);
|
|
324
349
|
// Update the current state of the system based on the GC run.
|
|
325
|
-
const
|
|
326
|
-
this.updateCurrentState(gcData, gcResult,
|
|
327
|
-
this.provider.updateUsedRoutes(gcResult.referencedNodeIds,
|
|
350
|
+
const currentReferenceTimestampMs = this.getCurrentReferenceTimestampMs();
|
|
351
|
+
this.updateCurrentState(gcData, gcResult, currentReferenceTimestampMs);
|
|
352
|
+
this.provider.updateUsedRoutes(gcResult.referencedNodeIds, currentReferenceTimestampMs);
|
|
328
353
|
if (runSweep) {
|
|
329
354
|
// Placeholder for running sweep logic.
|
|
330
355
|
}
|
|
@@ -390,14 +415,15 @@ class GarbageCollector {
|
|
|
390
415
|
* Called when a node with the given id is updated. If the node is inactive, log an error.
|
|
391
416
|
* @param nodePath - The id of the node that changed.
|
|
392
417
|
* @param reason - Whether the node was loaded or changed.
|
|
418
|
+
* @param timestampMs - The timestamp when the node changed.
|
|
393
419
|
* @param packagePath - The package path of the node. This may not be available if the node hasn't been loaded yet.
|
|
394
420
|
* @param requestHeaders - If the node was loaded via request path, the headers in the request.
|
|
395
421
|
*/
|
|
396
|
-
nodeUpdated(nodePath, reason, packagePath, requestHeaders) {
|
|
422
|
+
nodeUpdated(nodePath, reason, timestampMs, packagePath, requestHeaders) {
|
|
397
423
|
if (!this.shouldRunGC) {
|
|
398
424
|
return;
|
|
399
425
|
}
|
|
400
|
-
this.logIfInactive(reason, nodePath,
|
|
426
|
+
this.logIfInactive(reason, nodePath, timestampMs, packagePath, requestHeaders);
|
|
401
427
|
}
|
|
402
428
|
/**
|
|
403
429
|
* Called when an outbound reference is added to a node. This is used to identify all nodes that have been
|
|
@@ -415,7 +441,7 @@ class GarbageCollector {
|
|
|
415
441
|
outboundRoutes.push(toNodePath);
|
|
416
442
|
this.referencesSinceLastRun.set(fromNodePath, outboundRoutes);
|
|
417
443
|
// If the node that got referenced is inactive, log an event as that may indicate use-after-delete.
|
|
418
|
-
this.logIfInactive("Revived", toNodePath
|
|
444
|
+
this.logIfInactive("Revived", toNodePath);
|
|
419
445
|
}
|
|
420
446
|
dispose() {
|
|
421
447
|
if (this.sessionExpiryTimer !== undefined) {
|
|
@@ -440,24 +466,11 @@ class GarbageCollector {
|
|
|
440
466
|
* 3. Clears tracking for nodes that were unreferenced but became referenced in this run.
|
|
441
467
|
* @param gcData - The data representing the reference graph on which GC is run.
|
|
442
468
|
* @param gcResult - The result of the GC run on the gcData.
|
|
443
|
-
* @param
|
|
469
|
+
* @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.
|
|
444
470
|
*/
|
|
445
|
-
updateCurrentState(gcData, gcResult,
|
|
471
|
+
updateCurrentState(gcData, gcResult, currentReferenceTimestampMs) {
|
|
446
472
|
this.gcDataFromLastRun = garbage_collector_1.cloneGCData(gcData);
|
|
447
473
|
this.referencesSinceLastRun.clear();
|
|
448
|
-
// Iterate through the deleted nodes and start tracking if they became unreferenced in this run.
|
|
449
|
-
for (const nodeId of gcResult.deletedNodeIds) {
|
|
450
|
-
// The time when the node became unreferenced. This is added to the current GC state.
|
|
451
|
-
let unreferencedTimestampMs = currentTimestampMs;
|
|
452
|
-
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
453
|
-
if (nodeStateTracker !== undefined) {
|
|
454
|
-
unreferencedTimestampMs = nodeStateTracker.unreferencedTimestampMs;
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
// Start tracking this node as it became unreferenced in this run.
|
|
458
|
-
this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(unreferencedTimestampMs, this.deleteTimeoutMs));
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
474
|
// Iterate through the referenced nodes and stop tracking if they were unreferenced before.
|
|
462
475
|
for (const nodeId of gcResult.referencedNodeIds) {
|
|
463
476
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
@@ -468,6 +481,28 @@ class GarbageCollector {
|
|
|
468
481
|
this.unreferencedNodesState.delete(nodeId);
|
|
469
482
|
}
|
|
470
483
|
}
|
|
484
|
+
/**
|
|
485
|
+
* If there is no current reference time, skip tracking when a node becomes unreferenced. This would happen
|
|
486
|
+
* if no ops have been processed ever and we still try to run GC. If so, there is nothing interesting to track
|
|
487
|
+
* anyway.
|
|
488
|
+
*/
|
|
489
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* If a node became unreferenced in this run, start tracking it.
|
|
494
|
+
* If a node was already unreferenced, update its tracking information. Since the current reference time is
|
|
495
|
+
* from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.
|
|
496
|
+
*/
|
|
497
|
+
for (const nodeId of gcResult.deletedNodeIds) {
|
|
498
|
+
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
499
|
+
if (nodeStateTracker === undefined) {
|
|
500
|
+
this.unreferencedNodesState.set(nodeId, new UnreferencedStateTracker(currentReferenceTimestampMs, this.deleteTimeoutMs, currentReferenceTimestampMs));
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
nodeStateTracker.updateTracking(currentReferenceTimestampMs);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
471
506
|
}
|
|
472
507
|
/**
|
|
473
508
|
* Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in
|
|
@@ -631,10 +666,14 @@ class GarbageCollector {
|
|
|
631
666
|
return gcStats;
|
|
632
667
|
}
|
|
633
668
|
/**
|
|
634
|
-
* Logs an event if a node is inactive and is used.
|
|
635
|
-
* queue it and it will be logged the next time GC runs as the package data should be available then.
|
|
669
|
+
* Logs an event if a node is inactive and is used.
|
|
636
670
|
*/
|
|
637
|
-
logIfInactive(eventSuffix, nodeId,
|
|
671
|
+
logIfInactive(eventSuffix, nodeId, currentReferenceTimestampMs = this.getCurrentReferenceTimestampMs(), packagePath, requestHeaders) {
|
|
672
|
+
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
673
|
+
// logging as nothing interesting would have happened worth logging.
|
|
674
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
638
677
|
const eventName = `inactiveObject_${eventSuffix}`;
|
|
639
678
|
// We log a particular event for a given node only once so that it is not too noisy.
|
|
640
679
|
const uniqueEventId = `${nodeId}-${eventName}`;
|
|
@@ -644,13 +683,17 @@ class GarbageCollector {
|
|
|
644
683
|
const event = {
|
|
645
684
|
eventName,
|
|
646
685
|
id: nodeId,
|
|
647
|
-
age:
|
|
686
|
+
age: currentReferenceTimestampMs - nodeState.unreferencedTimestampMs,
|
|
648
687
|
timeout: this.deleteTimeoutMs,
|
|
688
|
+
lastSummaryTime: this.getLastSummaryTimestampMs(),
|
|
649
689
|
externalRequest: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[_1.RuntimeHeaders.externalRequest],
|
|
650
690
|
viaHandle: requestHeaders === null || requestHeaders === void 0 ? void 0 : requestHeaders[_1.RuntimeHeaders.viaHandle],
|
|
651
691
|
};
|
|
652
|
-
|
|
653
|
-
|
|
692
|
+
// If the package data for the node exists, log immediately. Otherwise, queue it and it will be logged the
|
|
693
|
+
// next time GC runs as the package data should be available then.
|
|
694
|
+
const pkg = packagePath !== null && packagePath !== void 0 ? packagePath : this.getNodePackagePath(nodeId);
|
|
695
|
+
if (pkg !== undefined) {
|
|
696
|
+
this.mc.logger.sendErrorEvent(Object.assign(Object.assign({}, event), { pkg: { value: `/${pkg.join("/")}`, tag: telemetry_utils_1.TelemetryDataTag.PackageData } }));
|
|
654
697
|
}
|
|
655
698
|
else {
|
|
656
699
|
this.pendingEventsQueue.push(event);
|