@fluidframework/container-runtime 2.0.0-dev.4.4.0.161652 → 2.0.0-dev.4.4.0.162089
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/containerRuntime.js +4 -4
- package/dist/containerRuntime.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +2 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +8 -2
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +2 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +8 -0
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +12 -1
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +6 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +10 -0
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +2 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +42 -22
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +1 -2
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +2 -5
- package/dist/gc/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/lib/containerRuntime.js +4 -4
- package/lib/containerRuntime.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +2 -0
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +8 -2
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +2 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +8 -0
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +10 -0
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +6 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +10 -0
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +2 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +43 -23
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +1 -2
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -2
- package/lib/gc/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/package.json +15 -15
- package/src/containerRuntime.ts +1 -1
- package/src/gc/garbageCollection.ts +9 -2
- package/src/gc/gcDefinitions.ts +2 -0
- package/src/gc/gcHelpers.ts +11 -0
- package/src/gc/gcSummaryStateTracker.ts +13 -1
- package/src/gc/gcTelemetry.ts +52 -37
- package/src/gc/index.ts +1 -5
- package/src/packageVersion.ts +1 -1
- package/dist/gc/gcSweepReadyUsageDetection.d.ts +0 -53
- package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/dist/gc/gcSweepReadyUsageDetection.js +0 -130
- package/dist/gc/gcSweepReadyUsageDetection.js.map +0 -1
- package/lib/gc/gcSweepReadyUsageDetection.d.ts +0 -53
- package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/lib/gc/gcSweepReadyUsageDetection.js +0 -125
- package/lib/gc/gcSweepReadyUsageDetection.js.map +0 -1
- package/src/gc/gcSweepReadyUsageDetection.ts +0 -145
package/lib/gc/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,+BAA+B,EAC/B,2BAA2B,EAG3B,uBAAuB,EASvB,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,WAAW,EACX,6BAA6B,EAC7B,qBAAqB,EACrB,iCAAiC,EACjC,kBAAkB,EAClB,6BAA6B,EAC7B,yBAAyB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gc/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,+BAA+B,EAC/B,2BAA2B,EAG3B,uBAAuB,EASvB,QAAQ,EACR,QAAQ,EACR,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,WAAW,EACX,6BAA6B,EAC7B,qBAAqB,EACrB,iCAAiC,EACjC,kBAAkB,EAClB,6BAA6B,EAC7B,yBAAyB,EACzB,iBAAiB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAOnE,OAAO,EACN,cAAc,EACd,qBAAqB,GAErB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { GarbageCollector } from \"./garbageCollection\";\nexport {\n\tcurrentGCVersion,\n\tdefaultInactiveTimeoutMs,\n\tdefaultSessionExpiryDurationMs,\n\tdisableSweepLogKey,\n\tGCNodeType,\n\tgcTestModeKey,\n\tgcTombstoneGenerationOptionName,\n\tgcSweepGenerationOptionName,\n\tGCFeatureMatrix,\n\tGCVersion,\n\tgcVersionUpgradeToV3Key,\n\tIGarbageCollectionRuntime,\n\tIGarbageCollector,\n\tIGarbageCollectorConfigs,\n\tIGarbageCollectorCreateParams,\n\tIGCMetadata,\n\tIGCResult,\n\tIGCRuntimeOptions,\n\tIGCStats,\n\toneDayMs,\n\trunGCKey,\n\trunSessionExpiryKey,\n\trunSweepKey,\n\tstableGCVersion,\n\tsweepAttachmentBlobsKey,\n\tsweepDatastoresKey,\n\tthrowOnTombstoneLoadKey,\n\tthrowOnTombstoneUsageKey,\n\tUnreferencedState,\n} from \"./gcDefinitions\";\nexport {\n\tcloneGCData,\n\tconcatGarbageCollectionStates,\n\tgetGCDataFromSnapshot,\n\tshouldAllowGcTombstoneEnforcement,\n\tshouldAllowGcSweep,\n\ttrimLeadingAndTrailingSlashes,\n\tunpackChildNodesGCDetails,\n\ttagAsCodeArtifact,\n} from \"./gcHelpers\";\nexport { runGarbageCollection } from \"./gcReferenceGraphAlgorithm\";\nexport {\n\tIGarbageCollectionNodeData,\n\tIGarbageCollectionSnapshotData,\n\tIGarbageCollectionState,\n\tIGarbageCollectionSummaryDetailsLegacy,\n} from \"./gcSummaryDefinitions\";\nexport {\n\tgcStateBlobKey,\n\tGCSummaryStateTracker,\n\tIGCSummaryTrackingData,\n} from \"./gcSummaryStateTracker\";\nexport { GCTelemetryTracker, sendGCUnexpectedUsageEvent } from \"./gcTelemetry\";\nexport { UnreferencedStateTracker } from \"./gcUnreferencedStateTracker\";\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/container-runtime";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-dev.4.4.0.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-dev.4.4.0.162089";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export const pkgName = "@fluidframework/container-runtime";
|
|
8
|
-
export const pkgVersion = "2.0.0-dev.4.4.0.
|
|
8
|
+
export const pkgVersion = "2.0.0-dev.4.4.0.162089";
|
|
9
9
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.4.4.0.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"2.0.0-dev.4.4.0.162089\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-runtime",
|
|
3
|
-
"version": "2.0.0-dev.4.4.0.
|
|
3
|
+
"version": "2.0.0-dev.4.4.0.162089",
|
|
4
4
|
"description": "Fluid container runtime",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -37,19 +37,19 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
39
39
|
"@fluidframework/common-utils": "^1.1.1",
|
|
40
|
-
"@fluidframework/container-definitions": "2.0.0-dev.4.4.0.
|
|
41
|
-
"@fluidframework/container-runtime-definitions": "2.0.0-dev.4.4.0.
|
|
42
|
-
"@fluidframework/container-utils": "2.0.0-dev.4.4.0.
|
|
43
|
-
"@fluidframework/core-interfaces": "2.0.0-dev.4.4.0.
|
|
44
|
-
"@fluidframework/datastore": "2.0.0-dev.4.4.0.
|
|
45
|
-
"@fluidframework/driver-definitions": "2.0.0-dev.4.4.0.
|
|
46
|
-
"@fluidframework/driver-utils": "2.0.0-dev.4.4.0.
|
|
47
|
-
"@fluidframework/garbage-collector": "2.0.0-dev.4.4.0.
|
|
40
|
+
"@fluidframework/container-definitions": "2.0.0-dev.4.4.0.162089",
|
|
41
|
+
"@fluidframework/container-runtime-definitions": "2.0.0-dev.4.4.0.162089",
|
|
42
|
+
"@fluidframework/container-utils": "2.0.0-dev.4.4.0.162089",
|
|
43
|
+
"@fluidframework/core-interfaces": "2.0.0-dev.4.4.0.162089",
|
|
44
|
+
"@fluidframework/datastore": "2.0.0-dev.4.4.0.162089",
|
|
45
|
+
"@fluidframework/driver-definitions": "2.0.0-dev.4.4.0.162089",
|
|
46
|
+
"@fluidframework/driver-utils": "2.0.0-dev.4.4.0.162089",
|
|
47
|
+
"@fluidframework/garbage-collector": "2.0.0-dev.4.4.0.162089",
|
|
48
48
|
"@fluidframework/protocol-base": "^0.1039.1000",
|
|
49
49
|
"@fluidframework/protocol-definitions": "^1.1.0",
|
|
50
|
-
"@fluidframework/runtime-definitions": "2.0.0-dev.4.4.0.
|
|
51
|
-
"@fluidframework/runtime-utils": "2.0.0-dev.4.4.0.
|
|
52
|
-
"@fluidframework/telemetry-utils": "2.0.0-dev.4.4.0.
|
|
50
|
+
"@fluidframework/runtime-definitions": "2.0.0-dev.4.4.0.162089",
|
|
51
|
+
"@fluidframework/runtime-utils": "2.0.0-dev.4.4.0.162089",
|
|
52
|
+
"@fluidframework/telemetry-utils": "2.0.0-dev.4.4.0.162089",
|
|
53
53
|
"double-ended-queue": "^2.1.0-0",
|
|
54
54
|
"events": "^3.1.0",
|
|
55
55
|
"lz4js": "^0.2.0",
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
"uuid": "^8.3.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@fluid-internal/stochastic-test-utils": "2.0.0-dev.4.4.0.
|
|
60
|
+
"@fluid-internal/stochastic-test-utils": "2.0.0-dev.4.4.0.162089",
|
|
61
61
|
"@fluid-tools/benchmark": "^0.46.0",
|
|
62
62
|
"@fluid-tools/build-cli": "^0.17.0",
|
|
63
63
|
"@fluidframework/build-common": "^1.1.0",
|
|
64
64
|
"@fluidframework/build-tools": "^0.17.0",
|
|
65
65
|
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.0.0-internal.4.1.0",
|
|
66
66
|
"@fluidframework/eslint-config-fluid": "^2.0.0",
|
|
67
|
-
"@fluidframework/mocha-test-setup": "2.0.0-dev.4.4.0.
|
|
68
|
-
"@fluidframework/test-runtime-utils": "2.0.0-dev.4.4.0.
|
|
67
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.4.4.0.162089",
|
|
68
|
+
"@fluidframework/test-runtime-utils": "2.0.0-dev.4.4.0.162089",
|
|
69
69
|
"@microsoft/api-extractor": "^7.34.4",
|
|
70
70
|
"@types/double-ended-queue": "^2.1.0",
|
|
71
71
|
"@types/events": "^3.0.0",
|
package/src/containerRuntime.ts
CHANGED
|
@@ -2791,7 +2791,7 @@ export class ContainerRuntime
|
|
|
2791
2791
|
const summaryStats: IGeneratedSummaryStats = {
|
|
2792
2792
|
dataStoreCount: this.dataStores.size,
|
|
2793
2793
|
summarizedDataStoreCount: this.dataStores.size - handleCount,
|
|
2794
|
-
gcStateUpdatedDataStoreCount:
|
|
2794
|
+
gcStateUpdatedDataStoreCount: this.garbageCollector.updatedDSCountSinceLastSummary,
|
|
2795
2795
|
gcBlobNodeCount: gcSummaryTreeStats?.blobNodeCount,
|
|
2796
2796
|
gcTotalBlobsSize: gcSummaryTreeStats?.totalBlobSize,
|
|
2797
2797
|
summaryNumber,
|
|
@@ -121,6 +121,11 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
121
121
|
return this.summaryStateTracker.doesSummaryStateNeedReset;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/** Returns the count of data stores whose GC state updated since the last summary. */
|
|
125
|
+
public get updatedDSCountSinceLastSummary(): number {
|
|
126
|
+
return this.summaryStateTracker.updatedDSCountSinceLastSummary;
|
|
127
|
+
}
|
|
128
|
+
|
|
124
129
|
protected constructor(createParams: IGarbageCollectorCreateParams) {
|
|
125
130
|
this.runtime = createParams.runtime;
|
|
126
131
|
this.isSummarizerClient = createParams.isSummarizerClient;
|
|
@@ -505,6 +510,8 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
505
510
|
// updates its state so that we don't send false positives based on intermediate state. For example, we may get
|
|
506
511
|
// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.
|
|
507
512
|
await this.telemetryTracker.logPendingEvents(logger);
|
|
513
|
+
// Update the state of summary state tracker from this run's stats.
|
|
514
|
+
this.summaryStateTracker.updateStateFromGCRunStats(gcStats);
|
|
508
515
|
this.newReferencesSinceLastRun.clear();
|
|
509
516
|
this.completedRuns++;
|
|
510
517
|
|
|
@@ -884,7 +891,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
884
891
|
}
|
|
885
892
|
|
|
886
893
|
this.telemetryTracker.nodeUsed({
|
|
887
|
-
|
|
894
|
+
id: nodePath,
|
|
888
895
|
usageType: reason,
|
|
889
896
|
currentReferenceTimestampMs:
|
|
890
897
|
timestampMs ?? this.runtime.getCurrentReferenceTimestampMs(),
|
|
@@ -913,7 +920,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
913
920
|
this.newReferencesSinceLastRun.set(fromNodePath, outboundRoutes);
|
|
914
921
|
|
|
915
922
|
this.telemetryTracker.nodeUsed({
|
|
916
|
-
|
|
923
|
+
id: toNodePath,
|
|
917
924
|
usageType: "Revived",
|
|
918
925
|
currentReferenceTimestampMs: this.runtime.getCurrentReferenceTimestampMs(),
|
|
919
926
|
packagePath: undefined,
|
package/src/gc/gcDefinitions.ts
CHANGED
|
@@ -204,6 +204,8 @@ export interface IGarbageCollector {
|
|
|
204
204
|
readonly shouldRunGC: boolean;
|
|
205
205
|
/** Tells whether the GC state in summary needs to be reset in the next summary. */
|
|
206
206
|
readonly summaryStateNeedsReset: boolean;
|
|
207
|
+
/** The count of data stores whose GC state updated since the last summary. */
|
|
208
|
+
readonly updatedDSCountSinceLastSummary: number;
|
|
207
209
|
/** Initialize the state from the base snapshot after its creation. */
|
|
208
210
|
initializeBaseState(): Promise<void>;
|
|
209
211
|
/** Run garbage collection and update the reference / used state of the system. */
|
package/src/gc/gcHelpers.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
IGarbageCollectionData,
|
|
13
13
|
IGarbageCollectionDetailsBase,
|
|
14
14
|
} from "@fluidframework/runtime-definitions";
|
|
15
|
+
import { TelemetryDataTag } from "@fluidframework/telemetry-utils";
|
|
15
16
|
import { GCFeatureMatrix, GCVersion, IGCMetadata } from "./gcDefinitions";
|
|
16
17
|
import {
|
|
17
18
|
IGarbageCollectionNodeData,
|
|
@@ -303,3 +304,13 @@ export function unpackChildNodesGCDetails(gcDetails: IGarbageCollectionDetailsBa
|
|
|
303
304
|
export function trimLeadingAndTrailingSlashes(str: string) {
|
|
304
305
|
return str.replace(/^\/+|\/+$/g, "");
|
|
305
306
|
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Tags the passed value as a CodeArtifact and returns the tagged value.
|
|
310
|
+
*/
|
|
311
|
+
export function tagAsCodeArtifact(value: string) {
|
|
312
|
+
return {
|
|
313
|
+
value,
|
|
314
|
+
tag: TelemetryDataTag.CodeArtifact,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "@fluidframework/runtime-definitions";
|
|
15
15
|
import { mergeStats, ReadAndParseBlob, SummaryTreeBuilder } from "@fluidframework/runtime-utils";
|
|
16
16
|
import { IContainerRuntimeMetadata, metadataBlobName, RefreshSummaryResult } from "../summary";
|
|
17
|
-
import { GCVersion } from "./gcDefinitions";
|
|
17
|
+
import { GCVersion, IGCStats } from "./gcDefinitions";
|
|
18
18
|
import { getGCDataFromSnapshot, generateSortedGCState, getGCVersion } from "./gcHelpers";
|
|
19
19
|
import { IGarbageCollectionSnapshotData, IGarbageCollectionState } from "./gcSummaryDefinitions";
|
|
20
20
|
import { IGarbageCollectorConfigs } from ".";
|
|
@@ -50,6 +50,10 @@ export class GCSummaryStateTracker {
|
|
|
50
50
|
// Tracks whether there was GC was run in latest summary being tracked.
|
|
51
51
|
private wasGCRunInLatestSummary: boolean;
|
|
52
52
|
|
|
53
|
+
// Tracks the count of data stores whose state updated since the last summary, i.e., they went from referenced
|
|
54
|
+
// to unreferenced or vice-versa.
|
|
55
|
+
public updatedDSCountSinceLastSummary: number = 0;
|
|
56
|
+
|
|
53
57
|
constructor(
|
|
54
58
|
// Tells whether GC should run or not.
|
|
55
59
|
private readonly configs: Pick<
|
|
@@ -286,6 +290,7 @@ export class GCSummaryStateTracker {
|
|
|
286
290
|
this.latestSummaryGCVersion = this.currentGCVersion;
|
|
287
291
|
this.latestSummaryData = this.pendingSummaryData;
|
|
288
292
|
this.pendingSummaryData = undefined;
|
|
293
|
+
this.updatedDSCountSinceLastSummary = 0;
|
|
289
294
|
return undefined;
|
|
290
295
|
}
|
|
291
296
|
|
|
@@ -326,4 +331,11 @@ export class GCSummaryStateTracker {
|
|
|
326
331
|
};
|
|
327
332
|
return snapshotData;
|
|
328
333
|
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Called to update the state from a GC run's stats. Used to update the count of data stores whose state updated.
|
|
337
|
+
*/
|
|
338
|
+
public updateStateFromGCRunStats(stats: IGCStats) {
|
|
339
|
+
this.updatedDSCountSinceLastSummary += stats.updatedDataStoreCount;
|
|
340
|
+
}
|
|
329
341
|
}
|
package/src/gc/gcTelemetry.ts
CHANGED
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
import { ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import { IGarbageCollectionData } from "@fluidframework/runtime-definitions";
|
|
8
8
|
import { packagePathToTelemetryProperty } from "@fluidframework/runtime-utils";
|
|
9
|
-
import {
|
|
10
|
-
generateStack,
|
|
11
|
-
MonitoringContext,
|
|
12
|
-
TelemetryDataTag,
|
|
13
|
-
} from "@fluidframework/telemetry-utils";
|
|
9
|
+
import { generateStack, MonitoringContext } from "@fluidframework/telemetry-utils";
|
|
14
10
|
import { ICreateContainerMetadata } from "../summary";
|
|
15
11
|
import {
|
|
16
12
|
disableSweepLogKey,
|
|
@@ -23,6 +19,7 @@ import {
|
|
|
23
19
|
runSweepKey,
|
|
24
20
|
} from "./gcDefinitions";
|
|
25
21
|
import { UnreferencedStateTracker } from "./gcUnreferencedStateTracker";
|
|
22
|
+
import { tagAsCodeArtifact } from "./gcHelpers";
|
|
26
23
|
|
|
27
24
|
type NodeUsageType = "Changed" | "Loaded" | "Revived";
|
|
28
25
|
|
|
@@ -32,25 +29,32 @@ interface ICommonProps {
|
|
|
32
29
|
completedGCRuns: number;
|
|
33
30
|
isTombstoned: boolean;
|
|
34
31
|
lastSummaryTime?: number;
|
|
35
|
-
fromId?: string;
|
|
36
32
|
viaHandle?: boolean;
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
/** The event that is logged when unreferenced node is used after a certain time. */
|
|
40
36
|
interface IUnreferencedEventProps extends ICreateContainerMetadata, ICommonProps {
|
|
41
37
|
state: UnreferencedState;
|
|
42
|
-
id:
|
|
38
|
+
id: {
|
|
39
|
+
value: string;
|
|
40
|
+
tag: string;
|
|
41
|
+
};
|
|
43
42
|
type: GCNodeType;
|
|
44
43
|
unrefTime: number;
|
|
45
44
|
age: number;
|
|
46
45
|
timeout?: number;
|
|
46
|
+
fromId?: {
|
|
47
|
+
value: string;
|
|
48
|
+
tag: string;
|
|
49
|
+
};
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
/** Properties passed to nodeUsed function when a node is used. */
|
|
50
53
|
interface INodeUsageProps extends ICommonProps {
|
|
51
|
-
|
|
54
|
+
id: string;
|
|
52
55
|
currentReferenceTimestampMs: number | undefined;
|
|
53
56
|
packagePath: readonly string[] | undefined;
|
|
57
|
+
fromId?: string;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
/**
|
|
@@ -125,18 +129,18 @@ export class GCTelemetryTracker {
|
|
|
125
129
|
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
126
130
|
// logging as nothing interesting would have happened worth logging.
|
|
127
131
|
// If the node is not unreferenced, skip logging.
|
|
128
|
-
const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.
|
|
132
|
+
const nodeStateTracker = this.getNodeStateTracker(nodeUsageProps.id);
|
|
129
133
|
if (!nodeStateTracker || nodeUsageProps.currentReferenceTimestampMs === undefined) {
|
|
130
134
|
return;
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
// We log these events once per event per node. A unique id is generated by joining node state (inactive / sweep ready),
|
|
134
138
|
// node's id and usage (loaded / changed / revived).
|
|
135
|
-
const uniqueEventId = `${nodeStateTracker.state}-${nodeUsageProps.
|
|
136
|
-
const nodeType = this.getNodeType(nodeUsageProps.
|
|
139
|
+
const uniqueEventId = `${nodeStateTracker.state}-${nodeUsageProps.id}-${nodeUsageProps.usageType}`;
|
|
140
|
+
const nodeType = this.getNodeType(nodeUsageProps.id);
|
|
137
141
|
if (
|
|
138
142
|
!this.shouldLogNonActiveEvent(
|
|
139
|
-
nodeUsageProps.
|
|
143
|
+
nodeUsageProps.id,
|
|
140
144
|
nodeType,
|
|
141
145
|
nodeUsageProps.usageType,
|
|
142
146
|
nodeStateTracker,
|
|
@@ -150,10 +154,10 @@ export class GCTelemetryTracker {
|
|
|
150
154
|
this.loggedUnreferencedEvents.add(uniqueEventId);
|
|
151
155
|
|
|
152
156
|
const state = nodeStateTracker.state;
|
|
153
|
-
const { usageType, currentReferenceTimestampMs, packagePath, ...propsToLog } =
|
|
157
|
+
const { usageType, currentReferenceTimestampMs, packagePath, id, fromId, ...propsToLog } =
|
|
154
158
|
nodeUsageProps;
|
|
155
159
|
const eventProps: Omit<IUnreferencedEventProps, "state" | "usageType"> = {
|
|
156
|
-
id:
|
|
160
|
+
id: tagAsCodeArtifact(id),
|
|
157
161
|
type: nodeType,
|
|
158
162
|
unrefTime: nodeStateTracker.unreferencedTimestampMs,
|
|
159
163
|
age:
|
|
@@ -163,6 +167,7 @@ export class GCTelemetryTracker {
|
|
|
163
167
|
state === UnreferencedState.Inactive
|
|
164
168
|
? this.configs.inactiveTimeoutMs
|
|
165
169
|
: this.configs.sweepTimeoutMs,
|
|
170
|
+
fromId: fromId ? tagAsCodeArtifact(fromId) : undefined,
|
|
166
171
|
...propsToLog,
|
|
167
172
|
...this.createContainerMetadata,
|
|
168
173
|
};
|
|
@@ -175,7 +180,7 @@ export class GCTelemetryTracker {
|
|
|
175
180
|
{
|
|
176
181
|
eventName: `GC_Tombstone_${nodeType}_Revived`,
|
|
177
182
|
category: "generic",
|
|
178
|
-
url:
|
|
183
|
+
url: tagAsCodeArtifact(id),
|
|
179
184
|
gcTombstoneEnforcementAllowed: this.gcTombstoneEnforcementAllowed,
|
|
180
185
|
},
|
|
181
186
|
undefined /* packagePath */,
|
|
@@ -199,11 +204,16 @@ export class GCTelemetryTracker {
|
|
|
199
204
|
// Events generated:
|
|
200
205
|
// InactiveObject_Loaded, SweepReadyObject_Loaded
|
|
201
206
|
if (nodeUsageProps.usageType === "Loaded") {
|
|
207
|
+
const { id: taggedId, fromId: taggedFromId, ...otherProps } = eventProps;
|
|
202
208
|
const event = {
|
|
203
209
|
eventName: `${state}Object_${nodeUsageProps.usageType}`,
|
|
204
210
|
pkg: packagePathToTelemetryProperty(nodeUsageProps.packagePath),
|
|
205
211
|
stack: generateStack(),
|
|
206
|
-
|
|
212
|
+
id: taggedId,
|
|
213
|
+
fromId: taggedFromId,
|
|
214
|
+
details: JSON.stringify({
|
|
215
|
+
...otherProps,
|
|
216
|
+
}),
|
|
207
217
|
};
|
|
208
218
|
|
|
209
219
|
// Do not log the inactive object x events as error events as they are not the best signal for
|
|
@@ -263,8 +273,8 @@ export class GCTelemetryTracker {
|
|
|
263
273
|
if (missingExplicitRoutes.length > 0) {
|
|
264
274
|
logger.sendErrorEvent({
|
|
265
275
|
eventName: "gcUnknownOutboundReferences",
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
id: tagAsCodeArtifact(nodeId),
|
|
277
|
+
routes: tagAsCodeArtifact(JSON.stringify(missingExplicitRoutes)),
|
|
268
278
|
});
|
|
269
279
|
}
|
|
270
280
|
}
|
|
@@ -281,31 +291,31 @@ export class GCTelemetryTracker {
|
|
|
281
291
|
// InactiveObject_Loaded, InactiveObject_Changed, InactiveObject_Revived
|
|
282
292
|
// SweepReadyObject_Loaded, SweepReadyObject_Changed, SweepReadyObject_Revived
|
|
283
293
|
for (const eventProps of this.pendingEventsQueue) {
|
|
284
|
-
const { usageType, state, ...propsToLog } = eventProps;
|
|
294
|
+
const { usageType, state, id, fromId, ...propsToLog } = eventProps;
|
|
285
295
|
/**
|
|
286
296
|
* Revived event is logged only if the node is active. If the node is not active, the reference to it was
|
|
287
297
|
* from another unreferenced node and this scenario is not interesting to log.
|
|
288
298
|
* Loaded and Changed events are logged only if the node is not active. If the node is active, it was
|
|
289
299
|
* revived and a Revived event will be logged for it.
|
|
290
300
|
*/
|
|
291
|
-
const nodeStateTracker = this.getNodeStateTracker(eventProps.id);
|
|
301
|
+
const nodeStateTracker = this.getNodeStateTracker(eventProps.id.value);
|
|
292
302
|
const active =
|
|
293
303
|
nodeStateTracker === undefined ||
|
|
294
304
|
nodeStateTracker.state === UnreferencedState.Active;
|
|
295
305
|
if ((usageType === "Revived") === active) {
|
|
296
|
-
const pkg = await this.getNodePackagePath(eventProps.id);
|
|
306
|
+
const pkg = await this.getNodePackagePath(eventProps.id.value);
|
|
297
307
|
const fromPkg = eventProps.fromId
|
|
298
|
-
? await this.getNodePackagePath(eventProps.fromId)
|
|
308
|
+
? await this.getNodePackagePath(eventProps.fromId.value)
|
|
299
309
|
: undefined;
|
|
300
310
|
const event = {
|
|
301
|
-
...propsToLog,
|
|
302
311
|
eventName: `${state}Object_${usageType}`,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
details: JSON.stringify({
|
|
313
|
+
...propsToLog,
|
|
314
|
+
}),
|
|
315
|
+
id,
|
|
316
|
+
fromId,
|
|
317
|
+
pkg: pkg ? tagAsCodeArtifact(pkg.join("/")) : undefined,
|
|
318
|
+
fromPkg: fromPkg ? tagAsCodeArtifact(fromPkg.join("/")) : undefined,
|
|
309
319
|
};
|
|
310
320
|
|
|
311
321
|
if (state === UnreferencedState.Inactive) {
|
|
@@ -336,6 +346,7 @@ export class GCTelemetryTracker {
|
|
|
336
346
|
return;
|
|
337
347
|
}
|
|
338
348
|
|
|
349
|
+
const deletedNodeIds: string[] = [];
|
|
339
350
|
for (const [nodeId, nodeStateTracker] of unreferencedNodesState) {
|
|
340
351
|
if (nodeStateTracker.state !== UnreferencedState.SweepReady) {
|
|
341
352
|
return;
|
|
@@ -352,15 +363,19 @@ export class GCTelemetryTracker {
|
|
|
352
363
|
return;
|
|
353
364
|
}
|
|
354
365
|
this.loggedUnreferencedEvents.add(uniqueEventId);
|
|
366
|
+
deletedNodeIds.push(nodeId);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (deletedNodeIds.length > 0) {
|
|
355
370
|
logger.sendTelemetryEvent({
|
|
356
|
-
eventName: "
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
371
|
+
eventName: "GC_SweepReadyObjects_Delete",
|
|
372
|
+
details: JSON.stringify({
|
|
373
|
+
timeout: this.configs.sweepTimeoutMs,
|
|
374
|
+
completedGCRuns,
|
|
375
|
+
lastSummaryTime,
|
|
376
|
+
...this.createContainerMetadata,
|
|
377
|
+
}),
|
|
378
|
+
id: tagAsCodeArtifact(JSON.stringify(deletedNodeIds)),
|
|
364
379
|
});
|
|
365
380
|
}
|
|
366
381
|
}
|
package/src/gc/index.ts
CHANGED
|
@@ -43,6 +43,7 @@ export {
|
|
|
43
43
|
shouldAllowGcSweep,
|
|
44
44
|
trimLeadingAndTrailingSlashes,
|
|
45
45
|
unpackChildNodesGCDetails,
|
|
46
|
+
tagAsCodeArtifact,
|
|
46
47
|
} from "./gcHelpers";
|
|
47
48
|
export { runGarbageCollection } from "./gcReferenceGraphAlgorithm";
|
|
48
49
|
export {
|
|
@@ -56,10 +57,5 @@ export {
|
|
|
56
57
|
GCSummaryStateTracker,
|
|
57
58
|
IGCSummaryTrackingData,
|
|
58
59
|
} from "./gcSummaryStateTracker";
|
|
59
|
-
export {
|
|
60
|
-
skipClosureForXDaysKey,
|
|
61
|
-
closuresMapLocalStorageKey,
|
|
62
|
-
SweepReadyUsageDetectionHandler,
|
|
63
|
-
} from "./gcSweepReadyUsageDetection";
|
|
64
60
|
export { GCTelemetryTracker, sendGCUnexpectedUsageEvent } from "./gcTelemetry";
|
|
65
61
|
export { UnreferencedStateTracker } from "./gcUnreferencedStateTracker";
|
package/src/packageVersion.ts
CHANGED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
6
|
-
import { ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
7
|
-
import { IFluidErrorBase, LoggingError, MonitoringContext } from "@fluidframework/telemetry-utils";
|
|
8
|
-
/**
|
|
9
|
-
* Feature Gate Key -
|
|
10
|
-
* How many days between closing the container from this error (avoids locking user out of their file altogether)
|
|
11
|
-
*/
|
|
12
|
-
export declare const skipClosureForXDaysKey = "Fluid.GarbageCollection.Dogfood.SweepReadyUsageDetection.SkipClosureForXDays";
|
|
13
|
-
/**
|
|
14
|
-
* LocalStorage key (NOT via feature gate / monitoring context)
|
|
15
|
-
* A map from docId to info about the last time we closed due to this error
|
|
16
|
-
*/
|
|
17
|
-
export declare const closuresMapLocalStorageKey = "Fluid.GarbageCollection.Dogfood.SweepReadyUsageDetection.Closures";
|
|
18
|
-
/**
|
|
19
|
-
* Error class raised when a SweepReady object is used, indicating a bug in how
|
|
20
|
-
* references are managed in the container by the application, or a bug in how
|
|
21
|
-
* GC tracks those references.
|
|
22
|
-
*
|
|
23
|
-
* There's a chance for false positives when this error is raised by an Interactive Container,
|
|
24
|
-
* since only the Summarizer has the latest truth about unreferenced node tracking
|
|
25
|
-
*/
|
|
26
|
-
export declare class SweepReadyUsageError extends LoggingError implements IFluidErrorBase {
|
|
27
|
-
/** This errorType will be in temporary use (until Sweep is fully implemented) so don't add to any errorType type */
|
|
28
|
-
errorType: string;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* This class encapsulates the logic around what to do when a SweepReady object is used.
|
|
32
|
-
* There are several tactics we plan to use in Dogfood environments to aid diagnosis of these cases:
|
|
33
|
-
* - Closing the interactive container when either the interactive or summarizer client detects this kind of violation
|
|
34
|
-
* (via sweepReadyUsageDetectionSetting above)
|
|
35
|
-
* - Throttling the frequency of these crashes via a "Skip Closure Period" per container per device
|
|
36
|
-
* (via skipClosureForXDaysKey above. Uses localStorage and closuresMapLocalStorageKey to implement this behavior)
|
|
37
|
-
*/
|
|
38
|
-
export declare class SweepReadyUsageDetectionHandler {
|
|
39
|
-
private readonly uniqueContainerKey;
|
|
40
|
-
private readonly mc;
|
|
41
|
-
private readonly closeFn;
|
|
42
|
-
private readonly localStorage;
|
|
43
|
-
constructor(uniqueContainerKey: string, mc: MonitoringContext, closeFn: (error?: ICriticalContainerError) => void, localStorageOverride?: Pick<Storage, "getItem" | "setItem">);
|
|
44
|
-
/**
|
|
45
|
-
* If SweepReady Usage Detection is enabled, close the interactive container.
|
|
46
|
-
* If the SkipClosureForXDays setting is set, don't close the container more than once in that period.
|
|
47
|
-
*
|
|
48
|
-
* Once Sweep is fully implemented, this will be removed since the objects will be gone
|
|
49
|
-
* and errors will arise elsewhere in the runtime
|
|
50
|
-
*/
|
|
51
|
-
usageDetectedInInteractiveClient(errorProps: ITelemetryProperties): void;
|
|
52
|
-
}
|
|
53
|
-
//# sourceMappingURL=gcSweepReadyUsageDetection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gcSweepReadyUsageDetection.d.ts","sourceRoot":"","sources":["../../src/gc/gcSweepReadyUsageDetection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAEN,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,MAAM,iCAAiC,CAAC;AAGzC;;;GAGG;AACH,eAAO,MAAM,sBAAsB,iFAC4C,CAAC;AAEhF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,sEAC6B,CAAC;AAqBrE;;;;;;;GAOG;AACH,qBAAa,oBAAqB,SAAQ,YAAa,YAAW,eAAe;IAChF,oHAAoH;IAC7G,SAAS,EAAE,MAAM,CAAiD;CACzE;AAED;;;;;;;GAOG;AACH,qBAAa,+BAA+B;IAI1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IALzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuC;gBAGlD,kBAAkB,EAAE,MAAM,EAC1B,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,uBAAuB,KAAK,IAAI,EACnE,oBAAoB,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAc5D;;;;;;OAMG;IACI,gCAAgC,CAAC,UAAU,EAAE,oBAAoB;CA+CxE"}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*!
|
|
3
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.SweepReadyUsageDetectionHandler = exports.SweepReadyUsageError = exports.closuresMapLocalStorageKey = exports.skipClosureForXDaysKey = void 0;
|
|
8
|
-
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
9
|
-
const gcDefinitions_1 = require("./gcDefinitions");
|
|
10
|
-
/**
|
|
11
|
-
* Feature Gate Key -
|
|
12
|
-
* How many days between closing the container from this error (avoids locking user out of their file altogether)
|
|
13
|
-
*/
|
|
14
|
-
exports.skipClosureForXDaysKey = "Fluid.GarbageCollection.Dogfood.SweepReadyUsageDetection.SkipClosureForXDays";
|
|
15
|
-
/**
|
|
16
|
-
* LocalStorage key (NOT via feature gate / monitoring context)
|
|
17
|
-
* A map from docId to info about the last time we closed due to this error
|
|
18
|
-
*/
|
|
19
|
-
exports.closuresMapLocalStorageKey = "Fluid.GarbageCollection.Dogfood.SweepReadyUsageDetection.Closures";
|
|
20
|
-
/**
|
|
21
|
-
* Feature gate key to enable closing the container if SweepReady objects are used.
|
|
22
|
-
* Value should contain keywords "interactiveClient" and/or "summarizer" to enable detection in each container type
|
|
23
|
-
*/
|
|
24
|
-
const sweepReadyUsageDetectionSetting = {
|
|
25
|
-
read(config) {
|
|
26
|
-
const sweepReadyUsageDetectionKey = "Fluid.GarbageCollection.Dogfood.SweepReadyUsageDetection";
|
|
27
|
-
const value = config.getString(sweepReadyUsageDetectionKey);
|
|
28
|
-
if (value === undefined) {
|
|
29
|
-
return { interactiveClient: false, summarizer: false };
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
interactiveClient: value.includes("interactiveClient"),
|
|
33
|
-
summarizer: value.includes("summarizer"),
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Error class raised when a SweepReady object is used, indicating a bug in how
|
|
39
|
-
* references are managed in the container by the application, or a bug in how
|
|
40
|
-
* GC tracks those references.
|
|
41
|
-
*
|
|
42
|
-
* There's a chance for false positives when this error is raised by an Interactive Container,
|
|
43
|
-
* since only the Summarizer has the latest truth about unreferenced node tracking
|
|
44
|
-
*/
|
|
45
|
-
class SweepReadyUsageError extends telemetry_utils_1.LoggingError {
|
|
46
|
-
constructor() {
|
|
47
|
-
super(...arguments);
|
|
48
|
-
/** This errorType will be in temporary use (until Sweep is fully implemented) so don't add to any errorType type */
|
|
49
|
-
this.errorType = "unreferencedObjectUsedAfterGarbageCollected";
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
exports.SweepReadyUsageError = SweepReadyUsageError;
|
|
53
|
-
/**
|
|
54
|
-
* This class encapsulates the logic around what to do when a SweepReady object is used.
|
|
55
|
-
* There are several tactics we plan to use in Dogfood environments to aid diagnosis of these cases:
|
|
56
|
-
* - Closing the interactive container when either the interactive or summarizer client detects this kind of violation
|
|
57
|
-
* (via sweepReadyUsageDetectionSetting above)
|
|
58
|
-
* - Throttling the frequency of these crashes via a "Skip Closure Period" per container per device
|
|
59
|
-
* (via skipClosureForXDaysKey above. Uses localStorage and closuresMapLocalStorageKey to implement this behavior)
|
|
60
|
-
*/
|
|
61
|
-
class SweepReadyUsageDetectionHandler {
|
|
62
|
-
constructor(uniqueContainerKey, mc, closeFn, localStorageOverride) {
|
|
63
|
-
var _a;
|
|
64
|
-
this.uniqueContainerKey = uniqueContainerKey;
|
|
65
|
-
this.mc = mc;
|
|
66
|
-
this.closeFn = closeFn;
|
|
67
|
-
const noopStorage = { getItem: () => null, setItem: () => { } };
|
|
68
|
-
// localStorage is not defined in Node environment, so fall back to noopStorage if needed.
|
|
69
|
-
this.localStorage = (_a = localStorageOverride !== null && localStorageOverride !== void 0 ? localStorageOverride : globalThis.localStorage) !== null && _a !== void 0 ? _a : noopStorage;
|
|
70
|
-
if (this.localStorage === noopStorage) {
|
|
71
|
-
// This means the Skip Closure Period logic will not work.
|
|
72
|
-
this.mc.logger.sendTelemetryEvent({
|
|
73
|
-
eventName: "SweepReadyUsageDetectionHandlerNoopStorage",
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* If SweepReady Usage Detection is enabled, close the interactive container.
|
|
79
|
-
* If the SkipClosureForXDays setting is set, don't close the container more than once in that period.
|
|
80
|
-
*
|
|
81
|
-
* Once Sweep is fully implemented, this will be removed since the objects will be gone
|
|
82
|
-
* and errors will arise elsewhere in the runtime
|
|
83
|
-
*/
|
|
84
|
-
usageDetectedInInteractiveClient(errorProps) {
|
|
85
|
-
var _a;
|
|
86
|
-
if (!sweepReadyUsageDetectionSetting.read(this.mc.config).interactiveClient) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
// Default stance is we close every time - this reflects the severity of SweepReady Object Usage.
|
|
90
|
-
// However, we may choose to "throttle" the closures by setting the SkipClosureForXDays setting,
|
|
91
|
-
// which will only allow the container to close once during that period, to avoid locking users out.
|
|
92
|
-
let shouldClose = true;
|
|
93
|
-
let pastClosuresMap = {};
|
|
94
|
-
let lastCloseTime;
|
|
95
|
-
const skipClosureForXDays = this.mc.config.getNumber(exports.skipClosureForXDaysKey);
|
|
96
|
-
if (skipClosureForXDays !== undefined) {
|
|
97
|
-
// Read pastClosuresMap from localStorage then extract the lastCloseTime from the map
|
|
98
|
-
try {
|
|
99
|
-
const rawValue = this.localStorage.getItem(exports.closuresMapLocalStorageKey);
|
|
100
|
-
const parsedValue = rawValue === null ? {} : JSON.parse(rawValue);
|
|
101
|
-
if (typeof parsedValue === "object") {
|
|
102
|
-
pastClosuresMap = parsedValue;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch (e) { }
|
|
106
|
-
lastCloseTime = (_a = pastClosuresMap[this.uniqueContainerKey]) === null || _a === void 0 ? void 0 : _a.lastCloseTime;
|
|
107
|
-
// Don't close if we did already within the Skip Closure Period
|
|
108
|
-
if (lastCloseTime !== undefined &&
|
|
109
|
-
Date.now() < lastCloseTime + skipClosureForXDays * gcDefinitions_1.oneDayMs) {
|
|
110
|
-
shouldClose = false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const error = new SweepReadyUsageError("SweepReady object used in Non-Summarizer Client", {
|
|
114
|
-
errorDetails: JSON.stringify(Object.assign(Object.assign({}, errorProps), { lastCloseTime, skipClosureForXDays })),
|
|
115
|
-
});
|
|
116
|
-
if (shouldClose) {
|
|
117
|
-
// Update closures map in localStorage before closing
|
|
118
|
-
// Note there is a race condition between different tabs updating localStorage and overwriting
|
|
119
|
-
// each others' updates. If so, some tab will crash again. Just reload one at a time to get unstuck
|
|
120
|
-
pastClosuresMap[this.uniqueContainerKey] = { lastCloseTime: Date.now() };
|
|
121
|
-
this.localStorage.setItem(exports.closuresMapLocalStorageKey, JSON.stringify(pastClosuresMap));
|
|
122
|
-
this.closeFn(error);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
this.mc.logger.sendErrorEvent({ eventName: "SweepReadyObject_UsageAllowed" }, error);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
exports.SweepReadyUsageDetectionHandler = SweepReadyUsageDetectionHandler;
|
|
130
|
-
//# sourceMappingURL=gcSweepReadyUsageDetection.js.map
|