@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/lib/containerRuntime.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
2
|
-
import { assert, delay,
|
|
3
|
-
import {
|
|
4
|
-
import { createChildLogger,
|
|
2
|
+
import { assert, delay, LazyPromise } from "@fluidframework/core-utils";
|
|
3
|
+
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
4
|
+
import { createChildLogger, createChildMonitoringContext, DataCorruptionError, DataProcessingError, GenericError, raiseConnectedEvent, PerformanceEvent,
|
|
5
|
+
// eslint-disable-next-line import/no-deprecated
|
|
6
|
+
TaggedLoggerAdapter, wrapError, UsageError, } from "@fluidframework/telemetry-utils";
|
|
5
7
|
import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
6
8
|
import { readAndParse } from "@fluidframework/driver-utils";
|
|
7
|
-
import { DataCorruptionError, DataProcessingError, GenericError, UsageError, } from "@fluidframework/container-utils";
|
|
8
9
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
9
10
|
import { FlushMode, FlushModeExperimental, gcTreeKey, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
10
11
|
import { addBlobToSummary, addSummarizeResultToSummary, addTreeToSummary, RequestParser, create404Response, exceptionToResponse, GCDataBuilder, requestFluidObject, seqFromTree, calculateStats, TelemetryContext, } from "@fluidframework/runtime-utils";
|
|
@@ -45,6 +46,18 @@ export var ContainerMessageType;
|
|
|
45
46
|
*/
|
|
46
47
|
ContainerMessageType["IdAllocation"] = "idAllocation";
|
|
47
48
|
})(ContainerMessageType || (ContainerMessageType = {}));
|
|
49
|
+
/**
|
|
50
|
+
* Utility to implement compat behaviors given an unknown message type
|
|
51
|
+
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
52
|
+
*
|
|
53
|
+
* @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
|
|
54
|
+
* handled before calling this function (e.g. in a switch statement).
|
|
55
|
+
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
56
|
+
*/
|
|
57
|
+
function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
|
|
58
|
+
// undefined defaults to same behavior as "FailToProcess"
|
|
59
|
+
return compatBehavior === "Ignore";
|
|
60
|
+
}
|
|
48
61
|
export const DefaultSummaryConfiguration = {
|
|
49
62
|
state: "enabled",
|
|
50
63
|
minIdleTime: 0,
|
|
@@ -71,8 +84,12 @@ export var RuntimeHeaders;
|
|
|
71
84
|
})(RuntimeHeaders || (RuntimeHeaders = {}));
|
|
72
85
|
/** True if a tombstoned object should be returned without erroring */
|
|
73
86
|
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
87
|
+
/** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
|
|
88
|
+
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
74
89
|
/** Tombstone error responses will have this header set to true */
|
|
75
90
|
export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
91
|
+
/** Inactive error responses will have this header set to true */
|
|
92
|
+
export const InactiveResponseHeaderKey = "isInactive";
|
|
76
93
|
/** Default values for Runtime Headers */
|
|
77
94
|
export const defaultRuntimeHeaderData = {
|
|
78
95
|
wait: true,
|
|
@@ -99,6 +116,10 @@ const defaultCompressionConfig = {
|
|
|
99
116
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
100
117
|
};
|
|
101
118
|
const defaultChunkSizeInBytes = 204800;
|
|
119
|
+
/** The default time to wait for pending ops to be processed during summarization */
|
|
120
|
+
export const defaultPendingOpsWaitTimeoutMs = 1000;
|
|
121
|
+
/** The default time to delay a summarization retry attempt when there are pending ops */
|
|
122
|
+
export const defaultPendingOpsRetryDelayMs = 1000;
|
|
102
123
|
/**
|
|
103
124
|
* Instead of refreshing from latest because we do not have 100% confidence in the state
|
|
104
125
|
* of the current system, we should close the summarizer and let it recover.
|
|
@@ -200,34 +221,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
200
221
|
signalTimestamp: 0,
|
|
201
222
|
trackingSignalSequenceNumber: undefined,
|
|
202
223
|
};
|
|
203
|
-
this.summarizeOnDemand = (...args) => {
|
|
204
|
-
if (this.isSummarizerClient) {
|
|
205
|
-
return this.summarizer.summarizeOnDemand(...args);
|
|
206
|
-
}
|
|
207
|
-
else if (this.summaryManager !== undefined) {
|
|
208
|
-
return this.summaryManager.summarizeOnDemand(...args);
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
212
|
-
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
213
|
-
// because it is a misuse of the API rather than an expected failure.
|
|
214
|
-
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
this.enqueueSummarize = (...args) => {
|
|
218
|
-
if (this.isSummarizerClient) {
|
|
219
|
-
return this.summarizer.enqueueSummarize(...args);
|
|
220
|
-
}
|
|
221
|
-
else if (this.summaryManager !== undefined) {
|
|
222
|
-
return this.summaryManager.enqueueSummarize(...args);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
226
|
-
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
227
|
-
// because it is a misuse of the API rather than an expected failure.
|
|
228
|
-
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
224
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
232
225
|
this.innerDeltaManager = deltaManager;
|
|
233
226
|
this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
@@ -442,16 +435,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
442
435
|
});
|
|
443
436
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
444
437
|
this._audience = audience;
|
|
445
|
-
this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
|
|
446
438
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
447
439
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
448
440
|
this.validateSummaryBeforeUpload =
|
|
449
|
-
this.mc.config.getBoolean("Fluid.
|
|
450
|
-
false;
|
|
441
|
+
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
451
442
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
452
443
|
this.dirtyContainer =
|
|
453
|
-
this.attachState !== AttachState.Attached ||
|
|
454
|
-
this.pendingStateManager.hasPendingMessages();
|
|
444
|
+
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
455
445
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
456
446
|
if (this.summariesDisabled) {
|
|
457
447
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
@@ -499,6 +489,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
499
489
|
formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
|
|
500
490
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
501
491
|
}, this.heuristicsDisabled);
|
|
492
|
+
this.summaryManager.on("summarize", (eventProps) => {
|
|
493
|
+
this.emit("summarize", eventProps);
|
|
494
|
+
});
|
|
502
495
|
this.summaryManager.start();
|
|
503
496
|
}
|
|
504
497
|
}
|
|
@@ -543,7 +536,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
543
536
|
disableAttachReorder: this.disableAttachReorder,
|
|
544
537
|
disablePartialFlush,
|
|
545
538
|
idCompressorEnabled: this.idCompressorEnabled,
|
|
546
|
-
summaryStateUpdateMethod: this.summaryStateUpdateMethod,
|
|
547
539
|
closeSummarizerDelayOverride,
|
|
548
540
|
}),
|
|
549
541
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
@@ -607,11 +599,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
607
599
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
608
600
|
*/
|
|
609
601
|
static async loadRuntime(params) {
|
|
610
|
-
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime,
|
|
602
|
+
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
|
|
603
|
+
const initializeEntryPoint = params.initializeEntryPoint ??
|
|
604
|
+
(async (containerRuntime) => ({
|
|
605
|
+
get IFluidRouter() {
|
|
606
|
+
return this;
|
|
607
|
+
},
|
|
608
|
+
async request(req) {
|
|
609
|
+
return containerRuntime.request(req);
|
|
610
|
+
},
|
|
611
|
+
}));
|
|
611
612
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
612
613
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
613
614
|
const backCompatContext = context;
|
|
614
615
|
const passLogger = backCompatContext.taggedLogger ??
|
|
616
|
+
// eslint-disable-next-line import/no-deprecated
|
|
615
617
|
new TaggedLoggerAdapter(backCompatContext.logger);
|
|
616
618
|
const logger = createChildLogger({
|
|
617
619
|
logger: passLogger,
|
|
@@ -673,7 +675,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
673
675
|
idCompressor =
|
|
674
676
|
serializedIdCompressor !== undefined
|
|
675
677
|
? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
|
|
676
|
-
:
|
|
678
|
+
: IdCompressor.create(logger);
|
|
677
679
|
}
|
|
678
680
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
679
681
|
summaryOptions,
|
|
@@ -688,6 +690,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
688
690
|
enableGroupedBatching,
|
|
689
691
|
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
|
|
690
692
|
initializeEntryPoint);
|
|
693
|
+
await runtime.blobManager.processStashedChanges();
|
|
691
694
|
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
692
695
|
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
693
696
|
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
@@ -704,6 +707,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
704
707
|
/** @deprecated - The functionality is no longer exposed publicly */
|
|
705
708
|
get reSubmitFn() {
|
|
706
709
|
return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
710
|
+
// Note: compatDetails is not included in this deprecated API
|
|
707
711
|
}
|
|
708
712
|
get flushMode() {
|
|
709
713
|
return this._flushMode;
|
|
@@ -854,7 +858,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
854
858
|
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
855
859
|
// unintentionally modifying the url if that changes.
|
|
856
860
|
assert(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
|
|
857
|
-
return dataStore.
|
|
861
|
+
return dataStore.request(subRequest);
|
|
858
862
|
}
|
|
859
863
|
return create404Response(request);
|
|
860
864
|
}
|
|
@@ -962,7 +966,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
962
966
|
this.mc.logger.sendTelemetryEvent({
|
|
963
967
|
eventName: "ReconnectsWithNoProgress",
|
|
964
968
|
attempts: this.consecutiveReconnects,
|
|
965
|
-
pendingMessages: this.
|
|
969
|
+
pendingMessages: this.pendingMessagesCount,
|
|
966
970
|
});
|
|
967
971
|
}
|
|
968
972
|
return this.consecutiveReconnects < this.maxConsecutiveReconnects;
|
|
@@ -1022,13 +1026,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1022
1026
|
*/
|
|
1023
1027
|
parseOpContent(serializedContent) {
|
|
1024
1028
|
assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
|
|
1025
|
-
const { type, contents } = JSON.parse(serializedContent);
|
|
1029
|
+
const { type, contents, compatDetails } = JSON.parse(serializedContent);
|
|
1026
1030
|
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1027
|
-
return { type, contents };
|
|
1031
|
+
return { type, contents, compatDetails };
|
|
1028
1032
|
}
|
|
1029
1033
|
async applyStashedOp(op) {
|
|
1030
1034
|
// Need to parse from string for back-compat
|
|
1031
|
-
const { type, contents } = this.parseOpContent(op);
|
|
1035
|
+
const { type, contents, compatDetails } = this.parseOpContent(op);
|
|
1032
1036
|
switch (type) {
|
|
1033
1037
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1034
1038
|
return this.dataStores.applyStashedOp(contents);
|
|
@@ -1044,8 +1048,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1044
1048
|
throw new Error("chunkedOp not expected here");
|
|
1045
1049
|
case ContainerMessageType.Rejoin:
|
|
1046
1050
|
throw new Error("rejoin not expected here");
|
|
1047
|
-
default:
|
|
1048
|
-
|
|
1051
|
+
default: {
|
|
1052
|
+
// This should be extremely rare for stashed ops.
|
|
1053
|
+
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
1054
|
+
// e.g. if an app rolled back its container version
|
|
1055
|
+
const compatBehavior = compatDetails?.behavior;
|
|
1056
|
+
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
1057
|
+
const error = DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1058
|
+
messageDetails: JSON.stringify({
|
|
1059
|
+
type,
|
|
1060
|
+
compatBehavior,
|
|
1061
|
+
}),
|
|
1062
|
+
});
|
|
1063
|
+
this.closeFn(error);
|
|
1064
|
+
throw error;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1049
1067
|
}
|
|
1050
1068
|
}
|
|
1051
1069
|
setConnectionState(connected, clientId) {
|
|
@@ -1057,24 +1075,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1057
1075
|
// Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
|
|
1058
1076
|
return;
|
|
1059
1077
|
}
|
|
1060
|
-
// If attachment blobs were added while disconnected, we need to delay
|
|
1061
|
-
// propagation of the "connected" event until we have uploaded them to
|
|
1062
|
-
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1063
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1064
|
-
const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1065
|
-
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
1066
|
-
assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
|
|
1067
|
-
assert(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
1068
|
-
this.delayConnectClientId = clientId;
|
|
1069
|
-
this.blobManager.onConnected().then(() => {
|
|
1070
|
-
// make sure we didn't reconnect before the promise resolved
|
|
1071
|
-
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
1072
|
-
this.delayConnectClientId = undefined;
|
|
1073
|
-
this.setConnectionStateCore(connected, clientId);
|
|
1074
|
-
}
|
|
1075
|
-
}, (error) => this.closeFn(error));
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
1078
|
this.setConnectionStateCore(connected, clientId);
|
|
1079
1079
|
}
|
|
1080
1080
|
setConnectionStateCore(connected, clientId) {
|
|
@@ -1105,7 +1105,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1105
1105
|
this.closeFn(DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
|
|
1106
1106
|
dataLoss: 1,
|
|
1107
1107
|
attempts: this.consecutiveReconnects,
|
|
1108
|
-
pendingMessages: this.
|
|
1108
|
+
pendingMessages: this.pendingMessagesCount,
|
|
1109
1109
|
}));
|
|
1110
1110
|
return;
|
|
1111
1111
|
}
|
|
@@ -1122,23 +1122,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1122
1122
|
}
|
|
1123
1123
|
process(messageArg, local) {
|
|
1124
1124
|
this.verifyNotClosed();
|
|
1125
|
-
// Whether or not the message
|
|
1125
|
+
// Whether or not the message appears to be a runtime message from an up-to-date client.
|
|
1126
1126
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
1127
1127
|
// or something different, like a system message.
|
|
1128
|
-
const
|
|
1128
|
+
const modernRuntimeMessage = messageArg.type === MessageType.Operation;
|
|
1129
1129
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
1130
1130
|
const messageCopy = { ...messageArg };
|
|
1131
1131
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1132
|
-
this.processCore(message, local,
|
|
1132
|
+
this.processCore(message, local, modernRuntimeMessage);
|
|
1133
1133
|
}
|
|
1134
1134
|
}
|
|
1135
1135
|
/**
|
|
1136
1136
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
1137
1137
|
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
1138
1138
|
* @param local - Did this client send the op?
|
|
1139
|
-
* @param
|
|
1139
|
+
* @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
|
|
1140
1140
|
*/
|
|
1141
|
-
processCore(message, local,
|
|
1141
|
+
processCore(message, local, modernRuntimeMessage) {
|
|
1142
1142
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1143
1143
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1144
1144
|
// messages once a batch has been fully processed.
|
|
@@ -1146,7 +1146,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1146
1146
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1147
1147
|
try {
|
|
1148
1148
|
let localOpMetadata;
|
|
1149
|
-
if (local &&
|
|
1149
|
+
if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
|
|
1150
1150
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
|
|
1151
1151
|
}
|
|
1152
1152
|
// If there are no more pending messages after processing a local message,
|
|
@@ -1154,43 +1154,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1154
1154
|
if (!this.hasPendingMessages()) {
|
|
1155
1155
|
this.updateDocumentDirtyState(false);
|
|
1156
1156
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
case ContainerMessageType.Attach:
|
|
1160
|
-
this.dataStores.processAttachMessage(message, local);
|
|
1161
|
-
break;
|
|
1162
|
-
case ContainerMessageType.Alias:
|
|
1163
|
-
this.processAliasMessage(message, localOpMetadata, local);
|
|
1164
|
-
break;
|
|
1165
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
1166
|
-
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1167
|
-
break;
|
|
1168
|
-
case ContainerMessageType.BlobAttach:
|
|
1169
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
1170
|
-
break;
|
|
1171
|
-
case ContainerMessageType.IdAllocation:
|
|
1172
|
-
assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1173
|
-
this.idCompressor.finalizeCreationRange(message.contents);
|
|
1174
|
-
break;
|
|
1175
|
-
case ContainerMessageType.ChunkedOp:
|
|
1176
|
-
case ContainerMessageType.Rejoin:
|
|
1177
|
-
break;
|
|
1178
|
-
default:
|
|
1179
|
-
if (runtimeMessage) {
|
|
1180
|
-
const error = DataProcessingError.create(
|
|
1181
|
-
// Former assert 0x3ce
|
|
1182
|
-
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1183
|
-
local,
|
|
1184
|
-
type: message.type,
|
|
1185
|
-
contentType: typeof message.contents,
|
|
1186
|
-
batch: message.metadata?.batch,
|
|
1187
|
-
compression: message.compression,
|
|
1188
|
-
});
|
|
1189
|
-
this.closeFn(error);
|
|
1190
|
-
throw error;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
this.emit("op", message, runtimeMessage);
|
|
1157
|
+
this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
|
|
1158
|
+
this.emit("op", message, modernRuntimeMessage);
|
|
1194
1159
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
1195
1160
|
if (local) {
|
|
1196
1161
|
// If we have processed a local op, this means that the container is
|
|
@@ -1204,8 +1169,59 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1204
1169
|
throw e;
|
|
1205
1170
|
}
|
|
1206
1171
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1172
|
+
/**
|
|
1173
|
+
* Assuming the given message is also a ContainerRuntimeMessage,
|
|
1174
|
+
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
1175
|
+
* Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
|
|
1176
|
+
*/
|
|
1177
|
+
validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
|
|
1178
|
+
// Optimistically extract ContainerRuntimeMessage-specific props from the message
|
|
1179
|
+
const { type: maybeContainerMessageType, compatDetails } = message;
|
|
1180
|
+
switch (maybeContainerMessageType) {
|
|
1181
|
+
case ContainerMessageType.Attach:
|
|
1182
|
+
this.dataStores.processAttachMessage(message, local);
|
|
1183
|
+
break;
|
|
1184
|
+
case ContainerMessageType.Alias:
|
|
1185
|
+
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
1186
|
+
break;
|
|
1187
|
+
case ContainerMessageType.FluidDataStoreOp:
|
|
1188
|
+
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1189
|
+
break;
|
|
1190
|
+
case ContainerMessageType.BlobAttach:
|
|
1191
|
+
this.blobManager.processBlobAttachOp(message, local);
|
|
1192
|
+
break;
|
|
1193
|
+
case ContainerMessageType.IdAllocation:
|
|
1194
|
+
assert(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1195
|
+
this.idCompressor.finalizeCreationRange(message.contents);
|
|
1196
|
+
break;
|
|
1197
|
+
case ContainerMessageType.ChunkedOp:
|
|
1198
|
+
case ContainerMessageType.Rejoin:
|
|
1199
|
+
break;
|
|
1200
|
+
default: {
|
|
1201
|
+
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
1202
|
+
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
1203
|
+
if (!expectRuntimeMessageType) {
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const compatBehavior = compatDetails?.behavior;
|
|
1207
|
+
if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
|
|
1208
|
+
const error = DataProcessingError.create(
|
|
1209
|
+
// Former assert 0x3ce
|
|
1210
|
+
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1211
|
+
local,
|
|
1212
|
+
messageDetails: JSON.stringify({
|
|
1213
|
+
type: message.type,
|
|
1214
|
+
contentType: typeof message.contents,
|
|
1215
|
+
compatBehavior,
|
|
1216
|
+
batch: message.metadata?.batch,
|
|
1217
|
+
compression: message.compression,
|
|
1218
|
+
}),
|
|
1219
|
+
});
|
|
1220
|
+
this.closeFn(error);
|
|
1221
|
+
throw error;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1209
1225
|
}
|
|
1210
1226
|
/**
|
|
1211
1227
|
* Emits the Signal event and update the perf signal data.
|
|
@@ -1673,7 +1689,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1673
1689
|
* @param options - options controlling how the summary is generated or submitted
|
|
1674
1690
|
*/
|
|
1675
1691
|
async submitSummary(options) {
|
|
1676
|
-
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
1692
|
+
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
|
|
1677
1693
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1678
1694
|
// use it for all events logged during this summary.
|
|
1679
1695
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1695,6 +1711,40 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1695
1711
|
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
1696
1712
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
1697
1713
|
}
|
|
1714
|
+
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
1715
|
+
// incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
|
|
1716
|
+
// within the timeout, check if it should be failed or can continue.
|
|
1717
|
+
if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
|
|
1718
|
+
const countBefore = this.pendingMessagesCount;
|
|
1719
|
+
// The timeout for waiting for pending ops can be overridden via configurations.
|
|
1720
|
+
const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
|
|
1721
|
+
defaultPendingOpsWaitTimeoutMs;
|
|
1722
|
+
await new Promise((resolve, reject) => {
|
|
1723
|
+
const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
|
|
1724
|
+
this.once("saved", () => {
|
|
1725
|
+
clearTimeout(timeoutId);
|
|
1726
|
+
resolve();
|
|
1727
|
+
});
|
|
1728
|
+
this.once("dispose", () => {
|
|
1729
|
+
clearTimeout(timeoutId);
|
|
1730
|
+
reject(new Error("Runtime is disposed while summarizing"));
|
|
1731
|
+
});
|
|
1732
|
+
});
|
|
1733
|
+
// Log that there are pending ops while summarizing. This will help us gather data on how often this
|
|
1734
|
+
// happens, whether we attempted to wait for these ops to be acked and what was the result.
|
|
1735
|
+
summaryNumberLogger.sendTelemetryEvent({
|
|
1736
|
+
eventName: "PendingOpsWhileSummarizing",
|
|
1737
|
+
saved: this.hasPendingMessages() ? false : true,
|
|
1738
|
+
timeout: pendingOpsTimeout,
|
|
1739
|
+
countBefore,
|
|
1740
|
+
countAfter: this.pendingMessagesCount,
|
|
1741
|
+
});
|
|
1742
|
+
// There could still be pending ops. Check if summary should fail or continue.
|
|
1743
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, this.deltaManager.lastSequenceNumber, this.deltaManager.minimumSequenceNumber, finalAttempt, true /* beforeSummaryGeneration */);
|
|
1744
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
1745
|
+
return pendingMessagesFailResult;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1698
1748
|
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1699
1749
|
let summaryRefSeqNum;
|
|
1700
1750
|
try {
|
|
@@ -1770,9 +1820,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1770
1820
|
error,
|
|
1771
1821
|
};
|
|
1772
1822
|
}
|
|
1773
|
-
// If validateSummaryBeforeUpload is true, validate that the summary generated
|
|
1774
|
-
// correct before this summary is uploaded.
|
|
1823
|
+
// If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
|
|
1775
1824
|
if (this.validateSummaryBeforeUpload) {
|
|
1825
|
+
// Validate that the summaries generated by summarize nodes is correct.
|
|
1776
1826
|
const validateResult = this.summarizerNode.validateSummary();
|
|
1777
1827
|
if (!validateResult.success) {
|
|
1778
1828
|
const { success, ...loggingProps } = validateResult;
|
|
@@ -1784,6 +1834,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1784
1834
|
error,
|
|
1785
1835
|
};
|
|
1786
1836
|
}
|
|
1837
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
|
|
1838
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
1839
|
+
return pendingMessagesFailResult;
|
|
1840
|
+
}
|
|
1787
1841
|
}
|
|
1788
1842
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
1789
1843
|
// Now that we have generated the summary, update the message at last summary to the last message processed.
|
|
@@ -1904,8 +1958,55 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1904
1958
|
}
|
|
1905
1959
|
}
|
|
1906
1960
|
}
|
|
1961
|
+
/**
|
|
1962
|
+
* This helper is called during summarization. If there are pending ops, it will return a failed summarize result
|
|
1963
|
+
* (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
|
|
1964
|
+
* @param logger - The logger to be used for sending telemetry.
|
|
1965
|
+
* @param referenceSequenceNumber - The reference sequence number of the summary attempt.
|
|
1966
|
+
* @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
|
|
1967
|
+
* @param finalAttempt - Whether this is the final summary attempt.
|
|
1968
|
+
* @param beforeSummaryGeneration - Whether this is called before summary generation or after.
|
|
1969
|
+
* @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
|
|
1970
|
+
*/
|
|
1971
|
+
async shouldFailSummaryOnPendingOps(logger, referenceSequenceNumber, minimumSequenceNumber, finalAttempt, beforeSummaryGeneration) {
|
|
1972
|
+
if (!this.hasPendingMessages()) {
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
// If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
|
|
1976
|
+
// This is a fallback to make progress in documents where there are consistently pending ops in
|
|
1977
|
+
// the summarizer.
|
|
1978
|
+
if (finalAttempt &&
|
|
1979
|
+
this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
|
|
1980
|
+
const error = DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
|
|
1981
|
+
logger.sendErrorEvent({
|
|
1982
|
+
eventName: "SkipFailingIncorrectSummary",
|
|
1983
|
+
referenceSequenceNumber,
|
|
1984
|
+
minimumSequenceNumber,
|
|
1985
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
1986
|
+
}, error);
|
|
1987
|
+
}
|
|
1988
|
+
else {
|
|
1989
|
+
// The retry delay when there are pending ops can be overridden via config so that we can adjust it
|
|
1990
|
+
// based on telemetry while we decide on a stable number.
|
|
1991
|
+
const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
1992
|
+
defaultPendingOpsRetryDelayMs;
|
|
1993
|
+
const error = new RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
|
|
1994
|
+
count: this.pendingMessagesCount,
|
|
1995
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
1996
|
+
});
|
|
1997
|
+
return {
|
|
1998
|
+
stage: "base",
|
|
1999
|
+
referenceSequenceNumber,
|
|
2000
|
+
minimumSequenceNumber,
|
|
2001
|
+
error,
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
get pendingMessagesCount() {
|
|
2006
|
+
return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
|
|
2007
|
+
}
|
|
1907
2008
|
hasPendingMessages() {
|
|
1908
|
-
return this.
|
|
2009
|
+
return this.pendingMessagesCount !== 0;
|
|
1909
2010
|
}
|
|
1910
2011
|
updateDocumentDirtyState(dirty) {
|
|
1911
2012
|
if (this.attachState !== AttachState.Attached) {
|
|
@@ -1949,7 +2050,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1949
2050
|
assert(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
|
|
1950
2051
|
idRange = this.idCompressor.takeNextCreationRange();
|
|
1951
2052
|
// Don't include the idRange if there weren't any Ids allocated
|
|
1952
|
-
idRange = idRange?.ids
|
|
2053
|
+
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
1953
2054
|
}
|
|
1954
2055
|
if (idRange !== undefined) {
|
|
1955
2056
|
const idAllocationMessage = {
|
|
@@ -2168,8 +2269,27 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2168
2269
|
case ContainerMessageType.Rejoin:
|
|
2169
2270
|
this.submit(message);
|
|
2170
2271
|
break;
|
|
2171
|
-
default:
|
|
2172
|
-
|
|
2272
|
+
default: {
|
|
2273
|
+
// This case should be very rare - it would imply an op was stashed from a
|
|
2274
|
+
// future version of runtime code and now is being applied on an older version
|
|
2275
|
+
const compatBehavior = message.compatDetails?.behavior;
|
|
2276
|
+
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
2277
|
+
this.logger.sendTelemetryEvent({
|
|
2278
|
+
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
2279
|
+
messageDetails: { type: message.type, compatBehavior },
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
else {
|
|
2283
|
+
const error = DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
|
|
2284
|
+
messageDetails: JSON.stringify({
|
|
2285
|
+
type: message.type,
|
|
2286
|
+
compatBehavior,
|
|
2287
|
+
}),
|
|
2288
|
+
});
|
|
2289
|
+
this.closeFn(error);
|
|
2290
|
+
throw error;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2173
2293
|
}
|
|
2174
2294
|
}
|
|
2175
2295
|
rollback(content, localOpMetadata) {
|
|
@@ -2182,6 +2302,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2182
2302
|
this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
|
|
2183
2303
|
break;
|
|
2184
2304
|
default:
|
|
2305
|
+
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
2185
2306
|
throw new Error(`Can't rollback ${type}`);
|
|
2186
2307
|
}
|
|
2187
2308
|
}
|
|
@@ -2199,29 +2320,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2199
2320
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
2200
2321
|
async refreshLatestSummaryAck(options) {
|
|
2201
2322
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2323
|
+
// proposalHandle is always passed from RunningSummarizer.
|
|
2324
|
+
assert(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
2202
2325
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2326
|
+
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
|
|
2327
|
+
/**
|
|
2328
|
+
* When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
|
|
2329
|
+
* current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
|
|
2330
|
+
* it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
|
|
2331
|
+
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
2332
|
+
*/
|
|
2333
|
+
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
2334
|
+
const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
2208
2335
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
2209
2336
|
ackHandle,
|
|
2210
2337
|
targetSequenceNumber: summaryRefSeq,
|
|
2211
|
-
}, readAndParseBlob);
|
|
2212
|
-
/**
|
|
2213
|
-
* back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
|
|
2214
|
-
* getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
|
|
2215
|
-
* these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
|
|
2216
|
-
* change that started fetching latest snapshot always.
|
|
2217
|
-
*/
|
|
2218
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
2219
|
-
fetchResult = await this.fetchSnapshotFromStorageAndClose(summaryLogger, {
|
|
2220
|
-
eventName: "RefreshLatestSummaryAckFetchBackCompat",
|
|
2221
|
-
ackHandle,
|
|
2222
|
-
targetSequenceNumber: summaryRefSeq,
|
|
2223
|
-
}, readAndParseBlob, ackHandle);
|
|
2224
|
-
}
|
|
2338
|
+
}, readAndParseBlob, null);
|
|
2225
2339
|
/**
|
|
2226
2340
|
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
2227
2341
|
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
@@ -2241,17 +2355,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2241
2355
|
this.disposeFn(error);
|
|
2242
2356
|
throw error;
|
|
2243
2357
|
}
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
return {
|
|
2248
|
-
snapshotTree: fetchResult.snapshotTree,
|
|
2249
|
-
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
2250
|
-
};
|
|
2251
|
-
};
|
|
2252
|
-
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
2358
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2253
2361
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2254
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
2362
|
+
await this.garbageCollector.refreshLatestSummary(result);
|
|
2255
2363
|
}
|
|
2256
2364
|
/**
|
|
2257
2365
|
* Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
|
|
@@ -2261,23 +2369,31 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2261
2369
|
*/
|
|
2262
2370
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
2263
2371
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
2264
|
-
const {
|
|
2372
|
+
const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
2265
2373
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2266
|
-
}, readAndParseBlob);
|
|
2267
|
-
|
|
2268
|
-
snapshotTree,
|
|
2269
|
-
snapshotRefSeq: latestSnapshotRefSeq,
|
|
2270
|
-
};
|
|
2271
|
-
const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
2272
|
-
// Notify the garbage collector so it can update its latest summary state.
|
|
2273
|
-
await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
|
|
2374
|
+
}, readAndParseBlob, null);
|
|
2375
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
2274
2376
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
2275
2377
|
}
|
|
2276
|
-
async
|
|
2277
|
-
|
|
2378
|
+
async closeStaleSummarizer(codePath) {
|
|
2379
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2380
|
+
eventName: "ClosingSummarizerOnSummaryStale",
|
|
2381
|
+
codePath,
|
|
2382
|
+
message: "Stopping fetch from storage",
|
|
2383
|
+
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
2384
|
+
}, new GenericError("Restarting summarizer instead of refreshing"));
|
|
2385
|
+
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2386
|
+
await delay(this.closeSummarizerDelayMs);
|
|
2387
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
2388
|
+
this.disposeFn();
|
|
2278
2389
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2390
|
+
/**
|
|
2391
|
+
* Downloads snapshot from storage with the given versionId or latest if versionId is null.
|
|
2392
|
+
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
2393
|
+
* overridden via options.
|
|
2394
|
+
*/
|
|
2395
|
+
async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
|
|
2396
|
+
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2281
2397
|
const stats = {};
|
|
2282
2398
|
const trace = Trace.start();
|
|
2283
2399
|
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? FetchSource.noCache : undefined);
|
|
@@ -2296,41 +2412,65 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2296
2412
|
latestSnapshotRefSeq,
|
|
2297
2413
|
};
|
|
2298
2414
|
});
|
|
2299
|
-
// We choose to close the summarizer after the snapshot cache is updated to avoid
|
|
2300
|
-
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
2301
|
-
// loads the summarizer from cache.
|
|
2302
|
-
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
2303
|
-
this.mc.logger.sendTelemetryEvent({
|
|
2304
|
-
...event,
|
|
2305
|
-
eventName: "ClosingSummarizerOnSummaryStale",
|
|
2306
|
-
codePath: event.eventName,
|
|
2307
|
-
message: "Stopping fetch from storage",
|
|
2308
|
-
versionId: versionId != null ? versionId : undefined,
|
|
2309
|
-
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
2310
|
-
}, new GenericError("Restarting summarizer instead of refreshing"));
|
|
2311
|
-
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2312
|
-
await delay(this.closeSummarizerDelayMs);
|
|
2313
|
-
this._summarizer?.stop("latestSummaryStateStale");
|
|
2314
|
-
this.disposeFn();
|
|
2315
|
-
}
|
|
2316
|
-
return snapshotResults;
|
|
2317
2415
|
}
|
|
2318
2416
|
notifyAttaching() { } // do nothing (deprecated method)
|
|
2319
2417
|
async getPendingLocalState(props) {
|
|
2320
|
-
this.
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2418
|
+
return PerformanceEvent.timedExecAsync(this.mc.logger, {
|
|
2419
|
+
eventName: "getPendingLocalState",
|
|
2420
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
2421
|
+
}, async (event) => {
|
|
2422
|
+
this.verifyNotClosed();
|
|
2423
|
+
const waitBlobsToAttach = props?.notifyImminentClosure;
|
|
2424
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
2425
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
2426
|
+
}
|
|
2427
|
+
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
|
|
2428
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
2429
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
2430
|
+
return; // no pending state to save
|
|
2431
|
+
}
|
|
2432
|
+
// Flush pending batch.
|
|
2433
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2434
|
+
// to close current batch.
|
|
2435
|
+
this.flush();
|
|
2436
|
+
const pendingState = {
|
|
2437
|
+
pending,
|
|
2438
|
+
pendingAttachmentBlobs,
|
|
2439
|
+
};
|
|
2440
|
+
event.end({
|
|
2441
|
+
attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
|
|
2442
|
+
pendingOpsSize: pending?.pendingStates.length,
|
|
2443
|
+
});
|
|
2444
|
+
return pendingState;
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
summarizeOnDemand(options) {
|
|
2448
|
+
if (this.isSummarizerClient) {
|
|
2449
|
+
return this.summarizer.summarizeOnDemand(options);
|
|
2450
|
+
}
|
|
2451
|
+
else if (this.summaryManager !== undefined) {
|
|
2452
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
2453
|
+
}
|
|
2454
|
+
else {
|
|
2455
|
+
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2456
|
+
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
2457
|
+
// because it is a misuse of the API rather than an expected failure.
|
|
2458
|
+
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
enqueueSummarize(options) {
|
|
2462
|
+
if (this.isSummarizerClient) {
|
|
2463
|
+
return this.summarizer.enqueueSummarize(options);
|
|
2464
|
+
}
|
|
2465
|
+
else if (this.summaryManager !== undefined) {
|
|
2466
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
2467
|
+
}
|
|
2468
|
+
else {
|
|
2469
|
+
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2470
|
+
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
2471
|
+
// because it is a misuse of the API rather than an expected failure.
|
|
2472
|
+
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2473
|
+
}
|
|
2334
2474
|
}
|
|
2335
2475
|
/**
|
|
2336
2476
|
* * Forms a function that will request a Summarizer.
|