@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
package/src/containerRuntime.ts
CHANGED
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
} from "@fluidframework/core-interfaces";
|
|
18
18
|
import {
|
|
19
19
|
IAudience,
|
|
20
|
-
IFluidTokenProvider,
|
|
21
20
|
IContainerContext,
|
|
22
21
|
IDeltaManager,
|
|
23
22
|
IRuntime,
|
|
@@ -25,13 +24,18 @@ import {
|
|
|
25
24
|
AttachState,
|
|
26
25
|
ILoaderOptions,
|
|
27
26
|
LoaderHeader,
|
|
28
|
-
ISnapshotTreeWithBlobContents,
|
|
29
27
|
} from "@fluidframework/container-definitions";
|
|
30
28
|
import {
|
|
31
29
|
IContainerRuntime,
|
|
32
30
|
IContainerRuntimeEvents,
|
|
33
31
|
} from "@fluidframework/container-runtime-definitions";
|
|
34
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
assert,
|
|
34
|
+
LazyPromise,
|
|
35
|
+
Trace,
|
|
36
|
+
TypedEventEmitter,
|
|
37
|
+
unreachableCase,
|
|
38
|
+
} from "@fluidframework/common-utils";
|
|
35
39
|
import {
|
|
36
40
|
ChildLogger,
|
|
37
41
|
raiseConnectedEvent,
|
|
@@ -68,13 +72,13 @@ import {
|
|
|
68
72
|
} from "@fluidframework/protocol-definitions";
|
|
69
73
|
import {
|
|
70
74
|
FlushMode,
|
|
75
|
+
FlushModeExperimental,
|
|
71
76
|
gcTreeKey,
|
|
72
77
|
InboundAttachMessage,
|
|
73
78
|
IFluidDataStoreContextDetached,
|
|
74
79
|
IFluidDataStoreRegistry,
|
|
75
80
|
IFluidDataStoreChannel,
|
|
76
81
|
IGarbageCollectionData,
|
|
77
|
-
IGarbageCollectionDetailsBase,
|
|
78
82
|
IEnvelope,
|
|
79
83
|
IInboundSignalMessage,
|
|
80
84
|
ISignalEnvelope,
|
|
@@ -92,23 +96,19 @@ import {
|
|
|
92
96
|
addBlobToSummary,
|
|
93
97
|
addSummarizeResultToSummary,
|
|
94
98
|
addTreeToSummary,
|
|
95
|
-
createRootSummarizerNodeWithGC,
|
|
96
|
-
IRootSummarizerNodeWithGC,
|
|
97
99
|
RequestParser,
|
|
98
100
|
create404Response,
|
|
99
101
|
exceptionToResponse,
|
|
102
|
+
GCDataBuilder,
|
|
100
103
|
requestFluidObject,
|
|
101
|
-
responseToException,
|
|
102
104
|
seqFromTree,
|
|
103
105
|
calculateStats,
|
|
104
106
|
TelemetryContext,
|
|
107
|
+
ReadAndParseBlob,
|
|
105
108
|
} from "@fluidframework/runtime-utils";
|
|
106
|
-
import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
|
|
107
109
|
import { v4 as uuid } from "uuid";
|
|
108
110
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
109
111
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
110
|
-
import { Summarizer } from "./summarizer";
|
|
111
|
-
import { SummaryManager } from "./summaryManager";
|
|
112
112
|
import { ReportOpPerfTelemetry, IPerfSignalReport } from "./connectionTelemetry";
|
|
113
113
|
import { IPendingLocalState, PendingStateManager } from "./pendingStateManager";
|
|
114
114
|
import { pkgVersion } from "./packageVersion";
|
|
@@ -118,22 +118,24 @@ import {
|
|
|
118
118
|
aliasBlobName,
|
|
119
119
|
blobsTreeName,
|
|
120
120
|
chunksBlobName,
|
|
121
|
+
createRootSummarizerNodeWithGC,
|
|
121
122
|
electedSummarizerBlobName,
|
|
122
123
|
extractSummaryMetadataMessage,
|
|
123
124
|
IContainerRuntimeMetadata,
|
|
124
125
|
ICreateContainerMetadata,
|
|
126
|
+
IFetchSnapshotResult,
|
|
127
|
+
IRootSummarizerNodeWithGC,
|
|
125
128
|
ISummaryMetadataMessage,
|
|
126
129
|
metadataBlobName,
|
|
130
|
+
Summarizer,
|
|
131
|
+
SummaryManager,
|
|
127
132
|
wrapSummaryInChannelsTree,
|
|
128
|
-
|
|
129
|
-
import { SummaryCollection } from "./summaryCollection";
|
|
130
|
-
import {
|
|
133
|
+
SummaryCollection,
|
|
131
134
|
ISerializedElection,
|
|
132
135
|
OrderedClientCollection,
|
|
133
136
|
OrderedClientElection,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
import {
|
|
137
|
+
SummarizerClientElection,
|
|
138
|
+
summarizerClientType,
|
|
137
139
|
SubmitSummaryResult,
|
|
138
140
|
IConnectableRuntime,
|
|
139
141
|
IGeneratedSummaryStats,
|
|
@@ -142,22 +144,21 @@ import {
|
|
|
142
144
|
ISummarizerInternalsProvider,
|
|
143
145
|
ISummarizerRuntime,
|
|
144
146
|
IRefreshSummaryAckOptions,
|
|
145
|
-
|
|
147
|
+
RunWhileConnectedCoordinator,
|
|
148
|
+
} from "./summary";
|
|
146
149
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
147
|
-
import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
|
|
148
150
|
import {
|
|
149
151
|
GarbageCollector,
|
|
150
152
|
GCNodeType,
|
|
151
|
-
|
|
153
|
+
gcTombstoneGenerationOptionName,
|
|
152
154
|
IGarbageCollector,
|
|
155
|
+
IGCRuntimeOptions,
|
|
153
156
|
IGCStats,
|
|
154
|
-
|
|
157
|
+
shouldAllowGcTombstoneEnforcement,
|
|
158
|
+
trimLeadingAndTrailingSlashes,
|
|
159
|
+
} from "./gc";
|
|
155
160
|
import { channelToDataStore, IDataStoreAliasMessage, isDataStoreAliasMessage } from "./dataStore";
|
|
156
161
|
import { BindBatchTracker } from "./batchTracker";
|
|
157
|
-
import {
|
|
158
|
-
ISerializedBaseSnapshotBlobs,
|
|
159
|
-
SerializedSnapshotStorage,
|
|
160
|
-
} from "./serializedSnapshotStorage";
|
|
161
162
|
import { ScheduleManager } from "./scheduleManager";
|
|
162
163
|
import {
|
|
163
164
|
BatchMessage,
|
|
@@ -167,7 +168,9 @@ import {
|
|
|
167
168
|
Outbox,
|
|
168
169
|
OpSplitter,
|
|
169
170
|
RemoteMessageProcessor,
|
|
171
|
+
OpGroupingManager,
|
|
170
172
|
} from "./opLifecycle";
|
|
173
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
171
174
|
|
|
172
175
|
export enum ContainerMessageType {
|
|
173
176
|
// An op to be delivered to store
|
|
@@ -203,7 +206,7 @@ export interface ISummaryBaseConfiguration {
|
|
|
203
206
|
/**
|
|
204
207
|
* Defines the maximum allowed time to wait for a pending summary ack.
|
|
205
208
|
* The maximum amount of time client will wait for a summarize is the minimum of
|
|
206
|
-
* maxSummarizeAckWaitTime (currently
|
|
209
|
+
* maxSummarizeAckWaitTime (currently 3 * 60 * 1000) and maxAckWaitTime.
|
|
207
210
|
*/
|
|
208
211
|
maxAckWaitTime: number;
|
|
209
212
|
/**
|
|
@@ -299,7 +302,7 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
299
302
|
|
|
300
303
|
minOpsForLastSummaryAttempt: 10,
|
|
301
304
|
|
|
302
|
-
maxAckWaitTime:
|
|
305
|
+
maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
|
|
303
306
|
|
|
304
307
|
maxOpsSinceLastSummary: 7000,
|
|
305
308
|
|
|
@@ -312,54 +315,6 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
312
315
|
nonRuntimeHeuristicThreshold: 20,
|
|
313
316
|
};
|
|
314
317
|
|
|
315
|
-
export interface IGCRuntimeOptions {
|
|
316
|
-
/**
|
|
317
|
-
* Flag that if true, will enable running garbage collection (GC) for a new container.
|
|
318
|
-
*
|
|
319
|
-
* GC has mark phase and sweep phase. In mark phase, unreferenced objects are identified
|
|
320
|
-
* and marked as such in the summary. This option enables the mark phase.
|
|
321
|
-
* In sweep phase, unreferenced objects are eventually deleted from the container if they meet certain conditions.
|
|
322
|
-
* Sweep phase can be enabled via the "sweepAllowed" option.
|
|
323
|
-
*
|
|
324
|
-
* Note: This setting is persisted in the container's summary and cannot be changed.
|
|
325
|
-
*/
|
|
326
|
-
gcAllowed?: boolean;
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Flag that if true, enables GC's sweep phase for a new container.
|
|
330
|
-
*
|
|
331
|
-
* This will allow GC to eventually delete unreferenced objects from the container.
|
|
332
|
-
* This flag should only be set to true if "gcAllowed" is true.
|
|
333
|
-
*
|
|
334
|
-
* Note: This setting is persisted in the container's summary and cannot be changed.
|
|
335
|
-
*/
|
|
336
|
-
sweepAllowed?: boolean;
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Flag that if true, will disable garbage collection for the session.
|
|
340
|
-
* Can be used to disable running GC on containers where it is allowed via the gcAllowed option.
|
|
341
|
-
*/
|
|
342
|
-
disableGC?: boolean;
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Flag that will bypass optimizations and generate GC data for all nodes irrespective of whether a node
|
|
346
|
-
* changed or not.
|
|
347
|
-
*/
|
|
348
|
-
runFullGC?: boolean;
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Maximum session duration for a new container. If not present, a default value will be used.
|
|
352
|
-
*
|
|
353
|
-
* Note: This setting is persisted in the container's summary and cannot be changed.
|
|
354
|
-
*/
|
|
355
|
-
sessionExpiryTimeoutMs?: number;
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Allows additional GC options to be passed.
|
|
359
|
-
*/
|
|
360
|
-
[key: string]: any;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
318
|
export interface ISummaryRuntimeOptions {
|
|
364
319
|
/** Override summary configurations set by the server. */
|
|
365
320
|
summaryConfigOverrides?: ISummaryConfiguration;
|
|
@@ -411,10 +366,6 @@ export interface IContainerRuntimeOptions {
|
|
|
411
366
|
* By default, flush mode is TurnBased.
|
|
412
367
|
*/
|
|
413
368
|
readonly flushMode?: FlushMode;
|
|
414
|
-
/**
|
|
415
|
-
* Save enough runtime state to be able to serialize upon request and load to the same state in a new container.
|
|
416
|
-
*/
|
|
417
|
-
readonly enableOfflineLoad?: boolean;
|
|
418
369
|
/**
|
|
419
370
|
* Enables the runtime to compress ops. Compression is disabled when undefined.
|
|
420
371
|
* @experimental Not ready for use.
|
|
@@ -433,7 +384,8 @@ export interface IContainerRuntimeOptions {
|
|
|
433
384
|
readonly maxBatchSizeInBytes?: number;
|
|
434
385
|
/**
|
|
435
386
|
* If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
|
|
436
|
-
* how large the individual chunks will be. This is only supported when compression is enabled.
|
|
387
|
+
* how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
|
|
388
|
+
* batch size exceeds this value, it will be chunked into smaller ops of this size.
|
|
437
389
|
*
|
|
438
390
|
* If unspecified, if a batch exceeds `maxBatchSizeInBytes` after compression, the container will close with an instance
|
|
439
391
|
* of `GenericError` with the `BatchTooLarge` message.
|
|
@@ -451,6 +403,17 @@ export interface IContainerRuntimeOptions {
|
|
|
451
403
|
* can be used to disable it at runtime.
|
|
452
404
|
*/
|
|
453
405
|
readonly enableOpReentryCheck?: boolean;
|
|
406
|
+
/**
|
|
407
|
+
* If enabled, the runtime will group messages within a batch into a single
|
|
408
|
+
* message to be sent to the service.
|
|
409
|
+
* The grouping an ungrouping of such messages is handled by the "OpGroupingManager".
|
|
410
|
+
*
|
|
411
|
+
* By default, the feature is disabled. If enabled from options, the `Fluid.ContainerRuntime.DisableGroupedBatching`
|
|
412
|
+
* flag can be used to disable it at runtime.
|
|
413
|
+
*
|
|
414
|
+
* @experimental Not ready for use.
|
|
415
|
+
*/
|
|
416
|
+
readonly enableGroupedBatching?: boolean;
|
|
454
417
|
}
|
|
455
418
|
|
|
456
419
|
/**
|
|
@@ -467,11 +430,6 @@ export interface IRootSummaryTreeWithStats extends ISummaryTreeWithStats {
|
|
|
467
430
|
export enum RuntimeHeaders {
|
|
468
431
|
/** True to wait for a data store to be created and loaded before returning it. */
|
|
469
432
|
wait = "wait",
|
|
470
|
-
/**
|
|
471
|
-
* True if the request is from an external app. Used for GC to handle scenarios where a data store
|
|
472
|
-
* is deleted and requested via an external app.
|
|
473
|
-
*/
|
|
474
|
-
externalRequest = "externalRequest",
|
|
475
433
|
/** True if the request is coming from an IFluidHandle. */
|
|
476
434
|
viaHandle = "viaHandle",
|
|
477
435
|
}
|
|
@@ -487,7 +445,6 @@ export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
|
487
445
|
*/
|
|
488
446
|
export interface RuntimeHeaderData {
|
|
489
447
|
wait?: boolean;
|
|
490
|
-
externalRequest?: boolean;
|
|
491
448
|
viaHandle?: boolean;
|
|
492
449
|
allowTombstone?: boolean;
|
|
493
450
|
}
|
|
@@ -495,7 +452,6 @@ export interface RuntimeHeaderData {
|
|
|
495
452
|
/** Default values for Runtime Headers */
|
|
496
453
|
export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
|
|
497
454
|
wait: true,
|
|
498
|
-
externalRequest: false,
|
|
499
455
|
viaHandle: false,
|
|
500
456
|
allowTombstone: false,
|
|
501
457
|
};
|
|
@@ -532,21 +488,6 @@ interface IPendingRuntimeState {
|
|
|
532
488
|
* Pending blobs from BlobManager
|
|
533
489
|
*/
|
|
534
490
|
pendingAttachmentBlobs?: IPendingBlobs;
|
|
535
|
-
/**
|
|
536
|
-
* A base snapshot at a sequence number prior to the first pending op
|
|
537
|
-
*/
|
|
538
|
-
baseSnapshot: ISnapshotTree;
|
|
539
|
-
/**
|
|
540
|
-
* Serialized blobs from the base snapshot. Used to load offline since
|
|
541
|
-
* storage is not available.
|
|
542
|
-
*/
|
|
543
|
-
snapshotBlobs: ISerializedBaseSnapshotBlobs;
|
|
544
|
-
/**
|
|
545
|
-
* All runtime ops since base snapshot sequence number up to the latest op
|
|
546
|
-
* seen when the container was closed. Used to apply stashed (saved pending)
|
|
547
|
-
* ops at the same sequence number at which they were made.
|
|
548
|
-
*/
|
|
549
|
-
savedOps: ISequencedDocumentMessage[];
|
|
550
491
|
}
|
|
551
492
|
|
|
552
493
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
@@ -557,7 +498,15 @@ const defaultFlushMode = FlushMode.TurnBased;
|
|
|
557
498
|
// We can't estimate it fully, as we
|
|
558
499
|
// - do not know what properties relay service will add
|
|
559
500
|
// - we do not stringify final op, thus we do not know how much escaping will be added.
|
|
560
|
-
const defaultMaxBatchSizeInBytes =
|
|
501
|
+
const defaultMaxBatchSizeInBytes = 700 * 1024;
|
|
502
|
+
|
|
503
|
+
const defaultCompressionConfig = {
|
|
504
|
+
// Batches with content size exceeding this value will be compressed
|
|
505
|
+
minimumBatchSizeInBytes: 614400,
|
|
506
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const defaultChunkSizeInBytes = 204800;
|
|
561
510
|
|
|
562
511
|
/**
|
|
563
512
|
* @deprecated - use ContainerRuntimeMessage instead
|
|
@@ -605,12 +554,7 @@ export function getDeviceSpec() {
|
|
|
605
554
|
*/
|
|
606
555
|
export class ContainerRuntime
|
|
607
556
|
extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
608
|
-
implements
|
|
609
|
-
IContainerRuntime,
|
|
610
|
-
IGarbageCollectionRuntime,
|
|
611
|
-
IRuntime,
|
|
612
|
-
ISummarizerRuntime,
|
|
613
|
-
ISummarizerInternalsProvider
|
|
557
|
+
implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
|
|
614
558
|
{
|
|
615
559
|
public get IContainerRuntime() {
|
|
616
560
|
return this;
|
|
@@ -658,13 +602,16 @@ export class ContainerRuntime
|
|
|
658
602
|
* Load the stores from a snapshot and returns the runtime.
|
|
659
603
|
* @param params - An object housing the runtime properties:
|
|
660
604
|
* - context - Context of the container.
|
|
661
|
-
* - registryEntries - Mapping to
|
|
662
|
-
* - existing -
|
|
663
|
-
* - requestHandler - Request
|
|
605
|
+
* - registryEntries - Mapping from data store types to their corresponding factories.
|
|
606
|
+
* - existing - Pass 'true' if loading from an existing snapshot.
|
|
607
|
+
* - requestHandler - (optional) Request handler for the request() method of the container runtime.
|
|
608
|
+
* Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
|
|
664
609
|
* - runtimeOptions - Additional options to be passed to the runtime
|
|
665
610
|
* - containerScope - runtime services provided with context
|
|
666
611
|
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
667
612
|
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
613
|
+
* - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
614
|
+
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
668
615
|
*/
|
|
669
616
|
public static async loadRuntime(params: {
|
|
670
617
|
context: IContainerContext;
|
|
@@ -674,6 +621,7 @@ export class ContainerRuntime
|
|
|
674
621
|
runtimeOptions?: IContainerRuntimeOptions;
|
|
675
622
|
containerScope?: FluidObject;
|
|
676
623
|
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
624
|
+
initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
|
|
677
625
|
}): Promise<ContainerRuntime> {
|
|
678
626
|
const {
|
|
679
627
|
context,
|
|
@@ -683,6 +631,7 @@ export class ContainerRuntime
|
|
|
683
631
|
runtimeOptions = {},
|
|
684
632
|
containerScope = {},
|
|
685
633
|
containerRuntimeCtor = ContainerRuntime,
|
|
634
|
+
initializeEntryPoint,
|
|
686
635
|
} = params;
|
|
687
636
|
|
|
688
637
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
@@ -702,34 +651,25 @@ export class ContainerRuntime
|
|
|
702
651
|
gcOptions = {},
|
|
703
652
|
loadSequenceNumberVerification = "close",
|
|
704
653
|
flushMode = defaultFlushMode,
|
|
705
|
-
|
|
706
|
-
compressionOptions = {
|
|
707
|
-
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
708
|
-
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
709
|
-
},
|
|
654
|
+
compressionOptions = defaultCompressionConfig,
|
|
710
655
|
maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
|
|
711
|
-
chunkSizeInBytes =
|
|
656
|
+
chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
712
657
|
enableOpReentryCheck = false,
|
|
658
|
+
enableGroupedBatching = false,
|
|
713
659
|
} = runtimeOptions;
|
|
714
660
|
|
|
715
|
-
const pendingRuntimeState = context.pendingLocalState as IPendingRuntimeState | undefined;
|
|
716
|
-
const baseSnapshot: ISnapshotTree | undefined =
|
|
717
|
-
pendingRuntimeState?.baseSnapshot ?? context.baseSnapshot;
|
|
718
|
-
const storage = !pendingRuntimeState
|
|
719
|
-
? context.storage
|
|
720
|
-
: new SerializedSnapshotStorage(() => {
|
|
721
|
-
return context.storage;
|
|
722
|
-
}, pendingRuntimeState.snapshotBlobs);
|
|
723
|
-
|
|
724
661
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
725
662
|
|
|
726
663
|
const tryFetchBlob = async <T>(blobName: string): Promise<T | undefined> => {
|
|
727
|
-
const blobId = baseSnapshot?.blobs[blobName];
|
|
728
|
-
if (baseSnapshot && blobId) {
|
|
664
|
+
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
665
|
+
if (context.baseSnapshot && blobId) {
|
|
729
666
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
730
667
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
731
|
-
assert(
|
|
732
|
-
|
|
668
|
+
assert(
|
|
669
|
+
context.storage !== undefined,
|
|
670
|
+
0x1f5 /* "Attached state should have storage" */,
|
|
671
|
+
);
|
|
672
|
+
return readAndParse<T>(context.storage, blobId);
|
|
733
673
|
}
|
|
734
674
|
};
|
|
735
675
|
|
|
@@ -744,22 +684,22 @@ export class ContainerRuntime
|
|
|
744
684
|
|
|
745
685
|
// read snapshot blobs needed for BlobManager to load
|
|
746
686
|
const blobManagerSnapshot = await BlobManager.load(
|
|
747
|
-
baseSnapshot?.trees[blobsTreeName],
|
|
687
|
+
context.baseSnapshot?.trees[blobsTreeName],
|
|
748
688
|
async (id) => {
|
|
749
689
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
750
690
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
751
691
|
assert(
|
|
752
|
-
storage !== undefined,
|
|
692
|
+
context.storage !== undefined,
|
|
753
693
|
0x256 /* "storage undefined in attached container" */,
|
|
754
694
|
);
|
|
755
|
-
return readAndParse(storage, id);
|
|
695
|
+
return readAndParse(context.storage, id);
|
|
756
696
|
},
|
|
757
697
|
);
|
|
758
698
|
|
|
759
699
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
760
700
|
const runtimeSequenceNumber = metadata?.message?.sequenceNumber;
|
|
761
701
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
762
|
-
if (!
|
|
702
|
+
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
763
703
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
764
704
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
765
705
|
if (
|
|
@@ -795,25 +735,25 @@ export class ContainerRuntime
|
|
|
795
735
|
gcOptions,
|
|
796
736
|
loadSequenceNumberVerification,
|
|
797
737
|
flushMode,
|
|
798
|
-
enableOfflineLoad,
|
|
799
738
|
compressionOptions,
|
|
800
739
|
maxBatchSizeInBytes,
|
|
801
740
|
chunkSizeInBytes,
|
|
802
741
|
enableOpReentryCheck,
|
|
742
|
+
enableGroupedBatching,
|
|
803
743
|
},
|
|
804
744
|
containerScope,
|
|
805
745
|
logger,
|
|
806
746
|
loadExisting,
|
|
807
747
|
blobManagerSnapshot,
|
|
808
|
-
storage,
|
|
748
|
+
context.storage,
|
|
809
749
|
requestHandler,
|
|
750
|
+
undefined, // summaryConfiguration
|
|
751
|
+
initializeEntryPoint,
|
|
810
752
|
);
|
|
811
753
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
pendingRuntimeState.savedOps = [];
|
|
816
|
-
}
|
|
754
|
+
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
755
|
+
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
756
|
+
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
817
757
|
|
|
818
758
|
// Initialize the base state of the runtime before it's returned.
|
|
819
759
|
await runtime.initializeBaseState();
|
|
@@ -833,10 +773,6 @@ export class ContainerRuntime
|
|
|
833
773
|
return this.context.clientDetails;
|
|
834
774
|
}
|
|
835
775
|
|
|
836
|
-
public get deltaManager(): IDeltaManager<ISequencedDocumentMessage, IDocumentMessage> {
|
|
837
|
-
return this.context.deltaManager;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
776
|
public get storage(): IDocumentStorageService {
|
|
841
777
|
return this._storage;
|
|
842
778
|
}
|
|
@@ -885,6 +821,19 @@ export class ContainerRuntime
|
|
|
885
821
|
}
|
|
886
822
|
private readonly handleContext: ContainerFluidHandleContext;
|
|
887
823
|
|
|
824
|
+
/**
|
|
825
|
+
* This is a proxy to the delta manager provided by the container context (innerDeltaManager). It restricts certain
|
|
826
|
+
* accesses such as sets "read-only" mode for the summarizer client. This is the default delta manager that should
|
|
827
|
+
* be used unless the innerDeltaManager is required.
|
|
828
|
+
*/
|
|
829
|
+
public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
|
|
830
|
+
/**
|
|
831
|
+
* The delta manager provided by the container context. By default, using the default delta manager (proxy)
|
|
832
|
+
* should be sufficient. This should be used only if necessary. For example, for validating and propagating connected
|
|
833
|
+
* events which requires access to the actual real only info, this is needed.
|
|
834
|
+
*/
|
|
835
|
+
private readonly innerDeltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
|
|
836
|
+
|
|
888
837
|
// internal logger for ContainerRuntime. Use this.logger for stores, summaries, etc.
|
|
889
838
|
private readonly mc: MonitoringContext;
|
|
890
839
|
|
|
@@ -904,13 +853,10 @@ export class ContainerRuntime
|
|
|
904
853
|
|
|
905
854
|
private _orderSequentiallyCalls: number = 0;
|
|
906
855
|
private readonly _flushMode: FlushMode;
|
|
907
|
-
private
|
|
856
|
+
private flushTaskExists = false;
|
|
908
857
|
|
|
909
858
|
private _connected: boolean;
|
|
910
859
|
|
|
911
|
-
private readonly savedOps: ISequencedDocumentMessage[] = [];
|
|
912
|
-
private baseSnapshotBlobs?: ISerializedBaseSnapshotBlobs;
|
|
913
|
-
|
|
914
860
|
private consecutiveReconnects = 0;
|
|
915
861
|
|
|
916
862
|
/**
|
|
@@ -963,6 +909,7 @@ export class ContainerRuntime
|
|
|
963
909
|
private dirtyContainer: boolean;
|
|
964
910
|
private emitDirtyDocumentEvent = true;
|
|
965
911
|
private readonly enableOpReentryCheck: boolean;
|
|
912
|
+
private readonly disableAttachReorder: boolean | undefined;
|
|
966
913
|
|
|
967
914
|
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
968
915
|
private _perfSignalData: IPerfSignalReport = {
|
|
@@ -982,7 +929,6 @@ export class ContainerRuntime
|
|
|
982
929
|
private readonly blobManager: BlobManager;
|
|
983
930
|
private readonly pendingStateManager: PendingStateManager;
|
|
984
931
|
private readonly outbox: Outbox;
|
|
985
|
-
|
|
986
932
|
private readonly garbageCollector: IGarbageCollector;
|
|
987
933
|
|
|
988
934
|
private readonly dataStores: DataStores;
|
|
@@ -1032,6 +978,17 @@ export class ContainerRuntime
|
|
|
1032
978
|
*/
|
|
1033
979
|
private nextSummaryNumber: number;
|
|
1034
980
|
|
|
981
|
+
/**
|
|
982
|
+
* If false, loading or using a Tombstoned object should merely log, not fail
|
|
983
|
+
*/
|
|
984
|
+
public readonly gcTombstoneEnforcementAllowed: boolean;
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* GUID to identify a document in telemetry
|
|
988
|
+
* ! Note: should not be used for anything other than telemetry and is not considered a stable GUID
|
|
989
|
+
*/
|
|
990
|
+
private readonly telemetryDocumentId: string;
|
|
991
|
+
|
|
1035
992
|
/**
|
|
1036
993
|
* @internal
|
|
1037
994
|
*/
|
|
@@ -1058,9 +1015,13 @@ export class ContainerRuntime
|
|
|
1058
1015
|
// the runtime configuration overrides
|
|
1059
1016
|
...runtimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1060
1017
|
},
|
|
1018
|
+
initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1061
1019
|
) {
|
|
1062
1020
|
super();
|
|
1063
1021
|
|
|
1022
|
+
this.innerDeltaManager = context.deltaManager;
|
|
1023
|
+
this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
|
|
1024
|
+
|
|
1064
1025
|
let loadSummaryNumber: number;
|
|
1065
1026
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
1066
1027
|
// get the values from the metadata blob.
|
|
@@ -1085,18 +1046,46 @@ export class ContainerRuntime
|
|
|
1085
1046
|
|
|
1086
1047
|
this._connected = this.context.connected;
|
|
1087
1048
|
|
|
1049
|
+
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
|
|
1050
|
+
metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
|
|
1051
|
+
this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */,
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1088
1054
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
1089
1055
|
|
|
1056
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1057
|
+
eventName: "GCFeatureMatrix",
|
|
1058
|
+
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
1059
|
+
inputs: JSON.stringify({
|
|
1060
|
+
gcOptions_gcTombstoneGeneration:
|
|
1061
|
+
this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
|
|
1062
|
+
}),
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
|
|
1066
|
+
|
|
1067
|
+
this.disableAttachReorder = this.mc.config.getBoolean(
|
|
1068
|
+
"Fluid.ContainerRuntime.disableAttachOpReorder",
|
|
1069
|
+
);
|
|
1070
|
+
const disableChunking = this.mc.config.getBoolean(
|
|
1071
|
+
"Fluid.ContainerRuntime.CompressionChunkingDisabled",
|
|
1072
|
+
);
|
|
1073
|
+
|
|
1074
|
+
const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
|
|
1075
|
+
|
|
1090
1076
|
const opSplitter = new OpSplitter(
|
|
1091
1077
|
chunks,
|
|
1092
1078
|
this.context.submitBatchFn,
|
|
1093
|
-
|
|
1094
|
-
? Number.POSITIVE_INFINITY
|
|
1095
|
-
: runtimeOptions.chunkSizeInBytes,
|
|
1079
|
+
disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes,
|
|
1096
1080
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1097
1081
|
this.mc.logger,
|
|
1098
1082
|
);
|
|
1099
|
-
|
|
1083
|
+
|
|
1084
|
+
this.remoteMessageProcessor = new RemoteMessageProcessor(
|
|
1085
|
+
opSplitter,
|
|
1086
|
+
new OpDecompressor(this.mc.logger),
|
|
1087
|
+
opGroupingManager,
|
|
1088
|
+
);
|
|
1100
1089
|
|
|
1101
1090
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
1102
1091
|
|
|
@@ -1104,10 +1093,13 @@ export class ContainerRuntime
|
|
|
1104
1093
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
1105
1094
|
}
|
|
1106
1095
|
|
|
1096
|
+
const disableOpReentryCheck = this.mc.config.getBoolean(
|
|
1097
|
+
"Fluid.ContainerRuntime.DisableOpReentryCheck",
|
|
1098
|
+
);
|
|
1107
1099
|
this.enableOpReentryCheck =
|
|
1108
1100
|
runtimeOptions.enableOpReentryCheck === true &&
|
|
1109
1101
|
// Allow for a break-glass config to override the options
|
|
1110
|
-
|
|
1102
|
+
disableOpReentryCheck !== true;
|
|
1111
1103
|
|
|
1112
1104
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
1113
1105
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
@@ -1118,11 +1110,18 @@ export class ContainerRuntime
|
|
|
1118
1110
|
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
1119
1111
|
this.defaultMaxConsecutiveReconnects;
|
|
1120
1112
|
|
|
1121
|
-
|
|
1113
|
+
if (
|
|
1114
|
+
runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
|
|
1115
|
+
context.supportedFeatures?.get("referenceSequenceNumbers") !== true
|
|
1116
|
+
) {
|
|
1117
|
+
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
1118
|
+
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
1119
|
+
this._flushMode = FlushMode.TurnBased;
|
|
1120
|
+
} else {
|
|
1121
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
1122
|
+
}
|
|
1122
1123
|
|
|
1123
1124
|
const pendingRuntimeState = context.pendingLocalState as IPendingRuntimeState | undefined;
|
|
1124
|
-
const baseSnapshot: ISnapshotTree | undefined =
|
|
1125
|
-
pendingRuntimeState?.baseSnapshot ?? context.baseSnapshot;
|
|
1126
1125
|
|
|
1127
1126
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1128
1127
|
if (
|
|
@@ -1138,7 +1137,7 @@ export class ContainerRuntime
|
|
|
1138
1137
|
this.garbageCollector = GarbageCollector.create({
|
|
1139
1138
|
runtime: this,
|
|
1140
1139
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
1141
|
-
baseSnapshot,
|
|
1140
|
+
baseSnapshot: context.baseSnapshot,
|
|
1142
1141
|
baseLogger: this.mc.logger,
|
|
1143
1142
|
existing,
|
|
1144
1143
|
metadata,
|
|
@@ -1148,7 +1147,9 @@ export class ContainerRuntime
|
|
|
1148
1147
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1149
1148
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
1150
1149
|
getContainerDiagnosticId: () => this.context.id,
|
|
1151
|
-
|
|
1150
|
+
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
1151
|
+
// delta manager would always return false for summarizer client.
|
|
1152
|
+
activeConnection: () => this.innerDeltaManager.active,
|
|
1152
1153
|
});
|
|
1153
1154
|
|
|
1154
1155
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
@@ -1160,7 +1161,7 @@ export class ContainerRuntime
|
|
|
1160
1161
|
// Latest change sequence number, no changes since summary applied yet
|
|
1161
1162
|
loadedFromSequenceNumber,
|
|
1162
1163
|
// Summary reference sequence number, undefined if no summary yet
|
|
1163
|
-
baseSnapshot ? loadedFromSequenceNumber : undefined,
|
|
1164
|
+
context.baseSnapshot ? loadedFromSequenceNumber : undefined,
|
|
1164
1165
|
{
|
|
1165
1166
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1166
1167
|
// a summary with an older protocol state.
|
|
@@ -1177,19 +1178,18 @@ export class ContainerRuntime
|
|
|
1177
1178
|
async () => this.garbageCollector.getBaseGCDetails(),
|
|
1178
1179
|
);
|
|
1179
1180
|
|
|
1180
|
-
if (baseSnapshot) {
|
|
1181
|
-
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1181
|
+
if (context.baseSnapshot) {
|
|
1182
|
+
this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
|
|
1182
1183
|
}
|
|
1183
1184
|
|
|
1184
1185
|
this.dataStores = new DataStores(
|
|
1185
|
-
getSummaryForDatastores(baseSnapshot, metadata),
|
|
1186
|
+
getSummaryForDatastores(context.baseSnapshot, metadata),
|
|
1186
1187
|
this,
|
|
1187
1188
|
(attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg),
|
|
1188
1189
|
(id: string, createParam: CreateChildSummarizerNodeParam) =>
|
|
1189
1190
|
(
|
|
1190
1191
|
summarizeInternal: SummarizeInternalFn,
|
|
1191
1192
|
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
1192
|
-
getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,
|
|
1193
1193
|
) =>
|
|
1194
1194
|
this.summarizerNode.createChild(
|
|
1195
1195
|
summarizeInternal,
|
|
@@ -1197,13 +1197,12 @@ export class ContainerRuntime
|
|
|
1197
1197
|
createParam,
|
|
1198
1198
|
undefined,
|
|
1199
1199
|
getGCDataFn,
|
|
1200
|
-
getBaseGCDetailsFn,
|
|
1201
1200
|
),
|
|
1202
1201
|
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1203
1202
|
this.mc.logger,
|
|
1204
|
-
async () => this.garbageCollector.getBaseGCDetails(),
|
|
1205
1203
|
(path: string, timestampMs: number, packagePath?: readonly string[]) =>
|
|
1206
1204
|
this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath),
|
|
1205
|
+
(path: string) => this.garbageCollector.isNodeDeleted(path),
|
|
1207
1206
|
new Map<string, string>(dataStoreAliasMap),
|
|
1208
1207
|
);
|
|
1209
1208
|
|
|
@@ -1213,19 +1212,23 @@ export class ContainerRuntime
|
|
|
1213
1212
|
() => this.storage,
|
|
1214
1213
|
(localId: string, blobId?: string) => {
|
|
1215
1214
|
if (!this.disposed) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1215
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1216
|
+
Promise.resolve().then(() => {
|
|
1217
|
+
// Blob attaches need to be in their own batch (grouped batching would hide metadata)
|
|
1218
|
+
this.flush();
|
|
1219
|
+
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
|
|
1220
|
+
localId,
|
|
1221
|
+
blobId,
|
|
1222
|
+
});
|
|
1223
|
+
this.flush();
|
|
1219
1224
|
});
|
|
1220
1225
|
}
|
|
1221
1226
|
},
|
|
1222
1227
|
(blobPath: string) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
|
|
1223
|
-
(fromPath: string, toPath: string) =>
|
|
1224
|
-
this.garbageCollector.addedOutboundReference(fromPath, toPath),
|
|
1225
1228
|
(blobPath: string) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
1226
1229
|
this,
|
|
1227
1230
|
pendingRuntimeState?.pendingAttachmentBlobs,
|
|
1228
|
-
() => this.
|
|
1231
|
+
(error?: ICriticalContainerError) => this.closeFn(error),
|
|
1229
1232
|
);
|
|
1230
1233
|
|
|
1231
1234
|
this.scheduleManager = new ScheduleManager(
|
|
@@ -1248,14 +1251,20 @@ export class ContainerRuntime
|
|
|
1248
1251
|
pendingRuntimeState?.pending,
|
|
1249
1252
|
);
|
|
1250
1253
|
|
|
1254
|
+
const disableCompression = this.mc.config.getBoolean(
|
|
1255
|
+
"Fluid.ContainerRuntime.CompressionDisabled",
|
|
1256
|
+
);
|
|
1251
1257
|
const compressionOptions =
|
|
1252
|
-
|
|
1258
|
+
disableCompression === true
|
|
1253
1259
|
? {
|
|
1254
1260
|
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
1255
1261
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
1256
1262
|
}
|
|
1257
1263
|
: runtimeOptions.compressionOptions;
|
|
1258
1264
|
|
|
1265
|
+
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1266
|
+
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1267
|
+
);
|
|
1259
1268
|
this.outbox = new Outbox({
|
|
1260
1269
|
shouldSend: () => this.canSendOps(),
|
|
1261
1270
|
pendingStateManager: this.pendingStateManager,
|
|
@@ -1265,9 +1274,10 @@ export class ContainerRuntime
|
|
|
1265
1274
|
config: {
|
|
1266
1275
|
compressionOptions,
|
|
1267
1276
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
1268
|
-
|
|
1277
|
+
disablePartialFlush: disablePartialFlush === true,
|
|
1269
1278
|
},
|
|
1270
1279
|
logger: this.mc.logger,
|
|
1280
|
+
groupingManager: opGroupingManager,
|
|
1271
1281
|
});
|
|
1272
1282
|
|
|
1273
1283
|
this.context.quorum.on("removeMember", (clientId: string) => {
|
|
@@ -1306,14 +1316,18 @@ export class ContainerRuntime
|
|
|
1306
1316
|
|
|
1307
1317
|
if (this.context.clientDetails.type === summarizerClientType) {
|
|
1308
1318
|
this._summarizer = new Summarizer(
|
|
1309
|
-
"/_summarizer",
|
|
1310
1319
|
this /* ISummarizerRuntime */,
|
|
1311
1320
|
() => this.summaryConfiguration,
|
|
1312
1321
|
this /* ISummarizerInternalsProvider */,
|
|
1313
1322
|
this.handleContext,
|
|
1314
1323
|
this.summaryCollection,
|
|
1315
1324
|
async (runtime: IConnectableRuntime) =>
|
|
1316
|
-
RunWhileConnectedCoordinator.create(
|
|
1325
|
+
RunWhileConnectedCoordinator.create(
|
|
1326
|
+
runtime,
|
|
1327
|
+
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
1328
|
+
// information. The proxy delta manager would always return false for summarizer client.
|
|
1329
|
+
() => this.innerDeltaManager.active,
|
|
1330
|
+
),
|
|
1317
1331
|
);
|
|
1318
1332
|
} else if (
|
|
1319
1333
|
SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)
|
|
@@ -1363,8 +1377,9 @@ export class ContainerRuntime
|
|
|
1363
1377
|
this.deltaManager.on("readonly", (readonly: boolean) => {
|
|
1364
1378
|
// we accumulate ops while being in read-only state.
|
|
1365
1379
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
1380
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1366
1381
|
assert(
|
|
1367
|
-
readonly === this.
|
|
1382
|
+
readonly === this.innerDeltaManager.readOnlyInfo.readonly,
|
|
1368
1383
|
0x124 /* "inconsistent readonly property/event state" */,
|
|
1369
1384
|
);
|
|
1370
1385
|
|
|
@@ -1402,17 +1417,37 @@ export class ContainerRuntime
|
|
|
1402
1417
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1403
1418
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1404
1419
|
gcVersion: metadata?.gcFeature,
|
|
1420
|
+
options: JSON.stringify(runtimeOptions),
|
|
1421
|
+
featureGates: JSON.stringify({
|
|
1422
|
+
disableCompression,
|
|
1423
|
+
disableOpReentryCheck,
|
|
1424
|
+
disableChunking,
|
|
1425
|
+
disableAttachReorder: this.disableAttachReorder,
|
|
1426
|
+
disablePartialFlush,
|
|
1427
|
+
}),
|
|
1428
|
+
telemetryDocumentId: this.telemetryDocumentId,
|
|
1429
|
+
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1405
1430
|
});
|
|
1406
1431
|
|
|
1407
1432
|
ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
1408
1433
|
BindBatchTracker(this, this.logger);
|
|
1434
|
+
|
|
1435
|
+
this.entryPoint = new LazyPromise(async () => {
|
|
1436
|
+
if (this.context.clientDetails.type === summarizerClientType) {
|
|
1437
|
+
assert(
|
|
1438
|
+
this._summarizer !== undefined,
|
|
1439
|
+
0x5bf /* Summarizer object is undefined in a summarizer client */,
|
|
1440
|
+
);
|
|
1441
|
+
return this._summarizer;
|
|
1442
|
+
}
|
|
1443
|
+
return initializeEntryPoint?.(this);
|
|
1444
|
+
});
|
|
1409
1445
|
}
|
|
1410
1446
|
|
|
1411
1447
|
/**
|
|
1412
1448
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
1413
1449
|
*/
|
|
1414
1450
|
private async initializeBaseState(): Promise<void> {
|
|
1415
|
-
await this.initializeBaseSnapshotBlobs();
|
|
1416
1451
|
await this.garbageCollector.initializeBaseState();
|
|
1417
1452
|
}
|
|
1418
1453
|
|
|
@@ -1443,16 +1478,6 @@ export class ContainerRuntime
|
|
|
1443
1478
|
this.removeAllListeners();
|
|
1444
1479
|
}
|
|
1445
1480
|
|
|
1446
|
-
public get IFluidTokenProvider() {
|
|
1447
|
-
if (this.options?.intelligence) {
|
|
1448
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
1449
|
-
return {
|
|
1450
|
-
intelligence: this.options.intelligence,
|
|
1451
|
-
} as IFluidTokenProvider;
|
|
1452
|
-
}
|
|
1453
|
-
return undefined;
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
1481
|
/**
|
|
1457
1482
|
* Notifies this object about the request made to the container.
|
|
1458
1483
|
* @param request - Request made to the handler.
|
|
@@ -1522,6 +1547,14 @@ export class ContainerRuntime
|
|
|
1522
1547
|
}
|
|
1523
1548
|
}
|
|
1524
1549
|
|
|
1550
|
+
/**
|
|
1551
|
+
* {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
|
|
1552
|
+
*/
|
|
1553
|
+
public async getEntryPoint?(): Promise<FluidObject | undefined> {
|
|
1554
|
+
return this.entryPoint;
|
|
1555
|
+
}
|
|
1556
|
+
private readonly entryPoint: LazyPromise<FluidObject | undefined>;
|
|
1557
|
+
|
|
1525
1558
|
private internalId(maybeAlias: string): string {
|
|
1526
1559
|
return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
|
|
1527
1560
|
}
|
|
@@ -1541,29 +1574,6 @@ export class ContainerRuntime
|
|
|
1541
1574
|
await this.dataStores.waitIfPendingAlias(id);
|
|
1542
1575
|
const internalId = this.internalId(id);
|
|
1543
1576
|
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
1544
|
-
|
|
1545
|
-
/**
|
|
1546
|
-
* If GC should run and this an external app request with "externalRequest" header, we need to return
|
|
1547
|
-
* an error if the data store being requested is marked as unreferenced as per the data store's base
|
|
1548
|
-
* GC data.
|
|
1549
|
-
*
|
|
1550
|
-
* This is a workaround to handle scenarios where a data store shared with an external app is deleted
|
|
1551
|
-
* and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
|
|
1552
|
-
*/
|
|
1553
|
-
if (
|
|
1554
|
-
request.headers?.[RuntimeHeaders.externalRequest] &&
|
|
1555
|
-
this.garbageCollector.shouldRunGC
|
|
1556
|
-
) {
|
|
1557
|
-
// The data store is referenced if used routes in the base summary has a route to self.
|
|
1558
|
-
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
1559
|
-
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
1560
|
-
if (
|
|
1561
|
-
!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))
|
|
1562
|
-
) {
|
|
1563
|
-
throw responseToException(create404Response(request), request);
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
1577
|
const dataStoreChannel = await dataStoreContext.realize();
|
|
1568
1578
|
|
|
1569
1579
|
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
@@ -1592,6 +1602,7 @@ export class ContainerRuntime
|
|
|
1592
1602
|
message:
|
|
1593
1603
|
extractSummaryMetadataMessage(this.deltaManager.lastMessage) ??
|
|
1594
1604
|
this.messageAtLastSummary,
|
|
1605
|
+
telemetryDocumentId: this.telemetryDocumentId,
|
|
1595
1606
|
};
|
|
1596
1607
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
1597
1608
|
}
|
|
@@ -1736,8 +1747,9 @@ export class ContainerRuntime
|
|
|
1736
1747
|
// If attachment blobs were added while disconnected, we need to delay
|
|
1737
1748
|
// propagation of the "connected" event until we have uploaded them to
|
|
1738
1749
|
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1750
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1739
1751
|
const connecting =
|
|
1740
|
-
connected && !this._connected && !this.
|
|
1752
|
+
connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1741
1753
|
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
1742
1754
|
assert(
|
|
1743
1755
|
!this.delayConnectClientId,
|
|
@@ -1815,16 +1827,13 @@ export class ContainerRuntime
|
|
|
1815
1827
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
1816
1828
|
}
|
|
1817
1829
|
|
|
1830
|
+
public async notifyOpReplay(message: ISequencedDocumentMessage) {
|
|
1831
|
+
await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1818
1834
|
public process(messageArg: ISequencedDocumentMessage, local: boolean) {
|
|
1819
1835
|
this.verifyNotClosed();
|
|
1820
1836
|
|
|
1821
|
-
if (
|
|
1822
|
-
this.mc.config.getBoolean("enableOfflineLoad") ??
|
|
1823
|
-
this.runtimeOptions.enableOfflineLoad
|
|
1824
|
-
) {
|
|
1825
|
-
this.savedOps.push(messageArg);
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
1837
|
// Whether or not the message is actually a runtime message.
|
|
1829
1838
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
1830
1839
|
// or something different, like a system message.
|
|
@@ -1832,8 +1841,16 @@ export class ContainerRuntime
|
|
|
1832
1841
|
|
|
1833
1842
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
1834
1843
|
const messageCopy = { ...messageArg };
|
|
1835
|
-
const message
|
|
1844
|
+
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1845
|
+
this.processCore(message, local, runtimeMessage);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1836
1848
|
|
|
1849
|
+
private processCore(
|
|
1850
|
+
message: ISequencedDocumentMessage,
|
|
1851
|
+
local: boolean,
|
|
1852
|
+
runtimeMessage: boolean,
|
|
1853
|
+
) {
|
|
1837
1854
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1838
1855
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1839
1856
|
// messages once a batch has been fully processed.
|
|
@@ -1869,11 +1886,26 @@ export class ContainerRuntime
|
|
|
1869
1886
|
case ContainerMessageType.Rejoin:
|
|
1870
1887
|
break;
|
|
1871
1888
|
default:
|
|
1872
|
-
|
|
1889
|
+
if (runtimeMessage) {
|
|
1890
|
+
const error = DataProcessingError.create(
|
|
1891
|
+
// Former assert 0x3ce
|
|
1892
|
+
"Runtime message of unknown type",
|
|
1893
|
+
"OpProcessing",
|
|
1894
|
+
message,
|
|
1895
|
+
{
|
|
1896
|
+
local,
|
|
1897
|
+
type: message.type,
|
|
1898
|
+
contentType: typeof message.contents,
|
|
1899
|
+
batch: message.metadata?.batch,
|
|
1900
|
+
compression: message.compression,
|
|
1901
|
+
},
|
|
1902
|
+
);
|
|
1903
|
+
this.closeFn(error);
|
|
1904
|
+
throw error;
|
|
1905
|
+
}
|
|
1873
1906
|
}
|
|
1874
1907
|
|
|
1875
|
-
|
|
1876
|
-
if (runtimeMessage) {
|
|
1908
|
+
if (runtimeMessage || this.groupedBatchingEnabled) {
|
|
1877
1909
|
this.emit("op", message, runtimeMessage);
|
|
1878
1910
|
}
|
|
1879
1911
|
|
|
@@ -1944,7 +1976,10 @@ export class ContainerRuntime
|
|
|
1944
1976
|
envelope.clientSignalSequenceNumber ===
|
|
1945
1977
|
this._perfSignalData.trackingSignalSequenceNumber
|
|
1946
1978
|
) {
|
|
1947
|
-
|
|
1979
|
+
// only logging for the first connection and the trackingSignalSequenceNUmber.
|
|
1980
|
+
if (this.consecutiveReconnects === 0) {
|
|
1981
|
+
this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
|
|
1982
|
+
}
|
|
1948
1983
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
1949
1984
|
}
|
|
1950
1985
|
}
|
|
@@ -2084,14 +2119,16 @@ export class ContainerRuntime
|
|
|
2084
2119
|
}
|
|
2085
2120
|
|
|
2086
2121
|
private canSendOps() {
|
|
2087
|
-
|
|
2122
|
+
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
2123
|
+
// container runtime's ability to send ops depend on the actual readonly state of the delta manager.
|
|
2124
|
+
return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
2088
2125
|
}
|
|
2089
2126
|
|
|
2090
2127
|
/**
|
|
2091
2128
|
* Are we in the middle of batching ops together?
|
|
2092
2129
|
*/
|
|
2093
2130
|
private currentlyBatching() {
|
|
2094
|
-
return this.flushMode
|
|
2131
|
+
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
2095
2132
|
}
|
|
2096
2133
|
|
|
2097
2134
|
public getQuorum(): IQuorumClients {
|
|
@@ -2278,12 +2315,24 @@ export class ContainerRuntime
|
|
|
2278
2315
|
fullGC,
|
|
2279
2316
|
} = options;
|
|
2280
2317
|
|
|
2318
|
+
const telemetryContext = new TelemetryContext();
|
|
2319
|
+
// Add the options that are used to generate this summary to the telemetry context.
|
|
2320
|
+
telemetryContext.setMultiple("fluid_Summarize", "Options", {
|
|
2321
|
+
fullTree,
|
|
2322
|
+
trackState,
|
|
2323
|
+
runGC,
|
|
2324
|
+
fullGC,
|
|
2325
|
+
runSweep,
|
|
2326
|
+
});
|
|
2327
|
+
|
|
2281
2328
|
let gcStats: IGCStats | undefined;
|
|
2282
2329
|
if (runGC) {
|
|
2283
|
-
gcStats = await this.collectGarbage(
|
|
2330
|
+
gcStats = await this.collectGarbage(
|
|
2331
|
+
{ logger: summaryLogger, runSweep, fullGC },
|
|
2332
|
+
telemetryContext,
|
|
2333
|
+
);
|
|
2284
2334
|
}
|
|
2285
2335
|
|
|
2286
|
-
const telemetryContext = new TelemetryContext();
|
|
2287
2336
|
const { stats, summary } = await this.summarizerNode.summarize(
|
|
2288
2337
|
fullTree,
|
|
2289
2338
|
trackState,
|
|
@@ -2304,10 +2353,10 @@ export class ContainerRuntime
|
|
|
2304
2353
|
}
|
|
2305
2354
|
|
|
2306
2355
|
/**
|
|
2307
|
-
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
2308
2356
|
* Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
|
|
2309
2357
|
* the garbage collector of references detected since the last GC run. Most references are notified immediately
|
|
2310
2358
|
* but there can be some for which async operation is required (such as detecting new root data stores).
|
|
2359
|
+
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
2311
2360
|
*/
|
|
2312
2361
|
public async updateStateBeforeGC() {
|
|
2313
2362
|
return this.dataStores.updateStateBeforeGC();
|
|
@@ -2318,9 +2367,9 @@ export class ContainerRuntime
|
|
|
2318
2367
|
}
|
|
2319
2368
|
|
|
2320
2369
|
/**
|
|
2321
|
-
* Implementation of IGarbageCollectionRuntime::getGCData.
|
|
2322
2370
|
* Generates and returns the GC data for this container.
|
|
2323
2371
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
2372
|
+
* @see IGarbageCollectionRuntime.getGCData
|
|
2324
2373
|
*/
|
|
2325
2374
|
public async getGCData(fullGC?: boolean): Promise<IGarbageCollectionData> {
|
|
2326
2375
|
const builder = new GCDataBuilder();
|
|
@@ -2333,9 +2382,9 @@ export class ContainerRuntime
|
|
|
2333
2382
|
}
|
|
2334
2383
|
|
|
2335
2384
|
/**
|
|
2336
|
-
* Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
|
|
2337
2385
|
* After GC has run, called to notify this container's nodes of routes that are used in it.
|
|
2338
2386
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
2387
|
+
* @see IGarbageCollectionRuntime.updateUsedRoutes
|
|
2339
2388
|
*/
|
|
2340
2389
|
public updateUsedRoutes(usedRoutes: string[]) {
|
|
2341
2390
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
@@ -2358,6 +2407,26 @@ export class ContainerRuntime
|
|
|
2358
2407
|
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
2359
2408
|
}
|
|
2360
2409
|
|
|
2410
|
+
/**
|
|
2411
|
+
* @deprecated - Replaced by deleteSweepReadyNodes.
|
|
2412
|
+
*/
|
|
2413
|
+
public deleteUnusedNodes(unusedRoutes: string[]): string[] {
|
|
2414
|
+
throw new Error("deleteUnusedRoutes should not be called");
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
/**
|
|
2418
|
+
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
2419
|
+
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
2420
|
+
* @returns - The routes of nodes that were deleted.
|
|
2421
|
+
*/
|
|
2422
|
+
public deleteSweepReadyNodes(sweepReadyRoutes: string[]): string[] {
|
|
2423
|
+
const { dataStoreRoutes, blobManagerRoutes } =
|
|
2424
|
+
this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
2425
|
+
|
|
2426
|
+
const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
|
|
2427
|
+
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2361
2430
|
/**
|
|
2362
2431
|
* This is called to update objects that are tombstones.
|
|
2363
2432
|
* @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
|
|
@@ -2439,15 +2508,18 @@ export class ContainerRuntime
|
|
|
2439
2508
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
2440
2509
|
* @returns the statistics of the garbage collection run; undefined if GC did not run.
|
|
2441
2510
|
*/
|
|
2442
|
-
public async collectGarbage(
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2511
|
+
public async collectGarbage(
|
|
2512
|
+
options: {
|
|
2513
|
+
/** Logger to use for logging GC events */
|
|
2514
|
+
logger?: ITelemetryLogger;
|
|
2515
|
+
/** True to run GC sweep phase after the mark phase */
|
|
2516
|
+
runSweep?: boolean;
|
|
2517
|
+
/** True to generate full GC data */
|
|
2518
|
+
fullGC?: boolean;
|
|
2519
|
+
},
|
|
2520
|
+
telemetryContext?: ITelemetryContext,
|
|
2521
|
+
): Promise<IGCStats | undefined> {
|
|
2522
|
+
return this.garbageCollector.collectGarbage(options, telemetryContext);
|
|
2451
2523
|
}
|
|
2452
2524
|
|
|
2453
2525
|
/**
|
|
@@ -2472,7 +2544,7 @@ export class ContainerRuntime
|
|
|
2472
2544
|
* @param options - options controlling how the summary is generated or submitted
|
|
2473
2545
|
*/
|
|
2474
2546
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
2475
|
-
const { fullTree, refreshLatestAck, summaryLogger } = options;
|
|
2547
|
+
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
2476
2548
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2477
2549
|
// use it for all events logged during this summary.
|
|
2478
2550
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -2494,8 +2566,15 @@ export class ContainerRuntime
|
|
|
2494
2566
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
2495
2567
|
}
|
|
2496
2568
|
|
|
2569
|
+
const shouldPauseInboundSignal =
|
|
2570
|
+
this.mc.config.getBoolean(
|
|
2571
|
+
"Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
|
|
2572
|
+
) !== true;
|
|
2497
2573
|
try {
|
|
2498
2574
|
await this.deltaManager.inbound.pause();
|
|
2575
|
+
if (shouldPauseInboundSignal) {
|
|
2576
|
+
await this.deltaManager.inboundSignal.pause();
|
|
2577
|
+
}
|
|
2499
2578
|
|
|
2500
2579
|
const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
2501
2580
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
@@ -2560,7 +2639,7 @@ export class ContainerRuntime
|
|
|
2560
2639
|
const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
|
|
2561
2640
|
try {
|
|
2562
2641
|
summarizeResult = await this.summarize({
|
|
2563
|
-
fullTree: fullTree
|
|
2642
|
+
fullTree: fullTree || forcedFullTree,
|
|
2564
2643
|
trackState: true,
|
|
2565
2644
|
summaryLogger: summaryNumberLogger,
|
|
2566
2645
|
runGC: this.garbageCollector.shouldRunGC,
|
|
@@ -2674,7 +2753,7 @@ export class ContainerRuntime
|
|
|
2674
2753
|
|
|
2675
2754
|
let clientSequenceNumber: number;
|
|
2676
2755
|
try {
|
|
2677
|
-
clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
|
|
2756
|
+
clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
|
|
2678
2757
|
} catch (error) {
|
|
2679
2758
|
return { stage: "upload", ...uploadData, error };
|
|
2680
2759
|
}
|
|
@@ -2691,8 +2770,12 @@ export class ContainerRuntime
|
|
|
2691
2770
|
} finally {
|
|
2692
2771
|
// Cleanup wip summary in case of failure
|
|
2693
2772
|
this.summarizerNode.clearSummary();
|
|
2773
|
+
|
|
2694
2774
|
// Restart the delta manager
|
|
2695
2775
|
this.deltaManager.inbound.resume();
|
|
2776
|
+
if (shouldPauseInboundSignal) {
|
|
2777
|
+
this.deltaManager.inboundSignal.resume();
|
|
2778
|
+
}
|
|
2696
2779
|
}
|
|
2697
2780
|
}
|
|
2698
2781
|
|
|
@@ -2763,10 +2846,11 @@ export class ContainerRuntime
|
|
|
2763
2846
|
0x132 /* "sending ops in detached container" */,
|
|
2764
2847
|
);
|
|
2765
2848
|
|
|
2766
|
-
const
|
|
2767
|
-
const serializedContent = JSON.stringify(deserializedContent);
|
|
2849
|
+
const serializedContent = JSON.stringify({ type, contents });
|
|
2768
2850
|
|
|
2769
|
-
|
|
2851
|
+
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
2852
|
+
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
2853
|
+
if (this.innerDeltaManager.readOnlyInfo.readonly) {
|
|
2770
2854
|
this.logger.sendTelemetryEvent({
|
|
2771
2855
|
eventName: "SubmitOpInReadonly",
|
|
2772
2856
|
connected: this.connected,
|
|
@@ -2775,7 +2859,7 @@ export class ContainerRuntime
|
|
|
2775
2859
|
|
|
2776
2860
|
const message: BatchMessage = {
|
|
2777
2861
|
contents: serializedContent,
|
|
2778
|
-
deserializedContent,
|
|
2862
|
+
deserializedContent: JSON.parse(serializedContent), // Deep copy in case caller changes reference object
|
|
2779
2863
|
metadata,
|
|
2780
2864
|
localOpMetadata,
|
|
2781
2865
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
@@ -2805,7 +2889,7 @@ export class ContainerRuntime
|
|
|
2805
2889
|
if (
|
|
2806
2890
|
this.currentlyBatching() &&
|
|
2807
2891
|
type === ContainerMessageType.Attach &&
|
|
2808
|
-
this.
|
|
2892
|
+
this.disableAttachReorder !== true
|
|
2809
2893
|
) {
|
|
2810
2894
|
this.outbox.submitAttach(message);
|
|
2811
2895
|
} else {
|
|
@@ -2814,17 +2898,8 @@ export class ContainerRuntime
|
|
|
2814
2898
|
|
|
2815
2899
|
if (!this.currentlyBatching()) {
|
|
2816
2900
|
this.flush();
|
|
2817
|
-
} else
|
|
2818
|
-
this.
|
|
2819
|
-
// Queue a microtask to detect the end of the turn and force a flush.
|
|
2820
|
-
Promise.resolve()
|
|
2821
|
-
.then(() => {
|
|
2822
|
-
this.flushMicroTaskExists = false;
|
|
2823
|
-
this.flush();
|
|
2824
|
-
})
|
|
2825
|
-
.catch((error) => {
|
|
2826
|
-
this.closeFn(error as GenericError);
|
|
2827
|
-
});
|
|
2901
|
+
} else {
|
|
2902
|
+
this.scheduleFlush();
|
|
2828
2903
|
}
|
|
2829
2904
|
} catch (error) {
|
|
2830
2905
|
this.closeFn(error as GenericError);
|
|
@@ -2836,7 +2911,47 @@ export class ContainerRuntime
|
|
|
2836
2911
|
}
|
|
2837
2912
|
}
|
|
2838
2913
|
|
|
2839
|
-
private
|
|
2914
|
+
private scheduleFlush() {
|
|
2915
|
+
if (this.flushTaskExists) {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
this.flushTaskExists = true;
|
|
2920
|
+
const flush = () => {
|
|
2921
|
+
this.flushTaskExists = false;
|
|
2922
|
+
try {
|
|
2923
|
+
this.flush();
|
|
2924
|
+
} catch (error) {
|
|
2925
|
+
this.closeFn(error as GenericError);
|
|
2926
|
+
}
|
|
2927
|
+
};
|
|
2928
|
+
|
|
2929
|
+
switch (this.flushMode) {
|
|
2930
|
+
case FlushMode.TurnBased:
|
|
2931
|
+
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
2932
|
+
// batch at the end of the turn
|
|
2933
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2934
|
+
Promise.resolve().then(flush);
|
|
2935
|
+
break;
|
|
2936
|
+
|
|
2937
|
+
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
2938
|
+
case FlushModeExperimental.Async as unknown as FlushMode:
|
|
2939
|
+
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
2940
|
+
// batch when all micro-tasks are complete.
|
|
2941
|
+
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
2942
|
+
setTimeout(flush, 0);
|
|
2943
|
+
break;
|
|
2944
|
+
|
|
2945
|
+
default:
|
|
2946
|
+
assert(
|
|
2947
|
+
this._orderSequentiallyCalls > 0,
|
|
2948
|
+
0x587 /* Unreachable unless running under orderSequentially */,
|
|
2949
|
+
);
|
|
2950
|
+
break;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
private submitSummaryMessage(contents: ISummaryContent, referenceSequenceNumber: number) {
|
|
2840
2955
|
this.verifyNotClosed();
|
|
2841
2956
|
assert(
|
|
2842
2957
|
this.connected,
|
|
@@ -2848,7 +2963,7 @@ export class ContainerRuntime
|
|
|
2848
2963
|
|
|
2849
2964
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
2850
2965
|
return this.context.submitSummaryFn !== undefined
|
|
2851
|
-
? this.context.submitSummaryFn(contents)
|
|
2966
|
+
? this.context.submitSummaryFn(contents, referenceSequenceNumber)
|
|
2852
2967
|
: this.context.submitFn(MessageType.Summarize, contents, false);
|
|
2853
2968
|
}
|
|
2854
2969
|
|
|
@@ -2967,18 +3082,17 @@ export class ContainerRuntime
|
|
|
2967
3082
|
// The call to fetch the snapshot is very expensive and not always needed.
|
|
2968
3083
|
// It should only be done by the summarizerNode, if required.
|
|
2969
3084
|
// When fetching from storage we will always get the latest version and do not use the ackHandle.
|
|
2970
|
-
const
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
const latestSnapshotRefSeq = await seqFromTree(
|
|
2979
|
-
fetchResult.snapshotTree,
|
|
3085
|
+
const fetchLatestSnapshot: () => Promise<IFetchSnapshotResult> = async () => {
|
|
3086
|
+
let fetchResult = await this.fetchLatestSnapshotFromStorage(
|
|
3087
|
+
summaryLogger,
|
|
3088
|
+
{
|
|
3089
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
3090
|
+
ackHandle,
|
|
3091
|
+
targetSequenceNumber: summaryRefSeq,
|
|
3092
|
+
},
|
|
2980
3093
|
readAndParseBlob,
|
|
2981
3094
|
);
|
|
3095
|
+
|
|
2982
3096
|
/**
|
|
2983
3097
|
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
2984
3098
|
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
@@ -2989,50 +3103,58 @@ export class ContainerRuntime
|
|
|
2989
3103
|
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
2990
3104
|
* state.
|
|
2991
3105
|
*/
|
|
2992
|
-
if (latestSnapshotRefSeq < summaryRefSeq) {
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
undefined /* sequencedMessage */,
|
|
3106
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3107
|
+
/* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
|
|
3108
|
+
fetchResult = await this.fetchSnapshotFromStorage(
|
|
3109
|
+
summaryLogger,
|
|
2997
3110
|
{
|
|
3111
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
2998
3112
|
ackHandle,
|
|
2999
|
-
summaryRefSeq,
|
|
3000
|
-
latestSnapshotRefSeq,
|
|
3113
|
+
targetSequenceNumber: summaryRefSeq,
|
|
3001
3114
|
},
|
|
3115
|
+
readAndParseBlob,
|
|
3116
|
+
ackHandle,
|
|
3002
3117
|
);
|
|
3003
|
-
this.closeFn(error);
|
|
3004
|
-
throw error;
|
|
3005
|
-
}
|
|
3006
3118
|
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3119
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3120
|
+
const error = DataProcessingError.create(
|
|
3121
|
+
"Fetched snapshot is older than the received ack",
|
|
3122
|
+
"RefreshLatestSummaryAck",
|
|
3123
|
+
undefined /* sequencedMessage */,
|
|
3124
|
+
{
|
|
3125
|
+
ackHandle,
|
|
3126
|
+
summaryRefSeq,
|
|
3127
|
+
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3128
|
+
},
|
|
3129
|
+
);
|
|
3130
|
+
this.closeFn(error);
|
|
3131
|
+
throw error;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3013
3134
|
|
|
3014
3135
|
// In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
|
|
3015
3136
|
// wait for the delta manager to catch up before refreshing the latest Summary.
|
|
3016
|
-
await this.waitForDeltaManagerToCatchup(
|
|
3137
|
+
await this.waitForDeltaManagerToCatchup(
|
|
3138
|
+
fetchResult.latestSnapshotRefSeq,
|
|
3139
|
+
summaryLogger,
|
|
3140
|
+
);
|
|
3017
3141
|
|
|
3018
|
-
return
|
|
3142
|
+
return {
|
|
3143
|
+
snapshotTree: fetchResult.snapshotTree,
|
|
3144
|
+
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3145
|
+
};
|
|
3019
3146
|
};
|
|
3020
3147
|
|
|
3021
3148
|
const result = await this.summarizerNode.refreshLatestSummary(
|
|
3022
3149
|
proposalHandle,
|
|
3023
3150
|
summaryRefSeq,
|
|
3024
|
-
|
|
3151
|
+
fetchLatestSnapshot,
|
|
3025
3152
|
readAndParseBlob,
|
|
3026
3153
|
summaryLogger,
|
|
3027
3154
|
);
|
|
3028
3155
|
|
|
3029
3156
|
// Notify the garbage collector so it can update its latest summary state.
|
|
3030
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
3031
|
-
result,
|
|
3032
|
-
proposalHandle,
|
|
3033
|
-
summaryRefSeq,
|
|
3034
|
-
readAndParseBlob,
|
|
3035
|
-
);
|
|
3157
|
+
await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
|
|
3036
3158
|
}
|
|
3037
3159
|
|
|
3038
3160
|
/**
|
|
@@ -3044,30 +3166,31 @@ export class ContainerRuntime
|
|
|
3044
3166
|
private async refreshLatestSummaryAckFromServer(
|
|
3045
3167
|
summaryLogger: ITelemetryLogger,
|
|
3046
3168
|
): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
|
|
3047
|
-
const { snapshotTree, versionId } = await this.fetchLatestSnapshotFromStorage(
|
|
3048
|
-
summaryLogger,
|
|
3049
|
-
{
|
|
3050
|
-
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
3051
|
-
fetchLatest: true,
|
|
3052
|
-
},
|
|
3053
|
-
);
|
|
3054
|
-
|
|
3055
3169
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
3056
|
-
const
|
|
3057
|
-
|
|
3170
|
+
const { snapshotTree, versionId, latestSnapshotRefSeq } =
|
|
3171
|
+
await this.fetchLatestSnapshotFromStorage(
|
|
3172
|
+
summaryLogger,
|
|
3173
|
+
{
|
|
3174
|
+
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
3175
|
+
},
|
|
3176
|
+
readAndParseBlob,
|
|
3177
|
+
);
|
|
3178
|
+
const fetchLatestSnapshot: IFetchSnapshotResult = {
|
|
3179
|
+
snapshotTree,
|
|
3180
|
+
snapshotRefSeq: latestSnapshotRefSeq,
|
|
3181
|
+
};
|
|
3058
3182
|
const result = await this.summarizerNode.refreshLatestSummary(
|
|
3059
|
-
undefined
|
|
3183
|
+
undefined /* proposalHandle */,
|
|
3060
3184
|
latestSnapshotRefSeq,
|
|
3061
|
-
async () =>
|
|
3185
|
+
async () => fetchLatestSnapshot,
|
|
3062
3186
|
readAndParseBlob,
|
|
3063
3187
|
summaryLogger,
|
|
3064
3188
|
);
|
|
3065
3189
|
|
|
3066
3190
|
// Notify the garbage collector so it can update its latest summary state.
|
|
3067
3191
|
await this.garbageCollector.refreshLatestSummary(
|
|
3192
|
+
undefined /* proposalHandle */,
|
|
3068
3193
|
result,
|
|
3069
|
-
undefined,
|
|
3070
|
-
latestSnapshotRefSeq,
|
|
3071
3194
|
readAndParseBlob,
|
|
3072
3195
|
);
|
|
3073
3196
|
|
|
@@ -3077,7 +3200,37 @@ export class ContainerRuntime
|
|
|
3077
3200
|
private async fetchLatestSnapshotFromStorage(
|
|
3078
3201
|
logger: ITelemetryLogger,
|
|
3079
3202
|
event: ITelemetryGenericEvent,
|
|
3080
|
-
|
|
3203
|
+
readAndParseBlob: ReadAndParseBlob,
|
|
3204
|
+
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3205
|
+
return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
private async fetchSnapshotFromStorage(
|
|
3209
|
+
logger: ITelemetryLogger,
|
|
3210
|
+
event: ITelemetryGenericEvent,
|
|
3211
|
+
readAndParseBlob: ReadAndParseBlob,
|
|
3212
|
+
versionId: string | null,
|
|
3213
|
+
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3214
|
+
const recoveryMethod = this.mc.config.getString(
|
|
3215
|
+
"Fluid.ContainerRuntime.Test.SummarizationRecoveryMethod",
|
|
3216
|
+
);
|
|
3217
|
+
if (recoveryMethod === "restart") {
|
|
3218
|
+
const error = new GenericError("Restarting summarizer instead of refreshing");
|
|
3219
|
+
this.mc.logger.sendTelemetryEvent(
|
|
3220
|
+
{
|
|
3221
|
+
...event,
|
|
3222
|
+
eventName: "ClosingSummarizerOnSummaryStale",
|
|
3223
|
+
codePath: event.eventName,
|
|
3224
|
+
message: "Stopping fetch from storage",
|
|
3225
|
+
versionId: versionId != null ? versionId : undefined,
|
|
3226
|
+
},
|
|
3227
|
+
error,
|
|
3228
|
+
);
|
|
3229
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
3230
|
+
this.closeFn();
|
|
3231
|
+
throw error;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3081
3234
|
return PerformanceEvent.timedExecAsync(
|
|
3082
3235
|
logger,
|
|
3083
3236
|
event,
|
|
@@ -3085,16 +3238,23 @@ export class ContainerRuntime
|
|
|
3085
3238
|
end: (arg0: {
|
|
3086
3239
|
getVersionDuration?: number | undefined;
|
|
3087
3240
|
getSnapshotDuration?: number | undefined;
|
|
3241
|
+
snapshotRefSeq?: number | undefined;
|
|
3242
|
+
snapshotVersion?: string | undefined;
|
|
3088
3243
|
}) => void;
|
|
3089
3244
|
}) => {
|
|
3090
|
-
const stats: {
|
|
3245
|
+
const stats: {
|
|
3246
|
+
getVersionDuration?: number;
|
|
3247
|
+
getSnapshotDuration?: number;
|
|
3248
|
+
snapshotRefSeq?: number;
|
|
3249
|
+
snapshotVersion?: string;
|
|
3250
|
+
} = {};
|
|
3091
3251
|
const trace = Trace.start();
|
|
3092
3252
|
|
|
3093
3253
|
const versions = await this.storage.getVersions(
|
|
3094
|
-
|
|
3254
|
+
versionId,
|
|
3095
3255
|
1,
|
|
3096
3256
|
"refreshLatestSummaryAckFromServer",
|
|
3097
|
-
FetchSource.noCache,
|
|
3257
|
+
versionId === null ? FetchSource.noCache : undefined,
|
|
3098
3258
|
);
|
|
3099
3259
|
assert(
|
|
3100
3260
|
!!versions && !!versions[0],
|
|
@@ -3105,51 +3265,23 @@ export class ContainerRuntime
|
|
|
3105
3265
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
3106
3266
|
assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
3107
3267
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
3268
|
+
const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
|
|
3269
|
+
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
3270
|
+
stats.snapshotVersion = versions[0].id;
|
|
3108
3271
|
|
|
3109
3272
|
perfEvent.end(stats);
|
|
3110
|
-
return {
|
|
3273
|
+
return {
|
|
3274
|
+
snapshotTree: maybeSnapshot,
|
|
3275
|
+
versionId: versions[0].id,
|
|
3276
|
+
latestSnapshotRefSeq,
|
|
3277
|
+
};
|
|
3111
3278
|
},
|
|
3112
3279
|
);
|
|
3113
3280
|
}
|
|
3114
3281
|
|
|
3115
|
-
public notifyAttaching(
|
|
3116
|
-
if (
|
|
3117
|
-
this.mc.config.getBoolean("enableOfflineLoad") ??
|
|
3118
|
-
this.runtimeOptions.enableOfflineLoad
|
|
3119
|
-
) {
|
|
3120
|
-
this.baseSnapshotBlobs =
|
|
3121
|
-
SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
|
|
3125
|
-
private async initializeBaseSnapshotBlobs(): Promise<void> {
|
|
3126
|
-
if (
|
|
3127
|
-
!(
|
|
3128
|
-
this.mc.config.getBoolean("enableOfflineLoad") ??
|
|
3129
|
-
this.runtimeOptions.enableOfflineLoad
|
|
3130
|
-
) ||
|
|
3131
|
-
this.attachState !== AttachState.Attached ||
|
|
3132
|
-
this.context.pendingLocalState
|
|
3133
|
-
) {
|
|
3134
|
-
return;
|
|
3135
|
-
}
|
|
3136
|
-
assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
|
|
3137
|
-
this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(
|
|
3138
|
-
this.context.baseSnapshot,
|
|
3139
|
-
this.storage,
|
|
3140
|
-
);
|
|
3141
|
-
}
|
|
3282
|
+
public notifyAttaching() {} // do nothing (deprecated method)
|
|
3142
3283
|
|
|
3143
3284
|
public getPendingLocalState(): unknown {
|
|
3144
|
-
if (
|
|
3145
|
-
!(
|
|
3146
|
-
this.mc.config.getBoolean("enableOfflineLoad") ??
|
|
3147
|
-
this.runtimeOptions.enableOfflineLoad
|
|
3148
|
-
)
|
|
3149
|
-
) {
|
|
3150
|
-
throw new UsageError("can't get state when offline load disabled");
|
|
3151
|
-
}
|
|
3152
|
-
|
|
3153
3285
|
if (this._orderSequentiallyCalls !== 0) {
|
|
3154
3286
|
throw new UsageError("can't get state during orderSequentially");
|
|
3155
3287
|
}
|
|
@@ -3158,29 +3290,9 @@ export class ContainerRuntime
|
|
|
3158
3290
|
// to close current batch.
|
|
3159
3291
|
this.flush();
|
|
3160
3292
|
|
|
3161
|
-
const previousPendingState = this.context.pendingLocalState as
|
|
3162
|
-
| IPendingRuntimeState
|
|
3163
|
-
| undefined;
|
|
3164
|
-
if (previousPendingState) {
|
|
3165
|
-
return {
|
|
3166
|
-
pending: this.pendingStateManager.getLocalState(),
|
|
3167
|
-
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
3168
|
-
snapshotBlobs: previousPendingState.snapshotBlobs,
|
|
3169
|
-
baseSnapshot: previousPendingState.baseSnapshot,
|
|
3170
|
-
savedOps: this.savedOps,
|
|
3171
|
-
};
|
|
3172
|
-
}
|
|
3173
|
-
assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
|
|
3174
|
-
assert(
|
|
3175
|
-
!!this.baseSnapshotBlobs,
|
|
3176
|
-
0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */,
|
|
3177
|
-
);
|
|
3178
3293
|
return {
|
|
3179
3294
|
pending: this.pendingStateManager.getLocalState(),
|
|
3180
3295
|
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
3181
|
-
snapshotBlobs: this.baseSnapshotBlobs,
|
|
3182
|
-
baseSnapshot: this.context.baseSnapshot,
|
|
3183
|
-
savedOps: this.savedOps,
|
|
3184
3296
|
};
|
|
3185
3297
|
}
|
|
3186
3298
|
|
|
@@ -3243,25 +3355,6 @@ export class ContainerRuntime
|
|
|
3243
3355
|
};
|
|
3244
3356
|
}
|
|
3245
3357
|
|
|
3246
|
-
private async processSavedOps(state: IPendingRuntimeState) {
|
|
3247
|
-
for (const op of state.savedOps) {
|
|
3248
|
-
this.process(op, false);
|
|
3249
|
-
await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
|
|
3250
|
-
}
|
|
3251
|
-
// we may not have seen every sequence number (because of system ops) so apply everything once we
|
|
3252
|
-
// don't have any more saved ops
|
|
3253
|
-
await this.pendingStateManager.applyStashedOpsAt();
|
|
3254
|
-
|
|
3255
|
-
// If it's not the case, we should take it into account when calculating dirty state.
|
|
3256
|
-
assert(
|
|
3257
|
-
this.context.attachState === AttachState.Attached,
|
|
3258
|
-
0x3d5 /* this function is called for attached containers only */,
|
|
3259
|
-
);
|
|
3260
|
-
if (!this.hasPendingMessages()) {
|
|
3261
|
-
this.updateDocumentDirtyState(false);
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
|
|
3265
3358
|
private validateSummaryHeuristicConfiguration(configuration: ISummaryConfigurationHeuristics) {
|
|
3266
3359
|
// eslint-disable-next-line no-restricted-syntax
|
|
3267
3360
|
for (const prop in configuration) {
|
|
@@ -3277,6 +3370,13 @@ export class ContainerRuntime
|
|
|
3277
3370
|
);
|
|
3278
3371
|
}
|
|
3279
3372
|
}
|
|
3373
|
+
|
|
3374
|
+
private get groupedBatchingEnabled(): boolean {
|
|
3375
|
+
const killSwitch = this.mc.config.getBoolean(
|
|
3376
|
+
"Fluid.ContainerRuntime.DisableGroupedBatching",
|
|
3377
|
+
);
|
|
3378
|
+
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
3379
|
+
}
|
|
3280
3380
|
}
|
|
3281
3381
|
|
|
3282
3382
|
/**
|