@fluidframework/container-runtime 2.0.0-internal.3.0.5 → 2.0.0-internal.3.1.1
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/.eslintrc.js +19 -19
- package/.mocharc.js +2 -2
- package/api-extractor.json +2 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +2 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +9 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +80 -33
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +11 -9
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js +3 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +11 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +116 -72
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +11 -9
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +18 -13
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +68 -55
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -3
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +3 -1
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.d.ts +26 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +103 -18
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +8 -3
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/garbageCollection.d.ts +33 -14
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +178 -92
- package/dist/garbageCollection.js.map +1 -1
- package/dist/garbageCollectionConstants.d.ts +1 -0
- package/dist/garbageCollectionConstants.d.ts.map +1 -1
- package/dist/garbageCollectionConstants.js +4 -1
- package/dist/garbageCollectionConstants.js.map +1 -1
- package/dist/garbageCollectionHelpers.d.ts +26 -0
- package/dist/garbageCollectionHelpers.d.ts.map +1 -0
- package/dist/garbageCollectionHelpers.js +45 -0
- package/dist/garbageCollectionHelpers.js.map +1 -0
- package/dist/gcSweepReadyUsageDetection.d.ts +5 -5
- package/dist/gcSweepReadyUsageDetection.d.ts.map +1 -1
- package/dist/gcSweepReadyUsageDetection.js +14 -10
- package/dist/gcSweepReadyUsageDetection.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +5 -5
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +19 -12
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +0 -4
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +7 -43
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +4 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +20 -19
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/opProperties.d.ts.map +1 -1
- package/dist/opProperties.js +1 -3
- package/dist/opProperties.js.map +1 -1
- package/dist/orderedClientElection.d.ts.map +1 -1
- package/dist/orderedClientElection.js +10 -4
- package/dist/orderedClientElection.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 +7 -0
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +7 -4
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +34 -21
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +3 -2
- package/dist/scheduleManager.js.map +1 -1
- package/dist/serializedSnapshotStorage.d.ts +2 -2
- package/dist/serializedSnapshotStorage.d.ts.map +1 -1
- package/dist/serializedSnapshotStorage.js +5 -3
- package/dist/serializedSnapshotStorage.js.map +1 -1
- package/dist/summarizer.d.ts +2 -2
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +37 -17
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerClientElection.d.ts.map +1 -1
- package/dist/summarizerClientElection.js.map +1 -1
- package/dist/summarizerHandle.d.ts.map +1 -1
- package/dist/summarizerHandle.js.map +1 -1
- package/dist/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summarizerHeuristics.js +6 -9
- package/dist/summarizerHeuristics.js.map +1 -1
- package/dist/summarizerTypes.d.ts +21 -21
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryCollection.d.ts.map +1 -1
- package/dist/summaryCollection.js +18 -8
- package/dist/summaryCollection.js.map +1 -1
- package/dist/summaryFormat.d.ts +5 -2
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +18 -10
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +35 -16
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +21 -9
- package/dist/summaryManager.js.map +1 -1
- package/dist/throttler.d.ts +2 -2
- package/dist/throttler.d.ts.map +1 -1
- package/dist/throttler.js +4 -4
- package/dist/throttler.js.map +1 -1
- package/garbageCollection.md +15 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +9 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +82 -35
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +11 -9
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js +3 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +11 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +122 -78
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +11 -9
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +18 -13
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +71 -58
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -3
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +3 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.d.ts +26 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +109 -24
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +9 -4
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/garbageCollection.d.ts +33 -14
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +180 -94
- package/lib/garbageCollection.js.map +1 -1
- package/lib/garbageCollectionConstants.d.ts +1 -0
- package/lib/garbageCollectionConstants.d.ts.map +1 -1
- package/lib/garbageCollectionConstants.js +3 -0
- package/lib/garbageCollectionConstants.js.map +1 -1
- package/lib/garbageCollectionHelpers.d.ts +26 -0
- package/lib/garbageCollectionHelpers.d.ts.map +1 -0
- package/lib/garbageCollectionHelpers.js +40 -0
- package/lib/garbageCollectionHelpers.js.map +1 -0
- package/lib/gcSweepReadyUsageDetection.d.ts +5 -5
- package/lib/gcSweepReadyUsageDetection.d.ts.map +1 -1
- package/lib/gcSweepReadyUsageDetection.js +14 -10
- package/lib/gcSweepReadyUsageDetection.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +5 -5
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +19 -12
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +0 -4
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +7 -43
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +5 -2
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +20 -19
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/opProperties.d.ts.map +1 -1
- package/lib/opProperties.js +1 -3
- package/lib/opProperties.js.map +1 -1
- package/lib/orderedClientElection.d.ts.map +1 -1
- package/lib/orderedClientElection.js +10 -4
- package/lib/orderedClientElection.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 +7 -0
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +7 -4
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +35 -22
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +3 -2
- package/lib/scheduleManager.js.map +1 -1
- package/lib/serializedSnapshotStorage.d.ts +2 -2
- package/lib/serializedSnapshotStorage.d.ts.map +1 -1
- package/lib/serializedSnapshotStorage.js +5 -3
- package/lib/serializedSnapshotStorage.js.map +1 -1
- package/lib/summarizer.d.ts +2 -2
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +37 -17
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerClientElection.d.ts.map +1 -1
- package/lib/summarizerClientElection.js.map +1 -1
- package/lib/summarizerHandle.d.ts.map +1 -1
- package/lib/summarizerHandle.js.map +1 -1
- package/lib/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summarizerHeuristics.js +6 -9
- package/lib/summarizerHeuristics.js.map +1 -1
- package/lib/summarizerTypes.d.ts +21 -21
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryCollection.d.ts.map +1 -1
- package/lib/summaryCollection.js +18 -8
- package/lib/summaryCollection.js.map +1 -1
- package/lib/summaryFormat.d.ts +5 -2
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +20 -12
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +35 -16
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +21 -9
- package/lib/summaryManager.js.map +1 -1
- package/lib/throttler.d.ts +2 -2
- package/lib/throttler.d.ts.map +1 -1
- package/lib/throttler.js +4 -4
- package/lib/throttler.js.map +1 -1
- package/package.json +121 -115
- package/prettier.config.cjs +1 -1
- package/src/batchTracker.ts +54 -49
- package/src/blobManager.ts +793 -672
- package/src/connectionTelemetry.ts +280 -249
- package/src/containerHandleContext.ts +27 -29
- package/src/containerRuntime.ts +3168 -2988
- package/src/dataStore.ts +172 -159
- package/src/dataStoreContext.ts +1098 -1055
- package/src/dataStoreContexts.ts +178 -161
- package/src/dataStoreRegistry.ts +25 -20
- package/src/dataStores.ts +884 -728
- package/src/deltaScheduler.ts +158 -150
- package/src/garbageCollection.ts +1860 -1688
- package/src/garbageCollectionConstants.ts +3 -0
- package/src/garbageCollectionHelpers.ts +61 -0
- package/src/gcSweepReadyUsageDetection.ts +89 -83
- package/src/index.ts +67 -66
- package/src/opLifecycle/README.md +152 -0
- package/src/opLifecycle/batchManager.ts +145 -141
- package/src/opLifecycle/definitions.ts +29 -29
- package/src/opLifecycle/index.ts +5 -5
- package/src/opLifecycle/opCompressor.ts +54 -53
- package/src/opLifecycle/opDecompressor.ts +100 -128
- package/src/opLifecycle/opSplitter.ts +214 -188
- package/src/opLifecycle/outbox.ts +204 -195
- package/src/opLifecycle/remoteMessageProcessor.ts +62 -62
- package/src/opProperties.ts +11 -9
- package/src/orderedClientElection.ts +489 -457
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +384 -338
- package/src/runWhileConnectedCoordinator.ts +78 -71
- package/src/runningSummarizer.ts +619 -581
- package/src/scheduleManager.ts +299 -269
- package/src/serializedSnapshotStorage.ts +126 -112
- package/src/summarizer.ts +417 -381
- package/src/summarizerClientElection.ts +107 -100
- package/src/summarizerHandle.ts +11 -9
- package/src/summarizerHeuristics.ts +183 -186
- package/src/summarizerTypes.ts +344 -330
- package/src/summaryCollection.ts +378 -349
- package/src/summaryFormat.ts +165 -143
- package/src/summaryGenerator.ts +465 -410
- package/src/summaryManager.ts +377 -348
- package/src/throttler.ts +131 -122
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
- package/dist/garbageCollectionTombstoneUtils.d.ts +0 -14
- package/dist/garbageCollectionTombstoneUtils.d.ts.map +0 -1
- package/dist/garbageCollectionTombstoneUtils.js +0 -23
- package/dist/garbageCollectionTombstoneUtils.js.map +0 -1
- package/lib/garbageCollectionTombstoneUtils.d.ts +0 -14
- package/lib/garbageCollectionTombstoneUtils.d.ts.map +0 -1
- package/lib/garbageCollectionTombstoneUtils.js +0 -19
- package/lib/garbageCollectionTombstoneUtils.js.map +0 -1
- package/src/garbageCollectionTombstoneUtils.ts +0 -28
|
@@ -26,7 +26,7 @@ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
|
26
26
|
const containerRuntime_1 = require("./containerRuntime");
|
|
27
27
|
const dataStores_1 = require("./dataStores");
|
|
28
28
|
const garbageCollectionConstants_1 = require("./garbageCollectionConstants");
|
|
29
|
-
const
|
|
29
|
+
const garbageCollectionHelpers_1 = require("./garbageCollectionHelpers");
|
|
30
30
|
const summaryFormat_1 = require("./summaryFormat");
|
|
31
31
|
/** The types of GC nodes in the GC reference graph. */
|
|
32
32
|
exports.GCNodeType = {
|
|
@@ -127,15 +127,15 @@ exports.UnreferencedStateTracker = UnreferencedStateTracker;
|
|
|
127
127
|
* Graph - all nodes with their respective routes
|
|
128
128
|
*
|
|
129
129
|
* ```
|
|
130
|
-
*
|
|
130
|
+
* GC Graph
|
|
131
131
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* NodeId = "dds1"
|
|
132
|
+
* Node
|
|
133
|
+
* NodeId = "datastore1"
|
|
134
|
+
* / \\
|
|
135
|
+
* OutboundRoute OutboundRoute
|
|
136
|
+
* / \\
|
|
137
|
+
* Node Node
|
|
138
|
+
* NodeId = "dds1" NodeId = "dds2"
|
|
139
139
|
* ```
|
|
140
140
|
*/
|
|
141
141
|
class GarbageCollector {
|
|
@@ -167,10 +167,14 @@ class GarbageCollector {
|
|
|
167
167
|
const baseSnapshot = createParams.baseSnapshot;
|
|
168
168
|
const metadata = createParams.metadata;
|
|
169
169
|
const readAndParseBlob = createParams.readAndParseBlob;
|
|
170
|
-
this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(createParams.baseLogger, "GarbageCollector", {
|
|
170
|
+
this.mc = (0, telemetry_utils_1.loggerToMonitoringContext)(telemetry_utils_1.ChildLogger.create(createParams.baseLogger, "GarbageCollector", {
|
|
171
|
+
all: { completedGCRuns: () => this.completedRuns },
|
|
172
|
+
}));
|
|
171
173
|
// If version upgrade is not enabled, fall back to the stable GC version.
|
|
172
174
|
this.currentGCVersion =
|
|
173
|
-
this.mc.config.getBoolean(garbageCollectionConstants_1.gcVersionUpgradeToV2Key) === true
|
|
175
|
+
this.mc.config.getBoolean(garbageCollectionConstants_1.gcVersionUpgradeToV2Key) === true
|
|
176
|
+
? garbageCollectionConstants_1.currentGCVersion
|
|
177
|
+
: garbageCollectionConstants_1.stableGCVersion;
|
|
174
178
|
let prevSummaryGCVersion;
|
|
175
179
|
/**
|
|
176
180
|
* Sweep timeout is the time after which unreferenced content can be swept.
|
|
@@ -183,8 +187,8 @@ class GarbageCollector {
|
|
|
183
187
|
function computeSweepTimeout(sessionExpiryTimeoutMs) {
|
|
184
188
|
const maxSnapshotCacheExpiryMs = 5 * garbageCollectionConstants_1.oneDayMs;
|
|
185
189
|
const bufferMs = garbageCollectionConstants_1.oneDayMs;
|
|
186
|
-
return sessionExpiryTimeoutMs &&
|
|
187
|
-
|
|
190
|
+
return (sessionExpiryTimeoutMs &&
|
|
191
|
+
sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs);
|
|
188
192
|
}
|
|
189
193
|
/**
|
|
190
194
|
* The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
|
|
@@ -219,7 +223,8 @@ class GarbageCollector {
|
|
|
219
223
|
this.sweepEnabled = this.gcOptions.sweepAllowed === true;
|
|
220
224
|
// Set the Session Expiry only if the flag is enabled and GC is enabled.
|
|
221
225
|
if (this.mc.config.getBoolean(garbageCollectionConstants_1.runSessionExpiryKey) && this.gcEnabled) {
|
|
222
|
-
this.sessionExpiryTimeoutMs =
|
|
226
|
+
this.sessionExpiryTimeoutMs =
|
|
227
|
+
(_c = this.gcOptions.sessionExpiryTimeoutMs) !== null && _c !== void 0 ? _c : garbageCollectionConstants_1.defaultSessionExpiryDurationMs;
|
|
223
228
|
}
|
|
224
229
|
this.sweepTimeoutMs =
|
|
225
230
|
testOverrideSweepTimeoutMs !== null && testOverrideSweepTimeoutMs !== void 0 ? testOverrideSweepTimeoutMs : computeSweepTimeout(this.sessionExpiryTimeoutMs);
|
|
@@ -234,7 +239,9 @@ class GarbageCollector {
|
|
|
234
239
|
// If Test Override config is set, override Session Expiry timeout.
|
|
235
240
|
const overrideSessionExpiryTimeoutMs = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.SessionExpiryMs");
|
|
236
241
|
const timeoutMs = overrideSessionExpiryTimeoutMs !== null && overrideSessionExpiryTimeoutMs !== void 0 ? overrideSessionExpiryTimeoutMs : this.sessionExpiryTimeoutMs;
|
|
237
|
-
this.sessionExpiryTimer = new common_utils_1.Timer(timeoutMs, () => {
|
|
242
|
+
this.sessionExpiryTimer = new common_utils_1.Timer(timeoutMs, () => {
|
|
243
|
+
this.runtime.closeFn(new container_utils_1.ClientSessionExpiredError(`Client session expired.`, timeoutMs));
|
|
244
|
+
});
|
|
238
245
|
this.sessionExpiryTimer.start();
|
|
239
246
|
}
|
|
240
247
|
// For existing document, the latest summary is the one that we loaded from. So, use its GC version as the
|
|
@@ -249,11 +256,12 @@ class GarbageCollector {
|
|
|
249
256
|
*
|
|
250
257
|
* These conditions can be overridden via runGCKey feature flag.
|
|
251
258
|
*/
|
|
252
|
-
this.shouldRunGC =
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
259
|
+
this.shouldRunGC =
|
|
260
|
+
(_d = this.mc.config.getBoolean(garbageCollectionConstants_1.runGCKey)) !== null && _d !== void 0 ? _d :
|
|
261
|
+
// GC must be enabled for the document.
|
|
262
|
+
(this.gcEnabled &&
|
|
263
|
+
// GC must not be disabled via GC options.
|
|
264
|
+
!this.gcOptions.disableGC);
|
|
257
265
|
/**
|
|
258
266
|
* Whether sweep should run or not. The following conditions have to be met to run sweep:
|
|
259
267
|
*
|
|
@@ -265,21 +273,24 @@ class GarbageCollector {
|
|
|
265
273
|
* feature flag.
|
|
266
274
|
*/
|
|
267
275
|
this.shouldRunSweep =
|
|
268
|
-
this.shouldRunGC
|
|
269
|
-
|
|
270
|
-
|
|
276
|
+
this.shouldRunGC &&
|
|
277
|
+
this.sweepTimeoutMs !== undefined &&
|
|
278
|
+
((_e = this.mc.config.getBoolean(garbageCollectionConstants_1.runSweepKey)) !== null && _e !== void 0 ? _e : this.sweepEnabled);
|
|
271
279
|
this.trackGCState = this.mc.config.getBoolean(garbageCollectionConstants_1.trackGCStateKey) === true;
|
|
272
280
|
// Override inactive timeout if test config or gc options to override it is set.
|
|
273
|
-
this.inactiveTimeoutMs =
|
|
281
|
+
this.inactiveTimeoutMs =
|
|
282
|
+
(_g = (_f = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _f !== void 0 ? _f : this.gcOptions.inactiveTimeoutMs) !== null && _g !== void 0 ? _g : garbageCollectionConstants_1.defaultInactiveTimeoutMs;
|
|
274
283
|
// Inactive timeout must be greater than sweep timeout since a node goes from active -> inactive -> sweep ready.
|
|
275
284
|
if (this.sweepTimeoutMs !== undefined && this.inactiveTimeoutMs > this.sweepTimeoutMs) {
|
|
276
285
|
throw new container_utils_1.UsageError("inactive timeout should not be greater than the sweep timeout");
|
|
277
286
|
}
|
|
278
287
|
// Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
|
|
279
|
-
this.testMode =
|
|
288
|
+
this.testMode =
|
|
289
|
+
(_h = this.mc.config.getBoolean(garbageCollectionConstants_1.gcTestModeKey)) !== null && _h !== void 0 ? _h : this.gcOptions.runGCInTestMode === true;
|
|
280
290
|
// Whether we are running in tombstone mode. This is enabled by default if sweep won't run. It can be disabled
|
|
281
291
|
// via feature flags.
|
|
282
|
-
this.tombstoneMode =
|
|
292
|
+
this.tombstoneMode =
|
|
293
|
+
!this.shouldRunSweep && this.mc.config.getBoolean(garbageCollectionConstants_1.disableTombstoneKey) !== true;
|
|
283
294
|
// If GC ran in the container that generated the base snapshot, it will have a GC tree.
|
|
284
295
|
this.wasGCRunInLatestSummary = (baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[runtime_definitions_1.gcTreeKey]) !== undefined;
|
|
285
296
|
// Get the GC data from the base snapshot. Use LazyPromise because we only want to do this once since it
|
|
@@ -298,7 +309,9 @@ class GarbageCollector {
|
|
|
298
309
|
// back-compat - Older documents will have the GC blobs in each data store's summary tree. Get them and
|
|
299
310
|
// consolidate into IGarbageCollectionState format.
|
|
300
311
|
// Add a node for the root node that is not present in older snapshot format.
|
|
301
|
-
const gcState = {
|
|
312
|
+
const gcState = {
|
|
313
|
+
gcNodes: { "/": { outboundRoutes: [] } },
|
|
314
|
+
};
|
|
302
315
|
const dataStoreSnapshotTree = (0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata);
|
|
303
316
|
(0, common_utils_1.assert)(dataStoreSnapshotTree !== undefined, 0x2a8 /* "Expected data store snapshot tree in base snapshot" */);
|
|
304
317
|
for (const [dsId, dsSnapshotTree] of Object.entries(dataStoreSnapshotTree.trees)) {
|
|
@@ -322,10 +335,13 @@ class GarbageCollector {
|
|
|
322
335
|
// Prefix the data store id to the GC node ids to make them relative to the root from being
|
|
323
336
|
// relative to the data store. Similar to how its done in DataStore::getGCData.
|
|
324
337
|
const rootId = id === "/" ? dsRootId : `${dsRootId}${id}`;
|
|
325
|
-
gcState.gcNodes[rootId] = {
|
|
338
|
+
gcState.gcNodes[rootId] = {
|
|
339
|
+
outboundRoutes: Array.from(outboundRoutes),
|
|
340
|
+
};
|
|
326
341
|
}
|
|
327
342
|
(0, common_utils_1.assert)(gcState.gcNodes[dsRootId] !== undefined, 0x2a9 /* GC nodes for data store not in GC blob */);
|
|
328
|
-
gcState.gcNodes[dsRootId].unreferencedTimestampMs =
|
|
343
|
+
gcState.gcNodes[dsRootId].unreferencedTimestampMs =
|
|
344
|
+
gcSummaryDetails.unrefTimestamp;
|
|
329
345
|
}
|
|
330
346
|
// If there is only one node (root node just added above), either GC is disabled or we are loading from
|
|
331
347
|
// the first summary generated by detached container. In both cases, GC was not run - return undefined.
|
|
@@ -419,8 +435,8 @@ class GarbageCollector {
|
|
|
419
435
|
* 4.2. This client's latest summary was updated from a snapshot that has a different GC version.
|
|
420
436
|
*/
|
|
421
437
|
get summaryStateNeedsReset() {
|
|
422
|
-
return this.gcStateNeedsReset ||
|
|
423
|
-
(this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion);
|
|
438
|
+
return (this.gcStateNeedsReset ||
|
|
439
|
+
(this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion));
|
|
424
440
|
}
|
|
425
441
|
/**
|
|
426
442
|
* Tells whether the GC state needs to be reset. This can happen under 3 conditions:
|
|
@@ -435,7 +451,7 @@ class GarbageCollector {
|
|
|
435
451
|
*
|
|
436
452
|
* Note that the state will be reset only once for the first summary generated after this returns true. After that,
|
|
437
453
|
* this will return false.
|
|
438
|
-
|
|
454
|
+
*/
|
|
439
455
|
get gcStateNeedsReset() {
|
|
440
456
|
return this.wasGCRunInLatestSummary !== this.shouldRunGC;
|
|
441
457
|
}
|
|
@@ -466,6 +482,7 @@ class GarbageCollector {
|
|
|
466
482
|
// If running in tombstone mode, initialize the tombstone state from the snapshot. Also, notify the runtime of
|
|
467
483
|
// tombstone routes.
|
|
468
484
|
if (this.tombstoneMode && baseSnapshotData.tombstones !== undefined) {
|
|
485
|
+
// Create a copy since we are writing from a source we don't control
|
|
469
486
|
this.tombstones = Array.from(baseSnapshotData.tombstones);
|
|
470
487
|
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
471
488
|
}
|
|
@@ -493,7 +510,6 @@ class GarbageCollector {
|
|
|
493
510
|
for (const [, nodeStateTracker] of this.unreferencedNodesState) {
|
|
494
511
|
nodeStateTracker.stopTracking();
|
|
495
512
|
}
|
|
496
|
-
;
|
|
497
513
|
this.unreferencedNodesState.clear();
|
|
498
514
|
// If running sweep, the tombstone state represents the list of nodes that have been deleted during sweep.
|
|
499
515
|
// If running in tombstone mode, the tombstone state represents the list of nodes that have been marked as
|
|
@@ -501,7 +517,9 @@ class GarbageCollector {
|
|
|
501
517
|
// If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state
|
|
502
518
|
// in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.
|
|
503
519
|
if (this.shouldRunSweep) {
|
|
504
|
-
const snapshotDeletedNodes = (snapshotData === null || snapshotData === void 0 ? void 0 : snapshotData.
|
|
520
|
+
const snapshotDeletedNodes = (snapshotData === null || snapshotData === void 0 ? void 0 : snapshotData.deletedNodes)
|
|
521
|
+
? new Set(snapshotData.deletedNodes)
|
|
522
|
+
: undefined;
|
|
505
523
|
// If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to
|
|
506
524
|
// delete them.
|
|
507
525
|
if (snapshotDeletedNodes !== undefined) {
|
|
@@ -575,11 +593,13 @@ class GarbageCollector {
|
|
|
575
593
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
576
594
|
* @returns stats of the GC run or undefined if GC did not run.
|
|
577
595
|
*/
|
|
578
|
-
async collectGarbage(options
|
|
596
|
+
async collectGarbage(options) {
|
|
579
597
|
var _a;
|
|
580
598
|
const fullGC = (_a = options.fullGC) !== null && _a !== void 0 ? _a : (this.gcOptions.runFullGC === true || this.summaryStateNeedsReset);
|
|
581
599
|
const logger = options.logger
|
|
582
|
-
? telemetry_utils_1.ChildLogger.create(options.logger, undefined, {
|
|
600
|
+
? telemetry_utils_1.ChildLogger.create(options.logger, undefined, {
|
|
601
|
+
all: { completedGCRuns: () => this.completedRuns },
|
|
602
|
+
})
|
|
583
603
|
: this.mc.logger;
|
|
584
604
|
/**
|
|
585
605
|
* If there is no current reference timestamp, skip running GC. We need the current timestamp to track
|
|
@@ -598,8 +618,6 @@ class GarbageCollector {
|
|
|
598
618
|
});
|
|
599
619
|
return undefined;
|
|
600
620
|
}
|
|
601
|
-
// Add the options that are used to run GC to the telemetry context.
|
|
602
|
-
telemetryContext === null || telemetryContext === void 0 ? void 0 : telemetryContext.setAll("fluid_GC", "Options", { fullGC, runSweep: options.runSweep });
|
|
603
621
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, { eventName: "GarbageCollection" }, async (event) => {
|
|
604
622
|
await this.runPreGCSteps();
|
|
605
623
|
// Get the runtime's GC data and run GC on the reference graph in it.
|
|
@@ -621,26 +639,29 @@ class GarbageCollector {
|
|
|
621
639
|
// Generate statistics from the current run. This is done before updating the current state because it
|
|
622
640
|
// generates some of its data based on previous state of the system.
|
|
623
641
|
const gcStats = this.generateStats(gcResult);
|
|
624
|
-
// Update the state
|
|
625
|
-
|
|
626
|
-
this.updateStateSinceLastRun(gcData, logger);
|
|
627
|
-
// Update the current state and update the runtime of all routes or ids that used as per the GC run.
|
|
628
|
-
this.updateCurrentState(gcData, gcResult, currentReferenceTimestampMs);
|
|
642
|
+
// Update the current mark state and update the runtime of all used routes or ids that used as per the GC run.
|
|
643
|
+
const sweepReadyNodes = this.updateMarkPhase(gcData, gcResult, currentReferenceTimestampMs, logger);
|
|
629
644
|
this.runtime.updateUsedRoutes(gcResult.referencedNodeIds);
|
|
630
645
|
// Log events for objects that are ready to be deleted by sweep. When we have sweep enabled, we will
|
|
631
646
|
// delete these objects here instead.
|
|
632
647
|
this.logSweepEvents(logger, currentReferenceTimestampMs);
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
648
|
+
let updatedGCData = gcData;
|
|
649
|
+
if (this.shouldRunSweep) {
|
|
650
|
+
updatedGCData = this.runSweepPhase(sweepReadyNodes, gcData);
|
|
651
|
+
}
|
|
652
|
+
else if (this.testMode) {
|
|
653
|
+
// If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios
|
|
654
|
+
// involving access to deleted data.
|
|
636
655
|
this.runtime.updateUnusedRoutes(gcResult.deletedNodeIds);
|
|
637
656
|
}
|
|
638
657
|
else if (this.tombstoneMode) {
|
|
658
|
+
this.tombstones = sweepReadyNodes;
|
|
639
659
|
// If we are running in GC tombstone mode, update tombstoned routes. This enables testing scenarios
|
|
640
660
|
// involving access to "deleted" data without actually deleting the data from summaries.
|
|
641
661
|
// Note: we will not tombstone in test mode.
|
|
642
662
|
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
643
663
|
}
|
|
664
|
+
this.gcDataFromLastRun = (0, garbage_collector_1.cloneGCData)(updatedGCData);
|
|
644
665
|
// Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and
|
|
645
666
|
// updates its state so that we don't send false positives based on intermediate state. For example, we may get
|
|
646
667
|
// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.
|
|
@@ -672,7 +693,9 @@ class GarbageCollector {
|
|
|
672
693
|
: undefined;
|
|
673
694
|
// If running in tombstone mode, serialize and write tombstones, if any.
|
|
674
695
|
const serializedTombstones = this.tombstoneMode
|
|
675
|
-
?
|
|
696
|
+
? this.tombstones.length > 0
|
|
697
|
+
? JSON.stringify(this.tombstones.sort())
|
|
698
|
+
: undefined
|
|
676
699
|
: undefined;
|
|
677
700
|
/**
|
|
678
701
|
* Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,
|
|
@@ -681,11 +704,15 @@ class GarbageCollector {
|
|
|
681
704
|
* for each of these that did not change, write a summary handle.
|
|
682
705
|
*/
|
|
683
706
|
if (this.trackGCState) {
|
|
684
|
-
this.pendingSummaryData = {
|
|
707
|
+
this.pendingSummaryData = {
|
|
708
|
+
serializedGCState,
|
|
709
|
+
serializedTombstones,
|
|
710
|
+
serializedDeletedNodes,
|
|
711
|
+
};
|
|
685
712
|
if (trackState && !fullTree && this.latestSummaryData !== undefined) {
|
|
686
713
|
// If nothing changed since last summary, send a summary handle for the entire GC data.
|
|
687
|
-
if (this.latestSummaryData.serializedGCState === serializedGCState
|
|
688
|
-
|
|
714
|
+
if (this.latestSummaryData.serializedGCState === serializedGCState &&
|
|
715
|
+
this.latestSummaryData.serializedTombstones === serializedTombstones) {
|
|
689
716
|
const stats = (0, runtime_utils_1.mergeStats)();
|
|
690
717
|
stats.handleNodeCount++;
|
|
691
718
|
return {
|
|
@@ -728,7 +755,8 @@ class GarbageCollector {
|
|
|
728
755
|
// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a
|
|
729
756
|
// summary blob.
|
|
730
757
|
if (serializedTombstones !== undefined) {
|
|
731
|
-
if (((_b = this.latestSummaryData) === null || _b === void 0 ? void 0 : _b.serializedTombstones) === serializedTombstones &&
|
|
758
|
+
if (((_b = this.latestSummaryData) === null || _b === void 0 ? void 0 : _b.serializedTombstones) === serializedTombstones &&
|
|
759
|
+
trackState) {
|
|
732
760
|
builder.addHandle(runtime_definitions_1.gcTombstoneBlobKey, protocol_definitions_1.SummaryType.Blob, `/${runtime_definitions_1.gcTreeKey}/${runtime_definitions_1.gcTombstoneBlobKey}`);
|
|
733
761
|
}
|
|
734
762
|
else {
|
|
@@ -740,7 +768,8 @@ class GarbageCollector {
|
|
|
740
768
|
return builder.getSummaryTree();
|
|
741
769
|
}
|
|
742
770
|
// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.
|
|
743
|
-
if (((_c = this.latestSummaryData) === null || _c === void 0 ? void 0 : _c.serializedDeletedNodes) === serializedDeletedNodes &&
|
|
771
|
+
if (((_c = this.latestSummaryData) === null || _c === void 0 ? void 0 : _c.serializedDeletedNodes) === serializedDeletedNodes &&
|
|
772
|
+
trackState) {
|
|
744
773
|
builder.addHandle(runtime_definitions_1.gcDeletedBlobKey, protocol_definitions_1.SummaryType.Blob, `/${runtime_definitions_1.gcTreeKey}/${runtime_definitions_1.gcDeletedBlobKey}`);
|
|
745
774
|
}
|
|
746
775
|
else {
|
|
@@ -804,7 +833,11 @@ class GarbageCollector {
|
|
|
804
833
|
// to be at least one op (summary op / ack, if nothing else) if a snapshot was taken.
|
|
805
834
|
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
806
835
|
if (currentReferenceTimestampMs === undefined) {
|
|
807
|
-
throw container_utils_1.DataProcessingError.create("No reference timestamp when updating GC state from snapshot", "refreshLatestSummary", undefined, {
|
|
836
|
+
throw container_utils_1.DataProcessingError.create("No reference timestamp when updating GC state from snapshot", "refreshLatestSummary", undefined, {
|
|
837
|
+
proposalHandle,
|
|
838
|
+
summaryRefSeq: result.summaryRefSeq,
|
|
839
|
+
details: JSON.stringify(this.configs),
|
|
840
|
+
});
|
|
808
841
|
}
|
|
809
842
|
const gcSnapshotTree = snapshotTree.trees[runtime_definitions_1.gcTreeKey];
|
|
810
843
|
// If GC ran in the container that generated this snapshot, it will have a GC tree.
|
|
@@ -861,12 +894,12 @@ class GarbageCollector {
|
|
|
861
894
|
else if (nodeType === exports.GCNodeType.Blob) {
|
|
862
895
|
eventName = "GC_Tombstone_Blob_Revived";
|
|
863
896
|
}
|
|
864
|
-
(0,
|
|
897
|
+
(0, garbageCollectionHelpers_1.sendGCUnexpectedUsageEvent)(this.mc, {
|
|
865
898
|
eventName,
|
|
866
899
|
category: "generic",
|
|
867
|
-
isSummarizerClient: this.isSummarizerClient,
|
|
868
900
|
url: (0, garbage_collector_1.trimLeadingSlashes)(toNodePath),
|
|
869
901
|
nodeType,
|
|
902
|
+
gcTombstoneEnforcementAllowed: this.runtime.gcTombstoneEnforcementAllowed,
|
|
870
903
|
}, undefined /* packagePath */);
|
|
871
904
|
}
|
|
872
905
|
}
|
|
@@ -890,13 +923,16 @@ class GarbageCollector {
|
|
|
890
923
|
* @param gcData - The data representing the reference graph on which GC is run.
|
|
891
924
|
* @param gcResult - The result of the GC run on the gcData.
|
|
892
925
|
* @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.
|
|
926
|
+
* @returns - A list of sweep ready nodes. (Nodes ready to be deleted)
|
|
893
927
|
*/
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
928
|
+
updateMarkPhase(gcData, gcResult, currentReferenceTimestampMs, logger) {
|
|
929
|
+
var _a;
|
|
930
|
+
// Get references from the current GC run + references between previous and current run and then update each
|
|
931
|
+
// node's state
|
|
932
|
+
const allNodesReferencedBetweenGCs = (_a = this.findAllNodesReferencedBetweenGCs(gcData, this.gcDataFromLastRun, logger)) !== null && _a !== void 0 ? _a : gcResult.referencedNodeIds;
|
|
897
933
|
this.newReferencesSinceLastRun.clear();
|
|
898
934
|
// Iterate through the referenced nodes and stop tracking if they were unreferenced before.
|
|
899
|
-
for (const nodeId of
|
|
935
|
+
for (const nodeId of allNodesReferencedBetweenGCs) {
|
|
900
936
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
901
937
|
if (nodeStateTracker !== undefined) {
|
|
902
938
|
// Stop tracking so as to clear out any running timers.
|
|
@@ -909,7 +945,10 @@ class GarbageCollector {
|
|
|
909
945
|
* If a node became unreferenced in this run, start tracking it.
|
|
910
946
|
* If a node was already unreferenced, update its tracking information. Since the current reference time is
|
|
911
947
|
* from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.
|
|
948
|
+
*
|
|
949
|
+
* If a node is sweep ready, store and then return it.
|
|
912
950
|
*/
|
|
951
|
+
const sweepReadyNodes = [];
|
|
913
952
|
for (const nodeId of gcResult.deletedNodeIds) {
|
|
914
953
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
915
954
|
if (nodeStateTracker === undefined) {
|
|
@@ -917,14 +956,51 @@ class GarbageCollector {
|
|
|
917
956
|
}
|
|
918
957
|
else {
|
|
919
958
|
nodeStateTracker.updateTracking(currentReferenceTimestampMs);
|
|
920
|
-
if (
|
|
921
|
-
|
|
922
|
-
if (nodeType === exports.GCNodeType.DataStore || nodeType === exports.GCNodeType.Blob) {
|
|
923
|
-
this.tombstones.push(nodeId);
|
|
924
|
-
}
|
|
959
|
+
if (nodeStateTracker.state === exports.UnreferencedState.SweepReady) {
|
|
960
|
+
sweepReadyNodes.push(nodeId);
|
|
925
961
|
}
|
|
926
962
|
}
|
|
927
963
|
}
|
|
964
|
+
return sweepReadyNodes;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Deletes nodes from both the runtime and garbage collection
|
|
968
|
+
* @param sweepReadyNodes - nodes that are ready to be deleted
|
|
969
|
+
*/
|
|
970
|
+
runSweepPhase(sweepReadyNodes, gcData) {
|
|
971
|
+
// TODO: GC:Validation - validate that removed routes are not double deleted
|
|
972
|
+
// TODO: GC:Validation - validate that the child routes of removed routes are deleted as well
|
|
973
|
+
const sweptRoutes = this.runtime.deleteUnusedNodes(sweepReadyNodes);
|
|
974
|
+
const updatedGCData = this.deleteSweptRoutes(sweptRoutes, gcData);
|
|
975
|
+
for (const nodeId of sweptRoutes) {
|
|
976
|
+
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
977
|
+
// TODO: GC:Validation - assert that the nodeStateTracker is defined
|
|
978
|
+
if (nodeStateTracker !== undefined) {
|
|
979
|
+
// Stop tracking so as to clear out any running timers.
|
|
980
|
+
nodeStateTracker.stopTracking();
|
|
981
|
+
// Delete the node as we don't need to track it any more.
|
|
982
|
+
this.unreferencedNodesState.delete(nodeId);
|
|
983
|
+
}
|
|
984
|
+
// TODO: GC:Validation - assert that the deleted node is not a duplicate
|
|
985
|
+
this.deletedNodes.add(nodeId);
|
|
986
|
+
}
|
|
987
|
+
return updatedGCData;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* @returns IGarbageCollectionData after deleting the sweptRoutes from the gcData
|
|
991
|
+
*/
|
|
992
|
+
deleteSweptRoutes(sweptRoutes, gcData) {
|
|
993
|
+
const sweptRoutesSet = new Set(sweptRoutes);
|
|
994
|
+
const gcNodes = {};
|
|
995
|
+
for (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {
|
|
996
|
+
if (!sweptRoutesSet.has(id)) {
|
|
997
|
+
gcNodes[id] = Array.from(outboundRoutes);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
// TODO: GC:Validation - assert that the nodeId is in gcData
|
|
1001
|
+
return {
|
|
1002
|
+
gcNodes,
|
|
1003
|
+
};
|
|
928
1004
|
}
|
|
929
1005
|
/**
|
|
930
1006
|
* Since GC runs periodically, the GC data that is generated only tells us the state of the world at that point in
|
|
@@ -936,16 +1012,19 @@ class GarbageCollector {
|
|
|
936
1012
|
* 2. A reference is added from one unreferenced node to one or more unreferenced nodes. Even though the node[s] were
|
|
937
1013
|
* unreferenced, they could have been accessed and in-memory reference to them added.
|
|
938
1014
|
*
|
|
939
|
-
* This function identifies nodes that were referenced since last run
|
|
1015
|
+
* This function identifies nodes that were referenced since the last run.
|
|
940
1016
|
* If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.
|
|
1017
|
+
*
|
|
1018
|
+
* @returns - a list of all nodes referenced from the last local summary until now.
|
|
941
1019
|
*/
|
|
942
|
-
|
|
1020
|
+
findAllNodesReferencedBetweenGCs(currentGCData, previousGCData, logger) {
|
|
943
1021
|
// If we haven't run GC before there is nothing to do.
|
|
944
|
-
|
|
945
|
-
|
|
1022
|
+
// No previousGCData, means nothing is unreferenced, and there are no reference state trackers to clear
|
|
1023
|
+
if (previousGCData === undefined) {
|
|
1024
|
+
return undefined;
|
|
946
1025
|
}
|
|
947
1026
|
// Find any references that haven't been identified correctly.
|
|
948
|
-
const missingExplicitReferences = this.findMissingExplicitReferences(currentGCData,
|
|
1027
|
+
const missingExplicitReferences = this.findMissingExplicitReferences(currentGCData, previousGCData, this.newReferencesSinceLastRun);
|
|
949
1028
|
if (missingExplicitReferences.length > 0) {
|
|
950
1029
|
missingExplicitReferences.forEach((missingExplicitReference) => {
|
|
951
1030
|
logger.sendErrorEvent({
|
|
@@ -956,9 +1035,9 @@ class GarbageCollector {
|
|
|
956
1035
|
});
|
|
957
1036
|
}
|
|
958
1037
|
// No references were added since the last run so we don't have to update reference states of any unreferenced
|
|
959
|
-
// nodes
|
|
1038
|
+
// nodes. There is no in between state at this point.
|
|
960
1039
|
if (this.newReferencesSinceLastRun.size === 0) {
|
|
961
|
-
return;
|
|
1040
|
+
return undefined;
|
|
962
1041
|
}
|
|
963
1042
|
/**
|
|
964
1043
|
* Generate a super set of the GC data that contains the nodes and edges from last run, plus any new node and
|
|
@@ -976,7 +1055,7 @@ class GarbageCollector {
|
|
|
976
1055
|
* - We don't require DDSes handles to be stored in a referenced DDS.
|
|
977
1056
|
* - A new data store may have "root" DDSes already created and we don't detect them today.
|
|
978
1057
|
*/
|
|
979
|
-
const gcDataSuperSet = (0, garbage_collector_1.concatGarbageCollectionData)(
|
|
1058
|
+
const gcDataSuperSet = (0, garbage_collector_1.concatGarbageCollectionData)(previousGCData, currentGCData);
|
|
980
1059
|
const newOutboundRoutesSinceLastRun = [];
|
|
981
1060
|
this.newReferencesSinceLastRun.forEach((outboundRoutes, sourceNodeId) => {
|
|
982
1061
|
if (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {
|
|
@@ -994,16 +1073,11 @@ class GarbageCollector {
|
|
|
994
1073
|
* Note that some of these nodes may be unreferenced now and if so, the current run will mark them as
|
|
995
1074
|
* unreferenced and add unreferenced state.
|
|
996
1075
|
*/
|
|
997
|
-
const gcResult = (0, garbage_collector_1.runGarbageCollection)(gcDataSuperSet.gcNodes, [
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
nodeStateTracker.stopTracking();
|
|
1003
|
-
// Delete the unreferenced state as we don't need to track it any more.
|
|
1004
|
-
this.unreferencedNodesState.delete(nodeId);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1076
|
+
const gcResult = (0, garbage_collector_1.runGarbageCollection)(gcDataSuperSet.gcNodes, [
|
|
1077
|
+
"/",
|
|
1078
|
+
...newOutboundRoutesSinceLastRun,
|
|
1079
|
+
]);
|
|
1080
|
+
return gcResult.referencedNodeIds;
|
|
1007
1081
|
}
|
|
1008
1082
|
/**
|
|
1009
1083
|
* Finds all new references or outbound routes in the current graph that haven't been explicitly notified to GC.
|
|
@@ -1019,7 +1093,7 @@ class GarbageCollector {
|
|
|
1019
1093
|
* @returns - a list of missing explicit references
|
|
1020
1094
|
*/
|
|
1021
1095
|
findMissingExplicitReferences(currentGCData, previousGCData, explicitReferences) {
|
|
1022
|
-
(0, common_utils_1.assert)(previousGCData !== undefined, 0x2b7);
|
|
1096
|
+
(0, common_utils_1.assert)(previousGCData !== undefined, 0x2b7 /* "Can't validate correctness without GC data from last run" */);
|
|
1023
1097
|
const currentGraph = Object.entries(currentGCData.gcNodes);
|
|
1024
1098
|
const missingExplicitReferences = [];
|
|
1025
1099
|
currentGraph.forEach(([nodeId, currentOutboundRoutes]) => {
|
|
@@ -1037,9 +1111,10 @@ class GarbageCollector {
|
|
|
1037
1111
|
*/
|
|
1038
1112
|
currentOutboundRoutes.forEach((route) => {
|
|
1039
1113
|
const nodeType = this.runtime.getNodeType(route);
|
|
1040
|
-
if ((nodeType === exports.GCNodeType.DataStore || nodeType === exports.GCNodeType.Blob)
|
|
1041
|
-
|
|
1042
|
-
|
|
1114
|
+
if ((nodeType === exports.GCNodeType.DataStore || nodeType === exports.GCNodeType.Blob) &&
|
|
1115
|
+
!nodeId.startsWith(route) &&
|
|
1116
|
+
!previousRoutes.includes(route) &&
|
|
1117
|
+
!explicitRoutes.includes(route)) {
|
|
1043
1118
|
missingExplicitRoutes.push(route);
|
|
1044
1119
|
}
|
|
1045
1120
|
});
|
|
@@ -1111,7 +1186,8 @@ class GarbageCollector {
|
|
|
1111
1186
|
* this will give us a view into how much deleted content a container has.
|
|
1112
1187
|
*/
|
|
1113
1188
|
logSweepEvents(logger, currentReferenceTimestampMs) {
|
|
1114
|
-
if (this.mc.config.getBoolean(garbageCollectionConstants_1.disableSweepLogKey) === true ||
|
|
1189
|
+
if (this.mc.config.getBoolean(garbageCollectionConstants_1.disableSweepLogKey) === true ||
|
|
1190
|
+
this.sweepTimeoutMs === undefined) {
|
|
1115
1191
|
return;
|
|
1116
1192
|
}
|
|
1117
1193
|
this.unreferencedNodesState.forEach((nodeStateTracker, nodeId) => {
|
|
@@ -1146,7 +1222,8 @@ class GarbageCollector {
|
|
|
1146
1222
|
// If there is no reference timestamp to work with, no ops have been processed after creation. If so, skip
|
|
1147
1223
|
// logging as nothing interesting would have happened worth logging.
|
|
1148
1224
|
// If the node is active, skip logging.
|
|
1149
|
-
if (currentReferenceTimestampMs === undefined ||
|
|
1225
|
+
if (currentReferenceTimestampMs === undefined ||
|
|
1226
|
+
nodeStateTracker.state === exports.UnreferencedState.Active) {
|
|
1150
1227
|
return;
|
|
1151
1228
|
}
|
|
1152
1229
|
// We only care about data stores and attachment blobs for this telemetry since GC only marks these objects
|
|
@@ -1205,11 +1282,18 @@ class GarbageCollector {
|
|
|
1205
1282
|
* revived and a Revived event will be logged for it.
|
|
1206
1283
|
*/
|
|
1207
1284
|
const nodeStateTracker = this.unreferencedNodesState.get(eventProps.id);
|
|
1208
|
-
const active = nodeStateTracker === undefined ||
|
|
1285
|
+
const active = nodeStateTracker === undefined ||
|
|
1286
|
+
nodeStateTracker.state === exports.UnreferencedState.Active;
|
|
1209
1287
|
if ((usageType === "Revived") === active) {
|
|
1210
1288
|
const pkg = await this.getNodePackagePath(eventProps.id);
|
|
1211
|
-
const fromPkg = eventProps.fromId
|
|
1212
|
-
|
|
1289
|
+
const fromPkg = eventProps.fromId
|
|
1290
|
+
? await this.getNodePackagePath(eventProps.fromId)
|
|
1291
|
+
: undefined;
|
|
1292
|
+
const event = Object.assign(Object.assign({}, propsToLog), { eventName: `${state}Object_${usageType}`, pkg: pkg
|
|
1293
|
+
? { value: pkg.join("/"), tag: telemetry_utils_1.TelemetryDataTag.CodeArtifact }
|
|
1294
|
+
: undefined, fromPkg: fromPkg
|
|
1295
|
+
? { value: fromPkg.join("/"), tag: telemetry_utils_1.TelemetryDataTag.CodeArtifact }
|
|
1296
|
+
: undefined });
|
|
1213
1297
|
if (state === exports.UnreferencedState.Inactive) {
|
|
1214
1298
|
logger.sendTelemetryEvent(event);
|
|
1215
1299
|
}
|
|
@@ -1236,7 +1320,9 @@ function generateSortedGCState(gcState) {
|
|
|
1236
1320
|
class TimerWithNoDefaultTimeout extends common_utils_1.Timer {
|
|
1237
1321
|
constructor(callback) {
|
|
1238
1322
|
// The default timeout/handlers will never be used since start/restart pass overrides below
|
|
1239
|
-
super(0, () => {
|
|
1323
|
+
super(0, () => {
|
|
1324
|
+
throw new Error("DefaultHandler should not be used");
|
|
1325
|
+
});
|
|
1240
1326
|
this.callback = callback;
|
|
1241
1327
|
}
|
|
1242
1328
|
start(timeoutMs) {
|