@fluidframework/container-runtime 2.13.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +71 -5
- package/CHANGELOG.md +84 -0
- package/api-report/container-runtime.legacy.alpha.api.md +38 -232
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager/blobManager.d.ts +5 -1
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +30 -13
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.d.ts +1 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.js +7 -5
- package/dist/blobManager/blobManagerSnapSum.js.map +1 -1
- package/dist/channelCollection.d.ts +23 -12
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +85 -53
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts +2 -2
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +10 -6
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerHandleContext.d.ts +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +87 -94
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +312 -226
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +7 -3
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +8 -4
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +41 -25
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +47 -29
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +6 -2
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -2
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts +1 -1
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/deltaManagerProxies.d.ts +1 -17
- package/dist/deltaManagerProxies.d.ts.map +1 -1
- package/dist/deltaManagerProxies.js.map +1 -1
- package/dist/deltaScheduler.d.ts +9 -6
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +95 -89
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +21 -7
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +48 -19
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts +11 -0
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +5 -2
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +218 -70
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +40 -13
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +6 -2
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +14 -7
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/dist/gc/gcSummaryDefinitions.d.ts +18 -6
- package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -1
- package/dist/gc/gcSummaryDefinitions.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +2 -1
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +33 -11
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +35 -17
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.d.ts +42 -13
- package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +27 -9
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/gc/index.d.ts +1 -0
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +3 -1
- package/dist/gc/index.js.map +1 -1
- package/dist/inboundBatchAggregator.d.ts +34 -0
- package/dist/inboundBatchAggregator.d.ts.map +1 -0
- package/dist/inboundBatchAggregator.js +185 -0
- package/dist/inboundBatchAggregator.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/layerCompatState.d.ts +19 -0
- package/dist/layerCompatState.d.ts.map +1 -0
- package/dist/layerCompatState.js +64 -0
- package/dist/layerCompatState.js.map +1 -0
- package/dist/legacy.d.ts +0 -4
- package/dist/messageTypes.d.ts +14 -5
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/metadata.d.ts +12 -4
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +6 -2
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +9 -3
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +3 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.d.ts +9 -3
- package/dist/opLifecycle/duplicateBatchDetector.d.ts.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.js +11 -5
- package/dist/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +3 -2
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +13 -19
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +6 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +16 -8
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +1 -2
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +9 -6
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +13 -10
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +16 -11
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +4 -4
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +17 -16
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +9 -3
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +3 -1
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/package.json +2 -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 +22 -11
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +24 -15
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +7 -0
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +8 -4
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/index.d.ts +1 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +94 -31
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +28 -16
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts +1 -0
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +7 -2
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +17 -6
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +48 -19
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +10 -5
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +26 -11
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js +1 -0
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.d.ts +6 -2
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js +13 -5
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/index.d.ts.map +1 -1
- package/dist/summary/summarizerNode/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +24 -8
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +45 -36
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +48 -16
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +13 -5
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +15 -7
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +253 -135
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +3 -4
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +10 -8
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +28 -9
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +3 -2
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +9 -3
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +22 -9
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +8 -4
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +20 -9
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.d.ts +26 -10
- package/dist/throttler.d.ts.map +1 -1
- package/dist/throttler.js +12 -4
- package/dist/throttler.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -2
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts +5 -1
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +30 -13
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.d.ts +1 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.js +7 -5
- package/lib/blobManager/blobManagerSnapSum.js.map +1 -1
- package/lib/channelCollection.d.ts +23 -12
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +88 -54
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +2 -2
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +11 -7
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.d.ts +1 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +87 -94
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +319 -228
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +7 -3
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +8 -4
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +41 -25
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +47 -29
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts +6 -2
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -2
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts +1 -1
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/deltaManagerProxies.d.ts +1 -17
- package/lib/deltaManagerProxies.d.ts.map +1 -1
- package/lib/deltaManagerProxies.js.map +1 -1
- package/lib/deltaScheduler.d.ts +9 -6
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +96 -90
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +21 -7
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +51 -20
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts +11 -0
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +4 -2
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +218 -70
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +40 -13
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +6 -2
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +14 -7
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts +18 -6
- package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -1
- package/lib/gc/gcSummaryDefinitions.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +2 -1
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +33 -11
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +38 -18
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.d.ts +42 -13
- package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js +27 -9
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/gc/index.d.ts +1 -0
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -0
- package/lib/gc/index.js.map +1 -1
- package/lib/inboundBatchAggregator.d.ts +34 -0
- package/lib/inboundBatchAggregator.d.ts.map +1 -0
- package/lib/inboundBatchAggregator.js +181 -0
- package/lib/inboundBatchAggregator.js.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/layerCompatState.d.ts +19 -0
- package/lib/layerCompatState.d.ts.map +1 -0
- package/lib/layerCompatState.js +60 -0
- package/lib/layerCompatState.js.map +1 -0
- package/lib/legacy.d.ts +0 -4
- package/lib/messageTypes.d.ts +14 -5
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/metadata.d.ts +12 -4
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js +6 -2
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +9 -3
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +3 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.d.ts +9 -3
- package/lib/opLifecycle/duplicateBatchDetector.d.ts.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.js +11 -5
- package/lib/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +3 -2
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +14 -20
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +6 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +17 -9
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +1 -2
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +10 -7
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +13 -10
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +16 -11
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +4 -4
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +17 -16
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +9 -3
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +3 -1
- 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 +22 -11
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +25 -16
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +7 -0
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +8 -4
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/index.d.ts +1 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +94 -31
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +28 -16
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts +1 -0
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +7 -2
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +17 -6
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +48 -19
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +10 -5
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +26 -11
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js +1 -0
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.d.ts +6 -2
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summarizerHeuristics.js +13 -5
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/index.d.ts.map +1 -1
- package/lib/summary/summarizerNode/index.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +24 -8
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +45 -36
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +48 -16
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +13 -5
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +15 -7
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +253 -135
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +3 -4
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +10 -8
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +28 -9
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +2 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +9 -3
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +22 -9
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +8 -4
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +20 -9
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.d.ts +26 -10
- package/lib/throttler.d.ts.map +1 -1
- package/lib/throttler.js +12 -4
- package/lib/throttler.js.map +1 -1
- package/package.json +22 -31
- package/src/batchTracker.ts +34 -36
- package/src/blobManager/blobManager.ts +54 -33
- package/src/blobManager/blobManagerSnapSum.ts +10 -10
- package/src/channelCollection.ts +108 -82
- package/src/connectionTelemetry.ts +43 -19
- package/src/containerHandleContext.ts +2 -2
- package/src/containerRuntime.ts +492 -364
- package/src/dataStore.ts +17 -9
- package/src/dataStoreContext.ts +94 -73
- package/src/dataStoreContexts.ts +17 -12
- package/src/dataStoreRegistry.ts +1 -1
- package/src/deltaManagerProxies.ts +5 -5
- package/src/deltaScheduler.ts +24 -18
- package/src/gc/garbageCollection.ts +89 -40
- package/src/gc/gcConfigs.ts +13 -5
- package/src/gc/gcDefinitions.ts +224 -70
- package/src/gc/gcHelpers.ts +22 -11
- package/src/gc/gcReferenceGraphAlgorithm.ts +1 -1
- package/src/gc/gcSummaryDefinitions.ts +18 -6
- package/src/gc/gcSummaryStateTracker.ts +7 -3
- package/src/gc/gcTelemetry.ts +73 -30
- package/src/gc/gcUnreferencedStateTracker.ts +40 -16
- package/src/gc/index.ts +1 -0
- package/src/{scheduleManager.ts → inboundBatchAggregator.ts} +55 -122
- package/src/index.ts +0 -3
- package/src/layerCompatState.ts +75 -0
- package/src/messageTypes.ts +16 -5
- package/src/metadata.ts +12 -4
- package/src/opLifecycle/README.md +43 -34
- package/src/opLifecycle/batchManager.ts +12 -6
- package/src/opLifecycle/duplicateBatchDetector.ts +12 -6
- package/src/opLifecycle/opCompressor.ts +22 -25
- package/src/opLifecycle/opDecompressor.ts +23 -11
- package/src/opLifecycle/opGroupingManager.ts +16 -11
- package/src/opLifecycle/opSplitter.ts +24 -18
- package/src/opLifecycle/outbox.ts +35 -33
- package/src/opLifecycle/remoteMessageProcessor.ts +13 -5
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +49 -26
- package/src/summary/documentSchema.ts +41 -22
- package/src/summary/index.ts +0 -3
- package/src/summary/orderedClientElection.ts +114 -49
- package/src/summary/runWhileConnectedCoordinator.ts +12 -3
- package/src/summary/runningSummarizer.ts +79 -36
- package/src/summary/summarizer.ts +51 -25
- package/src/summary/summarizerClientElection.ts +4 -2
- package/src/summary/summarizerHeuristics.ts +23 -12
- package/src/summary/summarizerNode/index.ts +1 -0
- package/src/summary/summarizerNode/summarizerNode.ts +54 -43
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +48 -16
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +25 -15
- package/src/summary/summarizerTypes.ts +253 -139
- package/src/summary/summaryCollection.ts +41 -31
- package/src/summary/summaryFormat.ts +34 -13
- package/src/summary/summaryGenerator.ts +39 -18
- package/src/summary/summaryManager.ts +36 -24
- package/src/throttler.ts +23 -11
- package/container-runtime.test-files.tar +0 -0
- package/dist/scheduleManager.d.ts +0 -28
- package/dist/scheduleManager.d.ts.map +0 -1
- package/dist/scheduleManager.js +0 -233
- package/dist/scheduleManager.js.map +0 -1
- package/lib/scheduleManager.d.ts +0 -28
- package/lib/scheduleManager.d.ts.map +0 -1
- package/lib/scheduleManager.js +0 -229
- package/lib/scheduleManager.js.map +0 -1
package/src/containerRuntime.ts
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Trace,
|
|
8
|
+
TypedEventEmitter,
|
|
9
|
+
type ILayerCompatDetails,
|
|
10
|
+
type IProvideLayerCompatDetails,
|
|
11
|
+
} from "@fluid-internal/client-utils";
|
|
7
12
|
import {
|
|
8
13
|
AttachState,
|
|
9
14
|
IAudience,
|
|
@@ -12,7 +17,6 @@ import {
|
|
|
12
17
|
type IAudienceEvents,
|
|
13
18
|
} from "@fluidframework/container-definitions";
|
|
14
19
|
import {
|
|
15
|
-
IBatchMessage,
|
|
16
20
|
IContainerContext,
|
|
17
21
|
IGetPendingLocalStateProps,
|
|
18
22
|
ILoader,
|
|
@@ -34,6 +38,7 @@ import {
|
|
|
34
38
|
ITelemetryBaseLogger,
|
|
35
39
|
} from "@fluidframework/core-interfaces";
|
|
36
40
|
import {
|
|
41
|
+
type IErrorBase,
|
|
37
42
|
IFluidHandleContext,
|
|
38
43
|
type IFluidHandleInternal,
|
|
39
44
|
IProvideFluidHandleContext,
|
|
@@ -64,7 +69,6 @@ import {
|
|
|
64
69
|
ISequencedDocumentMessage,
|
|
65
70
|
ISignalMessage,
|
|
66
71
|
type ISummaryContext,
|
|
67
|
-
type SummaryObject,
|
|
68
72
|
} from "@fluidframework/driver-definitions/internal";
|
|
69
73
|
import { readAndParse } from "@fluidframework/driver-utils/internal";
|
|
70
74
|
import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
@@ -93,6 +97,7 @@ import {
|
|
|
93
97
|
gcTreeKey,
|
|
94
98
|
IInboundSignalMessage,
|
|
95
99
|
type IRuntimeMessagesContent,
|
|
100
|
+
type ISummarizerNodeWithGC,
|
|
96
101
|
} from "@fluidframework/runtime-definitions/internal";
|
|
97
102
|
import {
|
|
98
103
|
GCDataBuilder,
|
|
@@ -142,6 +147,7 @@ import {
|
|
|
142
147
|
blobsTreeName,
|
|
143
148
|
isBlobPath,
|
|
144
149
|
loadBlobManagerLoadInfo,
|
|
150
|
+
// eslint-disable-next-line import/no-deprecated
|
|
145
151
|
type IBlobManagerLoadInfo,
|
|
146
152
|
} from "./blobManager/index.js";
|
|
147
153
|
import {
|
|
@@ -157,15 +163,20 @@ import {
|
|
|
157
163
|
DeltaManagerPendingOpsProxy,
|
|
158
164
|
DeltaManagerSummarizerProxy,
|
|
159
165
|
} from "./deltaManagerProxies.js";
|
|
166
|
+
import { DeltaScheduler } from "./deltaScheduler.js";
|
|
160
167
|
import {
|
|
168
|
+
// eslint-disable-next-line import/no-deprecated
|
|
161
169
|
GCNodeType,
|
|
162
170
|
GarbageCollector,
|
|
163
171
|
IGCRuntimeOptions,
|
|
172
|
+
// eslint-disable-next-line import/no-deprecated
|
|
164
173
|
IGCStats,
|
|
165
174
|
IGarbageCollector,
|
|
166
175
|
gcGenerationOptionName,
|
|
167
176
|
type GarbageCollectionMessage,
|
|
168
177
|
} from "./gc/index.js";
|
|
178
|
+
import { InboundBatchAggregator } from "./inboundBatchAggregator.js";
|
|
179
|
+
import { RuntimeCompatDetails, validateLoaderCompatibility } from "./layerCompatState.js";
|
|
169
180
|
import {
|
|
170
181
|
ContainerMessageType,
|
|
171
182
|
type ContainerRuntimeDocumentSchemaMessage,
|
|
@@ -199,28 +210,39 @@ import {
|
|
|
199
210
|
IPendingLocalState,
|
|
200
211
|
PendingStateManager,
|
|
201
212
|
} from "./pendingStateManager.js";
|
|
202
|
-
import { ScheduleManager } from "./scheduleManager.js";
|
|
203
213
|
import {
|
|
214
|
+
// eslint-disable-next-line import/no-deprecated
|
|
204
215
|
DocumentsSchemaController,
|
|
205
216
|
EnqueueSummarizeResult,
|
|
206
217
|
IBaseSummarizeResult,
|
|
218
|
+
// eslint-disable-next-line import/no-deprecated
|
|
207
219
|
IConnectableRuntime,
|
|
220
|
+
// eslint-disable-next-line import/no-deprecated
|
|
208
221
|
IContainerRuntimeMetadata,
|
|
222
|
+
// eslint-disable-next-line import/no-deprecated
|
|
209
223
|
ICreateContainerMetadata,
|
|
224
|
+
// eslint-disable-next-line import/no-deprecated
|
|
210
225
|
type IDocumentSchemaChangeMessage,
|
|
226
|
+
// eslint-disable-next-line import/no-deprecated
|
|
211
227
|
type IDocumentSchemaCurrent,
|
|
212
228
|
IEnqueueSummarizeOptions,
|
|
213
229
|
IGenerateSummaryTreeResult,
|
|
214
230
|
IGeneratedSummaryStats,
|
|
215
231
|
IOnDemandSummarizeOptions,
|
|
232
|
+
// eslint-disable-next-line import/no-deprecated
|
|
216
233
|
IRefreshSummaryAckOptions,
|
|
217
234
|
IRootSummarizerNodeWithGC,
|
|
235
|
+
// eslint-disable-next-line import/no-deprecated
|
|
218
236
|
ISerializedElection,
|
|
237
|
+
// eslint-disable-next-line import/no-deprecated
|
|
219
238
|
ISubmitSummaryOptions,
|
|
220
239
|
ISummarizeResults,
|
|
221
240
|
ISummarizer,
|
|
241
|
+
// eslint-disable-next-line import/no-deprecated
|
|
222
242
|
ISummarizerInternalsProvider,
|
|
243
|
+
// eslint-disable-next-line import/no-deprecated
|
|
223
244
|
ISummarizerRuntime,
|
|
245
|
+
// eslint-disable-next-line import/no-deprecated
|
|
224
246
|
ISummaryMetadataMessage,
|
|
225
247
|
IdCompressorMode,
|
|
226
248
|
OrderedClientCollection,
|
|
@@ -228,6 +250,7 @@ import {
|
|
|
228
250
|
RetriableSummaryError,
|
|
229
251
|
RunWhileConnectedCoordinator,
|
|
230
252
|
SubmitSummaryResult,
|
|
253
|
+
// eslint-disable-next-line import/no-deprecated
|
|
231
254
|
Summarizer,
|
|
232
255
|
SummarizerClientElection,
|
|
233
256
|
SummaryCollection,
|
|
@@ -243,6 +266,8 @@ import {
|
|
|
243
266
|
rootHasIsolatedChannels,
|
|
244
267
|
summarizerClientType,
|
|
245
268
|
wrapSummaryInChannelsTree,
|
|
269
|
+
// eslint-disable-next-line import/no-deprecated
|
|
270
|
+
type IDocumentSchemaFeatures,
|
|
246
271
|
} from "./summary/index.js";
|
|
247
272
|
import { Throttler, formExponentialFn } from "./throttler.js";
|
|
248
273
|
|
|
@@ -387,6 +412,12 @@ export type ISummaryConfiguration =
|
|
|
387
412
|
| ISummaryConfigurationDisableHeuristics
|
|
388
413
|
| ISummaryConfigurationHeuristics;
|
|
389
414
|
|
|
415
|
+
export function isSummariesDisabled(
|
|
416
|
+
config: ISummaryConfiguration,
|
|
417
|
+
): config is ISummaryConfigurationDisableSummarizer {
|
|
418
|
+
return config.state === "disabled";
|
|
419
|
+
}
|
|
420
|
+
|
|
390
421
|
/**
|
|
391
422
|
* @legacy
|
|
392
423
|
* @alpha
|
|
@@ -412,7 +443,7 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
412
443
|
|
|
413
444
|
nonRuntimeOpWeight: 0.1,
|
|
414
445
|
|
|
415
|
-
runtimeOpWeight: 1
|
|
446
|
+
runtimeOpWeight: 1,
|
|
416
447
|
|
|
417
448
|
nonRuntimeHeuristicThreshold: 20,
|
|
418
449
|
};
|
|
@@ -422,7 +453,9 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
422
453
|
* @alpha
|
|
423
454
|
*/
|
|
424
455
|
export interface ISummaryRuntimeOptions {
|
|
425
|
-
/**
|
|
456
|
+
/**
|
|
457
|
+
* Override summary configurations set by the server.
|
|
458
|
+
*/
|
|
426
459
|
summaryConfigOverrides?: ISummaryConfiguration;
|
|
427
460
|
|
|
428
461
|
/**
|
|
@@ -470,15 +503,7 @@ export interface IContainerRuntimeOptions {
|
|
|
470
503
|
* 3. "bypass" will skip the check entirely. This is not recommended.
|
|
471
504
|
*/
|
|
472
505
|
readonly loadSequenceNumberVerification?: "close" | "log" | "bypass";
|
|
473
|
-
|
|
474
|
-
* Sets the flush mode for the runtime. In Immediate flush mode the runtime will immediately
|
|
475
|
-
* send all operations to the driver layer, while in TurnBased the operations will be buffered
|
|
476
|
-
* and then sent them as a single batch at the end of the turn.
|
|
477
|
-
* By default, flush mode is TurnBased.
|
|
478
|
-
*
|
|
479
|
-
* @deprecated Only the default value TurnBased is supported. This option will be removed in the future.
|
|
480
|
-
*/
|
|
481
|
-
readonly flushMode?: FlushMode;
|
|
506
|
+
|
|
482
507
|
/**
|
|
483
508
|
* Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
|
|
484
509
|
*/
|
|
@@ -520,8 +545,8 @@ export interface IContainerRuntimeOptions {
|
|
|
520
545
|
* message to be sent to the service.
|
|
521
546
|
* The grouping and ungrouping of such messages is handled by the "OpGroupingManager".
|
|
522
547
|
*
|
|
523
|
-
* By default, the feature is enabled.
|
|
524
|
-
* @deprecated The ability to disable Grouped Batching is deprecated and will be removed in
|
|
548
|
+
* By default, the feature is enabled. This feature can only be disabled when compression is also disabled.
|
|
549
|
+
* @deprecated The ability to disable Grouped Batching is deprecated and will be removed in a future release. This feature is required for the proper functioning of the Fluid Framework.
|
|
525
550
|
*/
|
|
526
551
|
readonly enableGroupedBatching?: boolean;
|
|
527
552
|
|
|
@@ -564,6 +589,7 @@ export interface IContainerRuntimeOptionsInternal extends IContainerRuntimeOptio
|
|
|
564
589
|
* Error responses when requesting a deleted object will have this header set to true
|
|
565
590
|
* @legacy
|
|
566
591
|
* @alpha
|
|
592
|
+
* @deprecated This type will be moved to internal in 2.30. External usage is not necessary or supported.
|
|
567
593
|
*/
|
|
568
594
|
export const DeletedResponseHeaderKey = "wasDeleted";
|
|
569
595
|
/**
|
|
@@ -592,7 +618,9 @@ export interface RuntimeHeaderData {
|
|
|
592
618
|
allowTombstone?: boolean;
|
|
593
619
|
}
|
|
594
620
|
|
|
595
|
-
/**
|
|
621
|
+
/**
|
|
622
|
+
* Default values for Runtime Headers
|
|
623
|
+
*/
|
|
596
624
|
export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
|
|
597
625
|
wait: true,
|
|
598
626
|
viaHandle: false,
|
|
@@ -613,7 +641,7 @@ export enum CompressionAlgorithms {
|
|
|
613
641
|
* @alpha
|
|
614
642
|
*/
|
|
615
643
|
export const disabledCompressionConfig: ICompressionRuntimeOptions = {
|
|
616
|
-
minimumBatchSizeInBytes:
|
|
644
|
+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
617
645
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
618
646
|
};
|
|
619
647
|
|
|
@@ -671,9 +699,13 @@ const defaultCompressionConfig = {
|
|
|
671
699
|
|
|
672
700
|
const defaultChunkSizeInBytes = 204800;
|
|
673
701
|
|
|
674
|
-
/**
|
|
702
|
+
/**
|
|
703
|
+
* The default time to wait for pending ops to be processed during summarization
|
|
704
|
+
*/
|
|
675
705
|
export const defaultPendingOpsWaitTimeoutMs = 1000;
|
|
676
|
-
/**
|
|
706
|
+
/**
|
|
707
|
+
* The default time to delay a summarization retry attempt when there are pending ops
|
|
708
|
+
*/
|
|
677
709
|
export const defaultPendingOpsRetryDelayMs = 1000;
|
|
678
710
|
|
|
679
711
|
/**
|
|
@@ -699,15 +731,21 @@ export function isUnpackedRuntimeMessage(message: ISequencedDocumentMessage): bo
|
|
|
699
731
|
export const agentSchedulerId = "_scheduler";
|
|
700
732
|
|
|
701
733
|
// safely check navigator and get the hardware spec value
|
|
702
|
-
export function getDeviceSpec() {
|
|
734
|
+
export function getDeviceSpec(): {
|
|
735
|
+
deviceMemory?: number | undefined;
|
|
736
|
+
hardwareConcurrency?: number | undefined;
|
|
737
|
+
} {
|
|
703
738
|
try {
|
|
704
739
|
if (typeof navigator === "object" && navigator !== null) {
|
|
705
740
|
return {
|
|
741
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
|
|
706
742
|
deviceMemory: (navigator as any).deviceMemory,
|
|
707
743
|
hardwareConcurrency: navigator.hardwareConcurrency,
|
|
708
744
|
};
|
|
709
745
|
}
|
|
710
|
-
} catch {
|
|
746
|
+
} catch {
|
|
747
|
+
// Eat the error
|
|
748
|
+
}
|
|
711
749
|
return {};
|
|
712
750
|
}
|
|
713
751
|
|
|
@@ -718,10 +756,15 @@ export function getDeviceSpec() {
|
|
|
718
756
|
*/
|
|
719
757
|
export const makeLegacySendBatchFn =
|
|
720
758
|
(
|
|
721
|
-
submitFn: (
|
|
759
|
+
submitFn: (
|
|
760
|
+
type: MessageType,
|
|
761
|
+
contents: unknown,
|
|
762
|
+
batch: boolean,
|
|
763
|
+
appData?: unknown,
|
|
764
|
+
) => number,
|
|
722
765
|
deltaManager: Pick<IDeltaManager<unknown, unknown>, "flush">,
|
|
723
766
|
) =>
|
|
724
|
-
(batch: IBatch) => {
|
|
767
|
+
(batch: IBatch): number => {
|
|
725
768
|
// Default to negative one to match Container.submitBatch behavior
|
|
726
769
|
let clientSequenceNumber: number = -1;
|
|
727
770
|
for (const message of batch.messages) {
|
|
@@ -763,16 +806,18 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
763
806
|
|
|
764
807
|
// Older containers may not have the "getEntryPoint" API
|
|
765
808
|
// ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
|
|
766
|
-
if (resolvedContainer.getEntryPoint
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const response = await (resolvedContainer as any).request({
|
|
809
|
+
if (resolvedContainer.getEntryPoint === undefined) {
|
|
810
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
811
|
+
const response = (await (resolvedContainer as any).request({
|
|
770
812
|
url: `/${summarizerRequestUrl}`,
|
|
771
|
-
});
|
|
813
|
+
})) as IResponse;
|
|
772
814
|
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
773
815
|
throw responseToException(response, request);
|
|
774
816
|
}
|
|
817
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
775
818
|
fluidObject = response.value;
|
|
819
|
+
} else {
|
|
820
|
+
fluidObject = await resolvedContainer.getEntryPoint();
|
|
776
821
|
}
|
|
777
822
|
|
|
778
823
|
if (fluidObject?.ISummarizer === undefined) {
|
|
@@ -787,7 +832,11 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
787
832
|
* This allows new runtime to make documents not openable for old runtimes, one explicit document schema control is enabled.
|
|
788
833
|
* Please see addMetadataToSummary() as well
|
|
789
834
|
*/
|
|
790
|
-
function lastMessageFromMetadata(
|
|
835
|
+
function lastMessageFromMetadata(
|
|
836
|
+
// eslint-disable-next-line import/no-deprecated
|
|
837
|
+
metadata: IContainerRuntimeMetadata | undefined,
|
|
838
|
+
// eslint-disable-next-line import/no-deprecated
|
|
839
|
+
): ISummaryMetadataMessage | undefined {
|
|
791
840
|
return metadata?.documentSchema?.runtime?.explicitSchemaControl
|
|
792
841
|
? metadata?.lastMessage
|
|
793
842
|
: metadata?.message;
|
|
@@ -799,13 +848,14 @@ function lastMessageFromMetadata(metadata: IContainerRuntimeMetadata | undefined
|
|
|
799
848
|
* We only want to log this once, to avoid spamming telemetry if we are wrong and these cases are hit commonly.
|
|
800
849
|
*/
|
|
801
850
|
export let getSingleUseLegacyLogCallback = (logger: ITelemetryLoggerExt, type: string) => {
|
|
802
|
-
return (codePath: string) => {
|
|
851
|
+
return (codePath: string): void => {
|
|
803
852
|
logger.sendTelemetryEvent({
|
|
804
853
|
eventName: "LegacyMessageFormat",
|
|
805
854
|
details: { codePath, type },
|
|
806
855
|
});
|
|
807
856
|
|
|
808
857
|
// Now that we've logged, prevent future logging (globally).
|
|
858
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
809
859
|
getSingleUseLegacyLogCallback = () => () => {};
|
|
810
860
|
};
|
|
811
861
|
};
|
|
@@ -861,24 +911,27 @@ export async function loadContainerRuntime(
|
|
|
861
911
|
return ContainerRuntime.loadRuntime(params);
|
|
862
912
|
}
|
|
863
913
|
|
|
914
|
+
const defaultMaxConsecutiveReconnects = 7;
|
|
915
|
+
|
|
916
|
+
const defaultTelemetrySignalSampleCount = 100;
|
|
917
|
+
|
|
864
918
|
/**
|
|
865
919
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
866
920
|
* It will define the store level mappings.
|
|
867
921
|
*
|
|
868
|
-
* @
|
|
869
|
-
* Use the loadContainerRuntime function and interfaces IContainerRuntime / IRuntime instead.
|
|
870
|
-
*
|
|
871
|
-
* @legacy
|
|
872
|
-
* @alpha
|
|
922
|
+
* @internal
|
|
873
923
|
*/
|
|
874
924
|
export class ContainerRuntime
|
|
875
925
|
extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
876
926
|
implements
|
|
877
927
|
IContainerRuntime,
|
|
878
928
|
IRuntime,
|
|
929
|
+
// eslint-disable-next-line import/no-deprecated
|
|
879
930
|
ISummarizerRuntime,
|
|
931
|
+
// eslint-disable-next-line import/no-deprecated
|
|
880
932
|
ISummarizerInternalsProvider,
|
|
881
|
-
IProvideFluidHandleContext
|
|
933
|
+
IProvideFluidHandleContext,
|
|
934
|
+
IProvideLayerCompatDetails
|
|
882
935
|
{
|
|
883
936
|
/**
|
|
884
937
|
* Load the stores from a snapshot and returns the runtime.
|
|
@@ -902,7 +955,9 @@ export class ContainerRuntime
|
|
|
902
955
|
runtimeOptions?: IContainerRuntimeOptions; // May also include options from IContainerRuntimeOptionsInternal
|
|
903
956
|
containerScope?: FluidObject;
|
|
904
957
|
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
905
|
-
/**
|
|
958
|
+
/**
|
|
959
|
+
* @deprecated Will be removed once Loader LTS version is "2.0.0-internal.7.0.0". Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
960
|
+
*/
|
|
906
961
|
requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
|
|
907
962
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
|
|
908
963
|
}): Promise<ContainerRuntime> {
|
|
@@ -940,7 +995,9 @@ export class ContainerRuntime
|
|
|
940
995
|
gcOptions = {},
|
|
941
996
|
loadSequenceNumberVerification = "close",
|
|
942
997
|
flushMode = defaultFlushMode,
|
|
943
|
-
compressionOptions =
|
|
998
|
+
compressionOptions = runtimeOptions.enableGroupedBatching === false
|
|
999
|
+
? disabledCompressionConfig // Compression must be disabled if Grouping is disabled
|
|
1000
|
+
: defaultCompressionConfig,
|
|
944
1001
|
maxBatchSizeInBytes = defaultMaxBatchSizeInBytes,
|
|
945
1002
|
enableRuntimeIdCompressor,
|
|
946
1003
|
chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
@@ -975,7 +1032,9 @@ export class ContainerRuntime
|
|
|
975
1032
|
tryFetchBlob<ReturnType<DuplicateBatchDetector["getRecentBatchInfoForSummary"]>>(
|
|
976
1033
|
recentBatchInfoBlobName,
|
|
977
1034
|
),
|
|
1035
|
+
// eslint-disable-next-line import/no-deprecated
|
|
978
1036
|
tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
|
|
1037
|
+
// eslint-disable-next-line import/no-deprecated
|
|
979
1038
|
tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
|
|
980
1039
|
tryFetchBlob<[string, string][]>(aliasBlobName),
|
|
981
1040
|
tryFetchBlob<SerializedIdCompressorWithNoSession>(idCompressorBlobName),
|
|
@@ -992,6 +1051,7 @@ export class ContainerRuntime
|
|
|
992
1051
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
993
1052
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
994
1053
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
1054
|
+
// eslint-disable-next-line unicorn/no-lonely-if -- Separate if statements make flow easier to parse
|
|
995
1055
|
if (
|
|
996
1056
|
loadSequenceNumberVerification !== "bypass" &&
|
|
997
1057
|
runtimeSequenceNumber !== protocolSequenceNumber
|
|
@@ -1020,15 +1080,18 @@ export class ContainerRuntime
|
|
|
1020
1080
|
|
|
1021
1081
|
let desiredIdCompressorMode: IdCompressorMode;
|
|
1022
1082
|
switch (mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) {
|
|
1023
|
-
case true:
|
|
1083
|
+
case true: {
|
|
1024
1084
|
desiredIdCompressorMode = "on";
|
|
1025
1085
|
break;
|
|
1026
|
-
|
|
1086
|
+
}
|
|
1087
|
+
case false: {
|
|
1027
1088
|
desiredIdCompressorMode = undefined;
|
|
1028
1089
|
break;
|
|
1029
|
-
|
|
1090
|
+
}
|
|
1091
|
+
default: {
|
|
1030
1092
|
desiredIdCompressorMode = enableRuntimeIdCompressor;
|
|
1031
1093
|
break;
|
|
1094
|
+
}
|
|
1032
1095
|
}
|
|
1033
1096
|
|
|
1034
1097
|
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
@@ -1066,7 +1129,7 @@ export class ContainerRuntime
|
|
|
1066
1129
|
idCompressorMode = desiredIdCompressorMode;
|
|
1067
1130
|
}
|
|
1068
1131
|
|
|
1069
|
-
const createIdCompressorFn = async () => {
|
|
1132
|
+
const createIdCompressorFn = async (): Promise<IIdCompressor & IIdCompressorCore> => {
|
|
1070
1133
|
const { createIdCompressor, deserializeIdCompressor, createSessionId } = await import(
|
|
1071
1134
|
"@fluidframework/id-compressor/internal"
|
|
1072
1135
|
);
|
|
@@ -1092,21 +1155,22 @@ export class ContainerRuntime
|
|
|
1092
1155
|
pendingLocalState.pendingIdCompressorState,
|
|
1093
1156
|
compressorLogger,
|
|
1094
1157
|
);
|
|
1095
|
-
} else if (serializedIdCompressor
|
|
1158
|
+
} else if (serializedIdCompressor === undefined) {
|
|
1159
|
+
return createIdCompressor(compressorLogger);
|
|
1160
|
+
} else {
|
|
1096
1161
|
return deserializeIdCompressor(
|
|
1097
1162
|
serializedIdCompressor,
|
|
1098
1163
|
createSessionId(),
|
|
1099
1164
|
compressorLogger,
|
|
1100
1165
|
);
|
|
1101
|
-
} else {
|
|
1102
|
-
return createIdCompressor(compressorLogger);
|
|
1103
1166
|
}
|
|
1104
1167
|
};
|
|
1105
1168
|
|
|
1106
1169
|
const compressionLz4 =
|
|
1107
|
-
compressionOptions.minimumBatchSizeInBytes !==
|
|
1170
|
+
compressionOptions.minimumBatchSizeInBytes !== Number.POSITIVE_INFINITY &&
|
|
1108
1171
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
1109
1172
|
|
|
1173
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1110
1174
|
const documentSchemaController = new DocumentsSchemaController(
|
|
1111
1175
|
existing,
|
|
1112
1176
|
protocolSequenceNumber,
|
|
@@ -1123,6 +1187,10 @@ export class ContainerRuntime
|
|
|
1123
1187
|
},
|
|
1124
1188
|
);
|
|
1125
1189
|
|
|
1190
|
+
if (compressionLz4 && !enableGroupedBatching) {
|
|
1191
|
+
throw new UsageError("If compression is enabled, op grouping must be enabled too");
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1126
1194
|
const featureGatesForTelemetry: Record<string, boolean | number | undefined> = {};
|
|
1127
1195
|
|
|
1128
1196
|
// Make sure we've got all the options including internal ones
|
|
@@ -1170,7 +1238,7 @@ export class ContainerRuntime
|
|
|
1170
1238
|
runtime.setConnectionStateCore(true, runtime.delayConnectClientId);
|
|
1171
1239
|
}
|
|
1172
1240
|
},
|
|
1173
|
-
(error) => runtime.closeFn(error),
|
|
1241
|
+
(error: IErrorBase) => runtime.closeFn(error),
|
|
1174
1242
|
);
|
|
1175
1243
|
|
|
1176
1244
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
@@ -1183,7 +1251,7 @@ export class ContainerRuntime
|
|
|
1183
1251
|
return runtime;
|
|
1184
1252
|
}
|
|
1185
1253
|
|
|
1186
|
-
public readonly options: Record<string | number,
|
|
1254
|
+
public readonly options: Record<string | number, unknown>;
|
|
1187
1255
|
private imminentClosure: boolean = false;
|
|
1188
1256
|
|
|
1189
1257
|
private readonly _getClientId: () => string | undefined;
|
|
@@ -1197,22 +1265,10 @@ export class ContainerRuntime
|
|
|
1197
1265
|
return this._storage;
|
|
1198
1266
|
}
|
|
1199
1267
|
|
|
1200
|
-
public get containerRuntime() {
|
|
1268
|
+
public get containerRuntime(): ContainerRuntime {
|
|
1201
1269
|
return this;
|
|
1202
1270
|
}
|
|
1203
1271
|
|
|
1204
|
-
private readonly submitFn: (
|
|
1205
|
-
type: MessageType,
|
|
1206
|
-
contents: any,
|
|
1207
|
-
batch: boolean,
|
|
1208
|
-
appData?: any,
|
|
1209
|
-
) => number;
|
|
1210
|
-
/**
|
|
1211
|
-
* Although current IContainerContext guarantees submitBatchFn, it is not available on older loaders.
|
|
1212
|
-
*/
|
|
1213
|
-
private readonly submitBatchFn:
|
|
1214
|
-
| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)
|
|
1215
|
-
| undefined;
|
|
1216
1272
|
private readonly submitSummaryFn: (
|
|
1217
1273
|
summaryOp: ISummaryContent,
|
|
1218
1274
|
referenceSequenceNumber?: number,
|
|
@@ -1249,9 +1305,15 @@ export class ContainerRuntime
|
|
|
1249
1305
|
* has to deal with compressed ops as other clients might send them.
|
|
1250
1306
|
* And in reverse, session schema can have compression Off, but feature gates / runtime options want it On.
|
|
1251
1307
|
* In such case it will be off in session schema, however this client will propose change to schema, and once / if
|
|
1252
|
-
* this op
|
|
1308
|
+
* this op roundtrips, compression will be On. Client can't send compressed ops until it's change in schema.
|
|
1253
1309
|
*/
|
|
1254
|
-
public get sessionSchema() {
|
|
1310
|
+
public get sessionSchema(): {
|
|
1311
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1312
|
+
[P in keyof IDocumentSchemaFeatures]?: IDocumentSchemaFeatures[P] extends boolean
|
|
1313
|
+
? true
|
|
1314
|
+
: // eslint-disable-next-line import/no-deprecated
|
|
1315
|
+
IDocumentSchemaFeatures[P];
|
|
1316
|
+
} {
|
|
1255
1317
|
return this.documentsSchemaController.sessionSchema.runtime;
|
|
1256
1318
|
}
|
|
1257
1319
|
|
|
@@ -1267,18 +1329,15 @@ export class ContainerRuntime
|
|
|
1267
1329
|
// In such case we have to process all ops, including those marked with savedOp === true.
|
|
1268
1330
|
private readonly skipSavedCompressorOps: boolean;
|
|
1269
1331
|
|
|
1270
|
-
public get idCompressorMode() {
|
|
1271
|
-
return this.sessionSchema.idCompressorMode;
|
|
1272
|
-
}
|
|
1273
1332
|
/**
|
|
1274
|
-
*
|
|
1333
|
+
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor}
|
|
1275
1334
|
*/
|
|
1276
|
-
public get idCompressor() {
|
|
1335
|
+
public get idCompressor(): (IIdCompressor & IIdCompressorCore) | undefined {
|
|
1277
1336
|
// Expose ID Compressor only if it's On from the start.
|
|
1278
1337
|
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
1279
1338
|
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
1280
1339
|
// to reason over such things as session ID space.
|
|
1281
|
-
if (this.idCompressorMode === "on") {
|
|
1340
|
+
if (this.sessionSchema.idCompressorMode === "on") {
|
|
1282
1341
|
assert(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
1283
1342
|
return this._idCompressor;
|
|
1284
1343
|
}
|
|
@@ -1286,14 +1345,14 @@ export class ContainerRuntime
|
|
|
1286
1345
|
|
|
1287
1346
|
/**
|
|
1288
1347
|
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
1289
|
-
* this.idCompressorMode === "delayed" mode
|
|
1348
|
+
* this.sessionSchema.idCompressorMode === "delayed" mode
|
|
1290
1349
|
*/
|
|
1291
1350
|
protected _loadIdCompressor: Promise<void> | undefined;
|
|
1292
1351
|
|
|
1293
1352
|
/**
|
|
1294
|
-
*
|
|
1353
|
+
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.generateDocumentUniqueId}
|
|
1295
1354
|
*/
|
|
1296
|
-
public generateDocumentUniqueId() {
|
|
1355
|
+
public generateDocumentUniqueId(): string | number {
|
|
1297
1356
|
return this._idCompressor?.generateDocumentUniqueId() ?? uuid();
|
|
1298
1357
|
}
|
|
1299
1358
|
|
|
@@ -1330,14 +1389,10 @@ export class ContainerRuntime
|
|
|
1330
1389
|
* do not create it (see SummarizerClientElection.clientDetailsPermitElection() for details)
|
|
1331
1390
|
*/
|
|
1332
1391
|
private readonly summaryManager?: SummaryManager;
|
|
1333
|
-
private readonly summaryCollection: SummaryCollection;
|
|
1334
1392
|
|
|
1335
1393
|
private readonly summarizerNode: IRootSummarizerNodeWithGC;
|
|
1336
1394
|
|
|
1337
|
-
private readonly logger: ITelemetryLoggerExt;
|
|
1338
|
-
|
|
1339
1395
|
private readonly maxConsecutiveReconnects: number;
|
|
1340
|
-
private readonly defaultMaxConsecutiveReconnects = 7;
|
|
1341
1396
|
|
|
1342
1397
|
private _orderSequentiallyCalls: number = 0;
|
|
1343
1398
|
private readonly _flushMode: FlushMode;
|
|
@@ -1377,22 +1432,22 @@ export class ContainerRuntime
|
|
|
1377
1432
|
return this._connected;
|
|
1378
1433
|
}
|
|
1379
1434
|
|
|
1380
|
-
/**
|
|
1435
|
+
/**
|
|
1436
|
+
* clientId of parent (non-summarizing) container that owns summarizer container
|
|
1437
|
+
*/
|
|
1381
1438
|
public get summarizerClientId(): string | undefined {
|
|
1382
1439
|
return this.summarizerClientElection?.electedClientId;
|
|
1383
1440
|
}
|
|
1384
1441
|
|
|
1385
1442
|
private _disposed = false;
|
|
1386
|
-
public get disposed() {
|
|
1443
|
+
public get disposed(): boolean {
|
|
1387
1444
|
return this._disposed;
|
|
1388
1445
|
}
|
|
1389
1446
|
|
|
1390
1447
|
private dirtyContainer: boolean;
|
|
1391
1448
|
private emitDirtyDocumentEvent = true;
|
|
1392
|
-
private readonly disableAttachReorder: boolean | undefined;
|
|
1393
1449
|
private readonly useDeltaManagerOpsProxy: boolean;
|
|
1394
1450
|
private readonly closeSummarizerDelayMs: number;
|
|
1395
|
-
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
1396
1451
|
private readonly _signalTracking: IPerfSignalReport = {
|
|
1397
1452
|
totalSignalsSentInLatencyWindow: 0,
|
|
1398
1453
|
signalsLost: 0,
|
|
@@ -1410,8 +1465,10 @@ export class ContainerRuntime
|
|
|
1410
1465
|
* It is the main entry point for summary work.
|
|
1411
1466
|
* It is created only by summarizing container (i.e. one with clientType === "summarizer")
|
|
1412
1467
|
*/
|
|
1468
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1413
1469
|
private readonly _summarizer?: Summarizer;
|
|
1414
|
-
private readonly
|
|
1470
|
+
private readonly deltaScheduler: DeltaScheduler;
|
|
1471
|
+
private readonly inboundBatchAggregator: InboundBatchAggregator;
|
|
1415
1472
|
private readonly blobManager: BlobManager;
|
|
1416
1473
|
private readonly pendingStateManager: PendingStateManager;
|
|
1417
1474
|
private readonly duplicateBatchDetector: DuplicateBatchDetector | undefined;
|
|
@@ -1421,38 +1478,15 @@ export class ContainerRuntime
|
|
|
1421
1478
|
private readonly channelCollection: ChannelCollection;
|
|
1422
1479
|
private readonly remoteMessageProcessor: RemoteMessageProcessor;
|
|
1423
1480
|
|
|
1424
|
-
/**
|
|
1481
|
+
/**
|
|
1482
|
+
* The last message processed at the time of the last summary.
|
|
1483
|
+
*/
|
|
1484
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1425
1485
|
private messageAtLastSummary: ISummaryMetadataMessage | undefined;
|
|
1426
1486
|
|
|
1427
|
-
private get summarizer(): Summarizer {
|
|
1428
|
-
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
1429
|
-
return this._summarizer;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
1487
|
private readonly summariesDisabled: boolean;
|
|
1433
|
-
private isSummariesDisabled(): boolean {
|
|
1434
|
-
return this.summaryConfiguration.state === "disabled";
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
private readonly maxOpsSinceLastSummary: number;
|
|
1438
|
-
private getMaxOpsSinceLastSummary(): number {
|
|
1439
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
1440
|
-
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
1441
|
-
: 0;
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
private readonly initialSummarizerDelayMs: number;
|
|
1445
|
-
private getInitialSummarizerDelayMs(): number {
|
|
1446
|
-
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
1447
|
-
// to ISummaryConfiguration in 0.60.
|
|
1448
|
-
if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
|
|
1449
|
-
return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
|
|
1450
|
-
}
|
|
1451
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
1452
|
-
? this.summaryConfiguration.initialSummarizerDelayMs
|
|
1453
|
-
: 0;
|
|
1454
|
-
}
|
|
1455
1488
|
|
|
1489
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1456
1490
|
private readonly createContainerMetadata: ICreateContainerMetadata;
|
|
1457
1491
|
/**
|
|
1458
1492
|
* The summary number of the next summary that will be generated for this container. This is incremented every time
|
|
@@ -1484,11 +1518,6 @@ export class ContainerRuntime
|
|
|
1484
1518
|
*/
|
|
1485
1519
|
private readonly telemetryDocumentId: string;
|
|
1486
1520
|
|
|
1487
|
-
/**
|
|
1488
|
-
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1489
|
-
*/
|
|
1490
|
-
private readonly isSummarizerClient: boolean;
|
|
1491
|
-
|
|
1492
1521
|
/**
|
|
1493
1522
|
* The id of the version used to initially load this runtime, or undefined if it's newly created.
|
|
1494
1523
|
*/
|
|
@@ -1509,30 +1538,30 @@ export class ContainerRuntime
|
|
|
1509
1538
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
1510
1539
|
});
|
|
1511
1540
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
private readonly runtimeOptions: Readonly<Required<IContainerRuntimeOptionsInternal>>;
|
|
1541
|
+
public get ILayerCompatDetails(): ILayerCompatDetails {
|
|
1542
|
+
return RuntimeCompatDetails;
|
|
1543
|
+
}
|
|
1516
1544
|
|
|
1517
1545
|
/***/
|
|
1518
1546
|
protected constructor(
|
|
1519
1547
|
context: IContainerContext,
|
|
1520
1548
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1549
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1521
1550
|
private readonly metadata: IContainerRuntimeMetadata | undefined,
|
|
1551
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1522
1552
|
electedSummarizerData: ISerializedElection | undefined,
|
|
1523
1553
|
chunks: [string, string[]][],
|
|
1524
1554
|
dataStoreAliasMap: [string, string][],
|
|
1525
|
-
|
|
1526
|
-
Required<Omit<IContainerRuntimeOptions, "flushMode" | "enableGroupedBatching">> &
|
|
1527
|
-
IContainerRuntimeOptions // Let flushMode and enabledGroupedBatching be optional now since they're soon to be removed
|
|
1528
|
-
>,
|
|
1555
|
+
baseRuntimeOptions: Readonly<Required<IContainerRuntimeOptions>>,
|
|
1529
1556
|
private readonly containerScope: FluidObject,
|
|
1530
1557
|
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
1531
1558
|
public readonly baseLogger: ITelemetryBaseLogger,
|
|
1532
1559
|
existing: boolean,
|
|
1560
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1533
1561
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1534
1562
|
private readonly _storage: IDocumentStorageService,
|
|
1535
1563
|
private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
|
|
1564
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1536
1565
|
private readonly documentsSchemaController: DocumentsSchemaController,
|
|
1537
1566
|
featureGatesForTelemetry: Record<string, boolean | number | undefined>,
|
|
1538
1567
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
@@ -1540,11 +1569,12 @@ export class ContainerRuntime
|
|
|
1540
1569
|
request: IRequest,
|
|
1541
1570
|
runtime: IContainerRuntime,
|
|
1542
1571
|
) => Promise<IResponse>,
|
|
1543
|
-
|
|
1572
|
+
// eslint-disable-next-line unicorn/no-object-as-default-parameter
|
|
1573
|
+
summaryConfiguration: ISummaryConfiguration = {
|
|
1544
1574
|
// the defaults
|
|
1545
1575
|
...DefaultSummaryConfiguration,
|
|
1546
1576
|
// the runtime configuration overrides
|
|
1547
|
-
...
|
|
1577
|
+
...baseRuntimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1548
1578
|
},
|
|
1549
1579
|
recentBatchInfo?: [number, string][],
|
|
1550
1580
|
) {
|
|
@@ -1570,15 +1600,19 @@ export class ContainerRuntime
|
|
|
1570
1600
|
snapshotWithContents,
|
|
1571
1601
|
} = context;
|
|
1572
1602
|
|
|
1603
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1604
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
1605
|
+
|
|
1606
|
+
const maybeLoaderCompatDetails = context as FluidObject<ILayerCompatDetails>;
|
|
1607
|
+
validateLoaderCompatibility(maybeLoaderCompatDetails.ILayerCompatDetails, this.disposeFn);
|
|
1608
|
+
|
|
1573
1609
|
// Backfill in defaults for the internal runtimeOptions, since they may not be present on the provided runtimeOptions object
|
|
1574
|
-
|
|
1610
|
+
const runtimeOptions = {
|
|
1575
1611
|
flushMode: defaultFlushMode,
|
|
1576
|
-
|
|
1577
|
-
...runtimeOptions,
|
|
1612
|
+
...baseRuntimeOptions,
|
|
1578
1613
|
};
|
|
1579
|
-
this.logger = createChildLogger({ logger: this.baseLogger });
|
|
1580
1614
|
this.mc = createChildMonitoringContext({
|
|
1581
|
-
logger: this.
|
|
1615
|
+
logger: this.baseLogger,
|
|
1582
1616
|
namespace: "ContainerRuntime",
|
|
1583
1617
|
});
|
|
1584
1618
|
|
|
@@ -1598,20 +1632,24 @@ export class ContainerRuntime
|
|
|
1598
1632
|
|
|
1599
1633
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
1600
1634
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
1601
|
-
this
|
|
1602
|
-
this.
|
|
1603
|
-
|
|
1635
|
+
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
1636
|
+
this.submitSummaryFn =
|
|
1637
|
+
submitSummaryFn ??
|
|
1638
|
+
((summaryOp, refseq) => submitFn(MessageType.Summarize, summaryOp, false));
|
|
1604
1639
|
this.submitSignalFn = submitSignalFn;
|
|
1605
1640
|
|
|
1606
1641
|
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
1607
1642
|
// Values are generally expected to be set from the runtime side.
|
|
1608
1643
|
this.options = options ?? {};
|
|
1609
1644
|
this.clientDetails = clientDetails;
|
|
1610
|
-
|
|
1645
|
+
const isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1611
1646
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
1647
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1612
1648
|
this._getClientId = () => context.clientId;
|
|
1649
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1613
1650
|
this._getAttachState = () => context.attachState;
|
|
1614
1651
|
this.getAbsoluteUrl = async (relativeUrl: string) => {
|
|
1652
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1615
1653
|
if (context.getAbsoluteUrl === undefined) {
|
|
1616
1654
|
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
1617
1655
|
}
|
|
@@ -1625,10 +1663,8 @@ export class ContainerRuntime
|
|
|
1625
1663
|
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
1626
1664
|
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
1627
1665
|
|
|
1628
|
-
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1629
|
-
this.disposeFn = disposeFn ?? closeFn;
|
|
1630
1666
|
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
1631
|
-
this.closeFn =
|
|
1667
|
+
this.closeFn = isSummarizerClient ? this.disposeFn : closeFn;
|
|
1632
1668
|
|
|
1633
1669
|
let loadSummaryNumber: number;
|
|
1634
1670
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
@@ -1660,31 +1696,23 @@ export class ContainerRuntime
|
|
|
1660
1696
|
eventName: "GCFeatureMatrix",
|
|
1661
1697
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
1662
1698
|
inputs: JSON.stringify({
|
|
1663
|
-
|
|
1699
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1700
|
+
gcOptions_gcGeneration: runtimeOptions.gcOptions[gcGenerationOptionName],
|
|
1664
1701
|
}),
|
|
1665
1702
|
});
|
|
1666
1703
|
|
|
1667
1704
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
|
|
1668
1705
|
|
|
1669
|
-
this.disableAttachReorder = this.mc.config.getBoolean(
|
|
1670
|
-
"Fluid.ContainerRuntime.disableAttachOpReorder",
|
|
1671
|
-
);
|
|
1672
|
-
|
|
1673
1706
|
const opGroupingManager = new OpGroupingManager(
|
|
1674
1707
|
{
|
|
1675
1708
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1676
|
-
opCountThreshold:
|
|
1677
|
-
this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
1678
|
-
reentrantBatchGroupingEnabled:
|
|
1679
|
-
this.mc.config.getBoolean("Fluid.ContainerRuntime.GroupedBatchingReentrancy") ??
|
|
1680
|
-
true,
|
|
1681
1709
|
},
|
|
1682
1710
|
this.mc.logger,
|
|
1683
1711
|
);
|
|
1684
1712
|
|
|
1685
1713
|
const opSplitter = new OpSplitter(
|
|
1686
1714
|
chunks,
|
|
1687
|
-
|
|
1715
|
+
submitBatchFn,
|
|
1688
1716
|
runtimeOptions.chunkSizeInBytes,
|
|
1689
1717
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1690
1718
|
this.mc.logger,
|
|
@@ -1707,7 +1735,7 @@ export class ContainerRuntime
|
|
|
1707
1735
|
isAttached: () => this.attachState !== AttachState.Detached,
|
|
1708
1736
|
},
|
|
1709
1737
|
pendingRuntimeState?.pending,
|
|
1710
|
-
this.
|
|
1738
|
+
this.baseLogger,
|
|
1711
1739
|
);
|
|
1712
1740
|
|
|
1713
1741
|
let outerDeltaManager: IDeltaManagerFull;
|
|
@@ -1733,28 +1761,42 @@ export class ContainerRuntime
|
|
|
1733
1761
|
|
|
1734
1762
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
1735
1763
|
|
|
1736
|
-
if (
|
|
1737
|
-
this.validateSummaryHeuristicConfiguration(
|
|
1764
|
+
if (summaryConfiguration.state === "enabled") {
|
|
1765
|
+
this.validateSummaryHeuristicConfiguration(summaryConfiguration);
|
|
1738
1766
|
}
|
|
1739
1767
|
|
|
1740
|
-
this.summariesDisabled =
|
|
1741
|
-
|
|
1742
|
-
|
|
1768
|
+
this.summariesDisabled = isSummariesDisabled(summaryConfiguration);
|
|
1769
|
+
const { maxOpsSinceLastSummary = 0, initialSummarizerDelayMs = 0 } = isSummariesDisabled(
|
|
1770
|
+
summaryConfiguration,
|
|
1771
|
+
)
|
|
1772
|
+
? {}
|
|
1773
|
+
: {
|
|
1774
|
+
...summaryConfiguration,
|
|
1775
|
+
initialSummarizerDelayMs:
|
|
1776
|
+
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
1777
|
+
// to ISummaryConfiguration in 0.60.
|
|
1778
|
+
runtimeOptions.summaryOptions.initialSummarizerDelayMs ??
|
|
1779
|
+
summaryConfiguration.initialSummarizerDelayMs,
|
|
1780
|
+
};
|
|
1743
1781
|
|
|
1744
1782
|
this.maxConsecutiveReconnects =
|
|
1745
|
-
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
1746
|
-
|
|
1747
|
-
|
|
1783
|
+
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ?? defaultMaxConsecutiveReconnects;
|
|
1784
|
+
|
|
1785
|
+
// If the context has ILayerCompatDetails, it supports referenceSequenceNumbers since that features
|
|
1786
|
+
// predates ILayerCompatDetails.
|
|
1787
|
+
const referenceSequenceNumbersSupported =
|
|
1788
|
+
maybeLoaderCompatDetails.ILayerCompatDetails === undefined
|
|
1789
|
+
? supportedFeatures?.get("referenceSequenceNumbers") === true
|
|
1790
|
+
: true;
|
|
1748
1791
|
if (
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
supportedFeatures?.get("referenceSequenceNumbers") !== true
|
|
1792
|
+
runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
|
|
1793
|
+
!referenceSequenceNumbersSupported
|
|
1752
1794
|
) {
|
|
1753
1795
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
1754
1796
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
1755
1797
|
this._flushMode = FlushMode.TurnBased;
|
|
1756
1798
|
} else {
|
|
1757
|
-
this._flushMode =
|
|
1799
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
1758
1800
|
}
|
|
1759
1801
|
this.offlineEnabled =
|
|
1760
1802
|
this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ?? false;
|
|
@@ -1772,6 +1814,7 @@ export class ContainerRuntime
|
|
|
1772
1814
|
this.duplicateBatchDetector = new DuplicateBatchDetector(recentBatchInfo);
|
|
1773
1815
|
}
|
|
1774
1816
|
|
|
1817
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1775
1818
|
if (context.attachState === AttachState.Attached) {
|
|
1776
1819
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1777
1820
|
if (
|
|
@@ -1787,13 +1830,13 @@ export class ContainerRuntime
|
|
|
1787
1830
|
|
|
1788
1831
|
this.garbageCollector = GarbageCollector.create({
|
|
1789
1832
|
runtime: this,
|
|
1790
|
-
gcOptions:
|
|
1833
|
+
gcOptions: runtimeOptions.gcOptions,
|
|
1791
1834
|
baseSnapshot,
|
|
1792
1835
|
baseLogger: this.mc.logger,
|
|
1793
1836
|
existing,
|
|
1794
1837
|
metadata,
|
|
1795
1838
|
createContainerMetadata: this.createContainerMetadata,
|
|
1796
|
-
isSummarizerClient
|
|
1839
|
+
isSummarizerClient,
|
|
1797
1840
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1798
1841
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1799
1842
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
@@ -1810,7 +1853,7 @@ export class ContainerRuntime
|
|
|
1810
1853
|
? undefined
|
|
1811
1854
|
: loadedFromSequenceNumber;
|
|
1812
1855
|
this.summarizerNode = createRootSummarizerNodeWithGC(
|
|
1813
|
-
createChildLogger({ logger: this.
|
|
1856
|
+
createChildLogger({ logger: this.baseLogger, namespace: "SummarizerNode" }),
|
|
1814
1857
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
1815
1858
|
async (fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext) =>
|
|
1816
1859
|
this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
@@ -1902,23 +1945,28 @@ export class ContainerRuntime
|
|
|
1902
1945
|
closeContainer: (error?: ICriticalContainerError) => this.closeFn(error),
|
|
1903
1946
|
});
|
|
1904
1947
|
|
|
1905
|
-
this.
|
|
1948
|
+
this.deltaScheduler = new DeltaScheduler(
|
|
1906
1949
|
this.innerDeltaManager,
|
|
1907
1950
|
this,
|
|
1951
|
+
createChildLogger({ logger: this.baseLogger, namespace: "DeltaScheduler" }),
|
|
1952
|
+
);
|
|
1953
|
+
|
|
1954
|
+
this.inboundBatchAggregator = new InboundBatchAggregator(
|
|
1955
|
+
this.innerDeltaManager,
|
|
1908
1956
|
() => this.clientId,
|
|
1909
|
-
createChildLogger({ logger: this.
|
|
1957
|
+
createChildLogger({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }),
|
|
1910
1958
|
);
|
|
1911
1959
|
|
|
1912
1960
|
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1913
1961
|
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1914
1962
|
);
|
|
1915
1963
|
|
|
1916
|
-
const legacySendBatchFn = makeLegacySendBatchFn(
|
|
1964
|
+
const legacySendBatchFn = makeLegacySendBatchFn(submitFn, this.innerDeltaManager);
|
|
1917
1965
|
|
|
1918
1966
|
this.outbox = new Outbox({
|
|
1919
1967
|
shouldSend: () => this.canSendOps(),
|
|
1920
1968
|
pendingStateManager: this.pendingStateManager,
|
|
1921
|
-
submitBatchFn
|
|
1969
|
+
submitBatchFn,
|
|
1922
1970
|
legacySendBatchFn,
|
|
1923
1971
|
compressor: new OpCompressor(this.mc.logger),
|
|
1924
1972
|
splitter: opSplitter,
|
|
@@ -1975,7 +2023,7 @@ export class ContainerRuntime
|
|
|
1975
2023
|
);
|
|
1976
2024
|
this.closeSummarizerDelayMs =
|
|
1977
2025
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
1978
|
-
|
|
2026
|
+
const summaryCollection = new SummaryCollection(this.deltaManager, this.baseLogger);
|
|
1979
2027
|
|
|
1980
2028
|
this.dirtyContainer =
|
|
1981
2029
|
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
@@ -1985,7 +2033,7 @@ export class ContainerRuntime
|
|
|
1985
2033
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
1986
2034
|
} else {
|
|
1987
2035
|
const orderedClientLogger = createChildLogger({
|
|
1988
|
-
logger: this.
|
|
2036
|
+
logger: this.baseLogger,
|
|
1989
2037
|
namespace: "OrderedClientElection",
|
|
1990
2038
|
});
|
|
1991
2039
|
const orderedClientCollection = new OrderedClientCollection(
|
|
@@ -2005,18 +2053,20 @@ export class ContainerRuntime
|
|
|
2005
2053
|
|
|
2006
2054
|
this.summarizerClientElection = new SummarizerClientElection(
|
|
2007
2055
|
orderedClientLogger,
|
|
2008
|
-
|
|
2056
|
+
summaryCollection,
|
|
2009
2057
|
orderedClientElectionForSummarizer,
|
|
2010
|
-
|
|
2058
|
+
maxOpsSinceLastSummary,
|
|
2011
2059
|
);
|
|
2012
2060
|
|
|
2013
|
-
if (
|
|
2061
|
+
if (isSummarizerClient) {
|
|
2062
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2014
2063
|
this._summarizer = new Summarizer(
|
|
2015
2064
|
this /* ISummarizerRuntime */,
|
|
2016
|
-
() =>
|
|
2065
|
+
() => summaryConfiguration,
|
|
2017
2066
|
this /* ISummarizerInternalsProvider */,
|
|
2018
2067
|
this.handleContext,
|
|
2019
|
-
|
|
2068
|
+
summaryCollection,
|
|
2069
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2020
2070
|
async (runtime: IConnectableRuntime) =>
|
|
2021
2071
|
RunWhileConnectedCoordinator.create(
|
|
2022
2072
|
runtime,
|
|
@@ -2028,32 +2078,32 @@ export class ContainerRuntime
|
|
|
2028
2078
|
} else if (SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
2029
2079
|
// Only create a SummaryManager and SummarizerClientElection
|
|
2030
2080
|
// if summaries are enabled and we are not the summarizer client.
|
|
2031
|
-
const defaultAction = () => {
|
|
2032
|
-
if (
|
|
2081
|
+
const defaultAction = (): void => {
|
|
2082
|
+
if (summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
2033
2083
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
2034
2084
|
// unregister default to no log on every op after falling behind
|
|
2035
2085
|
// and register summary ack handler to re-register this handler
|
|
2036
2086
|
// after successful summary
|
|
2037
|
-
|
|
2087
|
+
summaryCollection.once(MessageType.SummaryAck, () => {
|
|
2038
2088
|
this.mc.logger.sendTelemetryEvent({
|
|
2039
2089
|
eventName: "SummaryStatus:CaughtUp",
|
|
2040
2090
|
});
|
|
2041
2091
|
// we've caught up, so re-register the default action to monitor for
|
|
2042
2092
|
// falling behind, and unregister ourself
|
|
2043
|
-
|
|
2093
|
+
summaryCollection.on("default", defaultAction);
|
|
2044
2094
|
});
|
|
2045
|
-
|
|
2095
|
+
summaryCollection.off("default", defaultAction);
|
|
2046
2096
|
}
|
|
2047
2097
|
};
|
|
2048
2098
|
|
|
2049
|
-
|
|
2099
|
+
summaryCollection.on("default", defaultAction);
|
|
2050
2100
|
|
|
2051
2101
|
// Create the SummaryManager and mark the initial state
|
|
2052
2102
|
this.summaryManager = new SummaryManager(
|
|
2053
2103
|
this.summarizerClientElection,
|
|
2054
2104
|
this, // IConnectedState
|
|
2055
|
-
|
|
2056
|
-
this.
|
|
2105
|
+
summaryCollection,
|
|
2106
|
+
this.baseLogger,
|
|
2057
2107
|
this.formCreateSummarizerFn(loader),
|
|
2058
2108
|
new Throttler(
|
|
2059
2109
|
60 * 1000, // 60 sec delay window
|
|
@@ -2062,28 +2112,29 @@ export class ContainerRuntime
|
|
|
2062
2112
|
formExponentialFn({ coefficient: 20, initialDelay: 0 }),
|
|
2063
2113
|
),
|
|
2064
2114
|
{
|
|
2065
|
-
initialDelayMs:
|
|
2115
|
+
initialDelayMs: initialSummarizerDelayMs,
|
|
2066
2116
|
},
|
|
2067
2117
|
);
|
|
2068
2118
|
// Forward events from SummaryManager
|
|
2069
|
-
[
|
|
2119
|
+
for (const eventName of [
|
|
2070
2120
|
"summarize",
|
|
2071
2121
|
"summarizeAllAttemptsFailed",
|
|
2072
2122
|
"summarizerStop",
|
|
2073
2123
|
"summarizerStart",
|
|
2074
2124
|
"summarizerStartupFailed",
|
|
2075
|
-
]
|
|
2076
|
-
this.summaryManager?.on(eventName, (...args:
|
|
2125
|
+
]) {
|
|
2126
|
+
this.summaryManager?.on(eventName, (...args: unknown[]) => {
|
|
2077
2127
|
this.emit(eventName, ...args);
|
|
2078
2128
|
});
|
|
2079
|
-
}
|
|
2129
|
+
}
|
|
2080
2130
|
|
|
2081
2131
|
this.summaryManager.start();
|
|
2082
2132
|
}
|
|
2083
2133
|
}
|
|
2084
2134
|
|
|
2085
2135
|
// logging hardware telemetry
|
|
2086
|
-
this.
|
|
2136
|
+
this.baseLogger.send({
|
|
2137
|
+
category: "generic",
|
|
2087
2138
|
eventName: "DeviceSpec",
|
|
2088
2139
|
...getDeviceSpec(),
|
|
2089
2140
|
});
|
|
@@ -2096,13 +2147,12 @@ export class ContainerRuntime
|
|
|
2096
2147
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
2097
2148
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
2098
2149
|
gcVersion: metadata?.gcFeature,
|
|
2099
|
-
options: JSON.stringify(
|
|
2150
|
+
options: JSON.stringify(baseRuntimeOptions),
|
|
2100
2151
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
2101
|
-
idCompressorMode: this.idCompressorMode,
|
|
2152
|
+
idCompressorMode: this.sessionSchema.idCompressorMode,
|
|
2102
2153
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
2103
2154
|
featureGates: JSON.stringify({
|
|
2104
2155
|
...featureGatesForTelemetry,
|
|
2105
|
-
disableAttachReorder: this.disableAttachReorder,
|
|
2106
2156
|
disablePartialFlush,
|
|
2107
2157
|
closeSummarizerDelayOverride,
|
|
2108
2158
|
}),
|
|
@@ -2111,15 +2161,11 @@ export class ContainerRuntime
|
|
|
2111
2161
|
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
2112
2162
|
});
|
|
2113
2163
|
|
|
2114
|
-
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.
|
|
2115
|
-
BindBatchTracker(this, this.
|
|
2164
|
+
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.baseLogger);
|
|
2165
|
+
BindBatchTracker(this, this.baseLogger);
|
|
2116
2166
|
|
|
2117
2167
|
this.entryPoint = new LazyPromise(async () => {
|
|
2118
|
-
if (this.
|
|
2119
|
-
assert(
|
|
2120
|
-
this._summarizer !== undefined,
|
|
2121
|
-
0x5bf /* Summarizer object is undefined in a summarizer client */,
|
|
2122
|
-
);
|
|
2168
|
+
if (this._summarizer !== undefined) {
|
|
2123
2169
|
return this._summarizer;
|
|
2124
2170
|
}
|
|
2125
2171
|
return provideEntryPoint(this);
|
|
@@ -2130,8 +2176,9 @@ export class ContainerRuntime
|
|
|
2130
2176
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
2131
2177
|
}
|
|
2132
2178
|
|
|
2133
|
-
|
|
2134
|
-
|
|
2179
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2180
|
+
public onSchemaChange(schema: IDocumentSchemaCurrent): void {
|
|
2181
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2135
2182
|
eventName: "SchemaChangeAccept",
|
|
2136
2183
|
sessionRuntimeSchema: JSON.stringify(schema),
|
|
2137
2184
|
});
|
|
@@ -2157,7 +2204,7 @@ export class ContainerRuntime
|
|
|
2157
2204
|
return (
|
|
2158
2205
|
summarizeInternal: SummarizeInternalFn,
|
|
2159
2206
|
getGCDataFn: (fullGC?: boolean) => Promise<IGarbageCollectionData>,
|
|
2160
|
-
) =>
|
|
2207
|
+
): ISummarizerNodeWithGC =>
|
|
2161
2208
|
this.summarizerNode.createChild(
|
|
2162
2209
|
summarizeInternal,
|
|
2163
2210
|
id,
|
|
@@ -2167,26 +2214,29 @@ export class ContainerRuntime
|
|
|
2167
2214
|
);
|
|
2168
2215
|
}
|
|
2169
2216
|
|
|
2170
|
-
public deleteChildSummarizerNode(id: string) {
|
|
2217
|
+
public deleteChildSummarizerNode(id: string): void {
|
|
2171
2218
|
return this.summarizerNode.deleteChild(id);
|
|
2172
2219
|
}
|
|
2173
2220
|
|
|
2174
|
-
|
|
2175
|
-
|
|
2221
|
+
// #region `IFluidParentContext` APIs that should not be called on Root
|
|
2222
|
+
|
|
2223
|
+
public makeLocallyVisible(): void {
|
|
2176
2224
|
assert(false, 0x8eb /* should not be called */);
|
|
2177
2225
|
}
|
|
2178
2226
|
|
|
2179
|
-
public setChannelDirty(address: string) {
|
|
2227
|
+
public setChannelDirty(address: string): void {
|
|
2180
2228
|
assert(false, 0x909 /* should not be called */);
|
|
2181
2229
|
}
|
|
2182
2230
|
|
|
2231
|
+
// #endregion
|
|
2232
|
+
|
|
2183
2233
|
/**
|
|
2184
2234
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
2185
2235
|
*/
|
|
2186
2236
|
private async initializeBaseState(): Promise<void> {
|
|
2187
2237
|
if (
|
|
2188
|
-
this.idCompressorMode === "on" ||
|
|
2189
|
-
(this.idCompressorMode === "delayed" && this.connected)
|
|
2238
|
+
this.sessionSchema.idCompressorMode === "on" ||
|
|
2239
|
+
(this.sessionSchema.idCompressorMode === "delayed" && this.connected)
|
|
2190
2240
|
) {
|
|
2191
2241
|
this._idCompressor = await this.createIdCompressor();
|
|
2192
2242
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
@@ -2219,6 +2269,8 @@ export class ContainerRuntime
|
|
|
2219
2269
|
this._summarizer?.dispose();
|
|
2220
2270
|
this.channelCollection.dispose();
|
|
2221
2271
|
this.pendingStateManager.dispose();
|
|
2272
|
+
this.inboundBatchAggregator.dispose();
|
|
2273
|
+
this.deltaScheduler.dispose();
|
|
2222
2274
|
this.emit("dispose");
|
|
2223
2275
|
this.removeAllListeners();
|
|
2224
2276
|
}
|
|
@@ -2243,7 +2295,7 @@ export class ContainerRuntime
|
|
|
2243
2295
|
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
2244
2296
|
// any request, then cache that as same group could be requested in future too.
|
|
2245
2297
|
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(
|
|
2246
|
-
sortedLoadingGroupIds.join(),
|
|
2298
|
+
sortedLoadingGroupIds.join(","),
|
|
2247
2299
|
async () => {
|
|
2248
2300
|
assert(
|
|
2249
2301
|
this.storage.getSnapshot !== undefined,
|
|
@@ -2258,7 +2310,7 @@ export class ContainerRuntime
|
|
|
2258
2310
|
},
|
|
2259
2311
|
);
|
|
2260
2312
|
|
|
2261
|
-
this.logger.sendTelemetryEvent({
|
|
2313
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2262
2314
|
eventName: "GroupIdSnapshotFetched",
|
|
2263
2315
|
details: JSON.stringify({
|
|
2264
2316
|
fromCache: loadedFromCache,
|
|
@@ -2299,7 +2351,7 @@ export class ContainerRuntime
|
|
|
2299
2351
|
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
2300
2352
|
// the summarizer state is not up to date.
|
|
2301
2353
|
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
2302
|
-
if (this.
|
|
2354
|
+
if (this._summarizer !== undefined) {
|
|
2303
2355
|
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
2304
2356
|
}
|
|
2305
2357
|
|
|
@@ -2370,7 +2422,7 @@ export class ContainerRuntime
|
|
|
2370
2422
|
return {
|
|
2371
2423
|
status: 200,
|
|
2372
2424
|
mimeType: "fluid/object",
|
|
2373
|
-
value: this.
|
|
2425
|
+
value: this._summarizer,
|
|
2374
2426
|
};
|
|
2375
2427
|
}
|
|
2376
2428
|
return create404Response(request);
|
|
@@ -2431,8 +2483,10 @@ export class ContainerRuntime
|
|
|
2431
2483
|
return this.channelCollection.internalId(maybeAlias);
|
|
2432
2484
|
}
|
|
2433
2485
|
|
|
2434
|
-
/**
|
|
2435
|
-
|
|
2486
|
+
/**
|
|
2487
|
+
* Adds the container's metadata to the given summary tree.
|
|
2488
|
+
*/
|
|
2489
|
+
private addMetadataToSummary(summaryTree: ISummaryTreeWithStats): void {
|
|
2436
2490
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
2437
2491
|
// last summary.
|
|
2438
2492
|
const message =
|
|
@@ -2446,6 +2500,7 @@ export class ContainerRuntime
|
|
|
2446
2500
|
// Is document schema explicit control on?
|
|
2447
2501
|
const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
|
|
2448
2502
|
|
|
2503
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2449
2504
|
const metadata: IContainerRuntimeMetadata = {
|
|
2450
2505
|
...this.createContainerMetadata,
|
|
2451
2506
|
// Increment the summary number for the next summary that will be generated.
|
|
@@ -2459,7 +2514,8 @@ export class ContainerRuntime
|
|
|
2459
2514
|
// last message's sequence number.
|
|
2460
2515
|
// See also lastMessageFromMetadata()
|
|
2461
2516
|
message: explicitSchemaControl
|
|
2462
|
-
?
|
|
2517
|
+
? // eslint-disable-next-line import/no-deprecated
|
|
2518
|
+
({ sequenceNumber: -1 } as unknown as ISummaryMetadataMessage)
|
|
2463
2519
|
: message,
|
|
2464
2520
|
lastMessage: explicitSchemaControl ? message : undefined,
|
|
2465
2521
|
documentSchema,
|
|
@@ -2473,7 +2529,7 @@ export class ContainerRuntime
|
|
|
2473
2529
|
fullTree: boolean,
|
|
2474
2530
|
trackState: boolean,
|
|
2475
2531
|
telemetryContext?: ITelemetryContext,
|
|
2476
|
-
) {
|
|
2532
|
+
): void {
|
|
2477
2533
|
this.addMetadataToSummary(summaryTree);
|
|
2478
2534
|
|
|
2479
2535
|
if (this._idCompressor) {
|
|
@@ -2549,11 +2605,11 @@ export class ContainerRuntime
|
|
|
2549
2605
|
return this.consecutiveReconnects < this.maxConsecutiveReconnects;
|
|
2550
2606
|
}
|
|
2551
2607
|
|
|
2552
|
-
private resetReconnectCount() {
|
|
2608
|
+
private resetReconnectCount(): void {
|
|
2553
2609
|
this.consecutiveReconnects = 0;
|
|
2554
2610
|
}
|
|
2555
2611
|
|
|
2556
|
-
private replayPendingStates() {
|
|
2612
|
+
private replayPendingStates(): void {
|
|
2557
2613
|
// We need to be able to send ops to replay states
|
|
2558
2614
|
if (!this.canSendOps()) {
|
|
2559
2615
|
return;
|
|
@@ -2593,7 +2649,7 @@ export class ContainerRuntime
|
|
|
2593
2649
|
// TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
|
|
2594
2650
|
private parseLocalOpContent(serializedContents?: string): LocalContainerRuntimeMessage {
|
|
2595
2651
|
assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
|
|
2596
|
-
const message
|
|
2652
|
+
const message = JSON.parse(serializedContents) as LocalContainerRuntimeMessage;
|
|
2597
2653
|
assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
2598
2654
|
return message;
|
|
2599
2655
|
}
|
|
@@ -2604,9 +2660,10 @@ export class ContainerRuntime
|
|
|
2604
2660
|
switch (opContents.type) {
|
|
2605
2661
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2606
2662
|
case ContainerMessageType.Attach:
|
|
2607
|
-
case ContainerMessageType.Alias:
|
|
2663
|
+
case ContainerMessageType.Alias: {
|
|
2608
2664
|
return this.channelCollection.applyStashedOp(opContents);
|
|
2609
|
-
|
|
2665
|
+
}
|
|
2666
|
+
case ContainerMessageType.IdAllocation: {
|
|
2610
2667
|
// IDs allocation ops in stashed state are ignored because the tip state of the compressor
|
|
2611
2668
|
// is serialized into the pending state. This is done because generation of new IDs during
|
|
2612
2669
|
// stashed op application (or, later, resubmit) must generate new IDs and if the compressor
|
|
@@ -2617,19 +2674,24 @@ export class ContainerRuntime
|
|
|
2617
2674
|
// before applying the rest of the stashed ops. This would accomplish the same thing but with
|
|
2618
2675
|
// better performance in future incremental stashed state creation.
|
|
2619
2676
|
assert(
|
|
2620
|
-
this.idCompressorMode !== undefined,
|
|
2677
|
+
this.sessionSchema.idCompressorMode !== undefined,
|
|
2621
2678
|
0x8f1 /* ID compressor should be in use */,
|
|
2622
2679
|
);
|
|
2623
2680
|
return;
|
|
2624
|
-
|
|
2681
|
+
}
|
|
2682
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
2625
2683
|
return;
|
|
2626
|
-
|
|
2684
|
+
}
|
|
2685
|
+
case ContainerMessageType.BlobAttach: {
|
|
2627
2686
|
return;
|
|
2628
|
-
|
|
2687
|
+
}
|
|
2688
|
+
case ContainerMessageType.Rejoin: {
|
|
2629
2689
|
throw new Error("rejoin not expected here");
|
|
2630
|
-
|
|
2690
|
+
}
|
|
2691
|
+
case ContainerMessageType.GC: {
|
|
2631
2692
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
2632
2693
|
throw new LoggingError("GC op not expected to be stashed in summarizer");
|
|
2694
|
+
}
|
|
2633
2695
|
default: {
|
|
2634
2696
|
const error = getUnknownMessageTypeError(
|
|
2635
2697
|
opContents.type,
|
|
@@ -2641,10 +2703,10 @@ export class ContainerRuntime
|
|
|
2641
2703
|
}
|
|
2642
2704
|
}
|
|
2643
2705
|
|
|
2644
|
-
private async loadIdCompressor() {
|
|
2706
|
+
private async loadIdCompressor(): Promise<void | undefined> {
|
|
2645
2707
|
if (
|
|
2646
2708
|
this._idCompressor === undefined &&
|
|
2647
|
-
this.idCompressorMode !== undefined &&
|
|
2709
|
+
this.sessionSchema.idCompressorMode !== undefined &&
|
|
2648
2710
|
this._loadIdCompressor === undefined
|
|
2649
2711
|
) {
|
|
2650
2712
|
this._loadIdCompressor = this.createIdCompressor()
|
|
@@ -2659,14 +2721,14 @@ export class ContainerRuntime
|
|
|
2659
2721
|
this._idCompressor = compressor;
|
|
2660
2722
|
})
|
|
2661
2723
|
.catch((error) => {
|
|
2662
|
-
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2724
|
+
this.mc.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2663
2725
|
throw error;
|
|
2664
2726
|
});
|
|
2665
2727
|
}
|
|
2666
2728
|
return this._loadIdCompressor;
|
|
2667
2729
|
}
|
|
2668
2730
|
|
|
2669
|
-
public setConnectionState(connected: boolean, clientId?: string) {
|
|
2731
|
+
public setConnectionState(connected: boolean, clientId?: string): void {
|
|
2670
2732
|
// Validate we have consistent state
|
|
2671
2733
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
2672
2734
|
assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
@@ -2675,7 +2737,7 @@ export class ContainerRuntime
|
|
|
2675
2737
|
0x978 /* this.clientId does not match Audience */,
|
|
2676
2738
|
);
|
|
2677
2739
|
|
|
2678
|
-
if (connected && this.idCompressorMode === "delayed") {
|
|
2740
|
+
if (connected && this.sessionSchema.idCompressorMode === "delayed") {
|
|
2679
2741
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2680
2742
|
this.loadIdCompressor();
|
|
2681
2743
|
}
|
|
@@ -2709,7 +2771,7 @@ export class ContainerRuntime
|
|
|
2709
2771
|
this.setConnectionStateCore(connected, clientId);
|
|
2710
2772
|
}
|
|
2711
2773
|
|
|
2712
|
-
private setConnectionStateCore(connected: boolean, clientId?: string) {
|
|
2774
|
+
private setConnectionStateCore(connected: boolean, clientId?: string): void {
|
|
2713
2775
|
assert(
|
|
2714
2776
|
!this.delayConnectClientId,
|
|
2715
2777
|
0x394 /* connect event delay must be cleared before propagating connect event */,
|
|
@@ -2777,7 +2839,7 @@ export class ContainerRuntime
|
|
|
2777
2839
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
2778
2840
|
}
|
|
2779
2841
|
|
|
2780
|
-
public async notifyOpReplay(message: ISequencedDocumentMessage) {
|
|
2842
|
+
public async notifyOpReplay(message: ISequencedDocumentMessage): Promise<void> {
|
|
2781
2843
|
await this.pendingStateManager.applyStashedOpsAt(message.sequenceNumber);
|
|
2782
2844
|
}
|
|
2783
2845
|
|
|
@@ -2786,7 +2848,7 @@ export class ContainerRuntime
|
|
|
2786
2848
|
* @param messageCopy - Sequenced message for a distributed document.
|
|
2787
2849
|
* @param local - true if the message was originally generated by the client receiving it.
|
|
2788
2850
|
*/
|
|
2789
|
-
public process({ ...messageCopy }: ISequencedDocumentMessage, local: boolean) {
|
|
2851
|
+
public process({ ...messageCopy }: ISequencedDocumentMessage, local: boolean): void {
|
|
2790
2852
|
// spread operator above ensure we make a shallow copy of message, as the processing flow will modify it.
|
|
2791
2853
|
// There might be multiple container instances receiving the same message.
|
|
2792
2854
|
|
|
@@ -2797,7 +2859,7 @@ export class ContainerRuntime
|
|
|
2797
2859
|
// or something different, like a system message.
|
|
2798
2860
|
const hasModernRuntimeMessageEnvelope = messageCopy.type === MessageType.Operation;
|
|
2799
2861
|
const savedOp = (messageCopy.metadata as ISavedOpMetadata)?.savedOp;
|
|
2800
|
-
const logLegacyCase = getSingleUseLegacyLogCallback(this.logger, messageCopy.type);
|
|
2862
|
+
const logLegacyCase = getSingleUseLegacyLogCallback(this.mc.logger, messageCopy.type);
|
|
2801
2863
|
|
|
2802
2864
|
let runtimeBatch: boolean =
|
|
2803
2865
|
hasModernRuntimeMessageEnvelope || isUnpackedRuntimeMessage(messageCopy);
|
|
@@ -2924,7 +2986,7 @@ export class ContainerRuntime
|
|
|
2924
2986
|
private _processedClientSequenceNumber: number | undefined;
|
|
2925
2987
|
|
|
2926
2988
|
/**
|
|
2927
|
-
* Processes inbound message(s). It calls
|
|
2989
|
+
* Processes inbound message(s). It calls delta scheduler according to the messages' location in the batch.
|
|
2928
2990
|
* @param messagesWithMetadata - messages to process along with their metadata.
|
|
2929
2991
|
* @param locationInBatch - Are we processing the start and/or end of a batch?
|
|
2930
2992
|
* @param local - true if the messages were originally generated by the client receiving it.
|
|
@@ -2942,27 +3004,29 @@ export class ContainerRuntime
|
|
|
2942
3004
|
savedOp: boolean | undefined,
|
|
2943
3005
|
runtimeBatch: boolean,
|
|
2944
3006
|
groupedBatch: boolean,
|
|
2945
|
-
) {
|
|
3007
|
+
): void {
|
|
2946
3008
|
if (locationInBatch.batchStart) {
|
|
2947
3009
|
const firstMessage = messagesWithMetadata[0]?.message;
|
|
2948
3010
|
assert(firstMessage !== undefined, 0xa31 /* Batch must have at least one message */);
|
|
2949
|
-
this.
|
|
3011
|
+
this.emit("batchBegin", firstMessage);
|
|
2950
3012
|
}
|
|
2951
3013
|
|
|
2952
3014
|
let error: unknown;
|
|
2953
3015
|
try {
|
|
2954
3016
|
if (!runtimeBatch) {
|
|
2955
|
-
|
|
3017
|
+
for (const { message } of messagesWithMetadata) {
|
|
2956
3018
|
this.ensureNoDataModelChanges(() => {
|
|
2957
3019
|
this.observeNonRuntimeMessage(message);
|
|
2958
3020
|
});
|
|
2959
|
-
}
|
|
3021
|
+
}
|
|
2960
3022
|
return;
|
|
2961
3023
|
}
|
|
2962
3024
|
|
|
2963
|
-
//
|
|
3025
|
+
// Updates a message's minimum sequence number to the minimum sequence number that container
|
|
2964
3026
|
// runtime is tracking and sets _processedClientSequenceNumber. It returns the updated message.
|
|
2965
|
-
const updateSequenceNumbers = (
|
|
3027
|
+
const updateSequenceNumbers = (
|
|
3028
|
+
message: ISequencedDocumentMessage,
|
|
3029
|
+
): InboundSequencedContainerRuntimeMessage => {
|
|
2966
3030
|
// Set the minimum sequence number to the containerRuntime's understanding of minimum sequence number.
|
|
2967
3031
|
message.minimumSequenceNumber =
|
|
2968
3032
|
this.useDeltaManagerOpsProxy &&
|
|
@@ -2999,8 +3063,8 @@ export class ContainerRuntime
|
|
|
2999
3063
|
let bunchedMessagesContent: IRuntimeMessagesContent[] = [];
|
|
3000
3064
|
let previousMessage: InboundSequencedContainerRuntimeMessage | undefined;
|
|
3001
3065
|
|
|
3002
|
-
//
|
|
3003
|
-
const sendBunchedMessages = () => {
|
|
3066
|
+
// Process the previous bunch of messages.
|
|
3067
|
+
const sendBunchedMessages = (): void => {
|
|
3004
3068
|
assert(previousMessage !== undefined, 0xa67 /* previous message must exist */);
|
|
3005
3069
|
this.ensureNoDataModelChanges(() => {
|
|
3006
3070
|
this.validateAndProcessRuntimeMessages(
|
|
@@ -3039,14 +3103,14 @@ export class ContainerRuntime
|
|
|
3039
3103
|
for (const { message } of messagesWithMetadata) {
|
|
3040
3104
|
this.emit("op", message, true /* runtimeMessage */);
|
|
3041
3105
|
}
|
|
3042
|
-
} catch (
|
|
3043
|
-
error =
|
|
3106
|
+
} catch (error_) {
|
|
3107
|
+
error = error_;
|
|
3044
3108
|
throw error;
|
|
3045
3109
|
} finally {
|
|
3046
3110
|
if (locationInBatch.batchEnd) {
|
|
3047
3111
|
const lastMessage = messagesWithMetadata[messagesWithMetadata.length - 1]?.message;
|
|
3048
3112
|
assert(lastMessage !== undefined, 0xa32 /* Batch must have at least one message */);
|
|
3049
|
-
this.
|
|
3113
|
+
this.emit("batchEnd", error, lastMessage);
|
|
3050
3114
|
}
|
|
3051
3115
|
}
|
|
3052
3116
|
}
|
|
@@ -3055,7 +3119,7 @@ export class ContainerRuntime
|
|
|
3055
3119
|
* Observes messages that are not intended for the runtime layer, updating/notifying Runtime systems as needed.
|
|
3056
3120
|
* @param message - non-runtime message to process.
|
|
3057
3121
|
*/
|
|
3058
|
-
private observeNonRuntimeMessage(message: ISequencedDocumentMessage) {
|
|
3122
|
+
private observeNonRuntimeMessage(message: ISequencedDocumentMessage): void {
|
|
3059
3123
|
// Set the minimum sequence number to the containerRuntime's understanding of minimum sequence number.
|
|
3060
3124
|
if (this.deltaManager.minimumSequenceNumber < message.minimumSequenceNumber) {
|
|
3061
3125
|
message.minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
@@ -3111,38 +3175,46 @@ export class ContainerRuntime
|
|
|
3111
3175
|
switch (message.type) {
|
|
3112
3176
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3113
3177
|
case ContainerMessageType.Attach:
|
|
3114
|
-
case ContainerMessageType.Alias:
|
|
3178
|
+
case ContainerMessageType.Alias: {
|
|
3115
3179
|
// Remove the metadata from the message before sending it to the channel collection. The metadata
|
|
3116
3180
|
// is added by the container runtime and is not part of the message that the channel collection and
|
|
3117
3181
|
// layers below it expect.
|
|
3118
3182
|
this.channelCollection.processMessages({ envelope: message, messagesContent, local });
|
|
3119
3183
|
break;
|
|
3120
|
-
|
|
3184
|
+
}
|
|
3185
|
+
case ContainerMessageType.BlobAttach: {
|
|
3121
3186
|
this.blobManager.processBlobAttachMessage(message, local);
|
|
3122
3187
|
break;
|
|
3123
|
-
|
|
3188
|
+
}
|
|
3189
|
+
case ContainerMessageType.IdAllocation: {
|
|
3124
3190
|
this.processIdCompressorMessages(contents as IdCreationRange[], savedOp);
|
|
3125
3191
|
break;
|
|
3126
|
-
|
|
3192
|
+
}
|
|
3193
|
+
case ContainerMessageType.GC: {
|
|
3127
3194
|
this.garbageCollector.processMessages(
|
|
3128
3195
|
contents as GarbageCollectionMessage[],
|
|
3129
3196
|
message.timestamp,
|
|
3130
3197
|
local,
|
|
3131
3198
|
);
|
|
3132
3199
|
break;
|
|
3133
|
-
|
|
3200
|
+
}
|
|
3201
|
+
case ContainerMessageType.ChunkedOp: {
|
|
3134
3202
|
// From observability POV, we should not expose the rest of the system (including "op" events on object) to these messages.
|
|
3135
3203
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
3136
3204
|
assert(false, 0x93d /* should not even get here */);
|
|
3137
|
-
|
|
3205
|
+
}
|
|
3206
|
+
case ContainerMessageType.Rejoin: {
|
|
3138
3207
|
break;
|
|
3139
|
-
|
|
3208
|
+
}
|
|
3209
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
3140
3210
|
this.documentsSchemaController.processDocumentSchemaMessages(
|
|
3211
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3141
3212
|
contents as IDocumentSchemaChangeMessage[],
|
|
3142
3213
|
local,
|
|
3143
3214
|
message.sequenceNumber,
|
|
3144
3215
|
);
|
|
3145
3216
|
break;
|
|
3217
|
+
}
|
|
3146
3218
|
default: {
|
|
3147
3219
|
const error = getUnknownMessageTypeError(
|
|
3148
3220
|
message.type,
|
|
@@ -3155,7 +3227,10 @@ export class ContainerRuntime
|
|
|
3155
3227
|
}
|
|
3156
3228
|
}
|
|
3157
3229
|
|
|
3158
|
-
private processIdCompressorMessages(
|
|
3230
|
+
private processIdCompressorMessages(
|
|
3231
|
+
messageContents: IdCreationRange[],
|
|
3232
|
+
savedOp?: boolean,
|
|
3233
|
+
): void {
|
|
3159
3234
|
for (const range of messageContents) {
|
|
3160
3235
|
// Don't re-finalize the range if we're processing a "savedOp" in
|
|
3161
3236
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
@@ -3166,7 +3241,7 @@ export class ContainerRuntime
|
|
|
3166
3241
|
// put it in a pending queue and delay finalization.
|
|
3167
3242
|
if (this._idCompressor === undefined) {
|
|
3168
3243
|
assert(
|
|
3169
|
-
this.idCompressorMode !== undefined,
|
|
3244
|
+
this.sessionSchema.idCompressorMode !== undefined,
|
|
3170
3245
|
0x93c /* id compressor should be enabled */,
|
|
3171
3246
|
);
|
|
3172
3247
|
this.pendingIdCompressorOps.push(range);
|
|
@@ -3184,7 +3259,7 @@ export class ContainerRuntime
|
|
|
3184
3259
|
/**
|
|
3185
3260
|
* Emits the Signal event and update the perf signal data.
|
|
3186
3261
|
*/
|
|
3187
|
-
private sendSignalTelemetryEvent() {
|
|
3262
|
+
private sendSignalTelemetryEvent(): void {
|
|
3188
3263
|
const duration = Date.now() - this._signalTracking.signalTimestamp;
|
|
3189
3264
|
this.mc.logger.sendPerformanceEvent({
|
|
3190
3265
|
eventName: "SignalLatency",
|
|
@@ -3206,7 +3281,11 @@ export class ContainerRuntime
|
|
|
3206
3281
|
* Updates signal telemetry including emitting telemetry events.
|
|
3207
3282
|
*/
|
|
3208
3283
|
private processSignalForTelemetry(envelope: ISignalEnvelope): void {
|
|
3209
|
-
const {
|
|
3284
|
+
const {
|
|
3285
|
+
clientBroadcastSignalSequenceNumber,
|
|
3286
|
+
contents: envelopeContents,
|
|
3287
|
+
address: envelopeAddress,
|
|
3288
|
+
} = envelope;
|
|
3210
3289
|
if (clientBroadcastSignalSequenceNumber === undefined) {
|
|
3211
3290
|
return;
|
|
3212
3291
|
}
|
|
@@ -3251,8 +3330,8 @@ export class ContainerRuntime
|
|
|
3251
3330
|
};
|
|
3252
3331
|
// Only log `contents.type` when address is for container to avoid
|
|
3253
3332
|
// chance that contents type is customer data.
|
|
3254
|
-
if (
|
|
3255
|
-
details.contentsType =
|
|
3333
|
+
if (envelopeAddress === undefined) {
|
|
3334
|
+
details.contentsType = envelopeContents.type; // Type of signal that was received out of order.
|
|
3256
3335
|
}
|
|
3257
3336
|
this.mc.logger.sendTelemetryEvent({
|
|
3258
3337
|
eventName: "SignalOutOfOrder",
|
|
@@ -3278,7 +3357,7 @@ export class ContainerRuntime
|
|
|
3278
3357
|
}
|
|
3279
3358
|
}
|
|
3280
3359
|
|
|
3281
|
-
public processSignal(message: ISignalMessage, local: boolean) {
|
|
3360
|
+
public processSignal(message: ISignalMessage, local: boolean): void {
|
|
3282
3361
|
const envelope = message.content as ISignalEnvelope;
|
|
3283
3362
|
const transformed: IInboundSignalMessage = {
|
|
3284
3363
|
clientId: message.clientId,
|
|
@@ -3348,8 +3427,8 @@ export class ContainerRuntime
|
|
|
3348
3427
|
checkpoint.rollback((message: BatchMessage) =>
|
|
3349
3428
|
this.rollback(message.contents, message.localOpMetadata),
|
|
3350
3429
|
);
|
|
3351
|
-
} catch (
|
|
3352
|
-
const error2 = wrapError(
|
|
3430
|
+
} catch (error_) {
|
|
3431
|
+
const error2 = wrapError(error_, (message) => {
|
|
3353
3432
|
return DataProcessingError.create(
|
|
3354
3433
|
`RollbackError: ${message}`,
|
|
3355
3434
|
"checkpointRollback",
|
|
@@ -3440,7 +3519,6 @@ export class ContainerRuntime
|
|
|
3440
3519
|
): Promise<IDataStore> {
|
|
3441
3520
|
const context = this.channelCollection.createDataStoreContext(
|
|
3442
3521
|
Array.isArray(pkg) ? pkg : [pkg],
|
|
3443
|
-
undefined, // props
|
|
3444
3522
|
loadingGroupId,
|
|
3445
3523
|
);
|
|
3446
3524
|
return channelToDataStore(
|
|
@@ -3451,26 +3529,7 @@ export class ContainerRuntime
|
|
|
3451
3529
|
);
|
|
3452
3530
|
}
|
|
3453
3531
|
|
|
3454
|
-
|
|
3455
|
-
* @deprecated 0.16 Issue #1537, #3631
|
|
3456
|
-
*/
|
|
3457
|
-
public async _createDataStoreWithProps(
|
|
3458
|
-
pkg: Readonly<string | string[]>,
|
|
3459
|
-
props?: any,
|
|
3460
|
-
): Promise<IDataStore> {
|
|
3461
|
-
const context = this.channelCollection.createDataStoreContext(
|
|
3462
|
-
Array.isArray(pkg) ? pkg : [pkg],
|
|
3463
|
-
props,
|
|
3464
|
-
);
|
|
3465
|
-
return channelToDataStore(
|
|
3466
|
-
await context.realize(),
|
|
3467
|
-
context.id,
|
|
3468
|
-
this.channelCollection,
|
|
3469
|
-
this.mc.logger,
|
|
3470
|
-
);
|
|
3471
|
-
}
|
|
3472
|
-
|
|
3473
|
-
private canSendOps() {
|
|
3532
|
+
private canSendOps(): boolean {
|
|
3474
3533
|
// Note that the real (non-proxy) delta manager is needed here to get the readonly info. This is because
|
|
3475
3534
|
// container runtime's ability to send ops depend on the actual readonly state of the delta manager.
|
|
3476
3535
|
return (
|
|
@@ -3481,7 +3540,7 @@ export class ContainerRuntime
|
|
|
3481
3540
|
/**
|
|
3482
3541
|
* Typically ops are batched and later flushed together, but in some cases we want to flush immediately.
|
|
3483
3542
|
*/
|
|
3484
|
-
private currentlyBatching() {
|
|
3543
|
+
private currentlyBatching(): boolean {
|
|
3485
3544
|
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
3486
3545
|
}
|
|
3487
3546
|
|
|
@@ -3503,7 +3562,10 @@ export class ContainerRuntime
|
|
|
3503
3562
|
return this.dirtyContainer;
|
|
3504
3563
|
}
|
|
3505
3564
|
|
|
3506
|
-
private isContainerMessageDirtyable({
|
|
3565
|
+
private isContainerMessageDirtyable({
|
|
3566
|
+
type,
|
|
3567
|
+
contents,
|
|
3568
|
+
}: OutboundContainerRuntimeMessage): boolean {
|
|
3507
3569
|
// Certain container runtime messages should not mark the container dirty such as the old built-in
|
|
3508
3570
|
// AgentScheduler and Garbage collector messages.
|
|
3509
3571
|
switch (type) {
|
|
@@ -3526,8 +3588,9 @@ export class ContainerRuntime
|
|
|
3526
3588
|
case ContainerMessageType.GC: {
|
|
3527
3589
|
return false;
|
|
3528
3590
|
}
|
|
3529
|
-
default:
|
|
3591
|
+
default: {
|
|
3530
3592
|
break;
|
|
3593
|
+
}
|
|
3531
3594
|
}
|
|
3532
3595
|
return true;
|
|
3533
3596
|
}
|
|
@@ -3535,7 +3598,7 @@ export class ContainerRuntime
|
|
|
3535
3598
|
private createNewSignalEnvelope(
|
|
3536
3599
|
address: string | undefined,
|
|
3537
3600
|
type: string,
|
|
3538
|
-
content:
|
|
3601
|
+
content: unknown,
|
|
3539
3602
|
): Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> {
|
|
3540
3603
|
const newEnvelope: Omit<ISignalEnvelope, "broadcastSignalSequenceNumber"> = {
|
|
3541
3604
|
address,
|
|
@@ -3545,7 +3608,7 @@ export class ContainerRuntime
|
|
|
3545
3608
|
return newEnvelope;
|
|
3546
3609
|
}
|
|
3547
3610
|
|
|
3548
|
-
private submitEnvelopedSignal(envelope: ISignalEnvelope, targetClientId?: string) {
|
|
3611
|
+
private submitEnvelopedSignal(envelope: ISignalEnvelope, targetClientId?: string): void {
|
|
3549
3612
|
const isBroadcastSignal = targetClientId === undefined;
|
|
3550
3613
|
|
|
3551
3614
|
if (isBroadcastSignal) {
|
|
@@ -3570,7 +3633,7 @@ export class ContainerRuntime
|
|
|
3570
3633
|
|
|
3571
3634
|
// We should not track the round trip of a new signal in the case we are already tracking one.
|
|
3572
3635
|
if (
|
|
3573
|
-
clientBroadcastSignalSequenceNumber %
|
|
3636
|
+
clientBroadcastSignalSequenceNumber % defaultTelemetrySignalSampleCount === 1 &&
|
|
3574
3637
|
this._signalTracking.roundTripSignalSequenceNumber === undefined
|
|
3575
3638
|
) {
|
|
3576
3639
|
this._signalTracking.signalTimestamp = Date.now();
|
|
@@ -3597,7 +3660,7 @@ export class ContainerRuntime
|
|
|
3597
3660
|
* Support for this option at container runtime is planned to be deprecated in the future.
|
|
3598
3661
|
*
|
|
3599
3662
|
*/
|
|
3600
|
-
public submitSignal(type: string, content: unknown, targetClientId?: string) {
|
|
3663
|
+
public submitSignal(type: string, content: unknown, targetClientId?: string): void {
|
|
3601
3664
|
this.verifyNotClosed();
|
|
3602
3665
|
const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
|
|
3603
3666
|
return this.submitEnvelopedSignal(envelope, targetClientId);
|
|
@@ -3664,6 +3727,12 @@ export class ContainerRuntime
|
|
|
3664
3727
|
|
|
3665
3728
|
public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>;
|
|
3666
3729
|
|
|
3730
|
+
/**
|
|
3731
|
+
* Builds the Summary tree including all the channels and the container state.
|
|
3732
|
+
*
|
|
3733
|
+
* @remarks - Unfortunately, this function is accessed in a non-typesafe way by a legacy first-party partner,
|
|
3734
|
+
* so until we can provide a proper API for their scenario, we need to ensure this function doesn't change.
|
|
3735
|
+
*/
|
|
3667
3736
|
private async summarizeInternal(
|
|
3668
3737
|
fullTree: boolean,
|
|
3669
3738
|
trackState: boolean,
|
|
@@ -3694,17 +3763,29 @@ export class ContainerRuntime
|
|
|
3694
3763
|
* Returns a summary of the runtime at the current sequence number.
|
|
3695
3764
|
*/
|
|
3696
3765
|
public async summarize(options: {
|
|
3697
|
-
/**
|
|
3766
|
+
/**
|
|
3767
|
+
* True to generate the full tree with no handle reuse optimizations; defaults to false
|
|
3768
|
+
*/
|
|
3698
3769
|
fullTree?: boolean;
|
|
3699
|
-
/**
|
|
3770
|
+
/**
|
|
3771
|
+
* True to track the state for this summary in the SummarizerNodes; defaults to true
|
|
3772
|
+
*/
|
|
3700
3773
|
trackState?: boolean;
|
|
3701
|
-
/**
|
|
3774
|
+
/**
|
|
3775
|
+
* Logger to use for correlated summary events
|
|
3776
|
+
*/
|
|
3702
3777
|
summaryLogger?: ITelemetryLoggerExt;
|
|
3703
|
-
/**
|
|
3778
|
+
/**
|
|
3779
|
+
* True to run garbage collection before summarizing; defaults to true
|
|
3780
|
+
*/
|
|
3704
3781
|
runGC?: boolean;
|
|
3705
|
-
/**
|
|
3782
|
+
/**
|
|
3783
|
+
* True to generate full GC data
|
|
3784
|
+
*/
|
|
3706
3785
|
fullGC?: boolean;
|
|
3707
|
-
/**
|
|
3786
|
+
/**
|
|
3787
|
+
* True to run GC sweep phase after the mark phase
|
|
3788
|
+
*/
|
|
3708
3789
|
runSweep?: boolean;
|
|
3709
3790
|
}): Promise<ISummaryTreeWithStats> {
|
|
3710
3791
|
this.verifyNotClosed();
|
|
@@ -3780,7 +3861,7 @@ export class ContainerRuntime
|
|
|
3780
3861
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
3781
3862
|
* @see IGarbageCollectionRuntime.updateUsedRoutes
|
|
3782
3863
|
*/
|
|
3783
|
-
public updateUsedRoutes(usedRoutes: readonly string[]) {
|
|
3864
|
+
public updateUsedRoutes(usedRoutes: readonly string[]): void {
|
|
3784
3865
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
3785
3866
|
// summarizing is required and asserted by the the summarizer node. We are the root and are
|
|
3786
3867
|
// always referenced, so the used routes is only self-route (empty string).
|
|
@@ -3799,8 +3880,10 @@ export class ContainerRuntime
|
|
|
3799
3880
|
const { dataStoreRoutes, blobManagerRoutes } =
|
|
3800
3881
|
this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
3801
3882
|
|
|
3802
|
-
|
|
3803
|
-
|
|
3883
|
+
return [
|
|
3884
|
+
...this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes),
|
|
3885
|
+
...this.blobManager.deleteSweepReadyNodes(blobManagerRoutes),
|
|
3886
|
+
];
|
|
3804
3887
|
}
|
|
3805
3888
|
|
|
3806
3889
|
/**
|
|
@@ -3811,7 +3894,7 @@ export class ContainerRuntime
|
|
|
3811
3894
|
*
|
|
3812
3895
|
* @param tombstonedRoutes - Data store and attachment blob routes that are tombstones in this Container.
|
|
3813
3896
|
*/
|
|
3814
|
-
public updateTombstonedRoutes(tombstonedRoutes: readonly string[]) {
|
|
3897
|
+
public updateTombstonedRoutes(tombstonedRoutes: readonly string[]): void {
|
|
3815
3898
|
const { dataStoreRoutes } = this.getDataStoreAndBlobManagerRoutes(tombstonedRoutes);
|
|
3816
3899
|
this.channelCollection.updateTombstonedRoutes(dataStoreRoutes);
|
|
3817
3900
|
}
|
|
@@ -3829,10 +3912,13 @@ export class ContainerRuntime
|
|
|
3829
3912
|
* Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
|
|
3830
3913
|
* blob manager.
|
|
3831
3914
|
*/
|
|
3915
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3832
3916
|
public getNodeType(nodePath: string): GCNodeType {
|
|
3833
3917
|
if (isBlobPath(nodePath)) {
|
|
3918
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3834
3919
|
return GCNodeType.Blob;
|
|
3835
3920
|
}
|
|
3921
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3836
3922
|
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
3837
3923
|
}
|
|
3838
3924
|
|
|
@@ -3848,13 +3934,19 @@ export class ContainerRuntime
|
|
|
3848
3934
|
}
|
|
3849
3935
|
|
|
3850
3936
|
switch (this.getNodeType(nodePath)) {
|
|
3851
|
-
|
|
3937
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3938
|
+
case GCNodeType.Blob: {
|
|
3852
3939
|
return [blobManagerBasePath];
|
|
3940
|
+
}
|
|
3941
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3853
3942
|
case GCNodeType.DataStore:
|
|
3854
|
-
|
|
3943
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3944
|
+
case GCNodeType.SubDataStore: {
|
|
3855
3945
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
3856
|
-
|
|
3946
|
+
}
|
|
3947
|
+
default: {
|
|
3857
3948
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
3949
|
+
}
|
|
3858
3950
|
}
|
|
3859
3951
|
}
|
|
3860
3952
|
|
|
@@ -3864,7 +3956,10 @@ export class ContainerRuntime
|
|
|
3864
3956
|
* @returns Two route lists - One that contains routes for blob manager and another one that contains routes
|
|
3865
3957
|
* for data stores.
|
|
3866
3958
|
*/
|
|
3867
|
-
private getDataStoreAndBlobManagerRoutes(routes: readonly string[]) {
|
|
3959
|
+
private getDataStoreAndBlobManagerRoutes(routes: readonly string[]): {
|
|
3960
|
+
blobManagerRoutes: string[];
|
|
3961
|
+
dataStoreRoutes: string[];
|
|
3962
|
+
} {
|
|
3868
3963
|
const blobManagerRoutes: string[] = [];
|
|
3869
3964
|
const dataStoreRoutes: string[] = [];
|
|
3870
3965
|
for (const route of routes) {
|
|
@@ -3883,14 +3978,21 @@ export class ContainerRuntime
|
|
|
3883
3978
|
*/
|
|
3884
3979
|
public async collectGarbage(
|
|
3885
3980
|
options: {
|
|
3886
|
-
/**
|
|
3981
|
+
/**
|
|
3982
|
+
* Logger to use for logging GC events
|
|
3983
|
+
*/
|
|
3887
3984
|
logger?: ITelemetryLoggerExt;
|
|
3888
|
-
/**
|
|
3985
|
+
/**
|
|
3986
|
+
* True to run GC sweep phase after the mark phase
|
|
3987
|
+
*/
|
|
3889
3988
|
runSweep?: boolean;
|
|
3890
|
-
/**
|
|
3989
|
+
/**
|
|
3990
|
+
* True to generate full GC data
|
|
3991
|
+
*/
|
|
3891
3992
|
fullGC?: boolean;
|
|
3892
3993
|
},
|
|
3893
3994
|
telemetryContext?: ITelemetryContext,
|
|
3995
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3894
3996
|
): Promise<IGCStats | undefined> {
|
|
3895
3997
|
return this.garbageCollector.collectGarbage(options, telemetryContext);
|
|
3896
3998
|
}
|
|
@@ -3902,7 +4004,11 @@ export class ContainerRuntime
|
|
|
3902
4004
|
* @param toPath - The absolute path of the outbound node that is referenced.
|
|
3903
4005
|
* @param messageTimestampMs - The timestamp of the message that added the reference.
|
|
3904
4006
|
*/
|
|
3905
|
-
public addedGCOutboundRoute(
|
|
4007
|
+
public addedGCOutboundRoute(
|
|
4008
|
+
fromPath: string,
|
|
4009
|
+
toPath: string,
|
|
4010
|
+
messageTimestampMs?: number,
|
|
4011
|
+
): void {
|
|
3906
4012
|
// This is always called when processing an op so messageTimestampMs should exist. Due to back-compat
|
|
3907
4013
|
// across the data store runtime / container runtime boundary, this may be undefined and if so, get
|
|
3908
4014
|
// the timestamp from the last processed message which should exist.
|
|
@@ -3929,8 +4035,10 @@ export class ContainerRuntime
|
|
|
3929
4035
|
* op processing, updating SummarizerNode state tracking, and garbage collection.
|
|
3930
4036
|
* @param options - options controlling how the summary is generated or submitted
|
|
3931
4037
|
*/
|
|
4038
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3932
4039
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
3933
4040
|
const {
|
|
4041
|
+
cancellationToken,
|
|
3934
4042
|
fullTree = false,
|
|
3935
4043
|
finalAttempt = false,
|
|
3936
4044
|
summaryLogger,
|
|
@@ -4050,7 +4158,7 @@ export class ContainerRuntime
|
|
|
4050
4158
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
4051
4159
|
details: {
|
|
4052
4160
|
...startSummaryResult,
|
|
4053
|
-
mismatchNumbers:
|
|
4161
|
+
mismatchNumbers: [...startSummaryResult.mismatchNumbers],
|
|
4054
4162
|
},
|
|
4055
4163
|
});
|
|
4056
4164
|
|
|
@@ -4074,7 +4182,7 @@ export class ContainerRuntime
|
|
|
4074
4182
|
// summarizer to reconnect in the future.
|
|
4075
4183
|
// Also checking for cancellation is a must as summary process may be abandoned for other reasons,
|
|
4076
4184
|
// like loss of connectivity for main (interactive) client.
|
|
4077
|
-
if (
|
|
4185
|
+
if (cancellationToken.cancelled) {
|
|
4078
4186
|
return { continue: false, error: "disconnected" };
|
|
4079
4187
|
}
|
|
4080
4188
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
@@ -4171,7 +4279,7 @@ export class ContainerRuntime
|
|
|
4171
4279
|
// Counting dataStores and handles
|
|
4172
4280
|
// Because handles are unchanged dataStores in the current logic,
|
|
4173
4281
|
// summarized dataStore count is total dataStore count minus handle count
|
|
4174
|
-
const dataStoreTree
|
|
4282
|
+
const dataStoreTree = summaryTree.tree[channelsTreeName];
|
|
4175
4283
|
|
|
4176
4284
|
assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
4177
4285
|
const handleCount = Object.values(dataStoreTree.tree).filter(
|
|
@@ -4215,10 +4323,7 @@ export class ContainerRuntime
|
|
|
4215
4323
|
|
|
4216
4324
|
let handle: string;
|
|
4217
4325
|
try {
|
|
4218
|
-
handle = await this.storage.uploadSummaryWithContext(
|
|
4219
|
-
summarizeResult.summary,
|
|
4220
|
-
summaryContext,
|
|
4221
|
-
);
|
|
4326
|
+
handle = await this.storage.uploadSummaryWithContext(summaryTree, summaryContext);
|
|
4222
4327
|
} catch (error) {
|
|
4223
4328
|
return {
|
|
4224
4329
|
stage: "generate",
|
|
@@ -4363,19 +4468,19 @@ export class ContainerRuntime
|
|
|
4363
4468
|
return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
|
|
4364
4469
|
}
|
|
4365
4470
|
|
|
4366
|
-
private hasPendingMessages() {
|
|
4471
|
+
private hasPendingMessages(): boolean {
|
|
4367
4472
|
return this.pendingMessagesCount !== 0;
|
|
4368
4473
|
}
|
|
4369
4474
|
|
|
4370
|
-
private updateDocumentDirtyState(dirty: boolean) {
|
|
4371
|
-
if (this.attachState
|
|
4372
|
-
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
4373
|
-
} else {
|
|
4475
|
+
private updateDocumentDirtyState(dirty: boolean): void {
|
|
4476
|
+
if (this.attachState === AttachState.Attached) {
|
|
4374
4477
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
4375
4478
|
assert(
|
|
4376
4479
|
!dirty || this.hasPendingMessages(),
|
|
4377
4480
|
0x3d3 /* if doc is dirty, there has to be pending ops */,
|
|
4378
4481
|
);
|
|
4482
|
+
} else {
|
|
4483
|
+
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
4379
4484
|
}
|
|
4380
4485
|
|
|
4381
4486
|
if (this.dirtyContainer === dirty) {
|
|
@@ -4393,9 +4498,12 @@ export class ContainerRuntime
|
|
|
4393
4498
|
| ContainerMessageType.FluidDataStoreOp
|
|
4394
4499
|
| ContainerMessageType.Alias
|
|
4395
4500
|
| ContainerMessageType.Attach,
|
|
4501
|
+
// TODO: better typing
|
|
4502
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
4396
4503
|
contents: any,
|
|
4397
4504
|
localOpMetadata: unknown = undefined,
|
|
4398
4505
|
): void {
|
|
4506
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4399
4507
|
this.submit({ type, contents }, localOpMetadata);
|
|
4400
4508
|
}
|
|
4401
4509
|
|
|
@@ -4469,7 +4577,7 @@ export class ContainerRuntime
|
|
|
4469
4577
|
// on this callback to do actual sending.
|
|
4470
4578
|
const schemaChangeMessage = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
4471
4579
|
if (schemaChangeMessage) {
|
|
4472
|
-
this.logger.sendTelemetryEvent({
|
|
4580
|
+
this.mc.logger.sendTelemetryEvent({
|
|
4473
4581
|
eventName: "SchemaChangeProposal",
|
|
4474
4582
|
refSeq: schemaChangeMessage.refSeq,
|
|
4475
4583
|
version: schemaChangeMessage.version,
|
|
@@ -4517,13 +4625,16 @@ export class ContainerRuntime
|
|
|
4517
4625
|
}
|
|
4518
4626
|
}
|
|
4519
4627
|
|
|
4520
|
-
private scheduleFlush() {
|
|
4628
|
+
private scheduleFlush(): void {
|
|
4521
4629
|
if (this.flushTaskExists) {
|
|
4522
4630
|
return;
|
|
4523
4631
|
}
|
|
4524
4632
|
|
|
4525
4633
|
this.flushTaskExists = true;
|
|
4526
|
-
|
|
4634
|
+
|
|
4635
|
+
// TODO: hoist this out of the function scope to save unnecessary allocations
|
|
4636
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping -- Separate `flush` method already exists in outer scope
|
|
4637
|
+
const flush = (): void => {
|
|
4527
4638
|
this.flushTaskExists = false;
|
|
4528
4639
|
try {
|
|
4529
4640
|
this.flush();
|
|
@@ -4533,31 +4644,37 @@ export class ContainerRuntime
|
|
|
4533
4644
|
};
|
|
4534
4645
|
|
|
4535
4646
|
switch (this.flushMode) {
|
|
4536
|
-
case FlushMode.TurnBased:
|
|
4647
|
+
case FlushMode.TurnBased: {
|
|
4537
4648
|
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
4538
4649
|
// batch at the end of the turn
|
|
4539
4650
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
4540
4651
|
Promise.resolve().then(flush);
|
|
4541
4652
|
break;
|
|
4653
|
+
}
|
|
4542
4654
|
|
|
4543
4655
|
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
4544
|
-
case FlushModeExperimental.Async as unknown as FlushMode:
|
|
4656
|
+
case FlushModeExperimental.Async as unknown as FlushMode: {
|
|
4545
4657
|
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
4546
4658
|
// batch when all micro-tasks are complete.
|
|
4547
4659
|
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
4548
4660
|
setTimeout(flush, 0);
|
|
4549
4661
|
break;
|
|
4662
|
+
}
|
|
4550
4663
|
|
|
4551
|
-
default:
|
|
4664
|
+
default: {
|
|
4552
4665
|
assert(
|
|
4553
4666
|
this._orderSequentiallyCalls > 0,
|
|
4554
4667
|
0x587 /* Unreachable unless running under orderSequentially */,
|
|
4555
4668
|
);
|
|
4556
4669
|
break;
|
|
4670
|
+
}
|
|
4557
4671
|
}
|
|
4558
4672
|
}
|
|
4559
4673
|
|
|
4560
|
-
private submitSummaryMessage(
|
|
4674
|
+
private submitSummaryMessage(
|
|
4675
|
+
contents: ISummaryContent,
|
|
4676
|
+
referenceSequenceNumber: number,
|
|
4677
|
+
): number {
|
|
4561
4678
|
this.verifyNotClosed();
|
|
4562
4679
|
assert(
|
|
4563
4680
|
this.connected,
|
|
@@ -4567,17 +4684,14 @@ export class ContainerRuntime
|
|
|
4567
4684
|
// System message should not be sent in the middle of the batch.
|
|
4568
4685
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
4569
4686
|
|
|
4570
|
-
|
|
4571
|
-
return this.submitSummaryFn !== undefined
|
|
4572
|
-
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
4573
|
-
: this.submitFn(MessageType.Summarize, contents, false);
|
|
4687
|
+
return this.submitSummaryFn(contents, referenceSequenceNumber);
|
|
4574
4688
|
}
|
|
4575
4689
|
|
|
4576
4690
|
/**
|
|
4577
4691
|
* Throw an error if the runtime is closed. Methods that are expected to potentially
|
|
4578
4692
|
* be called after dispose due to asynchrony should not call this.
|
|
4579
4693
|
*/
|
|
4580
|
-
private verifyNotClosed() {
|
|
4694
|
+
private verifyNotClosed(): void {
|
|
4581
4695
|
if (this._disposed) {
|
|
4582
4696
|
throw new Error("Runtime is closed");
|
|
4583
4697
|
}
|
|
@@ -4589,7 +4703,7 @@ export class ContainerRuntime
|
|
|
4589
4703
|
* @remarks - If the "Offline Load" feature is enabled, the batchId is included in the resubmitted messages,
|
|
4590
4704
|
* for correlation to detect container forking.
|
|
4591
4705
|
*/
|
|
4592
|
-
private reSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId) {
|
|
4706
|
+
private reSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId): void {
|
|
4593
4707
|
this.orderSequentially(() => {
|
|
4594
4708
|
for (const message of batch) {
|
|
4595
4709
|
this.reSubmit(message);
|
|
@@ -4601,7 +4715,7 @@ export class ContainerRuntime
|
|
|
4601
4715
|
this.flush(this.offlineEnabled ? batchId : undefined);
|
|
4602
4716
|
}
|
|
4603
4717
|
|
|
4604
|
-
private reSubmit(message: PendingMessageResubmitData) {
|
|
4718
|
+
private reSubmit(message: PendingMessageResubmitData): void {
|
|
4605
4719
|
// Need to parse from string for back-compat
|
|
4606
4720
|
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
4607
4721
|
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
@@ -4618,19 +4732,20 @@ export class ContainerRuntime
|
|
|
4618
4732
|
message: LocalContainerRuntimeMessage,
|
|
4619
4733
|
localOpMetadata: unknown,
|
|
4620
4734
|
opMetadata: Record<string, unknown> | undefined,
|
|
4621
|
-
) {
|
|
4735
|
+
): void {
|
|
4622
4736
|
assert(
|
|
4623
|
-
|
|
4737
|
+
this._summarizer === undefined,
|
|
4624
4738
|
0x8f2 /* Summarizer never reconnects so should never resubmit */,
|
|
4625
4739
|
);
|
|
4626
4740
|
switch (message.type) {
|
|
4627
4741
|
case ContainerMessageType.FluidDataStoreOp:
|
|
4628
4742
|
case ContainerMessageType.Attach:
|
|
4629
|
-
case ContainerMessageType.Alias:
|
|
4743
|
+
case ContainerMessageType.Alias: {
|
|
4630
4744
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
4631
4745
|
// and trigger resubmission on it.
|
|
4632
4746
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
4633
4747
|
break;
|
|
4748
|
+
}
|
|
4634
4749
|
case ContainerMessageType.IdAllocation: {
|
|
4635
4750
|
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
4636
4751
|
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
@@ -4641,20 +4756,24 @@ export class ContainerRuntime
|
|
|
4641
4756
|
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
4642
4757
|
break;
|
|
4643
4758
|
}
|
|
4644
|
-
case ContainerMessageType.BlobAttach:
|
|
4759
|
+
case ContainerMessageType.BlobAttach: {
|
|
4645
4760
|
this.blobManager.reSubmit(opMetadata);
|
|
4646
4761
|
break;
|
|
4647
|
-
|
|
4762
|
+
}
|
|
4763
|
+
case ContainerMessageType.Rejoin: {
|
|
4648
4764
|
this.submit(message);
|
|
4649
4765
|
break;
|
|
4650
|
-
|
|
4766
|
+
}
|
|
4767
|
+
case ContainerMessageType.GC: {
|
|
4651
4768
|
this.submit(message);
|
|
4652
4769
|
break;
|
|
4653
|
-
|
|
4770
|
+
}
|
|
4771
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
4654
4772
|
// There is no need to resend this message. Document schema controller will properly resend it again (if needed)
|
|
4655
4773
|
// on a first occasion (any ops sent after reconnect). There is a good chance, though, that it will not want to
|
|
4656
4774
|
// send any ops, as some other client already changed schema.
|
|
4657
4775
|
break;
|
|
4776
|
+
}
|
|
4658
4777
|
default: {
|
|
4659
4778
|
const error = getUnknownMessageTypeError(message.type, "reSubmitCore" /* codePath */);
|
|
4660
4779
|
this.closeFn(error);
|
|
@@ -4663,22 +4782,27 @@ export class ContainerRuntime
|
|
|
4663
4782
|
}
|
|
4664
4783
|
}
|
|
4665
4784
|
|
|
4666
|
-
private rollback(content: string | undefined, localOpMetadata: unknown) {
|
|
4785
|
+
private rollback(content: string | undefined, localOpMetadata: unknown): void {
|
|
4667
4786
|
// Need to parse from string for back-compat
|
|
4668
4787
|
const { type, contents } = this.parseLocalOpContent(content);
|
|
4669
4788
|
switch (type) {
|
|
4670
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
4789
|
+
case ContainerMessageType.FluidDataStoreOp: {
|
|
4671
4790
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
4672
4791
|
// and trigger rollback on it.
|
|
4673
4792
|
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
4674
4793
|
break;
|
|
4675
|
-
|
|
4794
|
+
}
|
|
4795
|
+
default: {
|
|
4676
4796
|
throw new Error(`Can't rollback ${type}`);
|
|
4797
|
+
}
|
|
4677
4798
|
}
|
|
4678
4799
|
}
|
|
4679
4800
|
|
|
4680
|
-
/**
|
|
4681
|
-
|
|
4801
|
+
/**
|
|
4802
|
+
* Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck
|
|
4803
|
+
*/
|
|
4804
|
+
// eslint-disable-next-line import/no-deprecated
|
|
4805
|
+
public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise<void> {
|
|
4682
4806
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
4683
4807
|
// proposalHandle is always passed from RunningSummarizer.
|
|
4684
4808
|
assert(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
@@ -4724,6 +4848,9 @@ export class ContainerRuntime
|
|
|
4724
4848
|
};
|
|
4725
4849
|
}
|
|
4726
4850
|
|
|
4851
|
+
private readonly readAndParseBlob = async <T>(id: string): Promise<T> =>
|
|
4852
|
+
readAndParse<T>(this.storage, id);
|
|
4853
|
+
|
|
4727
4854
|
/**
|
|
4728
4855
|
* Fetches the latest snapshot from storage. If the fetched snapshot is same or newer than the one for which ack
|
|
4729
4856
|
* was received, close this client. Fetching the snapshot will update the cache for this client so if it's
|
|
@@ -4735,7 +4862,7 @@ export class ContainerRuntime
|
|
|
4735
4862
|
targetRefSeq: number,
|
|
4736
4863
|
targetAckHandle: string,
|
|
4737
4864
|
logger: ITelemetryLoggerExt,
|
|
4738
|
-
) {
|
|
4865
|
+
): Promise<void> {
|
|
4739
4866
|
const fetchedSnapshotRefSeq = await PerformanceEvent.timedExecAsync(
|
|
4740
4867
|
logger,
|
|
4741
4868
|
{ eventName: "RefreshLatestSummaryAckFetch" },
|
|
@@ -4784,6 +4911,7 @@ export class ContainerRuntime
|
|
|
4784
4911
|
snapshotTree = snapshot.snapshotTree;
|
|
4785
4912
|
} else {
|
|
4786
4913
|
const versions = await this.storage.getVersions(
|
|
4914
|
+
// eslint-disable-next-line unicorn/no-null
|
|
4787
4915
|
null,
|
|
4788
4916
|
1,
|
|
4789
4917
|
scenarioName,
|
|
@@ -4799,8 +4927,8 @@ export class ContainerRuntime
|
|
|
4799
4927
|
}
|
|
4800
4928
|
|
|
4801
4929
|
props.getSnapshotDuration = trace.trace().duration;
|
|
4802
|
-
|
|
4803
|
-
const snapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
4930
|
+
|
|
4931
|
+
const snapshotRefSeq = await seqFromTree(snapshotTree, this.readAndParseBlob);
|
|
4804
4932
|
props.snapshotRefSeq = snapshotRefSeq;
|
|
4805
4933
|
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
4806
4934
|
|
|
@@ -4852,7 +4980,7 @@ export class ContainerRuntime
|
|
|
4852
4980
|
const logAndReturnPendingState = (
|
|
4853
4981
|
event: PerformanceEvent,
|
|
4854
4982
|
pendingState?: IPendingRuntimeState,
|
|
4855
|
-
) => {
|
|
4983
|
+
): IPendingRuntimeState | undefined => {
|
|
4856
4984
|
event.end({
|
|
4857
4985
|
attachmentBlobsSize: Object.keys(pendingState?.pendingAttachmentBlobs ?? {}).length,
|
|
4858
4986
|
pendingOpsSize: pendingState?.pending?.pendingStates.length,
|
|
@@ -4880,28 +5008,28 @@ export class ContainerRuntime
|
|
|
4880
5008
|
}
|
|
4881
5009
|
|
|
4882
5010
|
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|
|
4883
|
-
if (this.
|
|
4884
|
-
return this.
|
|
4885
|
-
} else if (this.summaryManager
|
|
4886
|
-
return this.summaryManager.summarizeOnDemand(options);
|
|
4887
|
-
} else {
|
|
5011
|
+
if (this._summarizer !== undefined) {
|
|
5012
|
+
return this._summarizer.summarizeOnDemand(options);
|
|
5013
|
+
} else if (this.summaryManager === undefined) {
|
|
4888
5014
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
4889
5015
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
4890
5016
|
// because it is a misuse of the API rather than an expected failure.
|
|
4891
5017
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
5018
|
+
} else {
|
|
5019
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
4892
5020
|
}
|
|
4893
5021
|
}
|
|
4894
5022
|
|
|
4895
5023
|
public enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
|
|
4896
|
-
if (this.
|
|
4897
|
-
return this.
|
|
4898
|
-
} else if (this.summaryManager
|
|
4899
|
-
return this.summaryManager.enqueueSummarize(options);
|
|
4900
|
-
} else {
|
|
5024
|
+
if (this._summarizer !== undefined) {
|
|
5025
|
+
return this._summarizer.enqueueSummarize(options);
|
|
5026
|
+
} else if (this.summaryManager === undefined) {
|
|
4901
5027
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
4902
5028
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
4903
5029
|
// because it is a misuse of the API rather than an expected failure.
|
|
4904
5030
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
5031
|
+
} else {
|
|
5032
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
4905
5033
|
}
|
|
4906
5034
|
}
|
|
4907
5035
|
|
|
@@ -4916,7 +5044,7 @@ export class ContainerRuntime
|
|
|
4916
5044
|
|
|
4917
5045
|
private validateSummaryHeuristicConfiguration(
|
|
4918
5046
|
configuration: ISummaryConfigurationHeuristics,
|
|
4919
|
-
) {
|
|
5047
|
+
): void {
|
|
4920
5048
|
// eslint-disable-next-line no-restricted-syntax
|
|
4921
5049
|
for (const prop in configuration) {
|
|
4922
5050
|
if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
|