@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/lib/containerRuntime.js
CHANGED
|
@@ -1,35 +1,28 @@
|
|
|
1
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
2
|
-
import { assert, Trace, TypedEventEmitter, unreachableCase } from "@fluidframework/common-utils";
|
|
2
|
+
import { assert, LazyPromise, Trace, TypedEventEmitter, unreachableCase, } from "@fluidframework/common-utils";
|
|
3
3
|
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, wrapError, } from "@fluidframework/telemetry-utils";
|
|
4
4
|
import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
5
5
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
6
6
|
import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
|
|
7
7
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
8
|
-
import { FlushMode, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
9
|
-
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary,
|
|
10
|
-
import { GCDataBuilder, trimLeadingAndTrailingSlashes } from "@fluidframework/garbage-collector";
|
|
8
|
+
import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
9
|
+
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
|
|
11
10
|
import { v4 as uuid } from "uuid";
|
|
12
11
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
13
12
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
14
|
-
import { Summarizer } from "./summarizer";
|
|
15
|
-
import { SummaryManager } from "./summaryManager";
|
|
16
13
|
import { ReportOpPerfTelemetry } from "./connectionTelemetry";
|
|
17
14
|
import { PendingStateManager } from "./pendingStateManager";
|
|
18
15
|
import { pkgVersion } from "./packageVersion";
|
|
19
16
|
import { BlobManager } from "./blobManager";
|
|
20
17
|
import { DataStores, getSummaryForDatastores } from "./dataStores";
|
|
21
|
-
import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./
|
|
22
|
-
import { SummaryCollection } from "./summaryCollection";
|
|
23
|
-
import { OrderedClientCollection, OrderedClientElection, } from "./orderedClientElection";
|
|
24
|
-
import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
|
|
18
|
+
import { aliasBlobName, blobsTreeName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, Summarizer, SummaryManager, wrapSummaryInChannelsTree, SummaryCollection, OrderedClientCollection, OrderedClientElection, SummarizerClientElection, summarizerClientType, RunWhileConnectedCoordinator, } from "./summary";
|
|
25
19
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
26
|
-
import {
|
|
27
|
-
import { GarbageCollector, GCNodeType, } from "./garbageCollection";
|
|
20
|
+
import { GarbageCollector, GCNodeType, gcTombstoneGenerationOptionName, shouldAllowGcTombstoneEnforcement, trimLeadingAndTrailingSlashes, } from "./gc";
|
|
28
21
|
import { channelToDataStore, isDataStoreAliasMessage } from "./dataStore";
|
|
29
22
|
import { BindBatchTracker } from "./batchTracker";
|
|
30
|
-
import { SerializedSnapshotStorage, } from "./serializedSnapshotStorage";
|
|
31
23
|
import { ScheduleManager } from "./scheduleManager";
|
|
32
|
-
import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, } from "./opLifecycle";
|
|
24
|
+
import { OpCompressor, OpDecompressor, Outbox, OpSplitter, RemoteMessageProcessor, OpGroupingManager, } from "./opLifecycle";
|
|
25
|
+
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
33
26
|
export var ContainerMessageType;
|
|
34
27
|
(function (ContainerMessageType) {
|
|
35
28
|
// An op to be delivered to store
|
|
@@ -52,7 +45,7 @@ export const DefaultSummaryConfiguration = {
|
|
|
52
45
|
maxTime: 60 * 1000,
|
|
53
46
|
maxOps: 100,
|
|
54
47
|
minOpsForLastSummaryAttempt: 10,
|
|
55
|
-
maxAckWaitTime:
|
|
48
|
+
maxAckWaitTime: 3 * 60 * 1000,
|
|
56
49
|
maxOpsSinceLastSummary: 7000,
|
|
57
50
|
initialSummarizerDelayMs: 5 * 1000,
|
|
58
51
|
nonRuntimeOpWeight: 0.1,
|
|
@@ -66,11 +59,6 @@ export var RuntimeHeaders;
|
|
|
66
59
|
(function (RuntimeHeaders) {
|
|
67
60
|
/** True to wait for a data store to be created and loaded before returning it. */
|
|
68
61
|
RuntimeHeaders["wait"] = "wait";
|
|
69
|
-
/**
|
|
70
|
-
* True if the request is from an external app. Used for GC to handle scenarios where a data store
|
|
71
|
-
* is deleted and requested via an external app.
|
|
72
|
-
*/
|
|
73
|
-
RuntimeHeaders["externalRequest"] = "externalRequest";
|
|
74
62
|
/** True if the request is coming from an IFluidHandle. */
|
|
75
63
|
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
76
64
|
})(RuntimeHeaders || (RuntimeHeaders = {}));
|
|
@@ -81,7 +69,6 @@ export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
|
81
69
|
/** Default values for Runtime Headers */
|
|
82
70
|
export const defaultRuntimeHeaderData = {
|
|
83
71
|
wait: true,
|
|
84
|
-
externalRequest: false,
|
|
85
72
|
viaHandle: false,
|
|
86
73
|
allowTombstone: false,
|
|
87
74
|
};
|
|
@@ -98,7 +85,13 @@ const defaultFlushMode = FlushMode.TurnBased;
|
|
|
98
85
|
// We can't estimate it fully, as we
|
|
99
86
|
// - do not know what properties relay service will add
|
|
100
87
|
// - we do not stringify final op, thus we do not know how much escaping will be added.
|
|
101
|
-
const defaultMaxBatchSizeInBytes =
|
|
88
|
+
const defaultMaxBatchSizeInBytes = 700 * 1024;
|
|
89
|
+
const defaultCompressionConfig = {
|
|
90
|
+
// Batches with content size exceeding this value will be compressed
|
|
91
|
+
minimumBatchSizeInBytes: 614400,
|
|
92
|
+
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
93
|
+
};
|
|
94
|
+
const defaultChunkSizeInBytes = 204800;
|
|
102
95
|
/**
|
|
103
96
|
* @deprecated - use ContainerRuntimeMessage instead
|
|
104
97
|
*/
|
|
@@ -145,8 +138,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
145
138
|
/**
|
|
146
139
|
* @internal
|
|
147
140
|
*/
|
|
148
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
|
|
149
|
-
var _a, _b, _c, _d, _e, _f;
|
|
141
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration, initializeEntryPoint) {
|
|
142
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
150
143
|
if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
|
|
151
144
|
super();
|
|
152
145
|
this.context = context;
|
|
@@ -159,8 +152,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
159
152
|
this.summaryConfiguration = summaryConfiguration;
|
|
160
153
|
this.defaultMaxConsecutiveReconnects = 7;
|
|
161
154
|
this._orderSequentiallyCalls = 0;
|
|
162
|
-
this.
|
|
163
|
-
this.savedOps = [];
|
|
155
|
+
this.flushTaskExists = false;
|
|
164
156
|
this.consecutiveReconnects = 0;
|
|
165
157
|
this.ensureNoDataModelChangesCalls = 0;
|
|
166
158
|
/**
|
|
@@ -207,6 +199,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
207
199
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
208
200
|
}
|
|
209
201
|
};
|
|
202
|
+
this.innerDeltaManager = context.deltaManager;
|
|
203
|
+
this.deltaManager = new DeltaManagerSummarizerProxy(context.deltaManager);
|
|
210
204
|
let loadSummaryNumber;
|
|
211
205
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
212
206
|
// get the values from the metadata blob.
|
|
@@ -229,29 +223,47 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
229
223
|
this.nextSummaryNumber = loadSummaryNumber + 1;
|
|
230
224
|
this.messageAtLastSummary = metadata === null || metadata === void 0 ? void 0 : metadata.message;
|
|
231
225
|
this._connected = this.context.connected;
|
|
226
|
+
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement((_c = metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix) === null || _c === void 0 ? void 0 : _c.tombstoneGeneration /* persisted */, this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName] /* current */);
|
|
232
227
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
:
|
|
236
|
-
|
|
228
|
+
this.mc.logger.sendTelemetryEvent({
|
|
229
|
+
eventName: "GCFeatureMatrix",
|
|
230
|
+
metadataValue: JSON.stringify(metadata === null || metadata === void 0 ? void 0 : metadata.gcFeatureMatrix),
|
|
231
|
+
inputs: JSON.stringify({
|
|
232
|
+
gcOptions_gcTombstoneGeneration: this.runtimeOptions.gcOptions[gcTombstoneGenerationOptionName],
|
|
233
|
+
}),
|
|
234
|
+
});
|
|
235
|
+
this.telemetryDocumentId = (_d = metadata === null || metadata === void 0 ? void 0 : metadata.telemetryDocumentId) !== null && _d !== void 0 ? _d : uuid();
|
|
236
|
+
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
237
|
+
const disableChunking = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionChunkingDisabled");
|
|
238
|
+
const opGroupingManager = new OpGroupingManager(this.groupedBatchingEnabled);
|
|
239
|
+
const opSplitter = new OpSplitter(chunks, this.context.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
240
|
+
this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
|
|
237
241
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
238
242
|
if (this.summaryConfiguration.state === "enabled") {
|
|
239
243
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
240
244
|
}
|
|
245
|
+
const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
|
|
241
246
|
this.enableOpReentryCheck =
|
|
242
247
|
runtimeOptions.enableOpReentryCheck === true &&
|
|
243
248
|
// Allow for a break-glass config to override the options
|
|
244
|
-
|
|
249
|
+
disableOpReentryCheck !== true;
|
|
245
250
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
246
251
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
247
252
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
248
253
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
249
254
|
this.maxConsecutiveReconnects =
|
|
250
|
-
(
|
|
251
|
-
|
|
255
|
+
(_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
|
|
256
|
+
if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
|
|
257
|
+
((_f = context.supportedFeatures) === null || _f === void 0 ? void 0 : _f.get("referenceSequenceNumbers")) !== true) {
|
|
258
|
+
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
259
|
+
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
260
|
+
this._flushMode = FlushMode.TurnBased;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
264
|
+
}
|
|
252
265
|
const pendingRuntimeState = context.pendingLocalState;
|
|
253
|
-
const
|
|
254
|
-
const maxSnapshotCacheDurationMs = (_f = (_e = this._storage) === null || _e === void 0 ? void 0 : _e.policies) === null || _f === void 0 ? void 0 : _f.maximumCacheDurationMs;
|
|
266
|
+
const maxSnapshotCacheDurationMs = (_h = (_g = this._storage) === null || _g === void 0 ? void 0 : _g.policies) === null || _h === void 0 ? void 0 : _h.maximumCacheDurationMs;
|
|
255
267
|
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
256
268
|
maxSnapshotCacheDurationMs > 5 * 24 * 60 * 60 * 1000) {
|
|
257
269
|
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
@@ -262,7 +274,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
262
274
|
this.garbageCollector = GarbageCollector.create({
|
|
263
275
|
runtime: this,
|
|
264
276
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
265
|
-
baseSnapshot,
|
|
277
|
+
baseSnapshot: context.baseSnapshot,
|
|
266
278
|
baseLogger: this.mc.logger,
|
|
267
279
|
existing,
|
|
268
280
|
metadata,
|
|
@@ -272,7 +284,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
272
284
|
getLastSummaryTimestampMs: () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; },
|
|
273
285
|
readAndParseBlob: async (id) => readAndParse(this.storage, id),
|
|
274
286
|
getContainerDiagnosticId: () => this.context.id,
|
|
275
|
-
|
|
287
|
+
// GC runs in summarizer client and needs access to the real (non-proxy) active information. The proxy
|
|
288
|
+
// delta manager would always return false for summarizer client.
|
|
289
|
+
activeConnection: () => this.innerDeltaManager.active,
|
|
276
290
|
});
|
|
277
291
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
278
292
|
this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
|
|
@@ -281,7 +295,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
281
295
|
// Latest change sequence number, no changes since summary applied yet
|
|
282
296
|
loadedFromSequenceNumber,
|
|
283
297
|
// Summary reference sequence number, undefined if no summary yet
|
|
284
|
-
baseSnapshot ? loadedFromSequenceNumber : undefined, {
|
|
298
|
+
context.baseSnapshot ? loadedFromSequenceNumber : undefined, {
|
|
285
299
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
286
300
|
// a summary with an older protocol state.
|
|
287
301
|
canReuseHandle: false,
|
|
@@ -295,18 +309,24 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
295
309
|
async (fullGC) => this.getGCDataInternal(fullGC),
|
|
296
310
|
// Function to get the GC details from the base snapshot we loaded from.
|
|
297
311
|
async () => this.garbageCollector.getBaseGCDetails());
|
|
298
|
-
if (baseSnapshot) {
|
|
299
|
-
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
312
|
+
if (context.baseSnapshot) {
|
|
313
|
+
this.summarizerNode.updateBaseSummaryState(context.baseSnapshot);
|
|
300
314
|
}
|
|
301
|
-
this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn
|
|
315
|
+
this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
|
|
302
316
|
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
303
317
|
if (!this.disposed) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
319
|
+
Promise.resolve().then(() => {
|
|
320
|
+
// Blob attaches need to be in their own batch (grouped batching would hide metadata)
|
|
321
|
+
this.flush();
|
|
322
|
+
this.submit(ContainerMessageType.BlobAttach, undefined, undefined, {
|
|
323
|
+
localId,
|
|
324
|
+
blobId,
|
|
325
|
+
});
|
|
326
|
+
this.flush();
|
|
307
327
|
});
|
|
308
328
|
}
|
|
309
|
-
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (
|
|
329
|
+
}, (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), (blobPath) => this.garbageCollector.isNodeDeleted(blobPath), this, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pendingAttachmentBlobs, (error) => this.closeFn(error));
|
|
310
330
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, () => this.clientId, ChildLogger.create(this.logger, "ScheduleManager"));
|
|
311
331
|
this.pendingStateManager = new PendingStateManager({
|
|
312
332
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
@@ -317,12 +337,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
317
337
|
rollback: this.rollback.bind(this),
|
|
318
338
|
orderSequentially: this.orderSequentially.bind(this),
|
|
319
339
|
}, pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.pending);
|
|
320
|
-
const
|
|
340
|
+
const disableCompression = this.mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
341
|
+
const compressionOptions = disableCompression === true
|
|
321
342
|
? {
|
|
322
343
|
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
323
344
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
324
345
|
}
|
|
325
346
|
: runtimeOptions.compressionOptions;
|
|
347
|
+
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
326
348
|
this.outbox = new Outbox({
|
|
327
349
|
shouldSend: () => this.canSendOps(),
|
|
328
350
|
pendingStateManager: this.pendingStateManager,
|
|
@@ -332,9 +354,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
332
354
|
config: {
|
|
333
355
|
compressionOptions,
|
|
334
356
|
maxBatchSizeInBytes: runtimeOptions.maxBatchSizeInBytes,
|
|
335
|
-
|
|
357
|
+
disablePartialFlush: disablePartialFlush === true,
|
|
336
358
|
},
|
|
337
359
|
logger: this.mc.logger,
|
|
360
|
+
groupingManager: opGroupingManager,
|
|
338
361
|
});
|
|
339
362
|
this.context.quorum.on("removeMember", (clientId) => {
|
|
340
363
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
@@ -353,7 +376,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
353
376
|
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
354
377
|
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
355
378
|
if (this.context.clientDetails.type === summarizerClientType) {
|
|
356
|
-
this._summarizer = new Summarizer(
|
|
379
|
+
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
380
|
+
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
381
|
+
// information. The proxy delta manager would always return false for summarizer client.
|
|
382
|
+
() => this.innerDeltaManager.active));
|
|
357
383
|
}
|
|
358
384
|
else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
|
|
359
385
|
// Only create a SummaryManager and SummarizerClientElection
|
|
@@ -388,7 +414,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
388
414
|
this.deltaManager.on("readonly", (readonly) => {
|
|
389
415
|
// we accumulate ops while being in read-only state.
|
|
390
416
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
391
|
-
|
|
417
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
418
|
+
assert(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
392
419
|
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
393
420
|
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
394
421
|
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
@@ -406,9 +433,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
406
433
|
});
|
|
407
434
|
// logging hardware telemetry
|
|
408
435
|
logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
|
|
409
|
-
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature
|
|
436
|
+
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature, options: JSON.stringify(runtimeOptions), featureGates: JSON.stringify({
|
|
437
|
+
disableCompression,
|
|
438
|
+
disableOpReentryCheck,
|
|
439
|
+
disableChunking,
|
|
440
|
+
disableAttachReorder: this.disableAttachReorder,
|
|
441
|
+
disablePartialFlush,
|
|
442
|
+
}), telemetryDocumentId: this.telemetryDocumentId, groupedBatchingEnabled: this.groupedBatchingEnabled }));
|
|
410
443
|
ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
411
444
|
BindBatchTracker(this, this.logger);
|
|
445
|
+
this.entryPoint = new LazyPromise(async () => {
|
|
446
|
+
if (this.context.clientDetails.type === summarizerClientType) {
|
|
447
|
+
assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
448
|
+
return this._summarizer;
|
|
449
|
+
}
|
|
450
|
+
return initializeEntryPoint === null || initializeEntryPoint === void 0 ? void 0 : initializeEntryPoint(this);
|
|
451
|
+
});
|
|
412
452
|
}
|
|
413
453
|
get IContainerRuntime() {
|
|
414
454
|
return this;
|
|
@@ -446,17 +486,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
446
486
|
* Load the stores from a snapshot and returns the runtime.
|
|
447
487
|
* @param params - An object housing the runtime properties:
|
|
448
488
|
* - context - Context of the container.
|
|
449
|
-
* - registryEntries - Mapping to
|
|
450
|
-
* - existing -
|
|
451
|
-
* - requestHandler - Request
|
|
489
|
+
* - registryEntries - Mapping from data store types to their corresponding factories.
|
|
490
|
+
* - existing - Pass 'true' if loading from an existing snapshot.
|
|
491
|
+
* - requestHandler - (optional) Request handler for the request() method of the container runtime.
|
|
492
|
+
* Only relevant for back-compat while we remove the request() method and move fully to entryPoint as the main pattern.
|
|
452
493
|
* - runtimeOptions - Additional options to be passed to the runtime
|
|
453
494
|
* - containerScope - runtime services provided with context
|
|
454
495
|
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
455
496
|
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
497
|
+
* - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
498
|
+
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
456
499
|
*/
|
|
457
500
|
static async loadRuntime(params) {
|
|
458
501
|
var _a, _b, _c, _d;
|
|
459
|
-
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
|
|
502
|
+
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, initializeEntryPoint, } = params;
|
|
460
503
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
461
504
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
462
505
|
const backCompatContext = context;
|
|
@@ -466,25 +509,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
466
509
|
runtimeVersion: pkgVersion,
|
|
467
510
|
},
|
|
468
511
|
});
|
|
469
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode,
|
|
470
|
-
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
471
|
-
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
472
|
-
}, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = Number.POSITIVE_INFINITY, enableOpReentryCheck = false, } = runtimeOptions;
|
|
473
|
-
const pendingRuntimeState = context.pendingLocalState;
|
|
474
|
-
const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
|
|
475
|
-
const storage = !pendingRuntimeState
|
|
476
|
-
? context.storage
|
|
477
|
-
: new SerializedSnapshotStorage(() => {
|
|
478
|
-
return context.storage;
|
|
479
|
-
}, pendingRuntimeState.snapshotBlobs);
|
|
512
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, chunkSizeInBytes = defaultChunkSizeInBytes, enableOpReentryCheck = false, enableGroupedBatching = false, } = runtimeOptions;
|
|
480
513
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
481
514
|
const tryFetchBlob = async (blobName) => {
|
|
482
|
-
|
|
483
|
-
|
|
515
|
+
var _a;
|
|
516
|
+
const blobId = (_a = context.baseSnapshot) === null || _a === void 0 ? void 0 : _a.blobs[blobName];
|
|
517
|
+
if (context.baseSnapshot && blobId) {
|
|
484
518
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
485
519
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
486
|
-
assert(storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
487
|
-
return readAndParse(storage, blobId);
|
|
520
|
+
assert(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
521
|
+
return readAndParse(context.storage, blobId);
|
|
488
522
|
}
|
|
489
523
|
};
|
|
490
524
|
const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
|
|
@@ -495,16 +529,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
495
529
|
]);
|
|
496
530
|
const loadExisting = existing === true || context.existing === true;
|
|
497
531
|
// read snapshot blobs needed for BlobManager to load
|
|
498
|
-
const blobManagerSnapshot = await BlobManager.load(baseSnapshot === null ||
|
|
532
|
+
const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
|
|
499
533
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
500
534
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
501
|
-
assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
502
|
-
return readAndParse(storage, id);
|
|
535
|
+
assert(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
536
|
+
return readAndParse(context.storage, id);
|
|
503
537
|
});
|
|
504
538
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
505
539
|
const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
|
|
506
540
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
507
|
-
if (!
|
|
541
|
+
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
508
542
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
509
543
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
510
544
|
if (loadSequenceNumberVerification !== "bypass" &&
|
|
@@ -528,17 +562,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
528
562
|
gcOptions,
|
|
529
563
|
loadSequenceNumberVerification,
|
|
530
564
|
flushMode,
|
|
531
|
-
enableOfflineLoad,
|
|
532
565
|
compressionOptions,
|
|
533
566
|
maxBatchSizeInBytes,
|
|
534
567
|
chunkSizeInBytes,
|
|
535
568
|
enableOpReentryCheck,
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
569
|
+
enableGroupedBatching,
|
|
570
|
+
}, containerScope, logger, loadExisting, blobManagerSnapshot, context.storage, requestHandler, undefined, // summaryConfiguration
|
|
571
|
+
initializeEntryPoint);
|
|
572
|
+
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
573
|
+
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
574
|
+
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
542
575
|
// Initialize the base state of the runtime before it's returned.
|
|
543
576
|
await runtime.initializeBaseState();
|
|
544
577
|
return runtime;
|
|
@@ -552,9 +585,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
552
585
|
get clientDetails() {
|
|
553
586
|
return this.context.clientDetails;
|
|
554
587
|
}
|
|
555
|
-
get deltaManager() {
|
|
556
|
-
return this.context.deltaManager;
|
|
557
|
-
}
|
|
558
588
|
get storage() {
|
|
559
589
|
return this._storage;
|
|
560
590
|
}
|
|
@@ -647,7 +677,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
647
677
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
648
678
|
*/
|
|
649
679
|
async initializeBaseState() {
|
|
650
|
-
await this.initializeBaseSnapshotBlobs();
|
|
651
680
|
await this.garbageCollector.initializeBaseState();
|
|
652
681
|
}
|
|
653
682
|
dispose(error) {
|
|
@@ -672,16 +701,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
672
701
|
this.emit("dispose");
|
|
673
702
|
this.removeAllListeners();
|
|
674
703
|
}
|
|
675
|
-
get IFluidTokenProvider() {
|
|
676
|
-
var _a;
|
|
677
|
-
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.intelligence) {
|
|
678
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
679
|
-
return {
|
|
680
|
-
intelligence: this.options.intelligence,
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
return undefined;
|
|
684
|
-
}
|
|
685
704
|
/**
|
|
686
705
|
* Notifies this object about the request made to the container.
|
|
687
706
|
* @param request - Request made to the handler.
|
|
@@ -744,12 +763,18 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
744
763
|
return exceptionToResponse(error);
|
|
745
764
|
}
|
|
746
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
|
|
768
|
+
*/
|
|
769
|
+
async getEntryPoint() {
|
|
770
|
+
return this.entryPoint;
|
|
771
|
+
}
|
|
747
772
|
internalId(maybeAlias) {
|
|
748
773
|
var _a;
|
|
749
774
|
return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
|
|
750
775
|
}
|
|
751
776
|
async getDataStoreFromRequest(id, request) {
|
|
752
|
-
var _a, _b, _c
|
|
777
|
+
var _a, _b, _c;
|
|
753
778
|
const headerData = {};
|
|
754
779
|
if (typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean") {
|
|
755
780
|
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
@@ -763,23 +788,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
763
788
|
await this.dataStores.waitIfPendingAlias(id);
|
|
764
789
|
const internalId = this.internalId(id);
|
|
765
790
|
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
766
|
-
/**
|
|
767
|
-
* If GC should run and this an external app request with "externalRequest" header, we need to return
|
|
768
|
-
* an error if the data store being requested is marked as unreferenced as per the data store's base
|
|
769
|
-
* GC data.
|
|
770
|
-
*
|
|
771
|
-
* This is a workaround to handle scenarios where a data store shared with an external app is deleted
|
|
772
|
-
* and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
|
|
773
|
-
*/
|
|
774
|
-
if (((_d = request.headers) === null || _d === void 0 ? void 0 : _d[RuntimeHeaders.externalRequest]) &&
|
|
775
|
-
this.garbageCollector.shouldRunGC) {
|
|
776
|
-
// The data store is referenced if used routes in the base summary has a route to self.
|
|
777
|
-
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
778
|
-
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
779
|
-
if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
|
|
780
|
-
throw responseToException(create404Response(request), request);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
791
|
const dataStoreChannel = await dataStoreContext.realize();
|
|
784
792
|
// Remove query params, leading and trailing slashes from the url. This is done to make sure the format is
|
|
785
793
|
// the same as GC nodes id.
|
|
@@ -795,7 +803,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
795
803
|
summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1 }), this.garbageCollector.getMetadata()), {
|
|
796
804
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
797
805
|
// last summary.
|
|
798
|
-
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary });
|
|
806
|
+
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.messageAtLastSummary, telemetryDocumentId: this.telemetryDocumentId });
|
|
799
807
|
addBlobToSummary(summaryTree, metadataBlobName, JSON.stringify(metadata));
|
|
800
808
|
}
|
|
801
809
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
@@ -911,7 +919,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
911
919
|
// If attachment blobs were added while disconnected, we need to delay
|
|
912
920
|
// propagation of the "connected" event until we have uploaded them to
|
|
913
921
|
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
914
|
-
|
|
922
|
+
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
923
|
+
const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
915
924
|
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
916
925
|
assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
|
|
917
926
|
assert(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
@@ -961,19 +970,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
961
970
|
this.garbageCollector.setConnectionState(connected, clientId);
|
|
962
971
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
963
972
|
}
|
|
973
|
+
async notifyOpReplay(message) {
|
|
974
|
+
await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
|
|
975
|
+
}
|
|
964
976
|
process(messageArg, local) {
|
|
965
|
-
var _a;
|
|
966
977
|
this.verifyNotClosed();
|
|
967
|
-
if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
|
|
968
|
-
this.savedOps.push(messageArg);
|
|
969
|
-
}
|
|
970
978
|
// Whether or not the message is actually a runtime message.
|
|
971
979
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
972
980
|
// or something different, like a system message.
|
|
973
981
|
const runtimeMessage = messageArg.type === MessageType.Operation;
|
|
974
982
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
975
983
|
const messageCopy = Object.assign({}, messageArg);
|
|
976
|
-
const message
|
|
984
|
+
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
985
|
+
this.processCore(message, local, runtimeMessage);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
processCore(message, local, runtimeMessage) {
|
|
989
|
+
var _a;
|
|
977
990
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
978
991
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
979
992
|
// messages once a batch has been fully processed.
|
|
@@ -1006,10 +1019,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1006
1019
|
case ContainerMessageType.Rejoin:
|
|
1007
1020
|
break;
|
|
1008
1021
|
default:
|
|
1009
|
-
|
|
1022
|
+
if (runtimeMessage) {
|
|
1023
|
+
const error = DataProcessingError.create(
|
|
1024
|
+
// Former assert 0x3ce
|
|
1025
|
+
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1026
|
+
local,
|
|
1027
|
+
type: message.type,
|
|
1028
|
+
contentType: typeof message.contents,
|
|
1029
|
+
batch: (_a = message.metadata) === null || _a === void 0 ? void 0 : _a.batch,
|
|
1030
|
+
compression: message.compression,
|
|
1031
|
+
});
|
|
1032
|
+
this.closeFn(error);
|
|
1033
|
+
throw error;
|
|
1034
|
+
}
|
|
1010
1035
|
}
|
|
1011
|
-
|
|
1012
|
-
if (runtimeMessage) {
|
|
1036
|
+
if (runtimeMessage || this.groupedBatchingEnabled) {
|
|
1013
1037
|
this.emit("op", message, runtimeMessage);
|
|
1014
1038
|
}
|
|
1015
1039
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
@@ -1067,7 +1091,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1067
1091
|
}
|
|
1068
1092
|
else if (envelope.clientSignalSequenceNumber ===
|
|
1069
1093
|
this._perfSignalData.trackingSignalSequenceNumber) {
|
|
1070
|
-
|
|
1094
|
+
// only logging for the first connection and the trackingSignalSequenceNUmber.
|
|
1095
|
+
if (this.consecutiveReconnects === 0) {
|
|
1096
|
+
this.sendSignalTelemetryEvent(envelope.clientSignalSequenceNumber);
|
|
1097
|
+
}
|
|
1071
1098
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
1072
1099
|
}
|
|
1073
1100
|
}
|
|
@@ -1164,13 +1191,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1164
1191
|
.realize();
|
|
1165
1192
|
}
|
|
1166
1193
|
canSendOps() {
|
|
1167
|
-
|
|
1194
|
+
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
1195
|
+
// container runtime's ability to send ops depend on the actual readonly state of the delta manager.
|
|
1196
|
+
return this.connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1168
1197
|
}
|
|
1169
1198
|
/**
|
|
1170
1199
|
* Are we in the middle of batching ops together?
|
|
1171
1200
|
*/
|
|
1172
1201
|
currentlyBatching() {
|
|
1173
|
-
return this.flushMode
|
|
1202
|
+
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
1174
1203
|
}
|
|
1175
1204
|
getQuorum() {
|
|
1176
1205
|
return this.context.quorum;
|
|
@@ -1286,11 +1315,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1286
1315
|
async summarize(options) {
|
|
1287
1316
|
this.verifyNotClosed();
|
|
1288
1317
|
const { fullTree = false, trackState = true, summaryLogger = this.mc.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
|
|
1318
|
+
const telemetryContext = new TelemetryContext();
|
|
1319
|
+
// Add the options that are used to generate this summary to the telemetry context.
|
|
1320
|
+
telemetryContext.setMultiple("fluid_Summarize", "Options", {
|
|
1321
|
+
fullTree,
|
|
1322
|
+
trackState,
|
|
1323
|
+
runGC,
|
|
1324
|
+
fullGC,
|
|
1325
|
+
runSweep,
|
|
1326
|
+
});
|
|
1289
1327
|
let gcStats;
|
|
1290
1328
|
if (runGC) {
|
|
1291
|
-
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1329
|
+
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
|
|
1292
1330
|
}
|
|
1293
|
-
const telemetryContext = new TelemetryContext();
|
|
1294
1331
|
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
|
|
1295
1332
|
this.logger.sendTelemetryEvent({
|
|
1296
1333
|
eventName: "SummarizeTelemetry",
|
|
@@ -1300,10 +1337,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1300
1337
|
return { stats, summary, gcStats };
|
|
1301
1338
|
}
|
|
1302
1339
|
/**
|
|
1303
|
-
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
1304
1340
|
* Before GC runs, called by the garbage collector to update any pending GC state. This is mainly used to notify
|
|
1305
1341
|
* the garbage collector of references detected since the last GC run. Most references are notified immediately
|
|
1306
1342
|
* but there can be some for which async operation is required (such as detecting new root data stores).
|
|
1343
|
+
* @see IGarbageCollectionRuntime.updateStateBeforeGC
|
|
1307
1344
|
*/
|
|
1308
1345
|
async updateStateBeforeGC() {
|
|
1309
1346
|
return this.dataStores.updateStateBeforeGC();
|
|
@@ -1312,9 +1349,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1312
1349
|
return this.dataStores.getGCData(fullGC);
|
|
1313
1350
|
}
|
|
1314
1351
|
/**
|
|
1315
|
-
* Implementation of IGarbageCollectionRuntime::getGCData.
|
|
1316
1352
|
* Generates and returns the GC data for this container.
|
|
1317
1353
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
1354
|
+
* @see IGarbageCollectionRuntime.getGCData
|
|
1318
1355
|
*/
|
|
1319
1356
|
async getGCData(fullGC) {
|
|
1320
1357
|
const builder = new GCDataBuilder();
|
|
@@ -1325,9 +1362,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1325
1362
|
return builder.getGCData();
|
|
1326
1363
|
}
|
|
1327
1364
|
/**
|
|
1328
|
-
* Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
|
|
1329
1365
|
* After GC has run, called to notify this container's nodes of routes that are used in it.
|
|
1330
1366
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
1367
|
+
* @see IGarbageCollectionRuntime.updateUsedRoutes
|
|
1331
1368
|
*/
|
|
1332
1369
|
updateUsedRoutes(usedRoutes) {
|
|
1333
1370
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
@@ -1346,6 +1383,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1346
1383
|
this.blobManager.updateUnusedRoutes(blobManagerRoutes);
|
|
1347
1384
|
this.dataStores.updateUnusedRoutes(dataStoreRoutes);
|
|
1348
1385
|
}
|
|
1386
|
+
/**
|
|
1387
|
+
* @deprecated - Replaced by deleteSweepReadyNodes.
|
|
1388
|
+
*/
|
|
1389
|
+
deleteUnusedNodes(unusedRoutes) {
|
|
1390
|
+
throw new Error("deleteUnusedRoutes should not be called");
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
1394
|
+
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
1395
|
+
* @returns - The routes of nodes that were deleted.
|
|
1396
|
+
*/
|
|
1397
|
+
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
1398
|
+
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
1399
|
+
const deletedRoutes = this.dataStores.deleteSweepReadyNodes(dataStoreRoutes);
|
|
1400
|
+
return deletedRoutes.concat(this.blobManager.deleteSweepReadyNodes(blobManagerRoutes));
|
|
1401
|
+
}
|
|
1349
1402
|
/**
|
|
1350
1403
|
* This is called to update objects that are tombstones.
|
|
1351
1404
|
* @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
|
|
@@ -1423,8 +1476,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1423
1476
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
1424
1477
|
* @returns the statistics of the garbage collection run; undefined if GC did not run.
|
|
1425
1478
|
*/
|
|
1426
|
-
async collectGarbage(options) {
|
|
1427
|
-
return this.garbageCollector.collectGarbage(options);
|
|
1479
|
+
async collectGarbage(options, telemetryContext) {
|
|
1480
|
+
return this.garbageCollector.collectGarbage(options, telemetryContext);
|
|
1428
1481
|
}
|
|
1429
1482
|
/**
|
|
1430
1483
|
* Called when a new outbound reference is added to another node. This is used by garbage collection to identify
|
|
@@ -1445,7 +1498,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1445
1498
|
*/
|
|
1446
1499
|
async submitSummary(options) {
|
|
1447
1500
|
var _a, _b;
|
|
1448
|
-
const { fullTree, refreshLatestAck, summaryLogger } = options;
|
|
1501
|
+
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
1449
1502
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1450
1503
|
// use it for all events logged during this summary.
|
|
1451
1504
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1461,8 +1514,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1461
1514
|
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
1462
1515
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
1463
1516
|
}
|
|
1517
|
+
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1464
1518
|
try {
|
|
1465
1519
|
await this.deltaManager.inbound.pause();
|
|
1520
|
+
if (shouldPauseInboundSignal) {
|
|
1521
|
+
await this.deltaManager.inboundSignal.pause();
|
|
1522
|
+
}
|
|
1466
1523
|
const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
1467
1524
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1468
1525
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
@@ -1518,7 +1575,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1518
1575
|
const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
|
|
1519
1576
|
try {
|
|
1520
1577
|
summarizeResult = await this.summarize({
|
|
1521
|
-
fullTree: fullTree
|
|
1578
|
+
fullTree: fullTree || forcedFullTree,
|
|
1522
1579
|
trackState: true,
|
|
1523
1580
|
summaryLogger: summaryNumberLogger,
|
|
1524
1581
|
runGC: this.garbageCollector.shouldRunGC,
|
|
@@ -1607,7 +1664,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1607
1664
|
}
|
|
1608
1665
|
let clientSequenceNumber;
|
|
1609
1666
|
try {
|
|
1610
|
-
clientSequenceNumber = this.submitSummaryMessage(summaryMessage);
|
|
1667
|
+
clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
|
|
1611
1668
|
}
|
|
1612
1669
|
catch (error) {
|
|
1613
1670
|
return Object.assign(Object.assign({ stage: "upload" }, uploadData), { error });
|
|
@@ -1621,6 +1678,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1621
1678
|
this.summarizerNode.clearSummary();
|
|
1622
1679
|
// Restart the delta manager
|
|
1623
1680
|
this.deltaManager.inbound.resume();
|
|
1681
|
+
if (shouldPauseInboundSignal) {
|
|
1682
|
+
this.deltaManager.inboundSignal.resume();
|
|
1683
|
+
}
|
|
1624
1684
|
}
|
|
1625
1685
|
}
|
|
1626
1686
|
hasPendingMessages() {
|
|
@@ -1666,9 +1726,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1666
1726
|
this.verifyCanSubmitOps();
|
|
1667
1727
|
// There should be no ops in detached container state!
|
|
1668
1728
|
assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
|
|
1729
|
+
const serializedContent = JSON.stringify({ type, contents });
|
|
1730
|
+
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
1731
|
+
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
1732
|
+
if (this.innerDeltaManager.readOnlyInfo.readonly) {
|
|
1672
1733
|
this.logger.sendTelemetryEvent({
|
|
1673
1734
|
eventName: "SubmitOpInReadonly",
|
|
1674
1735
|
connected: this.connected,
|
|
@@ -1676,7 +1737,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1676
1737
|
}
|
|
1677
1738
|
const message = {
|
|
1678
1739
|
contents: serializedContent,
|
|
1679
|
-
deserializedContent,
|
|
1740
|
+
deserializedContent: JSON.parse(serializedContent),
|
|
1680
1741
|
metadata,
|
|
1681
1742
|
localOpMetadata,
|
|
1682
1743
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
@@ -1704,7 +1765,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1704
1765
|
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
1705
1766
|
if (this.currentlyBatching() &&
|
|
1706
1767
|
type === ContainerMessageType.Attach &&
|
|
1707
|
-
this.
|
|
1768
|
+
this.disableAttachReorder !== true) {
|
|
1708
1769
|
this.outbox.submitAttach(message);
|
|
1709
1770
|
}
|
|
1710
1771
|
else {
|
|
@@ -1713,17 +1774,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1713
1774
|
if (!this.currentlyBatching()) {
|
|
1714
1775
|
this.flush();
|
|
1715
1776
|
}
|
|
1716
|
-
else
|
|
1717
|
-
this.
|
|
1718
|
-
// Queue a microtask to detect the end of the turn and force a flush.
|
|
1719
|
-
Promise.resolve()
|
|
1720
|
-
.then(() => {
|
|
1721
|
-
this.flushMicroTaskExists = false;
|
|
1722
|
-
this.flush();
|
|
1723
|
-
})
|
|
1724
|
-
.catch((error) => {
|
|
1725
|
-
this.closeFn(error);
|
|
1726
|
-
});
|
|
1777
|
+
else {
|
|
1778
|
+
this.scheduleFlush();
|
|
1727
1779
|
}
|
|
1728
1780
|
}
|
|
1729
1781
|
catch (error) {
|
|
@@ -1734,14 +1786,47 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1734
1786
|
this.updateDocumentDirtyState(true);
|
|
1735
1787
|
}
|
|
1736
1788
|
}
|
|
1737
|
-
|
|
1789
|
+
scheduleFlush() {
|
|
1790
|
+
if (this.flushTaskExists) {
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
this.flushTaskExists = true;
|
|
1794
|
+
const flush = () => {
|
|
1795
|
+
this.flushTaskExists = false;
|
|
1796
|
+
try {
|
|
1797
|
+
this.flush();
|
|
1798
|
+
}
|
|
1799
|
+
catch (error) {
|
|
1800
|
+
this.closeFn(error);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
switch (this.flushMode) {
|
|
1804
|
+
case FlushMode.TurnBased:
|
|
1805
|
+
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
1806
|
+
// batch at the end of the turn
|
|
1807
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1808
|
+
Promise.resolve().then(flush);
|
|
1809
|
+
break;
|
|
1810
|
+
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
1811
|
+
case FlushModeExperimental.Async:
|
|
1812
|
+
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
1813
|
+
// batch when all micro-tasks are complete.
|
|
1814
|
+
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
1815
|
+
setTimeout(flush, 0);
|
|
1816
|
+
break;
|
|
1817
|
+
default:
|
|
1818
|
+
assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
1819
|
+
break;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
1738
1823
|
this.verifyNotClosed();
|
|
1739
1824
|
assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
1740
1825
|
// System message should not be sent in the middle of the batch.
|
|
1741
1826
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
1742
1827
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
1743
1828
|
return this.context.submitSummaryFn !== undefined
|
|
1744
|
-
? this.context.submitSummaryFn(contents)
|
|
1829
|
+
? this.context.submitSummaryFn(contents, referenceSequenceNumber)
|
|
1745
1830
|
: this.context.submitFn(MessageType.Summarize, contents, false);
|
|
1746
1831
|
}
|
|
1747
1832
|
/**
|
|
@@ -1837,14 +1922,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1837
1922
|
// The call to fetch the snapshot is very expensive and not always needed.
|
|
1838
1923
|
// It should only be done by the summarizerNode, if required.
|
|
1839
1924
|
// When fetching from storage we will always get the latest version and do not use the ackHandle.
|
|
1840
|
-
const
|
|
1841
|
-
|
|
1842
|
-
eventName: "
|
|
1925
|
+
const fetchLatestSnapshot = async () => {
|
|
1926
|
+
let fetchResult = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1927
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
1843
1928
|
ackHandle,
|
|
1844
|
-
summaryRefSeq,
|
|
1845
|
-
|
|
1846
|
-
});
|
|
1847
|
-
const latestSnapshotRefSeq = await seqFromTree(fetchResult.snapshotTree, readAndParseBlob);
|
|
1929
|
+
targetSequenceNumber: summaryRefSeq,
|
|
1930
|
+
}, readAndParseBlob);
|
|
1848
1931
|
/**
|
|
1849
1932
|
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
1850
1933
|
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
@@ -1855,29 +1938,34 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1855
1938
|
* such cases, the file will be rolled back along with the ack and we will eventually reach a consistent
|
|
1856
1939
|
* state.
|
|
1857
1940
|
*/
|
|
1858
|
-
if (latestSnapshotRefSeq < summaryRefSeq) {
|
|
1859
|
-
|
|
1941
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
1942
|
+
/* before failing, let's try to retrieve the latest snapshot for that specific ackHandle */
|
|
1943
|
+
fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
1944
|
+
eventName: "RefreshLatestSummaryAckFetch",
|
|
1860
1945
|
ackHandle,
|
|
1861
|
-
summaryRefSeq,
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1946
|
+
targetSequenceNumber: summaryRefSeq,
|
|
1947
|
+
}, readAndParseBlob, ackHandle);
|
|
1948
|
+
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
1949
|
+
const error = DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
1950
|
+
ackHandle,
|
|
1951
|
+
summaryRefSeq,
|
|
1952
|
+
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
1953
|
+
});
|
|
1954
|
+
this.closeFn(error);
|
|
1955
|
+
throw error;
|
|
1956
|
+
}
|
|
1866
1957
|
}
|
|
1867
|
-
summaryLogger.sendTelemetryEvent({
|
|
1868
|
-
eventName: "LatestSummaryRetrieved",
|
|
1869
|
-
ackHandle,
|
|
1870
|
-
lastSequenceNumber: latestSnapshotRefSeq,
|
|
1871
|
-
targetSequenceNumber: summaryRefSeq,
|
|
1872
|
-
});
|
|
1873
1958
|
// In case we had to retrieve the latest snapshot and it is different than summaryRefSeq,
|
|
1874
1959
|
// wait for the delta manager to catch up before refreshing the latest Summary.
|
|
1875
|
-
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger);
|
|
1876
|
-
return
|
|
1960
|
+
await this.waitForDeltaManagerToCatchup(fetchResult.latestSnapshotRefSeq, summaryLogger);
|
|
1961
|
+
return {
|
|
1962
|
+
snapshotTree: fetchResult.snapshotTree,
|
|
1963
|
+
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
1964
|
+
};
|
|
1877
1965
|
};
|
|
1878
|
-
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq,
|
|
1966
|
+
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
1879
1967
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1880
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
1968
|
+
await this.garbageCollector.refreshLatestSummary(proposalHandle, result, readAndParseBlob);
|
|
1881
1969
|
}
|
|
1882
1970
|
/**
|
|
1883
1971
|
* Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
|
|
@@ -1886,53 +1974,54 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1886
1974
|
* @returns downloaded snapshot's reference sequence number
|
|
1887
1975
|
*/
|
|
1888
1976
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
1889
|
-
const { snapshotTree, versionId } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1890
|
-
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
1891
|
-
fetchLatest: true,
|
|
1892
|
-
});
|
|
1893
1977
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
1894
|
-
const latestSnapshotRefSeq = await
|
|
1895
|
-
|
|
1978
|
+
const { snapshotTree, versionId, latestSnapshotRefSeq } = await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
1979
|
+
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
1980
|
+
}, readAndParseBlob);
|
|
1981
|
+
const fetchLatestSnapshot = {
|
|
1982
|
+
snapshotTree,
|
|
1983
|
+
snapshotRefSeq: latestSnapshotRefSeq,
|
|
1984
|
+
};
|
|
1985
|
+
const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
1896
1986
|
// Notify the garbage collector so it can update its latest summary state.
|
|
1897
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
1987
|
+
await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
|
|
1898
1988
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
1899
1989
|
}
|
|
1900
|
-
async fetchLatestSnapshotFromStorage(logger, event) {
|
|
1990
|
+
async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
|
|
1991
|
+
return this.fetchSnapshotFromStorage(logger, event, readAndParseBlob, null /* latest */);
|
|
1992
|
+
}
|
|
1993
|
+
async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
|
|
1994
|
+
var _a;
|
|
1995
|
+
const recoveryMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummarizationRecoveryMethod");
|
|
1996
|
+
if (recoveryMethod === "restart") {
|
|
1997
|
+
const error = new GenericError("Restarting summarizer instead of refreshing");
|
|
1998
|
+
this.mc.logger.sendTelemetryEvent(Object.assign(Object.assign({}, event), { eventName: "ClosingSummarizerOnSummaryStale", codePath: event.eventName, message: "Stopping fetch from storage", versionId: versionId != null ? versionId : undefined }), error);
|
|
1999
|
+
(_a = this._summarizer) === null || _a === void 0 ? void 0 : _a.stop("latestSummaryStateStale");
|
|
2000
|
+
this.closeFn();
|
|
2001
|
+
throw error;
|
|
2002
|
+
}
|
|
1901
2003
|
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
1902
2004
|
const stats = {};
|
|
1903
2005
|
const trace = Trace.start();
|
|
1904
|
-
const versions = await this.storage.getVersions(
|
|
2006
|
+
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
|
|
1905
2007
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
1906
2008
|
stats.getVersionDuration = trace.trace().duration;
|
|
1907
2009
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
1908
2010
|
assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
1909
2011
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
2012
|
+
const latestSnapshotRefSeq = await seqFromTree(maybeSnapshot, readAndParseBlob);
|
|
2013
|
+
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
2014
|
+
stats.snapshotVersion = versions[0].id;
|
|
1910
2015
|
perfEvent.end(stats);
|
|
1911
|
-
return {
|
|
2016
|
+
return {
|
|
2017
|
+
snapshotTree: maybeSnapshot,
|
|
2018
|
+
versionId: versions[0].id,
|
|
2019
|
+
latestSnapshotRefSeq,
|
|
2020
|
+
};
|
|
1912
2021
|
});
|
|
1913
2022
|
}
|
|
1914
|
-
notifyAttaching(
|
|
1915
|
-
var _a;
|
|
1916
|
-
if ((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) {
|
|
1917
|
-
this.baseSnapshotBlobs =
|
|
1918
|
-
SerializedSnapshotStorage.serializeTreeWithBlobContents(snapshot);
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
async initializeBaseSnapshotBlobs() {
|
|
1922
|
-
var _a;
|
|
1923
|
-
if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad) ||
|
|
1924
|
-
this.attachState !== AttachState.Attached ||
|
|
1925
|
-
this.context.pendingLocalState) {
|
|
1926
|
-
return;
|
|
1927
|
-
}
|
|
1928
|
-
assert(!!this.context.baseSnapshot, 0x2e5 /* "Must have a base snapshot" */);
|
|
1929
|
-
this.baseSnapshotBlobs = await SerializedSnapshotStorage.serializeTree(this.context.baseSnapshot, this.storage);
|
|
1930
|
-
}
|
|
2023
|
+
notifyAttaching() { } // do nothing (deprecated method)
|
|
1931
2024
|
getPendingLocalState() {
|
|
1932
|
-
var _a;
|
|
1933
|
-
if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
|
|
1934
|
-
throw new UsageError("can't get state when offline load disabled");
|
|
1935
|
-
}
|
|
1936
2025
|
if (this._orderSequentiallyCalls !== 0) {
|
|
1937
2026
|
throw new UsageError("can't get state during orderSequentially");
|
|
1938
2027
|
}
|
|
@@ -1940,24 +2029,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1940
2029
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
1941
2030
|
// to close current batch.
|
|
1942
2031
|
this.flush();
|
|
1943
|
-
const previousPendingState = this.context.pendingLocalState;
|
|
1944
|
-
if (previousPendingState) {
|
|
1945
|
-
return {
|
|
1946
|
-
pending: this.pendingStateManager.getLocalState(),
|
|
1947
|
-
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
1948
|
-
snapshotBlobs: previousPendingState.snapshotBlobs,
|
|
1949
|
-
baseSnapshot: previousPendingState.baseSnapshot,
|
|
1950
|
-
savedOps: this.savedOps,
|
|
1951
|
-
};
|
|
1952
|
-
}
|
|
1953
|
-
assert(!!this.context.baseSnapshot, 0x2e6 /* "Must have a base snapshot" */);
|
|
1954
|
-
assert(!!this.baseSnapshotBlobs, 0x2e7 /* "Must serialize base snapshot blobs before getting runtime state" */);
|
|
1955
2032
|
return {
|
|
1956
2033
|
pending: this.pendingStateManager.getLocalState(),
|
|
1957
2034
|
pendingAttachmentBlobs: this.blobManager.getPendingBlobs(),
|
|
1958
|
-
snapshotBlobs: this.baseSnapshotBlobs,
|
|
1959
|
-
baseSnapshot: this.context.baseSnapshot,
|
|
1960
|
-
savedOps: this.savedOps,
|
|
1961
2035
|
};
|
|
1962
2036
|
}
|
|
1963
2037
|
/**
|
|
@@ -1986,20 +2060,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1986
2060
|
return summarizer;
|
|
1987
2061
|
};
|
|
1988
2062
|
}
|
|
1989
|
-
async processSavedOps(state) {
|
|
1990
|
-
for (const op of state.savedOps) {
|
|
1991
|
-
this.process(op, false);
|
|
1992
|
-
await this.pendingStateManager.applyStashedOpsAt(op.sequenceNumber);
|
|
1993
|
-
}
|
|
1994
|
-
// we may not have seen every sequence number (because of system ops) so apply everything once we
|
|
1995
|
-
// don't have any more saved ops
|
|
1996
|
-
await this.pendingStateManager.applyStashedOpsAt();
|
|
1997
|
-
// If it's not the case, we should take it into account when calculating dirty state.
|
|
1998
|
-
assert(this.context.attachState === AttachState.Attached, 0x3d5 /* this function is called for attached containers only */);
|
|
1999
|
-
if (!this.hasPendingMessages()) {
|
|
2000
|
-
this.updateDocumentDirtyState(false);
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
2063
|
validateSummaryHeuristicConfiguration(configuration) {
|
|
2004
2064
|
// eslint-disable-next-line no-restricted-syntax
|
|
2005
2065
|
for (const prop in configuration) {
|
|
@@ -2011,6 +2071,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2011
2071
|
throw new UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
|
|
2012
2072
|
}
|
|
2013
2073
|
}
|
|
2074
|
+
get groupedBatchingEnabled() {
|
|
2075
|
+
const killSwitch = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
|
|
2076
|
+
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
2077
|
+
}
|
|
2014
2078
|
}
|
|
2015
2079
|
/**
|
|
2016
2080
|
* Wait for a specific sequence number. Promise should resolve when we reach that number,
|