@fluidframework/container-runtime 2.0.0-dev.3.1.0.125672 → 2.0.0-dev.4.2.0.153917
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/CHANGELOG.md +58 -0
- package/README.md +69 -0
- package/dist/blobManager.d.ts +29 -24
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +162 -92
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +74 -76
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +328 -264
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +39 -13
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +112 -49
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +28 -4
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +107 -41
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts +19 -0
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/dist/deltaManagerSummarizerProxy.js +40 -0
- package/dist/deltaManagerSummarizerProxy.js.map +1 -0
- package/dist/gc/garbageCollection.d.ts +204 -0
- package/dist/gc/garbageCollection.d.ts.map +1 -0
- package/dist/{garbageCollection.js → gc/garbageCollection.js} +190 -554
- package/dist/gc/garbageCollection.js.map +1 -0
- package/dist/gc/gcConfigs.d.ts +22 -0
- package/dist/gc/gcConfigs.d.ts.map +1 -0
- package/dist/gc/gcConfigs.js +143 -0
- package/dist/gc/gcConfigs.js.map +1 -0
- package/dist/gc/gcDefinitions.d.ts +320 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -0
- package/dist/gc/gcDefinitions.js +81 -0
- package/dist/gc/gcDefinitions.js.map +1 -0
- package/dist/gc/gcHelpers.d.ts +86 -0
- package/dist/gc/gcHelpers.d.ts.map +1 -0
- package/dist/gc/gcHelpers.js +268 -0
- package/dist/gc/gcHelpers.js.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
- package/dist/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/dist/gc/gcReferenceGraphAlgorithm.js +49 -0
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/dist/gc/gcSummaryDefinitions.d.ts +52 -0
- package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/dist/gc/gcSummaryDefinitions.js +7 -0
- package/dist/gc/gcSummaryDefinitions.js.map +1 -0
- package/dist/gc/gcSummaryStateTracker.d.ts +93 -0
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/dist/gc/gcSummaryStateTracker.js +239 -0
- package/dist/gc/gcSummaryStateTracker.js.map +1 -0
- package/dist/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/dist/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +2 -2
- package/dist/gc/gcSweepReadyUsageDetection.js.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts +34 -0
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/dist/gc/gcUnreferencedStateTracker.js +94 -0
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -0
- package/dist/gc/index.d.ts +13 -0
- package/dist/gc/index.d.ts.map +1 -0
- package/dist/gc/index.js +50 -0
- package/dist/gc/index.js.map +1 -0
- package/dist/index.d.ts +3 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -9
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +11 -13
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +26 -38
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +4 -0
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +2 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +4 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +25 -10
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +4 -0
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +43 -4
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +14 -0
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/dist/opLifecycle/opGroupingManager.js +56 -0
- package/dist/opLifecycle/opGroupingManager.js.map +1 -0
- package/dist/opLifecycle/opSplitter.d.ts +16 -4
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +39 -15
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +21 -3
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +90 -51
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +4 -2
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +30 -20
- package/dist/opLifecycle/remoteMessageProcessor.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 +3 -3
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +20 -21
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.d.ts +17 -0
- package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/dist/storageServiceWithAttachBlobs.js +32 -0
- package/dist/storageServiceWithAttachBlobs.js.map +1 -0
- package/dist/summary/index.d.ts +17 -0
- package/dist/summary/index.d.ts.map +1 -0
- package/dist/summary/index.js +48 -0
- package/dist/summary/index.js.map +1 -0
- package/dist/summary/orderedClientElection.d.ts.map +1 -0
- package/dist/summary/orderedClientElection.js.map +1 -0
- package/dist/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/dist/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/{lib → dist/summary}/runningSummarizer.d.ts +23 -20
- package/dist/summary/runningSummarizer.d.ts.map +1 -0
- package/dist/{runningSummarizer.js → summary/runningSummarizer.js} +191 -74
- package/dist/summary/runningSummarizer.js.map +1 -0
- package/dist/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
- package/dist/summary/summarizer.d.ts.map +1 -0
- package/dist/{summarizer.js → summary/summarizer.js} +10 -79
- package/dist/summary/summarizer.js.map +1 -0
- package/dist/summary/summarizerClientElection.d.ts.map +1 -0
- package/dist/summary/summarizerClientElection.js.map +1 -0
- package/dist/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -0
- package/dist/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
- package/dist/summary/summarizerHeuristics.js.map +1 -0
- package/dist/summary/summarizerNode/index.d.ts +8 -0
- package/dist/summary/summarizerNode/index.d.ts.map +1 -0
- package/dist/summary/summarizerNode/index.js +12 -0
- package/dist/summary/summarizerNode/index.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts +149 -0
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNode.js +531 -0
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +132 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +424 -0
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/{lib → dist/summary}/summarizerTypes.d.ts +21 -19
- package/dist/summary/summarizerTypes.d.ts.map +1 -0
- package/dist/{summarizerTypes.js → summary/summarizerTypes.js} +0 -5
- package/dist/summary/summarizerTypes.js.map +1 -0
- package/dist/summary/summaryCollection.d.ts.map +1 -0
- package/dist/summary/summaryCollection.js.map +1 -0
- package/{lib → dist/summary}/summaryFormat.d.ts +3 -21
- package/dist/summary/summaryFormat.d.ts.map +1 -0
- package/dist/{summaryFormat.js → summary/summaryFormat.js} +1 -10
- package/dist/summary/summaryFormat.js.map +1 -0
- package/{lib → dist/summary}/summaryGenerator.d.ts +28 -2
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/{summaryGenerator.js → summary/summaryGenerator.js} +23 -20
- package/dist/summary/summaryGenerator.js.map +1 -0
- package/dist/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -0
- package/dist/summary/summaryManager.js.map +1 -0
- package/lib/blobManager.d.ts +29 -24
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +159 -89
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +74 -76
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +301 -237
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +39 -13
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +101 -38
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +28 -4
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +100 -34
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts +19 -0
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -0
- package/lib/deltaManagerSummarizerProxy.js +36 -0
- package/lib/deltaManagerSummarizerProxy.js.map +1 -0
- package/lib/gc/garbageCollection.d.ts +204 -0
- package/lib/gc/garbageCollection.d.ts.map +1 -0
- package/lib/{garbageCollection.js → gc/garbageCollection.js} +172 -535
- package/lib/gc/garbageCollection.js.map +1 -0
- package/lib/gc/gcConfigs.d.ts +22 -0
- package/lib/gc/gcConfigs.d.ts.map +1 -0
- package/lib/gc/gcConfigs.js +139 -0
- package/lib/gc/gcConfigs.js.map +1 -0
- package/lib/gc/gcDefinitions.d.ts +320 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -0
- package/lib/gc/gcDefinitions.js +78 -0
- package/lib/gc/gcDefinitions.js.map +1 -0
- package/lib/gc/gcHelpers.d.ts +86 -0
- package/lib/gc/gcHelpers.d.ts.map +1 -0
- package/lib/gc/gcHelpers.js +254 -0
- package/lib/gc/gcHelpers.js.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.ts +16 -0
- package/lib/gc/gcReferenceGraphAlgorithm.d.ts.map +1 -0
- package/lib/gc/gcReferenceGraphAlgorithm.js +45 -0
- package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -0
- package/lib/gc/gcSummaryDefinitions.d.ts +52 -0
- package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -0
- package/lib/gc/gcSummaryDefinitions.js +6 -0
- package/lib/gc/gcSummaryDefinitions.js.map +1 -0
- package/lib/gc/gcSummaryStateTracker.d.ts +93 -0
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -0
- package/lib/gc/gcSummaryStateTracker.js +235 -0
- package/lib/gc/gcSummaryStateTracker.js.map +1 -0
- package/lib/gc/gcSweepReadyUsageDetection.d.ts.map +1 -0
- package/lib/{gcSweepReadyUsageDetection.js → gc/gcSweepReadyUsageDetection.js} +1 -1
- package/lib/gc/gcSweepReadyUsageDetection.js.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.d.ts +34 -0
- package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -0
- package/lib/gc/gcUnreferencedStateTracker.js +90 -0
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -0
- package/lib/gc/index.d.ts +13 -0
- package/lib/gc/index.d.ts.map +1 -0
- package/lib/gc/index.js +12 -0
- package/lib/gc/index.js.map +1 -0
- package/lib/index.d.ts +3 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -4
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +11 -13
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +24 -37
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +4 -0
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +2 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +2 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +26 -11
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +4 -0
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +43 -4
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +14 -0
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -0
- package/lib/opLifecycle/opGroupingManager.js +52 -0
- package/lib/opLifecycle/opGroupingManager.js.map +1 -0
- package/lib/opLifecycle/opSplitter.d.ts +16 -4
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +39 -15
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +21 -3
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +92 -53
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +4 -2
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +30 -20
- package/lib/opLifecycle/remoteMessageProcessor.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 +3 -3
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +20 -21
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.d.ts +17 -0
- package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -0
- package/lib/storageServiceWithAttachBlobs.js +28 -0
- package/lib/storageServiceWithAttachBlobs.js.map +1 -0
- package/lib/summary/index.d.ts +17 -0
- package/lib/summary/index.d.ts.map +1 -0
- package/lib/summary/index.js +16 -0
- package/lib/summary/index.js.map +1 -0
- package/lib/summary/orderedClientElection.d.ts.map +1 -0
- package/lib/summary/orderedClientElection.js.map +1 -0
- package/lib/{runWhileConnectedCoordinator.d.ts → summary/runWhileConnectedCoordinator.d.ts} +3 -2
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -0
- package/lib/{runWhileConnectedCoordinator.js → summary/runWhileConnectedCoordinator.js} +5 -4
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -0
- package/{dist → lib/summary}/runningSummarizer.d.ts +23 -20
- package/lib/summary/runningSummarizer.d.ts.map +1 -0
- package/lib/{runningSummarizer.js → summary/runningSummarizer.js} +192 -75
- package/lib/summary/runningSummarizer.js.map +1 -0
- package/lib/{summarizer.d.ts → summary/summarizer.d.ts} +4 -9
- package/lib/summary/summarizer.d.ts.map +1 -0
- package/lib/{summarizer.js → summary/summarizer.js} +12 -81
- package/lib/summary/summarizer.js.map +1 -0
- package/lib/summary/summarizerClientElection.d.ts.map +1 -0
- package/lib/summary/summarizerClientElection.js.map +1 -0
- package/lib/{summarizerHeuristics.d.ts → summary/summarizerHeuristics.d.ts} +2 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -0
- package/lib/{summarizerHeuristics.js → summary/summarizerHeuristics.js} +6 -3
- package/lib/summary/summarizerHeuristics.js.map +1 -0
- package/lib/summary/summarizerNode/index.d.ts +8 -0
- package/lib/summary/summarizerNode/index.d.ts.map +1 -0
- package/lib/summary/summarizerNode/index.js +7 -0
- package/lib/summary/summarizerNode/index.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.d.ts +149 -0
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNode.js +526 -0
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +125 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +125 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +148 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +419 -0
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -0
- package/{dist → lib/summary}/summarizerTypes.d.ts +21 -19
- package/lib/summary/summarizerTypes.d.ts.map +1 -0
- package/lib/summary/summarizerTypes.js +6 -0
- package/lib/summary/summarizerTypes.js.map +1 -0
- package/lib/summary/summaryCollection.d.ts.map +1 -0
- package/lib/summary/summaryCollection.js.map +1 -0
- package/{dist → lib/summary}/summaryFormat.d.ts +3 -21
- package/lib/summary/summaryFormat.d.ts.map +1 -0
- package/lib/{summaryFormat.js → summary/summaryFormat.js} +0 -8
- package/lib/summary/summaryFormat.js.map +1 -0
- package/{dist → lib/summary}/summaryGenerator.d.ts +28 -2
- package/lib/summary/summaryGenerator.d.ts.map +1 -0
- package/lib/{summaryGenerator.js → summary/summaryGenerator.js} +21 -19
- package/lib/summary/summaryGenerator.js.map +1 -0
- package/lib/{summaryManager.d.ts → summary/summaryManager.d.ts} +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -0
- package/lib/summary/summaryManager.js.map +1 -0
- package/package.json +66 -60
- package/src/blobManager.ts +196 -110
- package/src/containerRuntime.ts +491 -391
- package/src/dataStoreContext.ts +140 -49
- package/src/dataStores.ts +139 -41
- package/src/deltaManagerSummarizerProxy.ts +46 -0
- package/{garbageCollection.md → src/gc/garbageCollection.md} +2 -2
- package/src/{garbageCollection.ts → gc/garbageCollection.ts} +245 -890
- package/src/gc/gcConfigs.ts +193 -0
- package/src/gc/gcDefinitions.ts +387 -0
- package/src/gc/gcHelpers.ts +335 -0
- package/src/gc/gcReferenceGraphAlgorithm.ts +52 -0
- package/src/gc/gcSummaryDefinitions.ts +54 -0
- package/src/gc/gcSummaryStateTracker.ts +329 -0
- package/src/{gcSweepReadyUsageDetection.ts → gc/gcSweepReadyUsageDetection.ts} +1 -1
- package/src/gc/gcUnreferencedStateTracker.ts +114 -0
- package/src/gc/index.ts +65 -0
- package/src/index.ts +10 -22
- package/src/opLifecycle/README.md +263 -0
- package/src/opLifecycle/batchManager.ts +26 -55
- package/src/opLifecycle/definitions.ts +4 -0
- package/src/opLifecycle/index.ts +2 -1
- package/src/opLifecycle/opCompressor.ts +32 -12
- package/src/opLifecycle/opDecompressor.ts +50 -5
- package/src/opLifecycle/opGroupingManager.ts +78 -0
- package/src/opLifecycle/opSplitter.ts +56 -17
- package/src/opLifecycle/outbox.ts +126 -62
- package/src/opLifecycle/remoteMessageProcessor.ts +38 -22
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +34 -27
- package/src/storageServiceWithAttachBlobs.ts +38 -0
- package/src/summary/index.ts +105 -0
- package/src/{runWhileConnectedCoordinator.ts → summary/runWhileConnectedCoordinator.ts} +7 -7
- package/src/{runningSummarizer.ts → summary/runningSummarizer.ts} +318 -156
- package/src/{summarizer.ts → summary/summarizer.ts} +12 -105
- package/src/{summarizerHeuristics.ts → summary/summarizerHeuristics.ts} +13 -4
- package/src/summary/summarizerNode/index.ts +12 -0
- package/src/summary/summarizerNode/summarizerNode.ts +766 -0
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +214 -0
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +644 -0
- package/src/{summarizerTypes.ts → summary/summarizerTypes.ts} +28 -25
- package/src/{summaryFormat.ts → summary/summaryFormat.ts} +3 -29
- package/src/{summaryGenerator.ts → summary/summaryGenerator.ts} +34 -27
- package/src/{summaryManager.ts → summary/summaryManager.ts} +1 -1
- package/dist/garbageCollection.d.ts +0 -411
- package/dist/garbageCollection.d.ts.map +0 -1
- package/dist/garbageCollection.js.map +0 -1
- package/dist/garbageCollectionConstants.d.ts +0 -23
- package/dist/garbageCollectionConstants.d.ts.map +0 -1
- package/dist/garbageCollectionConstants.js +0 -36
- package/dist/garbageCollectionConstants.js.map +0 -1
- package/dist/garbageCollectionHelpers.d.ts +0 -15
- package/dist/garbageCollectionHelpers.d.ts.map +0 -1
- package/dist/garbageCollectionHelpers.js +0 -27
- package/dist/garbageCollectionHelpers.js.map +0 -1
- package/dist/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/dist/gcSweepReadyUsageDetection.js.map +0 -1
- package/dist/orderedClientElection.d.ts.map +0 -1
- package/dist/orderedClientElection.js.map +0 -1
- package/dist/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/dist/runWhileConnectedCoordinator.js.map +0 -1
- package/dist/runningSummarizer.d.ts.map +0 -1
- package/dist/runningSummarizer.js.map +0 -1
- package/dist/serializedSnapshotStorage.d.ts +0 -58
- package/dist/serializedSnapshotStorage.d.ts.map +0 -1
- package/dist/serializedSnapshotStorage.js +0 -110
- package/dist/serializedSnapshotStorage.js.map +0 -1
- package/dist/summarizer.d.ts.map +0 -1
- package/dist/summarizer.js.map +0 -1
- package/dist/summarizerClientElection.d.ts.map +0 -1
- package/dist/summarizerClientElection.js.map +0 -1
- package/dist/summarizerHandle.d.ts +0 -12
- package/dist/summarizerHandle.d.ts.map +0 -1
- package/dist/summarizerHandle.js +0 -22
- package/dist/summarizerHandle.js.map +0 -1
- package/dist/summarizerHeuristics.d.ts.map +0 -1
- package/dist/summarizerHeuristics.js.map +0 -1
- package/dist/summarizerTypes.d.ts.map +0 -1
- package/dist/summarizerTypes.js.map +0 -1
- package/dist/summaryCollection.d.ts.map +0 -1
- package/dist/summaryCollection.js.map +0 -1
- package/dist/summaryFormat.d.ts.map +0 -1
- package/dist/summaryFormat.js.map +0 -1
- package/dist/summaryGenerator.d.ts.map +0 -1
- package/dist/summaryGenerator.js.map +0 -1
- package/dist/summaryManager.d.ts.map +0 -1
- package/dist/summaryManager.js.map +0 -1
- package/lib/garbageCollection.d.ts +0 -411
- package/lib/garbageCollection.d.ts.map +0 -1
- package/lib/garbageCollection.js.map +0 -1
- package/lib/garbageCollectionConstants.d.ts +0 -23
- package/lib/garbageCollectionConstants.d.ts.map +0 -1
- package/lib/garbageCollectionConstants.js +0 -33
- package/lib/garbageCollectionConstants.js.map +0 -1
- package/lib/garbageCollectionHelpers.d.ts +0 -15
- package/lib/garbageCollectionHelpers.d.ts.map +0 -1
- package/lib/garbageCollectionHelpers.js +0 -23
- package/lib/garbageCollectionHelpers.js.map +0 -1
- package/lib/gcSweepReadyUsageDetection.d.ts.map +0 -1
- package/lib/gcSweepReadyUsageDetection.js.map +0 -1
- package/lib/orderedClientElection.d.ts.map +0 -1
- package/lib/orderedClientElection.js.map +0 -1
- package/lib/runWhileConnectedCoordinator.d.ts.map +0 -1
- package/lib/runWhileConnectedCoordinator.js.map +0 -1
- package/lib/runningSummarizer.d.ts.map +0 -1
- package/lib/runningSummarizer.js.map +0 -1
- package/lib/serializedSnapshotStorage.d.ts +0 -58
- package/lib/serializedSnapshotStorage.d.ts.map +0 -1
- package/lib/serializedSnapshotStorage.js +0 -106
- package/lib/serializedSnapshotStorage.js.map +0 -1
- package/lib/summarizer.d.ts.map +0 -1
- package/lib/summarizer.js.map +0 -1
- package/lib/summarizerClientElection.d.ts.map +0 -1
- package/lib/summarizerClientElection.js.map +0 -1
- package/lib/summarizerHandle.d.ts +0 -12
- package/lib/summarizerHandle.d.ts.map +0 -1
- package/lib/summarizerHandle.js +0 -18
- package/lib/summarizerHandle.js.map +0 -1
- package/lib/summarizerHeuristics.d.ts.map +0 -1
- package/lib/summarizerHeuristics.js.map +0 -1
- package/lib/summarizerTypes.d.ts.map +0 -1
- package/lib/summarizerTypes.js +0 -9
- package/lib/summarizerTypes.js.map +0 -1
- package/lib/summaryCollection.d.ts.map +0 -1
- package/lib/summaryCollection.js.map +0 -1
- package/lib/summaryFormat.d.ts.map +0 -1
- package/lib/summaryFormat.js.map +0 -1
- package/lib/summaryGenerator.d.ts.map +0 -1
- package/lib/summaryGenerator.js.map +0 -1
- package/lib/summaryManager.d.ts.map +0 -1
- package/lib/summaryManager.js.map +0 -1
- package/src/garbageCollectionConstants.ts +0 -38
- package/src/garbageCollectionHelpers.ts +0 -37
- package/src/serializedSnapshotStorage.ts +0 -151
- package/src/summarizerHandle.ts +0 -23
- /package/dist/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
- /package/dist/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/dist/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
- /package/dist/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
- /package/dist/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
- /package/dist/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/dist/{summaryCollection.js → summary/summaryCollection.js} +0 -0
- /package/dist/{summaryManager.js → summary/summaryManager.js} +0 -0
- /package/lib/{gcSweepReadyUsageDetection.d.ts → gc/gcSweepReadyUsageDetection.d.ts} +0 -0
- /package/lib/{orderedClientElection.d.ts → summary/orderedClientElection.d.ts} +0 -0
- /package/lib/{orderedClientElection.js → summary/orderedClientElection.js} +0 -0
- /package/lib/{summarizerClientElection.d.ts → summary/summarizerClientElection.d.ts} +0 -0
- /package/lib/{summarizerClientElection.js → summary/summarizerClientElection.js} +0 -0
- /package/lib/{summaryCollection.d.ts → summary/summaryCollection.d.ts} +0 -0
- /package/lib/{summaryCollection.js → summary/summaryCollection.js} +0 -0
- /package/lib/{summaryManager.js → summary/summaryManager.js} +0 -0
- /package/src/{orderedClientElection.ts → summary/orderedClientElection.ts} +0 -0
- /package/src/{summarizerClientElection.ts → summary/summarizerClientElection.ts} +0 -0
- /package/src/{summaryCollection.ts → summary/summaryCollection.ts} +0 -0
|
@@ -5,44 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import { assert, LazyPromise, Timer } from "@fluidframework/common-utils";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
ClientSessionExpiredError,
|
|
11
|
-
DataProcessingError,
|
|
12
|
-
UsageError,
|
|
13
|
-
} from "@fluidframework/container-utils";
|
|
8
|
+
import { ClientSessionExpiredError, DataProcessingError } from "@fluidframework/container-utils";
|
|
14
9
|
import { IRequestHeader } from "@fluidframework/core-interfaces";
|
|
15
|
-
import {
|
|
16
|
-
cloneGCData,
|
|
17
|
-
concatGarbageCollectionData,
|
|
18
|
-
getGCDataFromSnapshot,
|
|
19
|
-
IGCResult,
|
|
20
|
-
runGarbageCollection,
|
|
21
|
-
trimLeadingSlashes,
|
|
22
|
-
} from "@fluidframework/garbage-collector";
|
|
23
|
-
import { ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
|
|
24
10
|
import {
|
|
25
11
|
gcTreeKey,
|
|
26
|
-
gcBlobPrefix,
|
|
27
|
-
gcTombstoneBlobKey,
|
|
28
12
|
IGarbageCollectionData,
|
|
29
13
|
IGarbageCollectionDetailsBase,
|
|
30
|
-
IGarbageCollectionSnapshotData,
|
|
31
|
-
IGarbageCollectionState,
|
|
32
14
|
ISummarizeResult,
|
|
33
15
|
ITelemetryContext,
|
|
34
|
-
IGarbageCollectionNodeData,
|
|
35
|
-
IGarbageCollectionSummaryDetailsLegacy,
|
|
36
|
-
ISummaryTreeWithStats,
|
|
37
|
-
gcDeletedBlobKey,
|
|
38
16
|
} from "@fluidframework/runtime-definitions";
|
|
39
|
-
import {
|
|
40
|
-
mergeStats,
|
|
41
|
-
packagePathToTelemetryProperty,
|
|
42
|
-
ReadAndParseBlob,
|
|
43
|
-
RefreshSummaryResult,
|
|
44
|
-
SummaryTreeBuilder,
|
|
45
|
-
} from "@fluidframework/runtime-utils";
|
|
17
|
+
import { packagePathToTelemetryProperty, ReadAndParseBlob } from "@fluidframework/runtime-utils";
|
|
46
18
|
import {
|
|
47
19
|
ChildLogger,
|
|
48
20
|
generateStack,
|
|
@@ -52,166 +24,31 @@ import {
|
|
|
52
24
|
TelemetryDataTag,
|
|
53
25
|
} from "@fluidframework/telemetry-utils";
|
|
54
26
|
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
27
|
+
import { RuntimeHeaders } from "../containerRuntime";
|
|
28
|
+
import { ICreateContainerMetadata, RefreshSummaryResult } from "../summary";
|
|
29
|
+
import { generateGCConfigs } from "./gcConfigs";
|
|
57
30
|
import {
|
|
58
|
-
currentGCVersion,
|
|
59
|
-
defaultInactiveTimeoutMs,
|
|
60
|
-
defaultSessionExpiryDurationMs,
|
|
61
31
|
disableSweepLogKey,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
stableGCVersion,
|
|
70
|
-
trackGCStateKey,
|
|
71
|
-
} from "./garbageCollectionConstants";
|
|
72
|
-
import { sendGCUnexpectedUsageEvent } from "./garbageCollectionHelpers";
|
|
73
|
-
import { SweepReadyUsageDetectionHandler } from "./gcSweepReadyUsageDetection";
|
|
74
|
-
import {
|
|
75
|
-
getGCVersion,
|
|
76
|
-
GCVersion,
|
|
77
|
-
IContainerRuntimeMetadata,
|
|
78
|
-
metadataBlobName,
|
|
79
|
-
ReadFluidDataStoreAttributes,
|
|
80
|
-
dataStoreAttributesBlobName,
|
|
32
|
+
GCNodeType,
|
|
33
|
+
IGarbageCollector,
|
|
34
|
+
IGarbageCollectorCreateParams,
|
|
35
|
+
IGarbageCollectionRuntime,
|
|
36
|
+
IGCResult,
|
|
37
|
+
IGCStats,
|
|
38
|
+
UnreferencedState,
|
|
81
39
|
IGCMetadata,
|
|
82
|
-
|
|
83
|
-
} from "./
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
unrefNodeCount: number;
|
|
95
|
-
/** The number of unreferenced data stores in the container. */
|
|
96
|
-
unrefDataStoreCount: number;
|
|
97
|
-
/** The number of unreferenced attachment blobs in the container. */
|
|
98
|
-
unrefAttachmentBlobCount: number;
|
|
99
|
-
/** The number of nodes whose reference state updated since last GC run. */
|
|
100
|
-
updatedNodeCount: number;
|
|
101
|
-
/** The number of data stores whose reference state updated since last GC run. */
|
|
102
|
-
updatedDataStoreCount: number;
|
|
103
|
-
/** The number of attachment blobs whose reference state updated since last GC run. */
|
|
104
|
-
updatedAttachmentBlobCount: number;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** The types of GC nodes in the GC reference graph. */
|
|
108
|
-
export const GCNodeType = {
|
|
109
|
-
// Nodes that are for data stores.
|
|
110
|
-
DataStore: "DataStore",
|
|
111
|
-
// Nodes that are within a data store. For example, DDS nodes.
|
|
112
|
-
SubDataStore: "SubDataStore",
|
|
113
|
-
// Nodes that are for attachment blobs, i.e., blobs uploaded via BlobManager.
|
|
114
|
-
Blob: "Blob",
|
|
115
|
-
// Nodes that are neither of the above. For example, root node.
|
|
116
|
-
Other: "Other",
|
|
117
|
-
};
|
|
118
|
-
export type GCNodeType = typeof GCNodeType[keyof typeof GCNodeType];
|
|
119
|
-
|
|
120
|
-
/** Defines the APIs for the runtime object to be passed to the garbage collector. */
|
|
121
|
-
export interface IGarbageCollectionRuntime {
|
|
122
|
-
/** Before GC runs, called to notify the runtime to update any pending GC state. */
|
|
123
|
-
updateStateBeforeGC(): Promise<void>;
|
|
124
|
-
/** Returns the garbage collection data of the runtime. */
|
|
125
|
-
getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
|
|
126
|
-
/** After GC has run, called to notify the runtime of routes that are used in it. */
|
|
127
|
-
updateUsedRoutes(usedRoutes: string[]): void;
|
|
128
|
-
/** After GC has run, called to notify the runtime of routes that are unused in it. */
|
|
129
|
-
updateUnusedRoutes(unusedRoutes: string[]): void;
|
|
130
|
-
/** Called to notify the runtime of routes that are tombstones. */
|
|
131
|
-
updateTombstonedRoutes(tombstoneRoutes: string[]): void;
|
|
132
|
-
/** Returns a referenced timestamp to be used to track unreferenced nodes. */
|
|
133
|
-
getCurrentReferenceTimestampMs(): number | undefined;
|
|
134
|
-
/** Returns the type of the GC node. */
|
|
135
|
-
getNodeType(nodePath: string): GCNodeType;
|
|
136
|
-
/** Called when the runtime should close because of an error. */
|
|
137
|
-
closeFn: (error?: ICriticalContainerError) => void;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Defines the contract for the garbage collector. */
|
|
141
|
-
export interface IGarbageCollector {
|
|
142
|
-
/** Tells whether GC should run or not. */
|
|
143
|
-
readonly shouldRunGC: boolean;
|
|
144
|
-
/** Tells whether the GC state in summary needs to be reset in the next summary. */
|
|
145
|
-
readonly summaryStateNeedsReset: boolean;
|
|
146
|
-
readonly trackGCState: boolean;
|
|
147
|
-
/** Initialize the state from the base snapshot after its creation. */
|
|
148
|
-
initializeBaseState(): Promise<void>;
|
|
149
|
-
/** Run garbage collection and update the reference / used state of the system. */
|
|
150
|
-
collectGarbage(options: {
|
|
151
|
-
logger?: ITelemetryLogger;
|
|
152
|
-
runSweep?: boolean;
|
|
153
|
-
fullGC?: boolean;
|
|
154
|
-
}): Promise<IGCStats | undefined>;
|
|
155
|
-
/** Summarizes the GC data and returns it as a summary tree. */
|
|
156
|
-
summarize(
|
|
157
|
-
fullTree: boolean,
|
|
158
|
-
trackState: boolean,
|
|
159
|
-
telemetryContext?: ITelemetryContext,
|
|
160
|
-
): ISummarizeResult | undefined;
|
|
161
|
-
/** Returns the garbage collector specific metadata to be written into the summary. */
|
|
162
|
-
getMetadata(): IGCMetadata;
|
|
163
|
-
/** Returns the GC details generated from the base snapshot. */
|
|
164
|
-
getBaseGCDetails(): Promise<IGarbageCollectionDetailsBase>;
|
|
165
|
-
/** Called when the latest summary of the system has been refreshed. */
|
|
166
|
-
refreshLatestSummary(
|
|
167
|
-
result: RefreshSummaryResult,
|
|
168
|
-
proposalHandle: string | undefined,
|
|
169
|
-
summaryRefSeq: number,
|
|
170
|
-
readAndParseBlob: ReadAndParseBlob,
|
|
171
|
-
): Promise<void>;
|
|
172
|
-
/** Called when a node is updated. Used to detect and log when an inactive node is changed or loaded. */
|
|
173
|
-
nodeUpdated(
|
|
174
|
-
nodePath: string,
|
|
175
|
-
reason: "Loaded" | "Changed",
|
|
176
|
-
timestampMs?: number,
|
|
177
|
-
packagePath?: readonly string[],
|
|
178
|
-
requestHeaders?: IRequestHeader,
|
|
179
|
-
): void;
|
|
180
|
-
/** Called when a reference is added to a node. Used to identify nodes that were referenced between summaries. */
|
|
181
|
-
addedOutboundReference(fromNodePath: string, toNodePath: string): void;
|
|
182
|
-
/** Returns true if this node has been deleted by GC during sweep phase. */
|
|
183
|
-
isNodeDeleted(nodePath: string): boolean;
|
|
184
|
-
setConnectionState(connected: boolean, clientId?: string): void;
|
|
185
|
-
dispose(): void;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/** Parameters necessary for creating a GarbageCollector. */
|
|
189
|
-
export interface IGarbageCollectorCreateParams {
|
|
190
|
-
readonly runtime: IGarbageCollectionRuntime;
|
|
191
|
-
readonly gcOptions: IGCRuntimeOptions;
|
|
192
|
-
readonly baseLogger: ITelemetryLogger;
|
|
193
|
-
readonly existing: boolean;
|
|
194
|
-
readonly metadata: IContainerRuntimeMetadata | undefined;
|
|
195
|
-
readonly createContainerMetadata: ICreateContainerMetadata;
|
|
196
|
-
readonly baseSnapshot: ISnapshotTree | undefined;
|
|
197
|
-
readonly isSummarizerClient: boolean;
|
|
198
|
-
readonly getNodePackagePath: (nodePath: string) => Promise<readonly string[] | undefined>;
|
|
199
|
-
readonly getLastSummaryTimestampMs: () => number | undefined;
|
|
200
|
-
readonly readAndParseBlob: ReadAndParseBlob;
|
|
201
|
-
readonly activeConnection: () => boolean;
|
|
202
|
-
readonly getContainerDiagnosticId: () => string;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/** The state of node that is unreferenced. */
|
|
206
|
-
export const UnreferencedState = {
|
|
207
|
-
/** The node is active, i.e., it can become referenced again. */
|
|
208
|
-
Active: "Active",
|
|
209
|
-
/** The node is inactive, i.e., it should not become referenced. */
|
|
210
|
-
Inactive: "Inactive",
|
|
211
|
-
/** The node is ready to be deleted by the sweep phase. */
|
|
212
|
-
SweepReady: "SweepReady",
|
|
213
|
-
} as const;
|
|
214
|
-
export type UnreferencedState = typeof UnreferencedState[keyof typeof UnreferencedState];
|
|
40
|
+
IGarbageCollectorConfigs,
|
|
41
|
+
} from "./gcDefinitions";
|
|
42
|
+
import {
|
|
43
|
+
cloneGCData,
|
|
44
|
+
concatGarbageCollectionData,
|
|
45
|
+
getGCDataFromSnapshot,
|
|
46
|
+
sendGCUnexpectedUsageEvent,
|
|
47
|
+
} from "./gcHelpers";
|
|
48
|
+
import { runGarbageCollection } from "./gcReferenceGraphAlgorithm";
|
|
49
|
+
import { IGarbageCollectionSnapshotData, IGarbageCollectionState } from "./gcSummaryDefinitions";
|
|
50
|
+
import { GCSummaryStateTracker } from "./gcSummaryStateTracker";
|
|
51
|
+
import { UnreferencedStateTracker } from "./gcUnreferencedStateTracker";
|
|
215
52
|
|
|
216
53
|
/** The event that is logged when unreferenced node is used after a certain time. */
|
|
217
54
|
interface IUnreferencedEventProps {
|
|
@@ -225,108 +62,9 @@ interface IUnreferencedEventProps {
|
|
|
225
62
|
fromId?: string;
|
|
226
63
|
timeout?: number;
|
|
227
64
|
lastSummaryTime?: number;
|
|
228
|
-
externalRequest?: boolean;
|
|
229
65
|
viaHandle?: boolean;
|
|
230
66
|
}
|
|
231
67
|
|
|
232
|
-
/**
|
|
233
|
-
* The GC data that is tracked for a summary that is submitted.
|
|
234
|
-
*/
|
|
235
|
-
interface IGCSummaryTrackingData {
|
|
236
|
-
serializedGCState: string | undefined;
|
|
237
|
-
serializedTombstones: string | undefined;
|
|
238
|
-
serializedDeletedNodes: string | undefined;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Helper class that tracks the state of an unreferenced node such as the time it was unreferenced and if it can
|
|
243
|
-
* be deleted by the sweep phase.
|
|
244
|
-
*/
|
|
245
|
-
export class UnreferencedStateTracker {
|
|
246
|
-
private _state: UnreferencedState = UnreferencedState.Active;
|
|
247
|
-
public get state(): UnreferencedState {
|
|
248
|
-
return this._state;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/** Timer to indicate when an unreferenced object is considered Inactive */
|
|
252
|
-
private readonly inactiveTimer: TimerWithNoDefaultTimeout;
|
|
253
|
-
/** Timer to indicate when an unreferenced object is Sweep-Ready */
|
|
254
|
-
private readonly sweepTimer: TimerWithNoDefaultTimeout;
|
|
255
|
-
|
|
256
|
-
constructor(
|
|
257
|
-
public readonly unreferencedTimestampMs: number,
|
|
258
|
-
/** The time after which node transitions to Inactive state. */
|
|
259
|
-
private readonly inactiveTimeoutMs: number,
|
|
260
|
-
/** The current reference timestamp used to track how long this node has been unreferenced for. */
|
|
261
|
-
currentReferenceTimestampMs: number,
|
|
262
|
-
/** The time after which node transitions to SweepReady state; undefined if session expiry is disabled. */
|
|
263
|
-
private readonly sweepTimeoutMs: number | undefined,
|
|
264
|
-
) {
|
|
265
|
-
if (this.sweepTimeoutMs !== undefined) {
|
|
266
|
-
assert(
|
|
267
|
-
this.inactiveTimeoutMs <= this.sweepTimeoutMs,
|
|
268
|
-
0x3b0 /* inactive timeout must not be greater than the sweep timeout */,
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
this.sweepTimer = new TimerWithNoDefaultTimeout(() => {
|
|
273
|
-
this._state = UnreferencedState.SweepReady;
|
|
274
|
-
assert(
|
|
275
|
-
!this.inactiveTimer.hasTimer,
|
|
276
|
-
0x3b1 /* inactiveTimer still running after sweepTimer fired! */,
|
|
277
|
-
);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
this.inactiveTimer = new TimerWithNoDefaultTimeout(() => {
|
|
281
|
-
this._state = UnreferencedState.Inactive;
|
|
282
|
-
|
|
283
|
-
// After the node becomes inactive, start the sweep timer after which the node will be ready for sweep.
|
|
284
|
-
if (this.sweepTimeoutMs !== undefined) {
|
|
285
|
-
this.sweepTimer.restart(this.sweepTimeoutMs - this.inactiveTimeoutMs);
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
this.updateTracking(currentReferenceTimestampMs);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/* Updates the unreferenced state based on the provided timestamp. */
|
|
292
|
-
public updateTracking(currentReferenceTimestampMs: number) {
|
|
293
|
-
const unreferencedDurationMs = currentReferenceTimestampMs - this.unreferencedTimestampMs;
|
|
294
|
-
|
|
295
|
-
// If the node has been unreferenced for sweep timeout amount of time, update the state to SweepReady.
|
|
296
|
-
if (this.sweepTimeoutMs !== undefined && unreferencedDurationMs >= this.sweepTimeoutMs) {
|
|
297
|
-
this._state = UnreferencedState.SweepReady;
|
|
298
|
-
this.clearTimers();
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// If the node has been unreferenced for inactive timeoutMs amount of time, update the state to inactive.
|
|
303
|
-
// Also, start a timer for the sweep timeout.
|
|
304
|
-
if (unreferencedDurationMs >= this.inactiveTimeoutMs) {
|
|
305
|
-
this._state = UnreferencedState.Inactive;
|
|
306
|
-
this.inactiveTimer.clear();
|
|
307
|
-
|
|
308
|
-
if (this.sweepTimeoutMs !== undefined) {
|
|
309
|
-
this.sweepTimer.restart(this.sweepTimeoutMs - unreferencedDurationMs);
|
|
310
|
-
}
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// The node is still active. Ensure the inactive timer is running with the proper remaining duration.
|
|
315
|
-
this.inactiveTimer.restart(this.inactiveTimeoutMs - unreferencedDurationMs);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
private clearTimers() {
|
|
319
|
-
this.inactiveTimer.clear();
|
|
320
|
-
this.sweepTimer.clear();
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/** Stop tracking this node. Reset the unreferenced timers and state, if any. */
|
|
324
|
-
public stopTracking() {
|
|
325
|
-
this.clearTimers();
|
|
326
|
-
this._state = UnreferencedState.Active;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
68
|
/**
|
|
331
69
|
* The garbage collector for the container runtime. It consolidates the garbage collection functionality and maintains
|
|
332
70
|
* its state across summaries.
|
|
@@ -338,15 +76,15 @@ export class UnreferencedStateTracker {
|
|
|
338
76
|
* Graph - all nodes with their respective routes
|
|
339
77
|
*
|
|
340
78
|
* ```
|
|
341
|
-
*
|
|
79
|
+
* GC Graph
|
|
342
80
|
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
* NodeId = "dds1"
|
|
81
|
+
* Node
|
|
82
|
+
* NodeId = "datastore1"
|
|
83
|
+
* / \\
|
|
84
|
+
* OutboundRoute OutboundRoute
|
|
85
|
+
* / \\
|
|
86
|
+
* Node Node
|
|
87
|
+
* NodeId = "dds1" NodeId = "dds2"
|
|
350
88
|
* ```
|
|
351
89
|
*/
|
|
352
90
|
export class GarbageCollector implements IGarbageCollector {
|
|
@@ -354,80 +92,13 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
354
92
|
return new GarbageCollector(createParams);
|
|
355
93
|
}
|
|
356
94
|
|
|
357
|
-
/**
|
|
358
|
-
* Tells whether the GC state needs to be reset in the next summary. We need to do this if:
|
|
359
|
-
*
|
|
360
|
-
* 1. GC was enabled and is now disabled. The GC state needs to be removed and everything becomes referenced.
|
|
361
|
-
*
|
|
362
|
-
* 2. GC was disabled and is now enabled. The GC state needs to be regenerated and added to summary.
|
|
363
|
-
*
|
|
364
|
-
* 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.
|
|
365
|
-
*
|
|
366
|
-
* 4. The GC version in the latest summary is different from the current GC version. This can happen if:
|
|
367
|
-
*
|
|
368
|
-
* 4.1. The summary this client loaded with has data from a different GC version.
|
|
369
|
-
*
|
|
370
|
-
* 4.2. This client's latest summary was updated from a snapshot that has a different GC version.
|
|
371
|
-
*/
|
|
372
|
-
public get summaryStateNeedsReset(): boolean {
|
|
373
|
-
return (
|
|
374
|
-
this.gcStateNeedsReset ||
|
|
375
|
-
(this.shouldRunGC && this.latestSummaryGCVersion !== this.currentGCVersion)
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Tracks if GC is enabled for this document. This is specified during document creation and doesn't change
|
|
381
|
-
* throughout its lifetime.
|
|
382
|
-
*/
|
|
383
|
-
private readonly gcEnabled: boolean;
|
|
384
|
-
/**
|
|
385
|
-
* Tracks if sweep phase is enabled for this document. This is specified during document creation and doesn't change
|
|
386
|
-
* throughout its lifetime.
|
|
387
|
-
*/
|
|
388
|
-
private readonly sweepEnabled: boolean;
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Tracks if GC should run or not. Even if GC is enabled for a document (see gcEnabled), it can be explicitly
|
|
392
|
-
* disabled via runtime options or feature flags.
|
|
393
|
-
*/
|
|
394
|
-
public readonly shouldRunGC: boolean;
|
|
395
|
-
/**
|
|
396
|
-
* Tracks if sweep phase should run or not. Even if the sweep phase is enabled for a document (see sweepEnabled), it
|
|
397
|
-
* can be explicitly disabled via feature flags. It also won't run if session expiry is not enabled.
|
|
398
|
-
*/
|
|
399
|
-
private readonly shouldRunSweep: boolean;
|
|
400
|
-
|
|
401
|
-
public readonly trackGCState: boolean;
|
|
402
|
-
|
|
403
|
-
private readonly testMode: boolean;
|
|
404
|
-
private readonly tombstoneMode: boolean;
|
|
405
95
|
private readonly mc: MonitoringContext;
|
|
406
96
|
|
|
407
|
-
|
|
408
|
-
* Tells whether the GC state needs to be reset. This can happen under 3 conditions:
|
|
409
|
-
*
|
|
410
|
-
* 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after
|
|
411
|
-
* it was enabled before. GC state needs to be removed from summary and all nodes should be marked referenced.
|
|
412
|
-
*
|
|
413
|
-
* 2. The base snapshot does not have GC state but GC is enabled. This will happen the very first time GC runs on
|
|
414
|
-
* a document and the first time GC is enabled after is was disabled before.
|
|
415
|
-
*
|
|
416
|
-
* 3. GC is enabled and the latest summary state is refreshed from a snapshot that had GC disabled and vice-versa.
|
|
417
|
-
*
|
|
418
|
-
* Note that the state will be reset only once for the first summary generated after this returns true. After that,
|
|
419
|
-
* this will return false.
|
|
420
|
-
*/
|
|
421
|
-
private get gcStateNeedsReset(): boolean {
|
|
422
|
-
return this.wasGCRunInLatestSummary !== this.shouldRunGC;
|
|
423
|
-
}
|
|
424
|
-
// Tracks whether there was GC was run in latest summary being tracked.
|
|
425
|
-
private wasGCRunInLatestSummary: boolean;
|
|
97
|
+
private readonly configs: IGarbageCollectorConfigs;
|
|
426
98
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
private latestSummaryGCVersion: GCVersion;
|
|
99
|
+
public get shouldRunGC(): boolean {
|
|
100
|
+
return this.configs.shouldRunGC;
|
|
101
|
+
}
|
|
431
102
|
|
|
432
103
|
// Keeps track of the GC state from the last run.
|
|
433
104
|
private gcDataFromLastRun: IGarbageCollectionData | undefined;
|
|
@@ -439,15 +110,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
439
110
|
// A list of nodes that have been deleted during sweep phase.
|
|
440
111
|
private deletedNodes: Set<string> = new Set();
|
|
441
112
|
|
|
442
|
-
/**
|
|
443
|
-
* Keeps track of the GC data from the latest summary successfully submitted to and acked from the server.
|
|
444
|
-
*/
|
|
445
|
-
private latestSummaryData: IGCSummaryTrackingData | undefined;
|
|
446
|
-
/**
|
|
447
|
-
* Keeps track of the GC data from the last summary submitted to the server but not yet acked.
|
|
448
|
-
*/
|
|
449
|
-
private pendingSummaryData: IGCSummaryTrackingData | undefined;
|
|
450
|
-
|
|
451
113
|
// Promise when resolved returns the GC data data in the base snapshot.
|
|
452
114
|
private readonly baseSnapshotDataP: Promise<IGarbageCollectionSnapshotData | undefined>;
|
|
453
115
|
// Promise when resolved initializes the GC state from the data in the base snapshot.
|
|
@@ -470,15 +132,9 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
470
132
|
|
|
471
133
|
private readonly runtime: IGarbageCollectionRuntime;
|
|
472
134
|
private readonly createContainerMetadata: ICreateContainerMetadata;
|
|
473
|
-
private readonly gcOptions: IGCRuntimeOptions;
|
|
474
135
|
private readonly isSummarizerClient: boolean;
|
|
475
136
|
|
|
476
|
-
|
|
477
|
-
private readonly sessionExpiryTimeoutMs: number | undefined;
|
|
478
|
-
/** The time after which an unreferenced node is inactive. */
|
|
479
|
-
private readonly inactiveTimeoutMs: number;
|
|
480
|
-
/** The time after which an unreferenced node is ready to be swept. */
|
|
481
|
-
private readonly sweepTimeoutMs: number | undefined;
|
|
137
|
+
private readonly summaryStateTracker: GCSummaryStateTracker;
|
|
482
138
|
|
|
483
139
|
/** For a given node path, returns the node's package path. */
|
|
484
140
|
private readonly getNodePackagePath: (
|
|
@@ -489,37 +145,19 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
489
145
|
/** Returns true if connection is active, i.e. it's "write" connection and the runtime is connected. */
|
|
490
146
|
private readonly activeConnection: () => boolean;
|
|
491
147
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return {
|
|
495
|
-
gcEnabled: this.gcEnabled,
|
|
496
|
-
sweepEnabled: this.sweepEnabled,
|
|
497
|
-
runGC: this.shouldRunGC,
|
|
498
|
-
runSweep: this.shouldRunSweep,
|
|
499
|
-
testMode: this.testMode,
|
|
500
|
-
tombstoneMode: this.tombstoneMode,
|
|
501
|
-
sessionExpiry: this.sessionExpiryTimeoutMs,
|
|
502
|
-
sweepTimeout: this.sweepTimeoutMs,
|
|
503
|
-
inactiveTimeout: this.inactiveTimeoutMs,
|
|
504
|
-
trackGCState: this.trackGCState,
|
|
505
|
-
...this.gcOptions,
|
|
506
|
-
};
|
|
148
|
+
public get summaryStateNeedsReset(): boolean {
|
|
149
|
+
return this.summaryStateTracker.doesSummaryStateNeedReset;
|
|
507
150
|
}
|
|
508
151
|
|
|
509
|
-
/** Handler to respond to when a SweepReady object is used */
|
|
510
|
-
private readonly sweepReadyUsageHandler: SweepReadyUsageDetectionHandler;
|
|
511
|
-
|
|
512
152
|
protected constructor(createParams: IGarbageCollectorCreateParams) {
|
|
513
153
|
this.runtime = createParams.runtime;
|
|
514
154
|
this.isSummarizerClient = createParams.isSummarizerClient;
|
|
515
|
-
this.gcOptions = createParams.gcOptions;
|
|
516
155
|
this.createContainerMetadata = createParams.createContainerMetadata;
|
|
517
156
|
this.getNodePackagePath = createParams.getNodePackagePath;
|
|
518
157
|
this.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;
|
|
519
158
|
this.activeConnection = createParams.activeConnection;
|
|
520
159
|
|
|
521
160
|
const baseSnapshot = createParams.baseSnapshot;
|
|
522
|
-
const metadata = createParams.metadata;
|
|
523
161
|
const readAndParseBlob = createParams.readAndParseBlob;
|
|
524
162
|
|
|
525
163
|
this.mc = loggerToMonitoringContext(
|
|
@@ -528,89 +166,15 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
528
166
|
}),
|
|
529
167
|
);
|
|
530
168
|
|
|
531
|
-
|
|
532
|
-
this.currentGCVersion =
|
|
533
|
-
this.mc.config.getBoolean(gcVersionUpgradeToV2Key) === true
|
|
534
|
-
? currentGCVersion
|
|
535
|
-
: stableGCVersion;
|
|
536
|
-
|
|
537
|
-
this.sweepReadyUsageHandler = new SweepReadyUsageDetectionHandler(
|
|
538
|
-
createParams.getContainerDiagnosticId(),
|
|
539
|
-
this.mc,
|
|
540
|
-
this.runtime.closeFn,
|
|
541
|
-
);
|
|
542
|
-
|
|
543
|
-
let prevSummaryGCVersion: number | undefined;
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Sweep timeout is the time after which unreferenced content can be swept.
|
|
547
|
-
* Sweep timeout = session expiry timeout + snapshot cache expiry timeout + one day buffer.
|
|
548
|
-
*
|
|
549
|
-
* The snapshot cache expiry timeout cannot be known precisely but the upper bound is 5 days.
|
|
550
|
-
* The buffer is added to account for any clock skew or other edge cases.
|
|
551
|
-
* We use server timestamps throughout so the skew should be minimal but make it 1 day to be safe.
|
|
552
|
-
*/
|
|
553
|
-
function computeSweepTimeout(sessionExpiryTimeoutMs: number | undefined) {
|
|
554
|
-
const maxSnapshotCacheExpiryMs = 5 * oneDayMs;
|
|
555
|
-
const bufferMs = oneDayMs;
|
|
556
|
-
return (
|
|
557
|
-
sessionExpiryTimeoutMs &&
|
|
558
|
-
sessionExpiryTimeoutMs + maxSnapshotCacheExpiryMs + bufferMs
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
|
|
564
|
-
* 1. Whether running GC mark phase is allowed or not.
|
|
565
|
-
* 2. Whether running GC sweep phase is allowed or not.
|
|
566
|
-
* 3. Whether GC session expiry is enabled or not.
|
|
567
|
-
* For existing containers, we get this information from the metadata blob of its summary.
|
|
568
|
-
*/
|
|
569
|
-
if (createParams.existing) {
|
|
570
|
-
prevSummaryGCVersion = getGCVersion(metadata);
|
|
571
|
-
// Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
|
|
572
|
-
// other existing documents, GC is enabled.
|
|
573
|
-
this.gcEnabled = prevSummaryGCVersion > 0;
|
|
574
|
-
this.sweepEnabled = metadata?.sweepEnabled ?? false;
|
|
575
|
-
this.sessionExpiryTimeoutMs = metadata?.sessionExpiryTimeoutMs;
|
|
576
|
-
this.sweepTimeoutMs =
|
|
577
|
-
metadata?.sweepTimeoutMs ?? computeSweepTimeout(this.sessionExpiryTimeoutMs); // Backfill old documents that didn't persist this
|
|
578
|
-
} else {
|
|
579
|
-
// Sweep should not be enabled without enabling GC mark phase. We could silently disable sweep in this
|
|
580
|
-
// scenario but explicitly failing makes it clearer and promotes correct usage.
|
|
581
|
-
if (this.gcOptions.sweepAllowed && this.gcOptions.gcAllowed === false) {
|
|
582
|
-
throw new UsageError(
|
|
583
|
-
"GC sweep phase cannot be enabled without enabling GC mark phase",
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// This Test Override only applies for new containers
|
|
588
|
-
const testOverrideSweepTimeoutMs = this.mc.config.getNumber(
|
|
589
|
-
"Fluid.GarbageCollection.TestOverride.SweepTimeoutMs",
|
|
590
|
-
);
|
|
591
|
-
|
|
592
|
-
// For new documents, GC is enabled by default. It can be explicitly disabled by setting the gcAllowed
|
|
593
|
-
// flag in GC options to false.
|
|
594
|
-
this.gcEnabled = this.gcOptions.gcAllowed !== false;
|
|
595
|
-
// The sweep phase has to be explicitly enabled by setting the sweepAllowed flag in GC options to true.
|
|
596
|
-
this.sweepEnabled = this.gcOptions.sweepAllowed === true;
|
|
597
|
-
|
|
598
|
-
// Set the Session Expiry only if the flag is enabled and GC is enabled.
|
|
599
|
-
if (this.mc.config.getBoolean(runSessionExpiryKey) && this.gcEnabled) {
|
|
600
|
-
this.sessionExpiryTimeoutMs =
|
|
601
|
-
this.gcOptions.sessionExpiryTimeoutMs ?? defaultSessionExpiryDurationMs;
|
|
602
|
-
}
|
|
603
|
-
this.sweepTimeoutMs =
|
|
604
|
-
testOverrideSweepTimeoutMs ?? computeSweepTimeout(this.sessionExpiryTimeoutMs);
|
|
605
|
-
}
|
|
169
|
+
this.configs = generateGCConfigs(this.mc, createParams);
|
|
606
170
|
|
|
607
171
|
// If session expiry is enabled, we need to close the container when the session expiry timeout expires.
|
|
608
|
-
if (this.sessionExpiryTimeoutMs !== undefined) {
|
|
172
|
+
if (this.configs.sessionExpiryTimeoutMs !== undefined) {
|
|
609
173
|
// If Test Override config is set, override Session Expiry timeout.
|
|
610
174
|
const overrideSessionExpiryTimeoutMs = this.mc.config.getNumber(
|
|
611
175
|
"Fluid.GarbageCollection.TestOverride.SessionExpiryMs",
|
|
612
176
|
);
|
|
613
|
-
const timeoutMs = overrideSessionExpiryTimeoutMs ?? this.sessionExpiryTimeoutMs;
|
|
177
|
+
const timeoutMs = overrideSessionExpiryTimeoutMs ?? this.configs.sessionExpiryTimeoutMs;
|
|
614
178
|
|
|
615
179
|
this.sessionExpiryTimer = new Timer(timeoutMs, () => {
|
|
616
180
|
this.runtime.closeFn(
|
|
@@ -620,64 +184,10 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
620
184
|
this.sessionExpiryTimer.start();
|
|
621
185
|
}
|
|
622
186
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Whether GC should run or not. The following conditions have to be met to run sweep:
|
|
629
|
-
*
|
|
630
|
-
* 1. GC should be enabled for this container.
|
|
631
|
-
*
|
|
632
|
-
* 2. GC should not be disabled via disableGC GC option.
|
|
633
|
-
*
|
|
634
|
-
* These conditions can be overridden via runGCKey feature flag.
|
|
635
|
-
*/
|
|
636
|
-
this.shouldRunGC =
|
|
637
|
-
this.mc.config.getBoolean(runGCKey) ??
|
|
638
|
-
// GC must be enabled for the document.
|
|
639
|
-
(this.gcEnabled &&
|
|
640
|
-
// GC must not be disabled via GC options.
|
|
641
|
-
!this.gcOptions.disableGC);
|
|
642
|
-
|
|
643
|
-
/**
|
|
644
|
-
* Whether sweep should run or not. The following conditions have to be met to run sweep:
|
|
645
|
-
*
|
|
646
|
-
* 1. Overall GC or mark phase must be enabled (this.shouldRunGC).
|
|
647
|
-
* 2. Sweep timeout should be available. Without this, we wouldn't know when an object should be deleted.
|
|
648
|
-
* 3. The driver must implement the policy limiting the age of snapshots used for loading. Otherwise
|
|
649
|
-
* the Sweep Timeout calculation is not valid. We use the persisted value to ensure consistency over time.
|
|
650
|
-
* 4. Sweep should be enabled for this container (this.sweepEnabled). This can be overridden via runSweep
|
|
651
|
-
* feature flag.
|
|
652
|
-
*/
|
|
653
|
-
this.shouldRunSweep =
|
|
654
|
-
this.shouldRunGC &&
|
|
655
|
-
this.sweepTimeoutMs !== undefined &&
|
|
656
|
-
(this.mc.config.getBoolean(runSweepKey) ?? this.sweepEnabled);
|
|
657
|
-
|
|
658
|
-
this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true;
|
|
659
|
-
|
|
660
|
-
// Override inactive timeout if test config or gc options to override it is set.
|
|
661
|
-
this.inactiveTimeoutMs =
|
|
662
|
-
this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs") ??
|
|
663
|
-
this.gcOptions.inactiveTimeoutMs ??
|
|
664
|
-
defaultInactiveTimeoutMs;
|
|
665
|
-
|
|
666
|
-
// Inactive timeout must be greater than sweep timeout since a node goes from active -> inactive -> sweep ready.
|
|
667
|
-
if (this.sweepTimeoutMs !== undefined && this.inactiveTimeoutMs > this.sweepTimeoutMs) {
|
|
668
|
-
throw new UsageError("inactive timeout should not be greater than the sweep timeout");
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
|
|
672
|
-
this.testMode =
|
|
673
|
-
this.mc.config.getBoolean(gcTestModeKey) ?? this.gcOptions.runGCInTestMode === true;
|
|
674
|
-
// Whether we are running in tombstone mode. This is enabled by default if sweep won't run. It can be disabled
|
|
675
|
-
// via feature flags.
|
|
676
|
-
this.tombstoneMode =
|
|
677
|
-
!this.shouldRunSweep && this.mc.config.getBoolean(disableTombstoneKey) !== true;
|
|
678
|
-
|
|
679
|
-
// If GC ran in the container that generated the base snapshot, it will have a GC tree.
|
|
680
|
-
this.wasGCRunInLatestSummary = baseSnapshot?.trees[gcTreeKey] !== undefined;
|
|
187
|
+
this.summaryStateTracker = new GCSummaryStateTracker(
|
|
188
|
+
this.configs,
|
|
189
|
+
baseSnapshot?.trees[gcTreeKey] !== undefined /* wasGCRunInBaseSnapshot */,
|
|
190
|
+
);
|
|
681
191
|
|
|
682
192
|
// Get the GC data from the base snapshot. Use LazyPromise because we only want to do this once since it
|
|
683
193
|
// it involves fetching blobs from storage which is expensive.
|
|
@@ -690,75 +200,40 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
690
200
|
try {
|
|
691
201
|
// For newer documents, GC data should be present in the GC tree in the root of the snapshot.
|
|
692
202
|
const gcSnapshotTree = baseSnapshot.trees[gcTreeKey];
|
|
693
|
-
if (gcSnapshotTree
|
|
694
|
-
|
|
203
|
+
if (gcSnapshotTree === undefined) {
|
|
204
|
+
// back-compat - Older documents get their gc data reset for simplicity as there are few of them
|
|
205
|
+
// incremental gc summary will not work with older gc data as well
|
|
206
|
+
return undefined;
|
|
695
207
|
}
|
|
696
208
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
const gcState: IGarbageCollectionState = {
|
|
701
|
-
gcNodes: { "/": { outboundRoutes: [] } },
|
|
702
|
-
};
|
|
703
|
-
const dataStoreSnapshotTree = getSummaryForDatastores(baseSnapshot, metadata);
|
|
704
|
-
assert(
|
|
705
|
-
dataStoreSnapshotTree !== undefined,
|
|
706
|
-
0x2a8 /* "Expected data store snapshot tree in base snapshot" */,
|
|
209
|
+
const snapshotData = await getGCDataFromSnapshot(
|
|
210
|
+
gcSnapshotTree,
|
|
211
|
+
readAndParseBlob,
|
|
707
212
|
);
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const dsRootId = `/${dsId}`;
|
|
724
|
-
// Since we used to write GC data at data store level, we won't have an entry for the root ("/").
|
|
725
|
-
// Construct that entry by adding root data store ids to its outbound routes.
|
|
726
|
-
const initialSnapshotDetails =
|
|
727
|
-
await readAndParseBlob<ReadFluidDataStoreAttributes>(
|
|
728
|
-
dsSnapshotTree.blobs[dataStoreAttributesBlobName],
|
|
729
|
-
);
|
|
730
|
-
if (initialSnapshotDetails.isRootDataStore) {
|
|
731
|
-
gcState.gcNodes["/"].outboundRoutes.push(dsRootId);
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
for (const [id, outboundRoutes] of Object.entries(
|
|
735
|
-
gcSummaryDetails.gcData.gcNodes,
|
|
736
|
-
)) {
|
|
737
|
-
// Prefix the data store id to the GC node ids to make them relative to the root from being
|
|
738
|
-
// relative to the data store. Similar to how its done in DataStore::getGCData.
|
|
739
|
-
const rootId = id === "/" ? dsRootId : `${dsRootId}${id}`;
|
|
740
|
-
gcState.gcNodes[rootId] = {
|
|
741
|
-
outboundRoutes: Array.from(outboundRoutes),
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
assert(
|
|
745
|
-
gcState.gcNodes[dsRootId] !== undefined,
|
|
746
|
-
0x2a9 /* GC nodes for data store not in GC blob */,
|
|
747
|
-
);
|
|
748
|
-
gcState.gcNodes[dsRootId].unreferencedTimestampMs =
|
|
749
|
-
gcSummaryDetails.unrefTimestamp;
|
|
213
|
+
|
|
214
|
+
// If the GC version in base snapshot does not match the GC version currently in effect, the GC data
|
|
215
|
+
// in the snapshot cannot be interpreted correctly. Set everything to undefined except for
|
|
216
|
+
// deletedNodes because irrespective of GC versions, these nodes have been deleted and cannot be
|
|
217
|
+
// brought back. The deletedNodes info is needed to identify when these nodes are used.
|
|
218
|
+
if (
|
|
219
|
+
this.configs.gcVersionInBaseSnapshot !==
|
|
220
|
+
this.summaryStateTracker.currentGCVersion
|
|
221
|
+
) {
|
|
222
|
+
return {
|
|
223
|
+
gcState: undefined,
|
|
224
|
+
tombstones: undefined,
|
|
225
|
+
deletedNodes: snapshotData.deletedNodes,
|
|
226
|
+
};
|
|
750
227
|
}
|
|
751
|
-
|
|
752
|
-
// the first summary generated by detached container. In both cases, GC was not run - return undefined.
|
|
753
|
-
return Object.keys(gcState.gcNodes).length === 1
|
|
754
|
-
? undefined
|
|
755
|
-
: { gcState, tombstones: undefined, deletedNodes: undefined };
|
|
228
|
+
return snapshotData;
|
|
756
229
|
} catch (error) {
|
|
757
230
|
const dpe = DataProcessingError.wrapIfUnrecognized(
|
|
758
231
|
error,
|
|
759
232
|
"FailedToInitializeGC",
|
|
760
233
|
);
|
|
761
|
-
dpe.addTelemetryProperties({
|
|
234
|
+
dpe.addTelemetryProperties({
|
|
235
|
+
gcConfigs: JSON.stringify(this.configs),
|
|
236
|
+
});
|
|
762
237
|
throw dpe;
|
|
763
238
|
}
|
|
764
239
|
},
|
|
@@ -798,13 +273,14 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
798
273
|
return;
|
|
799
274
|
}
|
|
800
275
|
this.updateStateFromSnapshotData(baseSnapshotData, currentReferenceTimestampMs);
|
|
276
|
+
this.summaryStateTracker.initializeBaseState(baseSnapshotData);
|
|
801
277
|
});
|
|
802
278
|
|
|
803
279
|
// Get the GC details from the GC state in the base summary. This is returned in getBaseGCDetails which is
|
|
804
280
|
// used to initialize the GC state of all the nodes in the container.
|
|
805
281
|
this.baseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {
|
|
806
282
|
const baseSnapshotData = await this.baseSnapshotDataP;
|
|
807
|
-
if (baseSnapshotData === undefined) {
|
|
283
|
+
if (baseSnapshotData?.gcState === undefined) {
|
|
808
284
|
return {};
|
|
809
285
|
}
|
|
810
286
|
|
|
@@ -826,6 +302,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
826
302
|
this.mc.logger.sendTelemetryEvent({
|
|
827
303
|
eventName: "GarbageCollectorLoaded",
|
|
828
304
|
gcConfigs: JSON.stringify(this.configs),
|
|
305
|
+
gcOptions: JSON.stringify(createParams.gcOptions),
|
|
829
306
|
});
|
|
830
307
|
}
|
|
831
308
|
}
|
|
@@ -854,7 +331,8 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
854
331
|
|
|
855
332
|
// If running in tombstone mode, initialize the tombstone state from the snapshot. Also, notify the runtime of
|
|
856
333
|
// tombstone routes.
|
|
857
|
-
if (this.tombstoneMode && baseSnapshotData.tombstones !== undefined) {
|
|
334
|
+
if (this.configs.tombstoneMode && baseSnapshotData.tombstones !== undefined) {
|
|
335
|
+
// Create a copy since we are writing from a source we don't control
|
|
858
336
|
this.tombstones = Array.from(baseSnapshotData.tombstones);
|
|
859
337
|
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
860
338
|
}
|
|
@@ -894,9 +372,9 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
894
372
|
// tombstones.
|
|
895
373
|
// If this call is because we are refreshing from a snapshot due to an ack, it is likely that the GC state
|
|
896
374
|
// in the snapshot is newer than this client's. And so, the deleted / tombstone nodes need to be updated.
|
|
897
|
-
if (this.shouldRunSweep) {
|
|
898
|
-
const snapshotDeletedNodes = snapshotData?.
|
|
899
|
-
? new Set(snapshotData.
|
|
375
|
+
if (this.configs.shouldRunSweep) {
|
|
376
|
+
const snapshotDeletedNodes = snapshotData?.deletedNodes
|
|
377
|
+
? new Set(snapshotData.deletedNodes)
|
|
900
378
|
: undefined;
|
|
901
379
|
// If the snapshot contains deleted nodes that are not yet deleted by this client, ask the runtime to
|
|
902
380
|
// delete them.
|
|
@@ -911,7 +389,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
911
389
|
// Call container runtime to delete these nodes and add deleted nodes to this.deletedNodes.
|
|
912
390
|
}
|
|
913
391
|
}
|
|
914
|
-
} else if (this.tombstoneMode) {
|
|
392
|
+
} else if (this.configs.tombstoneMode) {
|
|
915
393
|
// The snapshot may contain more or fewer tombstone nodes than this client. Update tombstone state and
|
|
916
394
|
// notify the runtime to update its state as well.
|
|
917
395
|
this.tombstones = snapshotData?.tombstones ? Array.from(snapshotData.tombstones) : [];
|
|
@@ -919,9 +397,8 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
919
397
|
}
|
|
920
398
|
|
|
921
399
|
// If there is no snapshot data, it means this snapshot was generated with GC disabled. Unset all GC state.
|
|
922
|
-
if (snapshotData === undefined) {
|
|
400
|
+
if (snapshotData?.gcState === undefined) {
|
|
923
401
|
this.gcDataFromLastRun = undefined;
|
|
924
|
-
this.latestSummaryData = undefined;
|
|
925
402
|
return;
|
|
926
403
|
}
|
|
927
404
|
|
|
@@ -934,24 +411,15 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
934
411
|
nodeId,
|
|
935
412
|
new UnreferencedStateTracker(
|
|
936
413
|
nodeData.unreferencedTimestampMs,
|
|
937
|
-
this.inactiveTimeoutMs,
|
|
414
|
+
this.configs.inactiveTimeoutMs,
|
|
938
415
|
currentReferenceTimestampMs,
|
|
939
|
-
this.sweepTimeoutMs,
|
|
416
|
+
this.configs.sweepTimeoutMs,
|
|
940
417
|
),
|
|
941
418
|
);
|
|
942
419
|
}
|
|
943
420
|
gcNodes[nodeId] = Array.from(nodeData.outboundRoutes);
|
|
944
421
|
}
|
|
945
422
|
this.gcDataFromLastRun = { gcNodes };
|
|
946
|
-
|
|
947
|
-
// If tracking state across summaries, update latest summary data from the snapshot's GC data.
|
|
948
|
-
if (this.trackGCState) {
|
|
949
|
-
this.latestSummaryData = {
|
|
950
|
-
serializedGCState: JSON.stringify(generateSortedGCState(snapshotData.gcState)),
|
|
951
|
-
serializedTombstones: JSON.stringify(snapshotData.tombstones),
|
|
952
|
-
serializedDeletedNodes: JSON.stringify(snapshotData.deletedNodes),
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
423
|
}
|
|
956
424
|
|
|
957
425
|
/**
|
|
@@ -974,7 +442,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
974
442
|
* Ideally, this initialization should only be done for summarizer client. However, we are currently rolling out
|
|
975
443
|
* sweep in phases and we want to track when inactive and sweep ready objects are used in any client.
|
|
976
444
|
*/
|
|
977
|
-
if (this.activeConnection() && this.shouldRunGC) {
|
|
445
|
+
if (this.activeConnection() && this.configs.shouldRunGC) {
|
|
978
446
|
this.initializeGCStateFromBaseSnapshotP.catch((error) => {});
|
|
979
447
|
}
|
|
980
448
|
}
|
|
@@ -983,16 +451,20 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
983
451
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
984
452
|
* @returns stats of the GC run or undefined if GC did not run.
|
|
985
453
|
*/
|
|
986
|
-
public async collectGarbage(
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
454
|
+
public async collectGarbage(
|
|
455
|
+
options: {
|
|
456
|
+
/** Logger to use for logging GC events */
|
|
457
|
+
logger?: ITelemetryLogger;
|
|
458
|
+
/** True to run GC sweep phase after the mark phase */
|
|
459
|
+
runSweep?: boolean;
|
|
460
|
+
/** True to generate full GC data */
|
|
461
|
+
fullGC?: boolean;
|
|
462
|
+
},
|
|
463
|
+
telemetryContext?: ITelemetryContext,
|
|
464
|
+
): Promise<IGCStats | undefined> {
|
|
994
465
|
const fullGC =
|
|
995
|
-
options.fullGC ??
|
|
466
|
+
options.fullGC ??
|
|
467
|
+
(this.configs.runFullGC === true || this.summaryStateTracker.doesSummaryStateNeedReset);
|
|
996
468
|
const logger = options.logger
|
|
997
469
|
? ChildLogger.create(options.logger, undefined, {
|
|
998
470
|
all: { completedGCRuns: () => this.completedRuns },
|
|
@@ -1017,6 +489,12 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1017
489
|
return undefined;
|
|
1018
490
|
}
|
|
1019
491
|
|
|
492
|
+
// Add the options that are used to run GC to the telemetry context.
|
|
493
|
+
telemetryContext?.setMultiple("fluid_GC", "Options", {
|
|
494
|
+
fullGC,
|
|
495
|
+
runSweep: options.runSweep,
|
|
496
|
+
});
|
|
497
|
+
|
|
1020
498
|
return PerformanceEvent.timedExecAsync(
|
|
1021
499
|
logger,
|
|
1022
500
|
{ eventName: "GarbageCollection" },
|
|
@@ -1058,29 +536,37 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1058
536
|
// generates some of its data based on previous state of the system.
|
|
1059
537
|
const gcStats = this.generateStats(gcResult);
|
|
1060
538
|
|
|
1061
|
-
// Update the state
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
539
|
+
// Update the current mark state and update the runtime of all used routes or ids that used as per the GC run.
|
|
540
|
+
const sweepReadyNodes = this.updateMarkPhase(
|
|
541
|
+
gcData,
|
|
542
|
+
gcResult,
|
|
543
|
+
currentReferenceTimestampMs,
|
|
544
|
+
logger,
|
|
545
|
+
);
|
|
1067
546
|
this.runtime.updateUsedRoutes(gcResult.referencedNodeIds);
|
|
1068
547
|
|
|
1069
548
|
// Log events for objects that are ready to be deleted by sweep. When we have sweep enabled, we will
|
|
1070
549
|
// delete these objects here instead.
|
|
1071
550
|
this.logSweepEvents(logger, currentReferenceTimestampMs);
|
|
1072
551
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
if (this.
|
|
552
|
+
let updatedGCData: IGarbageCollectionData = gcData;
|
|
553
|
+
|
|
554
|
+
if (this.configs.shouldRunSweep) {
|
|
555
|
+
updatedGCData = this.runSweepPhase(sweepReadyNodes, gcData);
|
|
556
|
+
} else if (this.configs.testMode) {
|
|
557
|
+
// If we are running in GC test mode, delete objects for unused routes. This enables testing scenarios
|
|
558
|
+
// involving access to deleted data.
|
|
1076
559
|
this.runtime.updateUnusedRoutes(gcResult.deletedNodeIds);
|
|
1077
|
-
} else if (this.tombstoneMode) {
|
|
560
|
+
} else if (this.configs.tombstoneMode) {
|
|
561
|
+
this.tombstones = sweepReadyNodes;
|
|
1078
562
|
// If we are running in GC tombstone mode, update tombstoned routes. This enables testing scenarios
|
|
1079
563
|
// involving access to "deleted" data without actually deleting the data from summaries.
|
|
1080
564
|
// Note: we will not tombstone in test mode.
|
|
1081
565
|
this.runtime.updateTombstonedRoutes(this.tombstones);
|
|
1082
566
|
}
|
|
1083
567
|
|
|
568
|
+
this.gcDataFromLastRun = cloneGCData(updatedGCData);
|
|
569
|
+
|
|
1084
570
|
// Log pending unreferenced events such as a node being used after inactive. This is done after GC runs and
|
|
1085
571
|
// updates its state so that we don't send false positives based on intermediate state. For example, we may get
|
|
1086
572
|
// reference to an unreferenced node from another unreferenced node which means the node wasn't revived.
|
|
@@ -1099,7 +585,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1099
585
|
trackState: boolean,
|
|
1100
586
|
telemetryContext?: ITelemetryContext,
|
|
1101
587
|
): ISummarizeResult | undefined {
|
|
1102
|
-
if (!this.shouldRunGC || this.gcDataFromLastRun === undefined) {
|
|
588
|
+
if (!this.configs.shouldRunGC || this.gcDataFromLastRun === undefined) {
|
|
1103
589
|
return;
|
|
1104
590
|
}
|
|
1105
591
|
|
|
@@ -1112,142 +598,26 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1112
598
|
};
|
|
1113
599
|
}
|
|
1114
600
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
this.deletedNodes
|
|
1120
|
-
|
|
1121
|
-
: undefined;
|
|
1122
|
-
// If running in tombstone mode, serialize and write tombstones, if any.
|
|
1123
|
-
const serializedTombstones = this.tombstoneMode
|
|
1124
|
-
? this.tombstones.length > 0
|
|
1125
|
-
? JSON.stringify(this.tombstones.sort())
|
|
1126
|
-
: undefined
|
|
1127
|
-
: undefined;
|
|
1128
|
-
|
|
1129
|
-
/**
|
|
1130
|
-
* Incremental summary of GC data - If none of GC state, deleted nodes or tombstones changed since last summary,
|
|
1131
|
-
* write summary handle instead of summary tree for GC.
|
|
1132
|
-
* Otherwise, write the GC summary tree. In the tree, for each of these that changed, write a summary blob and
|
|
1133
|
-
* for each of these that did not change, write a summary handle.
|
|
1134
|
-
*/
|
|
1135
|
-
if (this.trackGCState) {
|
|
1136
|
-
this.pendingSummaryData = {
|
|
1137
|
-
serializedGCState,
|
|
1138
|
-
serializedTombstones,
|
|
1139
|
-
serializedDeletedNodes,
|
|
1140
|
-
};
|
|
1141
|
-
if (trackState && !fullTree && this.latestSummaryData !== undefined) {
|
|
1142
|
-
// If nothing changed since last summary, send a summary handle for the entire GC data.
|
|
1143
|
-
if (
|
|
1144
|
-
this.latestSummaryData.serializedGCState === serializedGCState &&
|
|
1145
|
-
this.latestSummaryData.serializedTombstones === serializedTombstones
|
|
1146
|
-
) {
|
|
1147
|
-
const stats = mergeStats();
|
|
1148
|
-
stats.handleNodeCount++;
|
|
1149
|
-
return {
|
|
1150
|
-
summary: {
|
|
1151
|
-
type: SummaryType.Handle,
|
|
1152
|
-
handle: `/${gcTreeKey}`,
|
|
1153
|
-
handleType: SummaryType.Tree,
|
|
1154
|
-
},
|
|
1155
|
-
stats,
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
// If some state changed, build a GC summary tree.
|
|
1160
|
-
return this.buildGCSummaryTree(
|
|
1161
|
-
serializedGCState,
|
|
1162
|
-
serializedTombstones,
|
|
1163
|
-
serializedDeletedNodes,
|
|
1164
|
-
true /* trackState */,
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
// If not tracking GC state, build a GC summary tree without any summary handles.
|
|
1169
|
-
return this.buildGCSummaryTree(
|
|
1170
|
-
serializedGCState,
|
|
1171
|
-
serializedTombstones,
|
|
1172
|
-
serializedDeletedNodes,
|
|
1173
|
-
false /* trackState */,
|
|
601
|
+
return this.summaryStateTracker.summarize(
|
|
602
|
+
fullTree,
|
|
603
|
+
trackState,
|
|
604
|
+
gcState,
|
|
605
|
+
this.deletedNodes,
|
|
606
|
+
this.tombstones,
|
|
1174
607
|
);
|
|
1175
608
|
}
|
|
1176
609
|
|
|
1177
|
-
/**
|
|
1178
|
-
* Builds the GC summary tree which contains GC state, deleted nodes and tombstones.
|
|
1179
|
-
* If trackState is false, all of GC state, deleted nodes and tombstones are written as summary blobs.
|
|
1180
|
-
* If trackState is true, only states that changed are written. Rest are written as handles.
|
|
1181
|
-
* @param serializedGCState - The GC state serialized as string.
|
|
1182
|
-
* @param serializedTombstones - The tombstone state serialized as string.
|
|
1183
|
-
* @param serializedDeletedNodes - Deleted nodes serialized as string.
|
|
1184
|
-
* @param trackState - Whether we are tracking GC state across summaries.
|
|
1185
|
-
* @returns the GC summary tree.
|
|
1186
|
-
*/
|
|
1187
|
-
private buildGCSummaryTree(
|
|
1188
|
-
serializedGCState: string,
|
|
1189
|
-
serializedTombstones: string | undefined,
|
|
1190
|
-
serializedDeletedNodes: string | undefined,
|
|
1191
|
-
trackState: boolean,
|
|
1192
|
-
): ISummaryTreeWithStats {
|
|
1193
|
-
const gcStateBlobKey = `${gcBlobPrefix}_root`;
|
|
1194
|
-
const builder = new SummaryTreeBuilder();
|
|
1195
|
-
|
|
1196
|
-
// If the GC state hasn't changed, write a summary handle, else write a summary blob for it.
|
|
1197
|
-
if (this.latestSummaryData?.serializedGCState === serializedGCState && trackState) {
|
|
1198
|
-
builder.addHandle(gcStateBlobKey, SummaryType.Blob, `/${gcTreeKey}/${gcStateBlobKey}`);
|
|
1199
|
-
} else {
|
|
1200
|
-
builder.addBlob(gcStateBlobKey, serializedGCState);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// If tombstones exist, write a summary handle if it hasn't changed. If it has changed, write a
|
|
1204
|
-
// summary blob.
|
|
1205
|
-
if (serializedTombstones !== undefined) {
|
|
1206
|
-
if (
|
|
1207
|
-
this.latestSummaryData?.serializedTombstones === serializedTombstones &&
|
|
1208
|
-
trackState
|
|
1209
|
-
) {
|
|
1210
|
-
builder.addHandle(
|
|
1211
|
-
gcTombstoneBlobKey,
|
|
1212
|
-
SummaryType.Blob,
|
|
1213
|
-
`/${gcTreeKey}/${gcTombstoneBlobKey}`,
|
|
1214
|
-
);
|
|
1215
|
-
} else {
|
|
1216
|
-
builder.addBlob(gcTombstoneBlobKey, serializedTombstones);
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
// If there are no deleted nodes, return the summary tree.
|
|
1221
|
-
if (serializedDeletedNodes === undefined) {
|
|
1222
|
-
return builder.getSummaryTree();
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
// If the deleted nodes hasn't changed, write a summary handle, else write a summary blob for it.
|
|
1226
|
-
if (
|
|
1227
|
-
this.latestSummaryData?.serializedDeletedNodes === serializedDeletedNodes &&
|
|
1228
|
-
trackState
|
|
1229
|
-
) {
|
|
1230
|
-
builder.addHandle(
|
|
1231
|
-
gcDeletedBlobKey,
|
|
1232
|
-
SummaryType.Blob,
|
|
1233
|
-
`/${gcTreeKey}/${gcDeletedBlobKey}`,
|
|
1234
|
-
);
|
|
1235
|
-
} else {
|
|
1236
|
-
builder.addBlob(gcDeletedBlobKey, serializedDeletedNodes);
|
|
1237
|
-
}
|
|
1238
|
-
return builder.getSummaryTree();
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
610
|
public getMetadata(): IGCMetadata {
|
|
1242
611
|
return {
|
|
1243
612
|
/**
|
|
1244
613
|
* If GC is enabled, the GC data is written using the current GC version and that is the gcFeature that goes
|
|
1245
614
|
* into the metadata blob. If GC is disabled, the gcFeature is 0.
|
|
1246
615
|
*/
|
|
1247
|
-
gcFeature: this.gcEnabled ? this.currentGCVersion : 0,
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
616
|
+
gcFeature: this.configs.gcEnabled ? this.summaryStateTracker.currentGCVersion : 0,
|
|
617
|
+
gcFeatureMatrix: this.configs.persistedGcFeatureMatrix,
|
|
618
|
+
sessionExpiryTimeoutMs: this.configs.sessionExpiryTimeoutMs,
|
|
619
|
+
sweepEnabled: false, // DEPRECATED - to be removed
|
|
620
|
+
sweepTimeoutMs: this.configs.sweepTimeoutMs,
|
|
1251
621
|
};
|
|
1252
622
|
}
|
|
1253
623
|
|
|
@@ -1264,62 +634,36 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1264
634
|
* is downloaded and should be used to update the state.
|
|
1265
635
|
*/
|
|
1266
636
|
public async refreshLatestSummary(
|
|
1267
|
-
result: RefreshSummaryResult,
|
|
1268
637
|
proposalHandle: string | undefined,
|
|
1269
|
-
|
|
638
|
+
result: RefreshSummaryResult,
|
|
1270
639
|
readAndParseBlob: ReadAndParseBlob,
|
|
1271
640
|
): Promise<void> {
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
this.wasGCRunInLatestSummary = this.shouldRunGC;
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
if (!result.latestSummaryUpdated || !this.shouldRunGC) {
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
641
|
+
const latestSnapshotData = await this.summaryStateTracker.refreshLatestSummary(
|
|
642
|
+
proposalHandle,
|
|
643
|
+
result,
|
|
644
|
+
readAndParseBlob,
|
|
645
|
+
);
|
|
1283
646
|
|
|
1284
|
-
// If the summary was tracked by this client,
|
|
1285
|
-
//
|
|
1286
|
-
if (result.wasSummaryTracked) {
|
|
1287
|
-
|
|
1288
|
-
if
|
|
1289
|
-
|
|
1290
|
-
|
|
647
|
+
// If the latest summary was updated but it was not tracked by this client, our state needs to be updated from
|
|
648
|
+
// this snapshot data.
|
|
649
|
+
if (this.shouldRunGC && result.latestSummaryUpdated && !result.wasSummaryTracked) {
|
|
650
|
+
// The current reference timestamp should be available if we are refreshing state from a snapshot. There has
|
|
651
|
+
// to be at least one op (summary op / ack, if nothing else) if a snapshot was taken.
|
|
652
|
+
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
653
|
+
if (currentReferenceTimestampMs === undefined) {
|
|
654
|
+
throw DataProcessingError.create(
|
|
655
|
+
"No reference timestamp when updating GC state from snapshot",
|
|
656
|
+
"refreshLatestSummary",
|
|
657
|
+
undefined,
|
|
658
|
+
{
|
|
659
|
+
proposalHandle,
|
|
660
|
+
summaryRefSeq: result.summaryRefSeq,
|
|
661
|
+
gcConfigs: JSON.stringify(this.configs),
|
|
662
|
+
},
|
|
663
|
+
);
|
|
1291
664
|
}
|
|
1292
|
-
|
|
665
|
+
this.updateStateFromSnapshotData(latestSnapshotData, currentReferenceTimestampMs);
|
|
1293
666
|
}
|
|
1294
|
-
|
|
1295
|
-
// If the summary was not tracked by this client, the state should be updated from the downloaded snapshot.
|
|
1296
|
-
const snapshot = result.snapshot;
|
|
1297
|
-
const metadataBlobId = snapshot.blobs[metadataBlobName];
|
|
1298
|
-
if (metadataBlobId) {
|
|
1299
|
-
const metadata = await readAndParseBlob<IContainerRuntimeMetadata>(metadataBlobId);
|
|
1300
|
-
this.latestSummaryGCVersion = getGCVersion(metadata);
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// The current reference timestamp should be available if we are refreshing state from a snapshot. There has
|
|
1304
|
-
// to be at least one op (summary op / ack, if nothing else) if a snapshot was taken.
|
|
1305
|
-
const currentReferenceTimestampMs = this.runtime.getCurrentReferenceTimestampMs();
|
|
1306
|
-
if (currentReferenceTimestampMs === undefined) {
|
|
1307
|
-
throw DataProcessingError.create(
|
|
1308
|
-
"No reference timestamp when updating GC state from snapshot",
|
|
1309
|
-
"refreshLatestSummary",
|
|
1310
|
-
undefined,
|
|
1311
|
-
{ proposalHandle, summaryRefSeq, details: JSON.stringify(this.configs) },
|
|
1312
|
-
);
|
|
1313
|
-
}
|
|
1314
|
-
const gcSnapshotTree = snapshot.trees[gcTreeKey];
|
|
1315
|
-
// If GC ran in the container that generated this snapshot, it will have a GC tree.
|
|
1316
|
-
this.wasGCRunInLatestSummary = gcSnapshotTree !== undefined;
|
|
1317
|
-
let latestGCData: IGarbageCollectionSnapshotData | undefined;
|
|
1318
|
-
if (gcSnapshotTree !== undefined) {
|
|
1319
|
-
latestGCData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);
|
|
1320
|
-
}
|
|
1321
|
-
this.updateStateFromSnapshotData(latestGCData, currentReferenceTimestampMs);
|
|
1322
|
-
this.pendingSummaryData = undefined;
|
|
1323
667
|
}
|
|
1324
668
|
|
|
1325
669
|
/**
|
|
@@ -1337,7 +681,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1337
681
|
packagePath?: readonly string[],
|
|
1338
682
|
requestHeaders?: IRequestHeader,
|
|
1339
683
|
) {
|
|
1340
|
-
if (!this.shouldRunGC) {
|
|
684
|
+
if (!this.configs.shouldRunGC) {
|
|
1341
685
|
return;
|
|
1342
686
|
}
|
|
1343
687
|
|
|
@@ -1363,7 +707,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1363
707
|
* @param toNodePath - The node to which the reference is added.
|
|
1364
708
|
*/
|
|
1365
709
|
public addedOutboundReference(fromNodePath: string, toNodePath: string) {
|
|
1366
|
-
if (!this.shouldRunGC) {
|
|
710
|
+
if (!this.configs.shouldRunGC) {
|
|
1367
711
|
return;
|
|
1368
712
|
}
|
|
1369
713
|
|
|
@@ -1391,9 +735,9 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1391
735
|
{
|
|
1392
736
|
eventName,
|
|
1393
737
|
category: "generic",
|
|
1394
|
-
|
|
1395
|
-
url: trimLeadingSlashes(toNodePath),
|
|
738
|
+
url: toNodePath,
|
|
1396
739
|
nodeType,
|
|
740
|
+
gcTombstoneEnforcementAllowed: this.runtime.gcTombstoneEnforcementAllowed,
|
|
1397
741
|
},
|
|
1398
742
|
undefined /* packagePath */,
|
|
1399
743
|
);
|
|
@@ -1421,18 +765,23 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1421
765
|
* @param gcData - The data representing the reference graph on which GC is run.
|
|
1422
766
|
* @param gcResult - The result of the GC run on the gcData.
|
|
1423
767
|
* @param currentReferenceTimestampMs - The timestamp to be used for unreferenced nodes' timestamp.
|
|
768
|
+
* @returns - A list of sweep ready nodes. (Nodes ready to be deleted)
|
|
1424
769
|
*/
|
|
1425
|
-
private
|
|
770
|
+
private updateMarkPhase(
|
|
1426
771
|
gcData: IGarbageCollectionData,
|
|
1427
772
|
gcResult: IGCResult,
|
|
1428
773
|
currentReferenceTimestampMs: number,
|
|
774
|
+
logger: ITelemetryLogger,
|
|
1429
775
|
) {
|
|
1430
|
-
|
|
1431
|
-
|
|
776
|
+
// Get references from the current GC run + references between previous and current run and then update each
|
|
777
|
+
// node's state
|
|
778
|
+
const allNodesReferencedBetweenGCs =
|
|
779
|
+
this.findAllNodesReferencedBetweenGCs(gcData, this.gcDataFromLastRun, logger) ??
|
|
780
|
+
gcResult.referencedNodeIds;
|
|
1432
781
|
this.newReferencesSinceLastRun.clear();
|
|
1433
782
|
|
|
1434
783
|
// Iterate through the referenced nodes and stop tracking if they were unreferenced before.
|
|
1435
|
-
for (const nodeId of
|
|
784
|
+
for (const nodeId of allNodesReferencedBetweenGCs) {
|
|
1436
785
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
1437
786
|
if (nodeStateTracker !== undefined) {
|
|
1438
787
|
// Stop tracking so as to clear out any running timers.
|
|
@@ -1446,7 +795,10 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1446
795
|
* If a node became unreferenced in this run, start tracking it.
|
|
1447
796
|
* If a node was already unreferenced, update its tracking information. Since the current reference time is
|
|
1448
797
|
* from the ops seen, this will ensure that we keep updating the unreferenced state as time moves forward.
|
|
798
|
+
*
|
|
799
|
+
* If a node is sweep ready, store and then return it.
|
|
1449
800
|
*/
|
|
801
|
+
const sweepReadyNodes: string[] = [];
|
|
1450
802
|
for (const nodeId of gcResult.deletedNodeIds) {
|
|
1451
803
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
1452
804
|
if (nodeStateTracker === undefined) {
|
|
@@ -1454,21 +806,68 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1454
806
|
nodeId,
|
|
1455
807
|
new UnreferencedStateTracker(
|
|
1456
808
|
currentReferenceTimestampMs,
|
|
1457
|
-
this.inactiveTimeoutMs,
|
|
809
|
+
this.configs.inactiveTimeoutMs,
|
|
1458
810
|
currentReferenceTimestampMs,
|
|
1459
|
-
this.sweepTimeoutMs,
|
|
811
|
+
this.configs.sweepTimeoutMs,
|
|
1460
812
|
),
|
|
1461
813
|
);
|
|
1462
814
|
} else {
|
|
1463
815
|
nodeStateTracker.updateTracking(currentReferenceTimestampMs);
|
|
1464
|
-
if (
|
|
1465
|
-
|
|
1466
|
-
if (nodeType === GCNodeType.DataStore || nodeType === GCNodeType.Blob) {
|
|
1467
|
-
this.tombstones.push(nodeId);
|
|
1468
|
-
}
|
|
816
|
+
if (nodeStateTracker.state === UnreferencedState.SweepReady) {
|
|
817
|
+
sweepReadyNodes.push(nodeId);
|
|
1469
818
|
}
|
|
1470
819
|
}
|
|
1471
820
|
}
|
|
821
|
+
|
|
822
|
+
return sweepReadyNodes;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Deletes nodes from both the runtime and garbage collection
|
|
827
|
+
* @param sweepReadyNodes - nodes that are ready to be deleted
|
|
828
|
+
*/
|
|
829
|
+
private runSweepPhase(sweepReadyNodes: string[], gcData: IGarbageCollectionData) {
|
|
830
|
+
// TODO: GC:Validation - validate that removed routes are not double deleted
|
|
831
|
+
// TODO: GC:Validation - validate that the child routes of removed routes are deleted as well
|
|
832
|
+
const sweptRoutes = this.runtime.deleteSweepReadyNodes(sweepReadyNodes);
|
|
833
|
+
const updatedGCData = this.deleteSweptRoutes(sweptRoutes, gcData);
|
|
834
|
+
|
|
835
|
+
for (const nodeId of sweptRoutes) {
|
|
836
|
+
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
837
|
+
// TODO: GC:Validation - assert that the nodeStateTracker is defined
|
|
838
|
+
if (nodeStateTracker !== undefined) {
|
|
839
|
+
// Stop tracking so as to clear out any running timers.
|
|
840
|
+
nodeStateTracker.stopTracking();
|
|
841
|
+
// Delete the node as we don't need to track it any more.
|
|
842
|
+
this.unreferencedNodesState.delete(nodeId);
|
|
843
|
+
}
|
|
844
|
+
// TODO: GC:Validation - assert that the deleted node is not a duplicate
|
|
845
|
+
this.deletedNodes.add(nodeId);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
return updatedGCData;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* @returns IGarbageCollectionData after deleting the sweptRoutes from the gcData
|
|
853
|
+
*/
|
|
854
|
+
private deleteSweptRoutes(
|
|
855
|
+
sweptRoutes: string[],
|
|
856
|
+
gcData: IGarbageCollectionData,
|
|
857
|
+
): IGarbageCollectionData {
|
|
858
|
+
const sweptRoutesSet = new Set<string>(sweptRoutes);
|
|
859
|
+
const gcNodes: { [id: string]: string[] } = {};
|
|
860
|
+
for (const [id, outboundRoutes] of Object.entries(gcData.gcNodes)) {
|
|
861
|
+
if (!sweptRoutesSet.has(id)) {
|
|
862
|
+
gcNodes[id] = Array.from(outboundRoutes);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// TODO: GC:Validation - assert that the nodeId is in gcData
|
|
867
|
+
|
|
868
|
+
return {
|
|
869
|
+
gcNodes,
|
|
870
|
+
};
|
|
1472
871
|
}
|
|
1473
872
|
|
|
1474
873
|
/**
|
|
@@ -1481,22 +880,26 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1481
880
|
* 2. A reference is added from one unreferenced node to one or more unreferenced nodes. Even though the node[s] were
|
|
1482
881
|
* unreferenced, they could have been accessed and in-memory reference to them added.
|
|
1483
882
|
*
|
|
1484
|
-
* This function identifies nodes that were referenced since last run
|
|
883
|
+
* This function identifies nodes that were referenced since the last run.
|
|
1485
884
|
* If these nodes are currently unreferenced, they will be assigned new unreferenced state by the current run.
|
|
885
|
+
*
|
|
886
|
+
* @returns - a list of all nodes referenced from the last local summary until now.
|
|
1486
887
|
*/
|
|
1487
|
-
private
|
|
888
|
+
private findAllNodesReferencedBetweenGCs(
|
|
1488
889
|
currentGCData: IGarbageCollectionData,
|
|
890
|
+
previousGCData: IGarbageCollectionData | undefined,
|
|
1489
891
|
logger: ITelemetryLogger,
|
|
1490
|
-
) {
|
|
892
|
+
): string[] | undefined {
|
|
1491
893
|
// If we haven't run GC before there is nothing to do.
|
|
1492
|
-
|
|
1493
|
-
|
|
894
|
+
// No previousGCData, means nothing is unreferenced, and there are no reference state trackers to clear
|
|
895
|
+
if (previousGCData === undefined) {
|
|
896
|
+
return undefined;
|
|
1494
897
|
}
|
|
1495
898
|
|
|
1496
899
|
// Find any references that haven't been identified correctly.
|
|
1497
900
|
const missingExplicitReferences = this.findMissingExplicitReferences(
|
|
1498
901
|
currentGCData,
|
|
1499
|
-
|
|
902
|
+
previousGCData,
|
|
1500
903
|
this.newReferencesSinceLastRun,
|
|
1501
904
|
);
|
|
1502
905
|
|
|
@@ -1511,9 +914,9 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1511
914
|
}
|
|
1512
915
|
|
|
1513
916
|
// No references were added since the last run so we don't have to update reference states of any unreferenced
|
|
1514
|
-
// nodes
|
|
917
|
+
// nodes. There is no in between state at this point.
|
|
1515
918
|
if (this.newReferencesSinceLastRun.size === 0) {
|
|
1516
|
-
return;
|
|
919
|
+
return undefined;
|
|
1517
920
|
}
|
|
1518
921
|
|
|
1519
922
|
/**
|
|
@@ -1532,7 +935,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1532
935
|
* - We don't require DDSes handles to be stored in a referenced DDS.
|
|
1533
936
|
* - A new data store may have "root" DDSes already created and we don't detect them today.
|
|
1534
937
|
*/
|
|
1535
|
-
const gcDataSuperSet = concatGarbageCollectionData(
|
|
938
|
+
const gcDataSuperSet = concatGarbageCollectionData(previousGCData, currentGCData);
|
|
1536
939
|
const newOutboundRoutesSinceLastRun: string[] = [];
|
|
1537
940
|
this.newReferencesSinceLastRun.forEach((outboundRoutes: string[], sourceNodeId: string) => {
|
|
1538
941
|
if (gcDataSuperSet.gcNodes[sourceNodeId] === undefined) {
|
|
@@ -1554,15 +957,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1554
957
|
"/",
|
|
1555
958
|
...newOutboundRoutesSinceLastRun,
|
|
1556
959
|
]);
|
|
1557
|
-
|
|
1558
|
-
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
1559
|
-
if (nodeStateTracker !== undefined) {
|
|
1560
|
-
// Stop tracking so as to clear out any running timers.
|
|
1561
|
-
nodeStateTracker.stopTracking();
|
|
1562
|
-
// Delete the unreferenced state as we don't need to track it any more.
|
|
1563
|
-
this.unreferencedNodesState.delete(nodeId);
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
960
|
+
return gcResult.referencedNodeIds;
|
|
1566
961
|
}
|
|
1567
962
|
|
|
1568
963
|
/**
|
|
@@ -1693,7 +1088,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1693
1088
|
private logSweepEvents(logger: ITelemetryLogger, currentReferenceTimestampMs: number) {
|
|
1694
1089
|
if (
|
|
1695
1090
|
this.mc.config.getBoolean(disableSweepLogKey) === true ||
|
|
1696
|
-
this.sweepTimeoutMs === undefined
|
|
1091
|
+
this.configs.sweepTimeoutMs === undefined
|
|
1697
1092
|
) {
|
|
1698
1093
|
return;
|
|
1699
1094
|
}
|
|
@@ -1719,7 +1114,7 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1719
1114
|
id: nodeId,
|
|
1720
1115
|
type: nodeType,
|
|
1721
1116
|
age: currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs,
|
|
1722
|
-
timeout: this.sweepTimeoutMs,
|
|
1117
|
+
timeout: this.configs.sweepTimeoutMs,
|
|
1723
1118
|
completedGCRuns: this.completedRuns,
|
|
1724
1119
|
lastSummaryTime: this.getLastSummaryTimestampMs(),
|
|
1725
1120
|
});
|
|
@@ -1769,12 +1164,11 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1769
1164
|
age: currentReferenceTimestampMs - nodeStateTracker.unreferencedTimestampMs,
|
|
1770
1165
|
timeout:
|
|
1771
1166
|
nodeStateTracker.state === UnreferencedState.Inactive
|
|
1772
|
-
? this.inactiveTimeoutMs
|
|
1773
|
-
: this.sweepTimeoutMs,
|
|
1167
|
+
? this.configs.inactiveTimeoutMs
|
|
1168
|
+
: this.configs.sweepTimeoutMs,
|
|
1774
1169
|
completedGCRuns: this.completedRuns,
|
|
1775
1170
|
lastSummaryTime: this.getLastSummaryTimestampMs(),
|
|
1776
1171
|
...this.createContainerMetadata,
|
|
1777
|
-
externalRequest: requestHeaders?.[RuntimeHeaders.externalRequest],
|
|
1778
1172
|
viaHandle: requestHeaders?.[RuntimeHeaders.viaHandle],
|
|
1779
1173
|
fromId: fromNodeId,
|
|
1780
1174
|
};
|
|
@@ -1807,16 +1201,6 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1807
1201
|
this.mc.logger.sendErrorEvent(event);
|
|
1808
1202
|
}
|
|
1809
1203
|
}
|
|
1810
|
-
|
|
1811
|
-
// If SweepReady Usage Detection is enabled, the handler may close the interactive container.
|
|
1812
|
-
// Once Sweep is fully implemented, this will be removed since the objects will be gone
|
|
1813
|
-
// and errors will arise elsewhere in the runtime
|
|
1814
|
-
if (state === UnreferencedState.SweepReady) {
|
|
1815
|
-
this.sweepReadyUsageHandler.usageDetectedInInteractiveClient({
|
|
1816
|
-
...propsToLog,
|
|
1817
|
-
usageType,
|
|
1818
|
-
});
|
|
1819
|
-
}
|
|
1820
1204
|
}
|
|
1821
1205
|
}
|
|
1822
1206
|
|
|
@@ -1864,32 +1248,3 @@ export class GarbageCollector implements IGarbageCollector {
|
|
|
1864
1248
|
this.pendingEventsQueue = [];
|
|
1865
1249
|
}
|
|
1866
1250
|
}
|
|
1867
|
-
|
|
1868
|
-
function generateSortedGCState(gcState: IGarbageCollectionState): IGarbageCollectionState {
|
|
1869
|
-
const sortableArray: [string, IGarbageCollectionNodeData][] = Object.entries(gcState.gcNodes);
|
|
1870
|
-
sortableArray.sort(([a], [b]) => a.localeCompare(b));
|
|
1871
|
-
const sortedGCState: IGarbageCollectionState = { gcNodes: {} };
|
|
1872
|
-
for (const [nodeId, nodeData] of sortableArray) {
|
|
1873
|
-
nodeData.outboundRoutes.sort();
|
|
1874
|
-
sortedGCState.gcNodes[nodeId] = nodeData;
|
|
1875
|
-
}
|
|
1876
|
-
return sortedGCState;
|
|
1877
|
-
}
|
|
1878
|
-
|
|
1879
|
-
/** A wrapper around common-utils Timer that requires the timeout when calling start/restart */
|
|
1880
|
-
class TimerWithNoDefaultTimeout extends Timer {
|
|
1881
|
-
constructor(private readonly callback: () => void) {
|
|
1882
|
-
// The default timeout/handlers will never be used since start/restart pass overrides below
|
|
1883
|
-
super(0, () => {
|
|
1884
|
-
throw new Error("DefaultHandler should not be used");
|
|
1885
|
-
});
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
start(timeoutMs: number) {
|
|
1889
|
-
super.start(timeoutMs, this.callback);
|
|
1890
|
-
}
|
|
1891
|
-
|
|
1892
|
-
restart(timeoutMs: number): void {
|
|
1893
|
-
super.restart(timeoutMs, this.callback);
|
|
1894
|
-
}
|
|
1895
|
-
}
|