@fluidframework/container-runtime 2.0.0-internal.6.1.1 → 2.0.0-internal.6.3.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/CHANGELOG.md +39 -0
- package/README.md +4 -3
- package/dist/batchTracker.d.ts +1 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +5 -4
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +4 -21
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +119 -185
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +13 -12
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +99 -16
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +380 -242
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +4 -5
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +2 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +40 -41
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +1 -2
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -8
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.js +2 -2
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +23 -25
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerProxyBase.d.ts +1 -1
- package/dist/deltaManagerProxyBase.js +2 -2
- package/dist/deltaManagerProxyBase.js.map +1 -1
- package/dist/deltaScheduler.js +6 -6
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/error.d.ts +14 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +21 -0
- package/dist/error.js.map +1 -0
- package/dist/gc/garbageCollection.d.ts +4 -6
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +26 -25
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +5 -3
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.js +7 -7
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +4 -7
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +15 -52
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +2 -0
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +4 -4
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/gc/index.d.ts +1 -1
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +1 -2
- package/dist/gc/index.js.map +1 -1
- package/dist/id-compressor/appendOnlySortedMap.d.ts +8 -30
- package/dist/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
- package/dist/id-compressor/appendOnlySortedMap.js +26 -68
- package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/dist/id-compressor/finalSpace.d.ts +29 -0
- package/dist/id-compressor/finalSpace.d.ts.map +1 -0
- package/dist/id-compressor/finalSpace.js +62 -0
- package/dist/id-compressor/finalSpace.js.map +1 -0
- package/dist/id-compressor/idCompressor.d.ts +25 -250
- package/dist/id-compressor/idCompressor.d.ts.map +1 -1
- package/dist/id-compressor/idCompressor.js +387 -1150
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/id-compressor/identifiers.d.ts +32 -0
- package/dist/id-compressor/identifiers.d.ts.map +1 -0
- package/dist/id-compressor/identifiers.js +15 -0
- package/dist/id-compressor/identifiers.js.map +1 -0
- package/dist/id-compressor/index.d.ts +5 -6
- package/dist/id-compressor/index.d.ts.map +1 -1
- package/dist/id-compressor/index.js +20 -26
- package/dist/id-compressor/index.js.map +1 -1
- package/dist/id-compressor/persistanceUtilities.d.ts +22 -0
- package/dist/id-compressor/persistanceUtilities.d.ts.map +1 -0
- package/dist/id-compressor/persistanceUtilities.js +43 -0
- package/dist/id-compressor/persistanceUtilities.js.map +1 -0
- package/dist/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
- package/dist/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
- package/dist/id-compressor/sessionSpaceNormalizer.js +80 -0
- package/dist/id-compressor/sessionSpaceNormalizer.js.map +1 -0
- package/dist/id-compressor/sessions.d.ts +115 -0
- package/dist/id-compressor/sessions.d.ts.map +1 -0
- package/dist/id-compressor/sessions.js +305 -0
- package/dist/id-compressor/sessions.js.map +1 -0
- package/dist/id-compressor/utilities.d.ts +49 -0
- package/dist/id-compressor/utilities.d.ts.map +1 -0
- package/dist/id-compressor/utilities.js +166 -0
- package/dist/id-compressor/utilities.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.js +5 -5
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +11 -10
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +3 -3
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +14 -15
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +1 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +16 -17
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +11 -5
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +12 -5
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +36 -23
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +23 -23
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/index.d.ts +3 -3
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +2 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -3
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +8 -8
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +3 -3
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +27 -4
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +246 -74
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +6 -5
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +73 -69
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +2 -2
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js +2 -2
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +2 -2
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/index.d.ts +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 +5 -14
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +32 -109
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +5 -88
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +38 -25
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +2 -3
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +9 -8
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.js +2 -2
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +10 -4
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +52 -48
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +7 -6
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +30 -22
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +3 -2
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +4 -21
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +91 -157
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +2 -1
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +99 -16
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +332 -192
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +2 -3
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +2 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +3 -4
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts +1 -2
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +1 -2
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.js +1 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +2 -4
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerProxyBase.d.ts +1 -1
- package/lib/deltaManagerProxyBase.js +1 -1
- package/lib/deltaManagerProxyBase.js.map +1 -1
- package/lib/deltaScheduler.js +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/error.d.ts +14 -0
- package/lib/error.d.ts.map +1 -0
- package/lib/error.js +17 -0
- package/lib/error.js.map +1 -0
- package/lib/gc/garbageCollection.d.ts +4 -6
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +26 -25
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +3 -1
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -2
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.js +1 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +4 -7
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +16 -53
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +2 -0
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/gc/index.d.ts +1 -1
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/id-compressor/appendOnlySortedMap.d.ts +8 -30
- package/lib/id-compressor/appendOnlySortedMap.d.ts.map +1 -1
- package/lib/id-compressor/appendOnlySortedMap.js +25 -66
- package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/lib/id-compressor/finalSpace.d.ts +29 -0
- package/lib/id-compressor/finalSpace.d.ts.map +1 -0
- package/lib/id-compressor/finalSpace.js +58 -0
- package/lib/id-compressor/finalSpace.js.map +1 -0
- package/lib/id-compressor/idCompressor.d.ts +25 -250
- package/lib/id-compressor/idCompressor.d.ts.map +1 -1
- package/lib/id-compressor/idCompressor.js +382 -1139
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/id-compressor/identifiers.d.ts +32 -0
- package/lib/id-compressor/identifiers.d.ts.map +1 -0
- package/lib/id-compressor/identifiers.js +11 -0
- package/lib/id-compressor/identifiers.js.map +1 -0
- package/lib/id-compressor/index.d.ts +5 -6
- package/lib/id-compressor/index.d.ts.map +1 -1
- package/lib/id-compressor/index.js +5 -6
- package/lib/id-compressor/index.js.map +1 -1
- package/lib/id-compressor/persistanceUtilities.d.ts +22 -0
- package/lib/id-compressor/persistanceUtilities.d.ts.map +1 -0
- package/lib/id-compressor/persistanceUtilities.js +34 -0
- package/lib/id-compressor/persistanceUtilities.js.map +1 -0
- package/lib/id-compressor/sessionSpaceNormalizer.d.ts +46 -0
- package/lib/id-compressor/sessionSpaceNormalizer.d.ts.map +1 -0
- package/lib/id-compressor/sessionSpaceNormalizer.js +76 -0
- package/lib/id-compressor/sessionSpaceNormalizer.js.map +1 -0
- package/lib/id-compressor/sessions.d.ts +115 -0
- package/lib/id-compressor/sessions.d.ts.map +1 -0
- package/lib/id-compressor/sessions.js +290 -0
- package/lib/id-compressor/sessions.js.map +1 -0
- package/lib/id-compressor/utilities.d.ts +49 -0
- package/lib/id-compressor/utilities.d.ts.map +1 -0
- package/lib/id-compressor/utilities.js +148 -0
- package/lib/id-compressor/utilities.js.map +1 -0
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.js +3 -3
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +2 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +1 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +2 -3
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +1 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -8
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +12 -6
- 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 +12 -5
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +21 -8
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +3 -3
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/index.d.ts +3 -3
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -3
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +3 -3
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +27 -4
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +240 -68
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +6 -5
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +69 -65
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +2 -2
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/index.d.ts +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 +5 -14
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +16 -93
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +6 -30
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +0 -11
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -86
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +38 -25
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +2 -3
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +2 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.js +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +10 -4
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +46 -42
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +7 -6
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +26 -18
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +30 -29
- package/src/batchTracker.ts +3 -2
- package/src/blobManager.ts +105 -185
- package/src/connectionTelemetry.ts +2 -1
- package/src/containerRuntime.ts +481 -267
- package/src/dataStore.ts +2 -3
- package/src/dataStoreContext.ts +5 -8
- package/src/dataStoreContexts.ts +2 -4
- package/src/dataStoreRegistry.ts +1 -1
- package/src/dataStores.ts +4 -7
- package/src/deltaManagerProxyBase.ts +1 -1
- package/src/deltaScheduler.ts +1 -1
- package/src/error.ts +18 -0
- package/src/gc/garbageCollection.ts +39 -41
- package/src/gc/gcConfigs.ts +4 -2
- package/src/gc/gcDefinitions.ts +4 -6
- package/src/gc/gcHelpers.ts +1 -1
- package/src/gc/gcSummaryStateTracker.ts +19 -65
- package/src/gc/gcTelemetry.ts +2 -0
- package/src/gc/gcUnreferencedStateTracker.ts +1 -1
- package/src/gc/index.ts +0 -1
- package/src/id-compressor/appendOnlySortedMap.ts +26 -87
- package/src/id-compressor/finalSpace.ts +67 -0
- package/src/id-compressor/idCompressor.ts +456 -1681
- package/src/id-compressor/identifiers.ts +42 -0
- package/src/id-compressor/index.ts +11 -20
- package/src/id-compressor/persistanceUtilities.ts +58 -0
- package/src/id-compressor/sessionSpaceNormalizer.ts +83 -0
- package/src/id-compressor/sessions.ts +405 -0
- package/src/id-compressor/utilities.ts +187 -0
- package/src/index.ts +7 -1
- package/src/opLifecycle/opCompressor.ts +3 -3
- package/src/opLifecycle/opDecompressor.ts +2 -1
- package/src/opLifecycle/opGroupingManager.ts +1 -1
- package/src/opLifecycle/opSplitter.ts +4 -4
- package/src/opLifecycle/outbox.ts +14 -11
- package/src/opLifecycle/remoteMessageProcessor.ts +19 -6
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +50 -29
- package/src/scheduleManager.ts +6 -4
- package/src/summary/index.ts +4 -3
- package/src/summary/orderedClientElection.ts +8 -5
- package/src/summary/runWhileConnectedCoordinator.ts +1 -1
- package/src/summary/runningSummarizer.ts +273 -97
- package/src/summary/summarizer.ts +23 -12
- package/src/summary/summarizerClientElection.ts +2 -2
- package/src/summary/summarizerHeuristics.ts +1 -1
- package/src/summary/summarizerNode/index.ts +1 -2
- package/src/summary/summarizerNode/summarizerNode.ts +23 -145
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +7 -38
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +3 -123
- package/src/summary/summarizerTypes.ts +40 -25
- package/src/summary/summaryCollection.ts +3 -3
- package/src/summary/summaryFormat.ts +1 -1
- package/src/summary/summaryGenerator.ts +52 -55
- package/src/summary/summaryManager.ts +36 -13
- package/dist/id-compressor/idRange.d.ts +0 -11
- package/dist/id-compressor/idRange.d.ts.map +0 -1
- package/dist/id-compressor/idRange.js +0 -29
- package/dist/id-compressor/idRange.js.map +0 -1
- package/dist/id-compressor/numericUuid.d.ts +0 -59
- package/dist/id-compressor/numericUuid.d.ts.map +0 -1
- package/dist/id-compressor/numericUuid.js +0 -325
- package/dist/id-compressor/numericUuid.js.map +0 -1
- package/dist/id-compressor/sessionIdNormalizer.d.ts +0 -138
- package/dist/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
- package/dist/id-compressor/sessionIdNormalizer.js +0 -483
- package/dist/id-compressor/sessionIdNormalizer.js.map +0 -1
- package/dist/id-compressor/utils.d.ts +0 -57
- package/dist/id-compressor/utils.d.ts.map +0 -1
- package/dist/id-compressor/utils.js +0 -90
- package/dist/id-compressor/utils.js.map +0 -1
- package/dist/id-compressor/uuidUtilities.d.ts +0 -28
- package/dist/id-compressor/uuidUtilities.d.ts.map +0 -1
- package/dist/id-compressor/uuidUtilities.js +0 -104
- package/dist/id-compressor/uuidUtilities.js.map +0 -1
- package/lib/id-compressor/idRange.d.ts +0 -11
- package/lib/id-compressor/idRange.d.ts.map +0 -1
- package/lib/id-compressor/idRange.js +0 -25
- package/lib/id-compressor/idRange.js.map +0 -1
- package/lib/id-compressor/numericUuid.d.ts +0 -59
- package/lib/id-compressor/numericUuid.d.ts.map +0 -1
- package/lib/id-compressor/numericUuid.js +0 -315
- package/lib/id-compressor/numericUuid.js.map +0 -1
- package/lib/id-compressor/sessionIdNormalizer.d.ts +0 -138
- package/lib/id-compressor/sessionIdNormalizer.d.ts.map +0 -1
- package/lib/id-compressor/sessionIdNormalizer.js +0 -479
- package/lib/id-compressor/sessionIdNormalizer.js.map +0 -1
- package/lib/id-compressor/utils.d.ts +0 -57
- package/lib/id-compressor/utils.d.ts.map +0 -1
- package/lib/id-compressor/utils.js +0 -79
- package/lib/id-compressor/utils.js.map +0 -1
- package/lib/id-compressor/uuidUtilities.d.ts +0 -28
- package/lib/id-compressor/uuidUtilities.d.ts.map +0 -1
- package/lib/id-compressor/uuidUtilities.js +0 -96
- package/lib/id-compressor/uuidUtilities.js.map +0 -1
- package/src/id-compressor/idRange.ts +0 -35
- package/src/id-compressor/numericUuid.ts +0 -383
- package/src/id-compressor/sessionIdNormalizer.ts +0 -609
- package/src/id-compressor/utils.ts +0 -114
- package/src/id-compressor/uuidUtilities.ts +0 -120
package/src/containerRuntime.ts
CHANGED
|
@@ -27,23 +27,22 @@ import {
|
|
|
27
27
|
IContainerRuntime,
|
|
28
28
|
IContainerRuntimeEvents,
|
|
29
29
|
} from "@fluidframework/container-runtime-definitions";
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
delay,
|
|
33
|
-
Trace,
|
|
34
|
-
TypedEventEmitter,
|
|
35
|
-
unreachableCase,
|
|
36
|
-
} from "@fluidframework/common-utils";
|
|
37
|
-
import { LazyPromise } from "@fluidframework/core-utils";
|
|
30
|
+
import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
|
|
31
|
+
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
38
32
|
import {
|
|
39
33
|
createChildLogger,
|
|
34
|
+
createChildMonitoringContext,
|
|
35
|
+
DataCorruptionError,
|
|
36
|
+
DataProcessingError,
|
|
37
|
+
GenericError,
|
|
40
38
|
raiseConnectedEvent,
|
|
41
39
|
PerformanceEvent,
|
|
40
|
+
// eslint-disable-next-line import/no-deprecated
|
|
42
41
|
TaggedLoggerAdapter,
|
|
43
42
|
MonitoringContext,
|
|
44
43
|
wrapError,
|
|
45
44
|
ITelemetryLoggerExt,
|
|
46
|
-
|
|
45
|
+
UsageError,
|
|
47
46
|
} from "@fluidframework/telemetry-utils";
|
|
48
47
|
import {
|
|
49
48
|
DriverHeader,
|
|
@@ -52,12 +51,6 @@ import {
|
|
|
52
51
|
ISummaryContext,
|
|
53
52
|
} from "@fluidframework/driver-definitions";
|
|
54
53
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
55
|
-
import {
|
|
56
|
-
DataCorruptionError,
|
|
57
|
-
DataProcessingError,
|
|
58
|
-
GenericError,
|
|
59
|
-
UsageError,
|
|
60
|
-
} from "@fluidframework/container-utils";
|
|
61
54
|
import {
|
|
62
55
|
IClientDetails,
|
|
63
56
|
IDocumentMessage,
|
|
@@ -133,7 +126,6 @@ import {
|
|
|
133
126
|
IContainerRuntimeMetadata,
|
|
134
127
|
ICreateContainerMetadata,
|
|
135
128
|
idCompressorBlobName,
|
|
136
|
-
IFetchSnapshotResult,
|
|
137
129
|
IRootSummarizerNodeWithGC,
|
|
138
130
|
ISummaryMetadataMessage,
|
|
139
131
|
metadataBlobName,
|
|
@@ -157,6 +149,12 @@ import {
|
|
|
157
149
|
RunWhileConnectedCoordinator,
|
|
158
150
|
IGenerateSummaryTreeResult,
|
|
159
151
|
RetriableSummaryError,
|
|
152
|
+
IOnDemandSummarizeOptions,
|
|
153
|
+
ISummarizeResults,
|
|
154
|
+
IEnqueueSummarizeOptions,
|
|
155
|
+
EnqueueSummarizeResult,
|
|
156
|
+
ISummarizerEvents,
|
|
157
|
+
IBaseSummarizeResult,
|
|
160
158
|
} from "./summary";
|
|
161
159
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
162
160
|
import {
|
|
@@ -214,11 +212,64 @@ export enum ContainerMessageType {
|
|
|
214
212
|
IdAllocation = "idAllocation",
|
|
215
213
|
}
|
|
216
214
|
|
|
215
|
+
/**
|
|
216
|
+
* How should an older client handle an unrecognized remote op type?
|
|
217
|
+
*
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
export type CompatModeBehavior =
|
|
221
|
+
/** Ignore the op. It won't be persisted if this client summarizes */
|
|
222
|
+
| "Ignore"
|
|
223
|
+
/** Fail processing immediately. (The container will close) */
|
|
224
|
+
| "FailToProcess";
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* All the info an older client would need to know how to handle an unrecognized remote op type
|
|
228
|
+
*
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
export interface IContainerRuntimeMessageCompatDetails {
|
|
232
|
+
/** How should an older client handle an unrecognized remote op type? */
|
|
233
|
+
behavior: CompatModeBehavior;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Utility to implement compat behaviors given an unknown message type
|
|
238
|
+
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
239
|
+
*
|
|
240
|
+
* @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
|
|
241
|
+
* handled before calling this function (e.g. in a switch statement).
|
|
242
|
+
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
243
|
+
*/
|
|
244
|
+
function compatBehaviorAllowsMessageType(
|
|
245
|
+
_unknownContainerRuntimeMessageType: never,
|
|
246
|
+
compatBehavior: "Ignore" | "FailToProcess" | undefined,
|
|
247
|
+
): boolean {
|
|
248
|
+
// undefined defaults to same behavior as "FailToProcess"
|
|
249
|
+
return compatBehavior === "Ignore";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The unpacked runtime message / details to be handled or dispatched by the ContainerRuntime
|
|
254
|
+
*
|
|
255
|
+
* IMPORTANT: when creating one to be serialized, set the properties in the order they appear here.
|
|
256
|
+
* This way stringified values can be compared.
|
|
257
|
+
*/
|
|
217
258
|
export interface ContainerRuntimeMessage {
|
|
218
|
-
|
|
259
|
+
/** Type of the op, within the ContainerRuntime's domain */
|
|
219
260
|
type: ContainerMessageType;
|
|
261
|
+
/** Domain-specific contents, interpreted according to the type */
|
|
262
|
+
contents: any;
|
|
263
|
+
/** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
|
|
264
|
+
compatDetails?: IContainerRuntimeMessageCompatDetails;
|
|
220
265
|
}
|
|
221
266
|
|
|
267
|
+
/**
|
|
268
|
+
* An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
|
|
269
|
+
* promoted up to the outer object
|
|
270
|
+
*/
|
|
271
|
+
export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
|
|
272
|
+
|
|
222
273
|
export interface ISummaryBaseConfiguration {
|
|
223
274
|
/**
|
|
224
275
|
* Delay before first attempt to spawn summarizing container.
|
|
@@ -457,9 +508,13 @@ export enum RuntimeHeaders {
|
|
|
457
508
|
|
|
458
509
|
/** True if a tombstoned object should be returned without erroring */
|
|
459
510
|
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
511
|
+
/** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
|
|
512
|
+
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
460
513
|
|
|
461
514
|
/** Tombstone error responses will have this header set to true */
|
|
462
515
|
export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
516
|
+
/** Inactive error responses will have this header set to true */
|
|
517
|
+
export const InactiveResponseHeaderKey = "isInactive";
|
|
463
518
|
|
|
464
519
|
/**
|
|
465
520
|
* The full set of parsed header data that may be found on Runtime requests
|
|
@@ -500,7 +555,7 @@ interface OldContainerContextWithLogger extends Omit<IContainerContext, "taggedL
|
|
|
500
555
|
* instantiated runtime in a new instance of the container, so it can load to the
|
|
501
556
|
* same state
|
|
502
557
|
*/
|
|
503
|
-
interface IPendingRuntimeState {
|
|
558
|
+
export interface IPendingRuntimeState {
|
|
504
559
|
/**
|
|
505
560
|
* Pending ops from PendingStateManager
|
|
506
561
|
*/
|
|
@@ -529,6 +584,11 @@ const defaultCompressionConfig = {
|
|
|
529
584
|
|
|
530
585
|
const defaultChunkSizeInBytes = 204800;
|
|
531
586
|
|
|
587
|
+
/** The default time to wait for pending ops to be processed during summarization */
|
|
588
|
+
export const defaultPendingOpsWaitTimeoutMs = 1000;
|
|
589
|
+
/** The default time to delay a summarization retry attempt when there are pending ops */
|
|
590
|
+
export const defaultPendingOpsRetryDelayMs = 1000;
|
|
591
|
+
|
|
532
592
|
/**
|
|
533
593
|
* Instead of refreshing from latest because we do not have 100% confidence in the state
|
|
534
594
|
* of the current system, we should close the summarizer and let it recover.
|
|
@@ -605,7 +665,7 @@ export const makeLegacySendBatchFn =
|
|
|
605
665
|
* It will define the store level mappings.
|
|
606
666
|
*/
|
|
607
667
|
export class ContainerRuntime
|
|
608
|
-
extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
668
|
+
extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
|
|
609
669
|
implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
|
|
610
670
|
{
|
|
611
671
|
/**
|
|
@@ -665,16 +725,30 @@ export class ContainerRuntime
|
|
|
665
725
|
* - initializeEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
666
726
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
667
727
|
*/
|
|
668
|
-
public static async loadRuntime(
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
728
|
+
public static async loadRuntime(
|
|
729
|
+
params: {
|
|
730
|
+
context: IContainerContext;
|
|
731
|
+
registryEntries: NamedFluidDataStoreRegistryEntries;
|
|
732
|
+
existing: boolean;
|
|
733
|
+
runtimeOptions?: IContainerRuntimeOptions;
|
|
734
|
+
containerScope?: FluidObject;
|
|
735
|
+
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
736
|
+
} & (
|
|
737
|
+
| {
|
|
738
|
+
requestHandler?: (
|
|
739
|
+
request: IRequest,
|
|
740
|
+
runtime: IContainerRuntime,
|
|
741
|
+
) => Promise<IResponse>;
|
|
742
|
+
initializeEntryPoint?: undefined;
|
|
743
|
+
}
|
|
744
|
+
| {
|
|
745
|
+
requestHandler?: undefined;
|
|
746
|
+
initializeEntryPoint: (
|
|
747
|
+
containerRuntime: IContainerRuntime,
|
|
748
|
+
) => Promise<FluidObject>;
|
|
749
|
+
}
|
|
750
|
+
),
|
|
751
|
+
): Promise<ContainerRuntime> {
|
|
678
752
|
const {
|
|
679
753
|
context,
|
|
680
754
|
registryEntries,
|
|
@@ -683,14 +757,25 @@ export class ContainerRuntime
|
|
|
683
757
|
runtimeOptions = {},
|
|
684
758
|
containerScope = {},
|
|
685
759
|
containerRuntimeCtor = ContainerRuntime,
|
|
686
|
-
initializeEntryPoint,
|
|
687
760
|
} = params;
|
|
688
761
|
|
|
762
|
+
const initializeEntryPoint =
|
|
763
|
+
params.initializeEntryPoint ??
|
|
764
|
+
(async (containerRuntime: IContainerRuntime) => ({
|
|
765
|
+
get IFluidRouter() {
|
|
766
|
+
return this;
|
|
767
|
+
},
|
|
768
|
+
async request(req) {
|
|
769
|
+
return containerRuntime.request(req);
|
|
770
|
+
},
|
|
771
|
+
}));
|
|
772
|
+
|
|
689
773
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
690
774
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
691
775
|
const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
|
|
692
776
|
const passLogger =
|
|
693
777
|
backCompatContext.taggedLogger ??
|
|
778
|
+
// eslint-disable-next-line import/no-deprecated
|
|
694
779
|
new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
|
|
695
780
|
const logger = createChildLogger({
|
|
696
781
|
logger: passLogger,
|
|
@@ -785,7 +870,7 @@ export class ContainerRuntime
|
|
|
785
870
|
idCompressor =
|
|
786
871
|
serializedIdCompressor !== undefined
|
|
787
872
|
? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
|
|
788
|
-
:
|
|
873
|
+
: IdCompressor.create(logger);
|
|
789
874
|
}
|
|
790
875
|
|
|
791
876
|
const runtime = new containerRuntimeCtor(
|
|
@@ -818,6 +903,7 @@ export class ContainerRuntime
|
|
|
818
903
|
initializeEntryPoint,
|
|
819
904
|
);
|
|
820
905
|
|
|
906
|
+
await runtime.blobManager.processStashedChanges();
|
|
821
907
|
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
822
908
|
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
823
909
|
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
@@ -849,6 +935,7 @@ export class ContainerRuntime
|
|
|
849
935
|
localOpMetadata: unknown,
|
|
850
936
|
opMetadata: Record<string, unknown> | undefined,
|
|
851
937
|
) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
938
|
+
// Note: compatDetails is not included in this deprecated API
|
|
852
939
|
}
|
|
853
940
|
|
|
854
941
|
private readonly submitFn: (
|
|
@@ -984,7 +1071,6 @@ export class ContainerRuntime
|
|
|
984
1071
|
private emitDirtyDocumentEvent = true;
|
|
985
1072
|
private readonly enableOpReentryCheck: boolean;
|
|
986
1073
|
private readonly disableAttachReorder: boolean | undefined;
|
|
987
|
-
private readonly summaryStateUpdateMethod: string | undefined;
|
|
988
1074
|
private readonly closeSummarizerDelayMs: number;
|
|
989
1075
|
/**
|
|
990
1076
|
* If true, summary generated is validate before uploading it to the server. With single commit summaries,
|
|
@@ -994,7 +1080,7 @@ export class ContainerRuntime
|
|
|
994
1080
|
private readonly validateSummaryBeforeUpload: boolean;
|
|
995
1081
|
|
|
996
1082
|
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
997
|
-
private _perfSignalData: IPerfSignalReport = {
|
|
1083
|
+
private readonly _perfSignalData: IPerfSignalReport = {
|
|
998
1084
|
signalsLost: 0,
|
|
999
1085
|
signalSequenceNumber: 0,
|
|
1000
1086
|
signalTimestamp: 0,
|
|
@@ -1464,22 +1550,17 @@ export class ContainerRuntime
|
|
|
1464
1550
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1465
1551
|
this._audience = audience!;
|
|
1466
1552
|
|
|
1467
|
-
this.summaryStateUpdateMethod = this.mc.config.getString(
|
|
1468
|
-
"Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2",
|
|
1469
|
-
);
|
|
1470
1553
|
const closeSummarizerDelayOverride = this.mc.config.getNumber(
|
|
1471
1554
|
"Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs",
|
|
1472
1555
|
);
|
|
1473
1556
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
1474
1557
|
this.validateSummaryBeforeUpload =
|
|
1475
|
-
this.mc.config.getBoolean("Fluid.
|
|
1476
|
-
false;
|
|
1558
|
+
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
1477
1559
|
|
|
1478
1560
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1479
1561
|
|
|
1480
1562
|
this.dirtyContainer =
|
|
1481
|
-
this.attachState !== AttachState.Attached ||
|
|
1482
|
-
this.pendingStateManager.hasPendingMessages();
|
|
1563
|
+
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
1483
1564
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
1484
1565
|
|
|
1485
1566
|
if (this.summariesDisabled) {
|
|
@@ -1564,6 +1645,9 @@ export class ContainerRuntime
|
|
|
1564
1645
|
},
|
|
1565
1646
|
this.heuristicsDisabled,
|
|
1566
1647
|
);
|
|
1648
|
+
this.summaryManager.on("summarize", (eventProps) => {
|
|
1649
|
+
this.emit("summarize", eventProps);
|
|
1650
|
+
});
|
|
1567
1651
|
this.summaryManager.start();
|
|
1568
1652
|
}
|
|
1569
1653
|
}
|
|
@@ -1619,7 +1703,6 @@ export class ContainerRuntime
|
|
|
1619
1703
|
disableAttachReorder: this.disableAttachReorder,
|
|
1620
1704
|
disablePartialFlush,
|
|
1621
1705
|
idCompressorEnabled: this.idCompressorEnabled,
|
|
1622
|
-
summaryStateUpdateMethod: this.summaryStateUpdateMethod,
|
|
1623
1706
|
closeSummarizerDelayOverride,
|
|
1624
1707
|
}),
|
|
1625
1708
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
@@ -1736,7 +1819,7 @@ export class ContainerRuntime
|
|
|
1736
1819
|
subRequest.url.startsWith("/"),
|
|
1737
1820
|
0x126 /* "Expected createSubRequest url to include a leading slash" */,
|
|
1738
1821
|
);
|
|
1739
|
-
return dataStore.
|
|
1822
|
+
return dataStore.request(subRequest);
|
|
1740
1823
|
}
|
|
1741
1824
|
|
|
1742
1825
|
return create404Response(request);
|
|
@@ -1784,6 +1867,7 @@ export class ContainerRuntime
|
|
|
1784
1867
|
dataStoreContext.packagePath,
|
|
1785
1868
|
request?.headers,
|
|
1786
1869
|
);
|
|
1870
|
+
|
|
1787
1871
|
return dataStoreChannel;
|
|
1788
1872
|
}
|
|
1789
1873
|
|
|
@@ -1878,7 +1962,7 @@ export class ContainerRuntime
|
|
|
1878
1962
|
this.mc.logger.sendTelemetryEvent({
|
|
1879
1963
|
eventName: "ReconnectsWithNoProgress",
|
|
1880
1964
|
attempts: this.consecutiveReconnects,
|
|
1881
|
-
pendingMessages: this.
|
|
1965
|
+
pendingMessages: this.pendingMessagesCount,
|
|
1882
1966
|
});
|
|
1883
1967
|
}
|
|
1884
1968
|
|
|
@@ -1947,14 +2031,15 @@ export class ContainerRuntime
|
|
|
1947
2031
|
*/
|
|
1948
2032
|
private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
|
|
1949
2033
|
assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
|
|
1950
|
-
const { type, contents } =
|
|
2034
|
+
const { type, contents, compatDetails }: ContainerRuntimeMessage =
|
|
2035
|
+
JSON.parse(serializedContent);
|
|
1951
2036
|
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1952
|
-
return { type, contents };
|
|
2037
|
+
return { type, contents, compatDetails };
|
|
1953
2038
|
}
|
|
1954
2039
|
|
|
1955
2040
|
private async applyStashedOp(op: string): Promise<unknown> {
|
|
1956
2041
|
// Need to parse from string for back-compat
|
|
1957
|
-
const { type, contents } = this.parseOpContent(op);
|
|
2042
|
+
const { type, contents, compatDetails } = this.parseOpContent(op);
|
|
1958
2043
|
switch (type) {
|
|
1959
2044
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1960
2045
|
return this.dataStores.applyStashedOp(contents as IEnvelope);
|
|
@@ -1973,8 +2058,27 @@ export class ContainerRuntime
|
|
|
1973
2058
|
throw new Error("chunkedOp not expected here");
|
|
1974
2059
|
case ContainerMessageType.Rejoin:
|
|
1975
2060
|
throw new Error("rejoin not expected here");
|
|
1976
|
-
default:
|
|
1977
|
-
|
|
2061
|
+
default: {
|
|
2062
|
+
// This should be extremely rare for stashed ops.
|
|
2063
|
+
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
2064
|
+
// e.g. if an app rolled back its container version
|
|
2065
|
+
const compatBehavior = compatDetails?.behavior;
|
|
2066
|
+
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
2067
|
+
const error = DataProcessingError.create(
|
|
2068
|
+
"Stashed runtime message of unknown type",
|
|
2069
|
+
"applyStashedOp",
|
|
2070
|
+
undefined /* sequencedMessage */,
|
|
2071
|
+
{
|
|
2072
|
+
messageDetails: JSON.stringify({
|
|
2073
|
+
type,
|
|
2074
|
+
compatBehavior,
|
|
2075
|
+
}),
|
|
2076
|
+
},
|
|
2077
|
+
);
|
|
2078
|
+
this.closeFn(error);
|
|
2079
|
+
throw error;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
1978
2082
|
}
|
|
1979
2083
|
}
|
|
1980
2084
|
|
|
@@ -1988,32 +2092,6 @@ export class ContainerRuntime
|
|
|
1988
2092
|
return;
|
|
1989
2093
|
}
|
|
1990
2094
|
|
|
1991
|
-
// If attachment blobs were added while disconnected, we need to delay
|
|
1992
|
-
// propagation of the "connected" event until we have uploaded them to
|
|
1993
|
-
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1994
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1995
|
-
const connecting =
|
|
1996
|
-
connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1997
|
-
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
1998
|
-
assert(
|
|
1999
|
-
!this.delayConnectClientId,
|
|
2000
|
-
0x392 /* Connect event delay must be canceled before subsequent connect event */,
|
|
2001
|
-
);
|
|
2002
|
-
assert(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
2003
|
-
this.delayConnectClientId = clientId;
|
|
2004
|
-
this.blobManager.onConnected().then(
|
|
2005
|
-
() => {
|
|
2006
|
-
// make sure we didn't reconnect before the promise resolved
|
|
2007
|
-
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
2008
|
-
this.delayConnectClientId = undefined;
|
|
2009
|
-
this.setConnectionStateCore(connected, clientId);
|
|
2010
|
-
}
|
|
2011
|
-
},
|
|
2012
|
-
(error) => this.closeFn(error),
|
|
2013
|
-
);
|
|
2014
|
-
return;
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
2095
|
this.setConnectionStateCore(connected, clientId);
|
|
2018
2096
|
}
|
|
2019
2097
|
|
|
@@ -2061,7 +2139,7 @@ export class ContainerRuntime
|
|
|
2061
2139
|
{
|
|
2062
2140
|
dataLoss: 1,
|
|
2063
2141
|
attempts: this.consecutiveReconnects,
|
|
2064
|
-
pendingMessages: this.
|
|
2142
|
+
pendingMessages: this.pendingMessagesCount,
|
|
2065
2143
|
},
|
|
2066
2144
|
),
|
|
2067
2145
|
);
|
|
@@ -2086,15 +2164,15 @@ export class ContainerRuntime
|
|
|
2086
2164
|
public process(messageArg: ISequencedDocumentMessage, local: boolean) {
|
|
2087
2165
|
this.verifyNotClosed();
|
|
2088
2166
|
|
|
2089
|
-
// Whether or not the message
|
|
2167
|
+
// Whether or not the message appears to be a runtime message from an up-to-date client.
|
|
2090
2168
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
2091
2169
|
// or something different, like a system message.
|
|
2092
|
-
const
|
|
2170
|
+
const modernRuntimeMessage = messageArg.type === MessageType.Operation;
|
|
2093
2171
|
|
|
2094
2172
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
2095
2173
|
const messageCopy = { ...messageArg };
|
|
2096
2174
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
2097
|
-
this.processCore(message, local,
|
|
2175
|
+
this.processCore(message, local, modernRuntimeMessage);
|
|
2098
2176
|
}
|
|
2099
2177
|
}
|
|
2100
2178
|
|
|
@@ -2104,12 +2182,12 @@ export class ContainerRuntime
|
|
|
2104
2182
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2105
2183
|
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
2106
2184
|
* @param local - Did this client send the op?
|
|
2107
|
-
* @param
|
|
2185
|
+
* @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
|
|
2108
2186
|
*/
|
|
2109
2187
|
private processCore(
|
|
2110
|
-
message: ISequencedDocumentMessage,
|
|
2188
|
+
message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
|
|
2111
2189
|
local: boolean,
|
|
2112
|
-
|
|
2190
|
+
modernRuntimeMessage: boolean,
|
|
2113
2191
|
) {
|
|
2114
2192
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
2115
2193
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
@@ -2120,8 +2198,10 @@ export class ContainerRuntime
|
|
|
2120
2198
|
|
|
2121
2199
|
try {
|
|
2122
2200
|
let localOpMetadata: unknown;
|
|
2123
|
-
if (local &&
|
|
2124
|
-
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2201
|
+
if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
|
|
2202
|
+
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2203
|
+
message as SequencedContainerRuntimeMessage,
|
|
2204
|
+
);
|
|
2125
2205
|
}
|
|
2126
2206
|
|
|
2127
2207
|
// If there are no more pending messages after processing a local message,
|
|
@@ -2130,51 +2210,14 @@ export class ContainerRuntime
|
|
|
2130
2210
|
this.updateDocumentDirtyState(false);
|
|
2131
2211
|
}
|
|
2132
2212
|
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
this.processAliasMessage(message, localOpMetadata, local);
|
|
2140
|
-
break;
|
|
2141
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
2142
|
-
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
2143
|
-
break;
|
|
2144
|
-
case ContainerMessageType.BlobAttach:
|
|
2145
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
2146
|
-
break;
|
|
2147
|
-
case ContainerMessageType.IdAllocation:
|
|
2148
|
-
assert(
|
|
2149
|
-
this.idCompressor !== undefined,
|
|
2150
|
-
0x67c /* IdCompressor should be defined if enabled */,
|
|
2151
|
-
);
|
|
2152
|
-
this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
|
|
2153
|
-
break;
|
|
2154
|
-
case ContainerMessageType.ChunkedOp:
|
|
2155
|
-
case ContainerMessageType.Rejoin:
|
|
2156
|
-
break;
|
|
2157
|
-
default:
|
|
2158
|
-
if (runtimeMessage) {
|
|
2159
|
-
const error = DataProcessingError.create(
|
|
2160
|
-
// Former assert 0x3ce
|
|
2161
|
-
"Runtime message of unknown type",
|
|
2162
|
-
"OpProcessing",
|
|
2163
|
-
message,
|
|
2164
|
-
{
|
|
2165
|
-
local,
|
|
2166
|
-
type: message.type,
|
|
2167
|
-
contentType: typeof message.contents,
|
|
2168
|
-
batch: (message.metadata as IBatchMetadata | undefined)?.batch,
|
|
2169
|
-
compression: message.compression,
|
|
2170
|
-
},
|
|
2171
|
-
);
|
|
2172
|
-
this.closeFn(error);
|
|
2173
|
-
throw error;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2213
|
+
this.validateAndProcessRuntimeMessage(
|
|
2214
|
+
message,
|
|
2215
|
+
localOpMetadata,
|
|
2216
|
+
local,
|
|
2217
|
+
modernRuntimeMessage,
|
|
2218
|
+
);
|
|
2176
2219
|
|
|
2177
|
-
this.emit("op", message,
|
|
2220
|
+
this.emit("op", message, modernRuntimeMessage);
|
|
2178
2221
|
|
|
2179
2222
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
2180
2223
|
|
|
@@ -2189,13 +2232,74 @@ export class ContainerRuntime
|
|
|
2189
2232
|
throw e;
|
|
2190
2233
|
}
|
|
2191
2234
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2235
|
+
/**
|
|
2236
|
+
* Assuming the given message is also a ContainerRuntimeMessage,
|
|
2237
|
+
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
2238
|
+
* Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
|
|
2239
|
+
*/
|
|
2240
|
+
private validateAndProcessRuntimeMessage(
|
|
2194
2241
|
message: ISequencedDocumentMessage,
|
|
2195
2242
|
localOpMetadata: unknown,
|
|
2196
2243
|
local: boolean,
|
|
2197
|
-
|
|
2198
|
-
|
|
2244
|
+
expectRuntimeMessageType: boolean,
|
|
2245
|
+
): asserts message is SequencedContainerRuntimeMessage {
|
|
2246
|
+
// Optimistically extract ContainerRuntimeMessage-specific props from the message
|
|
2247
|
+
const { type: maybeContainerMessageType, compatDetails } =
|
|
2248
|
+
message as ContainerRuntimeMessage;
|
|
2249
|
+
|
|
2250
|
+
switch (maybeContainerMessageType) {
|
|
2251
|
+
case ContainerMessageType.Attach:
|
|
2252
|
+
this.dataStores.processAttachMessage(message, local);
|
|
2253
|
+
break;
|
|
2254
|
+
case ContainerMessageType.Alias:
|
|
2255
|
+
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
2256
|
+
break;
|
|
2257
|
+
case ContainerMessageType.FluidDataStoreOp:
|
|
2258
|
+
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
2259
|
+
break;
|
|
2260
|
+
case ContainerMessageType.BlobAttach:
|
|
2261
|
+
this.blobManager.processBlobAttachOp(message, local);
|
|
2262
|
+
break;
|
|
2263
|
+
case ContainerMessageType.IdAllocation:
|
|
2264
|
+
assert(
|
|
2265
|
+
this.idCompressor !== undefined,
|
|
2266
|
+
0x67c /* IdCompressor should be defined if enabled */,
|
|
2267
|
+
);
|
|
2268
|
+
this.idCompressor.finalizeCreationRange(message.contents as IdCreationRange);
|
|
2269
|
+
break;
|
|
2270
|
+
case ContainerMessageType.ChunkedOp:
|
|
2271
|
+
case ContainerMessageType.Rejoin:
|
|
2272
|
+
break;
|
|
2273
|
+
default: {
|
|
2274
|
+
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
2275
|
+
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
2276
|
+
if (!expectRuntimeMessageType) {
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
const compatBehavior = compatDetails?.behavior;
|
|
2281
|
+
if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
|
|
2282
|
+
const error = DataProcessingError.create(
|
|
2283
|
+
// Former assert 0x3ce
|
|
2284
|
+
"Runtime message of unknown type",
|
|
2285
|
+
"OpProcessing",
|
|
2286
|
+
message,
|
|
2287
|
+
{
|
|
2288
|
+
local,
|
|
2289
|
+
messageDetails: JSON.stringify({
|
|
2290
|
+
type: message.type,
|
|
2291
|
+
contentType: typeof message.contents,
|
|
2292
|
+
compatBehavior,
|
|
2293
|
+
batch: (message.metadata as IBatchMetadata | undefined)?.batch,
|
|
2294
|
+
compression: message.compression,
|
|
2295
|
+
}),
|
|
2296
|
+
},
|
|
2297
|
+
);
|
|
2298
|
+
this.closeFn(error);
|
|
2299
|
+
throw error;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2199
2303
|
}
|
|
2200
2304
|
|
|
2201
2305
|
/**
|
|
@@ -2834,7 +2938,7 @@ export class ContainerRuntime
|
|
|
2834
2938
|
* @param options - options controlling how the summary is generated or submitted
|
|
2835
2939
|
*/
|
|
2836
2940
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
2837
|
-
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
2941
|
+
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
|
|
2838
2942
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2839
2943
|
// use it for all events logged during this summary.
|
|
2840
2944
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -2862,6 +2966,50 @@ export class ContainerRuntime
|
|
|
2862
2966
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
2863
2967
|
}
|
|
2864
2968
|
|
|
2969
|
+
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
2970
|
+
// incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
|
|
2971
|
+
// within the timeout, check if it should be failed or can continue.
|
|
2972
|
+
if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
|
|
2973
|
+
const countBefore = this.pendingMessagesCount;
|
|
2974
|
+
// The timeout for waiting for pending ops can be overridden via configurations.
|
|
2975
|
+
const pendingOpsTimeout =
|
|
2976
|
+
this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
|
|
2977
|
+
defaultPendingOpsWaitTimeoutMs;
|
|
2978
|
+
await new Promise<void>((resolve, reject) => {
|
|
2979
|
+
const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
|
|
2980
|
+
this.once("saved", () => {
|
|
2981
|
+
clearTimeout(timeoutId);
|
|
2982
|
+
resolve();
|
|
2983
|
+
});
|
|
2984
|
+
this.once("dispose", () => {
|
|
2985
|
+
clearTimeout(timeoutId);
|
|
2986
|
+
reject(new Error("Runtime is disposed while summarizing"));
|
|
2987
|
+
});
|
|
2988
|
+
});
|
|
2989
|
+
|
|
2990
|
+
// Log that there are pending ops while summarizing. This will help us gather data on how often this
|
|
2991
|
+
// happens, whether we attempted to wait for these ops to be acked and what was the result.
|
|
2992
|
+
summaryNumberLogger.sendTelemetryEvent({
|
|
2993
|
+
eventName: "PendingOpsWhileSummarizing",
|
|
2994
|
+
saved: this.hasPendingMessages() ? false : true,
|
|
2995
|
+
timeout: pendingOpsTimeout,
|
|
2996
|
+
countBefore,
|
|
2997
|
+
countAfter: this.pendingMessagesCount,
|
|
2998
|
+
});
|
|
2999
|
+
|
|
3000
|
+
// There could still be pending ops. Check if summary should fail or continue.
|
|
3001
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(
|
|
3002
|
+
summaryNumberLogger,
|
|
3003
|
+
this.deltaManager.lastSequenceNumber,
|
|
3004
|
+
this.deltaManager.minimumSequenceNumber,
|
|
3005
|
+
finalAttempt,
|
|
3006
|
+
true /* beforeSummaryGeneration */,
|
|
3007
|
+
);
|
|
3008
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
3009
|
+
return pendingMessagesFailResult;
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
|
|
2865
3013
|
const shouldPauseInboundSignal =
|
|
2866
3014
|
this.mc.config.getBoolean(
|
|
2867
3015
|
"Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause",
|
|
@@ -2952,9 +3100,9 @@ export class ContainerRuntime
|
|
|
2952
3100
|
};
|
|
2953
3101
|
}
|
|
2954
3102
|
|
|
2955
|
-
// If validateSummaryBeforeUpload is true, validate that the summary generated
|
|
2956
|
-
// correct before this summary is uploaded.
|
|
3103
|
+
// If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
|
|
2957
3104
|
if (this.validateSummaryBeforeUpload) {
|
|
3105
|
+
// Validate that the summaries generated by summarize nodes is correct.
|
|
2958
3106
|
const validateResult = this.summarizerNode.validateSummary();
|
|
2959
3107
|
if (!validateResult.success) {
|
|
2960
3108
|
const { success, ...loggingProps } = validateResult;
|
|
@@ -2970,6 +3118,17 @@ export class ContainerRuntime
|
|
|
2970
3118
|
error,
|
|
2971
3119
|
};
|
|
2972
3120
|
}
|
|
3121
|
+
|
|
3122
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(
|
|
3123
|
+
summaryNumberLogger,
|
|
3124
|
+
summaryRefSeqNum,
|
|
3125
|
+
minimumSequenceNumber,
|
|
3126
|
+
finalAttempt,
|
|
3127
|
+
false /* beforeSummaryGeneration */,
|
|
3128
|
+
);
|
|
3129
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
3130
|
+
return pendingMessagesFailResult;
|
|
3131
|
+
}
|
|
2973
3132
|
}
|
|
2974
3133
|
|
|
2975
3134
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
@@ -3110,8 +3269,78 @@ export class ContainerRuntime
|
|
|
3110
3269
|
}
|
|
3111
3270
|
}
|
|
3112
3271
|
|
|
3272
|
+
/**
|
|
3273
|
+
* This helper is called during summarization. If there are pending ops, it will return a failed summarize result
|
|
3274
|
+
* (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
|
|
3275
|
+
* @param logger - The logger to be used for sending telemetry.
|
|
3276
|
+
* @param referenceSequenceNumber - The reference sequence number of the summary attempt.
|
|
3277
|
+
* @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
|
|
3278
|
+
* @param finalAttempt - Whether this is the final summary attempt.
|
|
3279
|
+
* @param beforeSummaryGeneration - Whether this is called before summary generation or after.
|
|
3280
|
+
* @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
|
|
3281
|
+
*/
|
|
3282
|
+
private async shouldFailSummaryOnPendingOps(
|
|
3283
|
+
logger: ITelemetryLoggerExt,
|
|
3284
|
+
referenceSequenceNumber: number,
|
|
3285
|
+
minimumSequenceNumber: number,
|
|
3286
|
+
finalAttempt: boolean,
|
|
3287
|
+
beforeSummaryGeneration: boolean,
|
|
3288
|
+
): Promise<IBaseSummarizeResult | undefined> {
|
|
3289
|
+
if (!this.hasPendingMessages()) {
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
// If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
|
|
3294
|
+
// This is a fallback to make progress in documents where there are consistently pending ops in
|
|
3295
|
+
// the summarizer.
|
|
3296
|
+
if (
|
|
3297
|
+
finalAttempt &&
|
|
3298
|
+
this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")
|
|
3299
|
+
) {
|
|
3300
|
+
const error = DataProcessingError.create(
|
|
3301
|
+
"Pending ops during summarization",
|
|
3302
|
+
"submitSummary",
|
|
3303
|
+
undefined,
|
|
3304
|
+
{ pendingMessages: this.pendingMessagesCount },
|
|
3305
|
+
);
|
|
3306
|
+
logger.sendErrorEvent(
|
|
3307
|
+
{
|
|
3308
|
+
eventName: "SkipFailingIncorrectSummary",
|
|
3309
|
+
referenceSequenceNumber,
|
|
3310
|
+
minimumSequenceNumber,
|
|
3311
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
3312
|
+
},
|
|
3313
|
+
error,
|
|
3314
|
+
);
|
|
3315
|
+
} else {
|
|
3316
|
+
// The retry delay when there are pending ops can be overridden via config so that we can adjust it
|
|
3317
|
+
// based on telemetry while we decide on a stable number.
|
|
3318
|
+
const retryDelayMs =
|
|
3319
|
+
this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
3320
|
+
defaultPendingOpsRetryDelayMs;
|
|
3321
|
+
const error = new RetriableSummaryError(
|
|
3322
|
+
"PendingOpsWhileSummarizing",
|
|
3323
|
+
retryDelayMs / 1000,
|
|
3324
|
+
{
|
|
3325
|
+
count: this.pendingMessagesCount,
|
|
3326
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
3327
|
+
},
|
|
3328
|
+
);
|
|
3329
|
+
return {
|
|
3330
|
+
stage: "base",
|
|
3331
|
+
referenceSequenceNumber,
|
|
3332
|
+
minimumSequenceNumber,
|
|
3333
|
+
error,
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
|
|
3338
|
+
private get pendingMessagesCount(): number {
|
|
3339
|
+
return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3113
3342
|
private hasPendingMessages() {
|
|
3114
|
-
return this.
|
|
3343
|
+
return this.pendingMessagesCount !== 0;
|
|
3115
3344
|
}
|
|
3116
3345
|
|
|
3117
3346
|
private updateDocumentDirtyState(dirty: boolean) {
|
|
@@ -3178,7 +3407,7 @@ export class ContainerRuntime
|
|
|
3178
3407
|
);
|
|
3179
3408
|
idRange = this.idCompressor.takeNextCreationRange();
|
|
3180
3409
|
// Don't include the idRange if there weren't any Ids allocated
|
|
3181
|
-
idRange = idRange?.ids
|
|
3410
|
+
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
3182
3411
|
}
|
|
3183
3412
|
|
|
3184
3413
|
if (idRange !== undefined) {
|
|
@@ -3439,11 +3668,31 @@ export class ContainerRuntime
|
|
|
3439
3668
|
case ContainerMessageType.Rejoin:
|
|
3440
3669
|
this.submit(message);
|
|
3441
3670
|
break;
|
|
3442
|
-
default:
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
)
|
|
3671
|
+
default: {
|
|
3672
|
+
// This case should be very rare - it would imply an op was stashed from a
|
|
3673
|
+
// future version of runtime code and now is being applied on an older version
|
|
3674
|
+
const compatBehavior = message.compatDetails?.behavior;
|
|
3675
|
+
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
3676
|
+
this.logger.sendTelemetryEvent({
|
|
3677
|
+
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
3678
|
+
messageDetails: { type: message.type, compatBehavior },
|
|
3679
|
+
});
|
|
3680
|
+
} else {
|
|
3681
|
+
const error = DataProcessingError.create(
|
|
3682
|
+
"Resubmitting runtime message of unknown type",
|
|
3683
|
+
"reSubmitCore",
|
|
3684
|
+
undefined /* sequencedMessage */,
|
|
3685
|
+
{
|
|
3686
|
+
messageDetails: JSON.stringify({
|
|
3687
|
+
type: message.type,
|
|
3688
|
+
compatBehavior,
|
|
3689
|
+
}),
|
|
3690
|
+
},
|
|
3691
|
+
);
|
|
3692
|
+
this.closeFn(error);
|
|
3693
|
+
throw error;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3447
3696
|
}
|
|
3448
3697
|
}
|
|
3449
3698
|
|
|
@@ -3457,6 +3706,7 @@ export class ContainerRuntime
|
|
|
3457
3706
|
this.dataStores.rollbackDataStoreOp(contents as IEnvelope, localOpMetadata);
|
|
3458
3707
|
break;
|
|
3459
3708
|
default:
|
|
3709
|
+
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
3460
3710
|
throw new Error(`Can't rollback ${type}`);
|
|
3461
3711
|
}
|
|
3462
3712
|
}
|
|
@@ -3484,12 +3734,22 @@ export class ContainerRuntime
|
|
|
3484
3734
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
3485
3735
|
public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
|
|
3486
3736
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
3737
|
+
// proposalHandle is always passed from RunningSummarizer.
|
|
3738
|
+
assert(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
3487
3739
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3740
|
+
const result = await this.summarizerNode.refreshLatestSummary(
|
|
3741
|
+
proposalHandle,
|
|
3742
|
+
summaryRefSeq,
|
|
3743
|
+
);
|
|
3744
|
+
|
|
3745
|
+
/**
|
|
3746
|
+
* When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
|
|
3747
|
+
* current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
|
|
3748
|
+
* it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
|
|
3749
|
+
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
3750
|
+
*/
|
|
3751
|
+
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
3752
|
+
const fetchResult = await this.fetchSnapshotFromStorage(
|
|
3493
3753
|
summaryLogger,
|
|
3494
3754
|
{
|
|
3495
3755
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
@@ -3497,27 +3757,9 @@ export class ContainerRuntime
|
|
|
3497
3757
|
targetSequenceNumber: summaryRefSeq,
|
|
3498
3758
|
},
|
|
3499
3759
|
readAndParseBlob,
|
|
3760
|
+
null,
|
|
3500
3761
|
);
|
|
3501
3762
|
|
|
3502
|
-
/**
|
|
3503
|
-
* back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
|
|
3504
|
-
* getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
|
|
3505
|
-
* these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
|
|
3506
|
-
* change that started fetching latest snapshot always.
|
|
3507
|
-
*/
|
|
3508
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3509
|
-
fetchResult = await this.fetchSnapshotFromStorageAndClose(
|
|
3510
|
-
summaryLogger,
|
|
3511
|
-
{
|
|
3512
|
-
eventName: "RefreshLatestSummaryAckFetchBackCompat",
|
|
3513
|
-
ackHandle,
|
|
3514
|
-
targetSequenceNumber: summaryRefSeq,
|
|
3515
|
-
},
|
|
3516
|
-
readAndParseBlob,
|
|
3517
|
-
ackHandle,
|
|
3518
|
-
);
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
3763
|
/**
|
|
3522
3764
|
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
3523
3765
|
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
@@ -3543,29 +3785,12 @@ export class ContainerRuntime
|
|
|
3543
3785
|
throw error;
|
|
3544
3786
|
}
|
|
3545
3787
|
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
fetchResult.latestSnapshotRefSeq,
|
|
3550
|
-
summaryLogger,
|
|
3551
|
-
);
|
|
3552
|
-
|
|
3553
|
-
return {
|
|
3554
|
-
snapshotTree: fetchResult.snapshotTree,
|
|
3555
|
-
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3556
|
-
};
|
|
3557
|
-
};
|
|
3558
|
-
|
|
3559
|
-
const result = await this.summarizerNode.refreshLatestSummary(
|
|
3560
|
-
proposalHandle,
|
|
3561
|
-
summaryRefSeq,
|
|
3562
|
-
fetchLatestSnapshot,
|
|
3563
|
-
readAndParseBlob,
|
|
3564
|
-
summaryLogger,
|
|
3565
|
-
);
|
|
3788
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
3789
|
+
return;
|
|
3790
|
+
}
|
|
3566
3791
|
|
|
3567
3792
|
// Notify the garbage collector so it can update its latest summary state.
|
|
3568
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
3793
|
+
await this.garbageCollector.refreshLatestSummary(result);
|
|
3569
3794
|
}
|
|
3570
3795
|
|
|
3571
3796
|
/**
|
|
@@ -3578,56 +3803,49 @@ export class ContainerRuntime
|
|
|
3578
3803
|
summaryLogger: ITelemetryLoggerExt,
|
|
3579
3804
|
): Promise<{ latestSnapshotRefSeq: number; latestSnapshotVersionId: string | undefined }> {
|
|
3580
3805
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
3581
|
-
const {
|
|
3582
|
-
await this.fetchLatestSnapshotFromStorage(
|
|
3583
|
-
summaryLogger,
|
|
3584
|
-
{
|
|
3585
|
-
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
3586
|
-
},
|
|
3587
|
-
readAndParseBlob,
|
|
3588
|
-
);
|
|
3589
|
-
const fetchLatestSnapshot: IFetchSnapshotResult = {
|
|
3590
|
-
snapshotTree,
|
|
3591
|
-
snapshotRefSeq: latestSnapshotRefSeq,
|
|
3592
|
-
};
|
|
3593
|
-
const result = await this.summarizerNode.refreshLatestSummary(
|
|
3594
|
-
undefined /* proposalHandle */,
|
|
3595
|
-
latestSnapshotRefSeq,
|
|
3596
|
-
async () => fetchLatestSnapshot,
|
|
3597
|
-
readAndParseBlob,
|
|
3806
|
+
const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(
|
|
3598
3807
|
summaryLogger,
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
3603
|
-
undefined /* proposalHandle */,
|
|
3604
|
-
result,
|
|
3808
|
+
{
|
|
3809
|
+
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
3810
|
+
},
|
|
3605
3811
|
readAndParseBlob,
|
|
3812
|
+
null,
|
|
3606
3813
|
);
|
|
3607
3814
|
|
|
3815
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
3816
|
+
|
|
3608
3817
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
3609
3818
|
}
|
|
3610
3819
|
|
|
3611
|
-
private async
|
|
3612
|
-
logger
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
null /* latest */,
|
|
3820
|
+
private async closeStaleSummarizer(codePath: string): Promise<void> {
|
|
3821
|
+
this.mc.logger.sendTelemetryEvent(
|
|
3822
|
+
{
|
|
3823
|
+
eventName: "ClosingSummarizerOnSummaryStale",
|
|
3824
|
+
codePath,
|
|
3825
|
+
message: "Stopping fetch from storage",
|
|
3826
|
+
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
3827
|
+
},
|
|
3828
|
+
new GenericError("Restarting summarizer instead of refreshing"),
|
|
3621
3829
|
);
|
|
3830
|
+
|
|
3831
|
+
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3832
|
+
await delay(this.closeSummarizerDelayMs);
|
|
3833
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
3834
|
+
this.disposeFn();
|
|
3622
3835
|
}
|
|
3623
3836
|
|
|
3624
|
-
|
|
3837
|
+
/**
|
|
3838
|
+
* Downloads snapshot from storage with the given versionId or latest if versionId is null.
|
|
3839
|
+
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
3840
|
+
* overridden via options.
|
|
3841
|
+
*/
|
|
3842
|
+
private async fetchSnapshotFromStorage(
|
|
3625
3843
|
logger: ITelemetryLoggerExt,
|
|
3626
3844
|
event: ITelemetryGenericEvent,
|
|
3627
3845
|
readAndParseBlob: ReadAndParseBlob,
|
|
3628
3846
|
versionId: string | null,
|
|
3629
3847
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3630
|
-
|
|
3848
|
+
return PerformanceEvent.timedExecAsync(
|
|
3631
3849
|
logger,
|
|
3632
3850
|
event,
|
|
3633
3851
|
async (perfEvent: {
|
|
@@ -3673,30 +3891,6 @@ export class ContainerRuntime
|
|
|
3673
3891
|
};
|
|
3674
3892
|
},
|
|
3675
3893
|
);
|
|
3676
|
-
|
|
3677
|
-
// We choose to close the summarizer after the snapshot cache is updated to avoid
|
|
3678
|
-
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
3679
|
-
// loads the summarizer from cache.
|
|
3680
|
-
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
3681
|
-
this.mc.logger.sendTelemetryEvent(
|
|
3682
|
-
{
|
|
3683
|
-
...event,
|
|
3684
|
-
eventName: "ClosingSummarizerOnSummaryStale",
|
|
3685
|
-
codePath: event.eventName,
|
|
3686
|
-
message: "Stopping fetch from storage",
|
|
3687
|
-
versionId: versionId != null ? versionId : undefined,
|
|
3688
|
-
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
3689
|
-
},
|
|
3690
|
-
new GenericError("Restarting summarizer instead of refreshing"),
|
|
3691
|
-
);
|
|
3692
|
-
|
|
3693
|
-
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3694
|
-
await delay(this.closeSummarizerDelayMs);
|
|
3695
|
-
this._summarizer?.stop("latestSummaryStateStale");
|
|
3696
|
-
this.disposeFn();
|
|
3697
|
-
}
|
|
3698
|
-
|
|
3699
|
-
return snapshotResults;
|
|
3700
3894
|
}
|
|
3701
3895
|
|
|
3702
3896
|
public notifyAttaching() {} // do nothing (deprecated method)
|
|
@@ -3704,48 +3898,68 @@ export class ContainerRuntime
|
|
|
3704
3898
|
public async getPendingLocalState(props?: {
|
|
3705
3899
|
notifyImminentClosure: boolean;
|
|
3706
3900
|
}): Promise<unknown> {
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3901
|
+
return PerformanceEvent.timedExecAsync(
|
|
3902
|
+
this.mc.logger,
|
|
3903
|
+
{
|
|
3904
|
+
eventName: "getPendingLocalState",
|
|
3905
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
3906
|
+
},
|
|
3907
|
+
async (event) => {
|
|
3908
|
+
this.verifyNotClosed();
|
|
3909
|
+
const waitBlobsToAttach = props?.notifyImminentClosure;
|
|
3910
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
3911
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
3912
|
+
}
|
|
3913
|
+
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(
|
|
3914
|
+
waitBlobsToAttach,
|
|
3915
|
+
);
|
|
3916
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
3917
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3918
|
+
return; // no pending state to save
|
|
3919
|
+
}
|
|
3920
|
+
// Flush pending batch.
|
|
3921
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3922
|
+
// to close current batch.
|
|
3923
|
+
this.flush();
|
|
3717
3924
|
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3925
|
+
const pendingState: IPendingRuntimeState = {
|
|
3926
|
+
pending,
|
|
3927
|
+
pendingAttachmentBlobs,
|
|
3928
|
+
};
|
|
3929
|
+
event.end({
|
|
3930
|
+
attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
|
|
3931
|
+
pendingOpsSize: pending?.pendingStates.length,
|
|
3932
|
+
});
|
|
3933
|
+
return pendingState;
|
|
3934
|
+
},
|
|
3935
|
+
);
|
|
3722
3936
|
}
|
|
3723
3937
|
|
|
3724
|
-
public
|
|
3938
|
+
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|
|
3725
3939
|
if (this.isSummarizerClient) {
|
|
3726
|
-
return this.summarizer.summarizeOnDemand(
|
|
3940
|
+
return this.summarizer.summarizeOnDemand(options);
|
|
3727
3941
|
} else if (this.summaryManager !== undefined) {
|
|
3728
|
-
return this.summaryManager.summarizeOnDemand(
|
|
3942
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
3729
3943
|
} else {
|
|
3730
3944
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3731
3945
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
3732
3946
|
// because it is a misuse of the API rather than an expected failure.
|
|
3733
3947
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3734
3948
|
}
|
|
3735
|
-
}
|
|
3949
|
+
}
|
|
3736
3950
|
|
|
3737
|
-
public
|
|
3951
|
+
public enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
|
|
3738
3952
|
if (this.isSummarizerClient) {
|
|
3739
|
-
return this.summarizer.enqueueSummarize(
|
|
3953
|
+
return this.summarizer.enqueueSummarize(options);
|
|
3740
3954
|
} else if (this.summaryManager !== undefined) {
|
|
3741
|
-
return this.summaryManager.enqueueSummarize(
|
|
3955
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
3742
3956
|
} else {
|
|
3743
3957
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3744
3958
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
3745
3959
|
// because it is a misuse of the API rather than an expected failure.
|
|
3746
3960
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3747
3961
|
}
|
|
3748
|
-
}
|
|
3962
|
+
}
|
|
3749
3963
|
|
|
3750
3964
|
/**
|
|
3751
3965
|
* * Forms a function that will request a Summarizer.
|