@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/dist/containerRuntime.js
CHANGED
|
@@ -19,14 +19,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.TombstoneResponseHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
|
|
22
|
+
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = exports.ContainerMessageType = void 0;
|
|
23
23
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
24
|
-
const common_utils_1 = require("@fluidframework/common-utils");
|
|
25
24
|
const core_utils_1 = require("@fluidframework/core-utils");
|
|
25
|
+
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
26
26
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
27
27
|
const driver_definitions_1 = require("@fluidframework/driver-definitions");
|
|
28
28
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
29
|
-
const container_utils_1 = require("@fluidframework/container-utils");
|
|
30
29
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
31
30
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
32
31
|
const runtime_utils_1 = require("@fluidframework/runtime-utils");
|
|
@@ -67,6 +66,18 @@ var ContainerMessageType;
|
|
|
67
66
|
*/
|
|
68
67
|
ContainerMessageType["IdAllocation"] = "idAllocation";
|
|
69
68
|
})(ContainerMessageType = exports.ContainerMessageType || (exports.ContainerMessageType = {}));
|
|
69
|
+
/**
|
|
70
|
+
* Utility to implement compat behaviors given an unknown message type
|
|
71
|
+
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
72
|
+
*
|
|
73
|
+
* @param _unknownContainerRuntimeMessageType - Typed as never, to ensure all known types have been
|
|
74
|
+
* handled before calling this function (e.g. in a switch statement).
|
|
75
|
+
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
76
|
+
*/
|
|
77
|
+
function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
|
|
78
|
+
// undefined defaults to same behavior as "FailToProcess"
|
|
79
|
+
return compatBehavior === "Ignore";
|
|
80
|
+
}
|
|
70
81
|
exports.DefaultSummaryConfiguration = {
|
|
71
82
|
state: "enabled",
|
|
72
83
|
minIdleTime: 0,
|
|
@@ -93,8 +104,12 @@ var RuntimeHeaders;
|
|
|
93
104
|
})(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
|
|
94
105
|
/** True if a tombstoned object should be returned without erroring */
|
|
95
106
|
exports.AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
107
|
+
/** [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring */
|
|
108
|
+
exports.AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
96
109
|
/** Tombstone error responses will have this header set to true */
|
|
97
110
|
exports.TombstoneResponseHeaderKey = "isTombstoned";
|
|
111
|
+
/** Inactive error responses will have this header set to true */
|
|
112
|
+
exports.InactiveResponseHeaderKey = "isInactive";
|
|
98
113
|
/** Default values for Runtime Headers */
|
|
99
114
|
exports.defaultRuntimeHeaderData = {
|
|
100
115
|
wait: true,
|
|
@@ -121,6 +136,10 @@ const defaultCompressionConfig = {
|
|
|
121
136
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
122
137
|
};
|
|
123
138
|
const defaultChunkSizeInBytes = 204800;
|
|
139
|
+
/** The default time to wait for pending ops to be processed during summarization */
|
|
140
|
+
exports.defaultPendingOpsWaitTimeoutMs = 1000;
|
|
141
|
+
/** The default time to delay a summarization retry attempt when there are pending ops */
|
|
142
|
+
exports.defaultPendingOpsRetryDelayMs = 1000;
|
|
124
143
|
/**
|
|
125
144
|
* Instead of refreshing from latest because we do not have 100% confidence in the state
|
|
126
145
|
* of the current system, we should close the summarizer and let it recover.
|
|
@@ -186,7 +205,7 @@ exports.makeLegacySendBatchFn = makeLegacySendBatchFn;
|
|
|
186
205
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
187
206
|
* It will define the store level mappings.
|
|
188
207
|
*/
|
|
189
|
-
class ContainerRuntime extends
|
|
208
|
+
class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
190
209
|
/**
|
|
191
210
|
* @internal
|
|
192
211
|
*/
|
|
@@ -225,34 +244,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
225
244
|
signalTimestamp: 0,
|
|
226
245
|
trackingSignalSequenceNumber: undefined,
|
|
227
246
|
};
|
|
228
|
-
this.summarizeOnDemand = (...args) => {
|
|
229
|
-
if (this.isSummarizerClient) {
|
|
230
|
-
return this.summarizer.summarizeOnDemand(...args);
|
|
231
|
-
}
|
|
232
|
-
else if (this.summaryManager !== undefined) {
|
|
233
|
-
return this.summaryManager.summarizeOnDemand(...args);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
237
|
-
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
238
|
-
// because it is a misuse of the API rather than an expected failure.
|
|
239
|
-
throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
this.enqueueSummarize = (...args) => {
|
|
243
|
-
if (this.isSummarizerClient) {
|
|
244
|
-
return this.summarizer.enqueueSummarize(...args);
|
|
245
|
-
}
|
|
246
|
-
else if (this.summaryManager !== undefined) {
|
|
247
|
-
return this.summaryManager.enqueueSummarize(...args);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
251
|
-
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
252
|
-
// because it is a misuse of the API rather than an expected failure.
|
|
253
|
-
throw new container_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
247
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
257
248
|
this.innerDeltaManager = deltaManager;
|
|
258
249
|
this.deltaManager = new deltaManagerSummarizerProxy_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
@@ -368,7 +359,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
368
359
|
// This is a runtime enforcement of what's already explicit in the policy's type itself,
|
|
369
360
|
// which dictates the value is either undefined or exactly 5 days in ms.
|
|
370
361
|
// As long as the actual value is less than 5 days, the assumptions GC makes here are valid.
|
|
371
|
-
throw new
|
|
362
|
+
throw new telemetry_utils_1.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
372
363
|
}
|
|
373
364
|
this.garbageCollector = gc_1.GarbageCollector.create({
|
|
374
365
|
runtime: this,
|
|
@@ -467,16 +458,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
467
458
|
});
|
|
468
459
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
469
460
|
this._audience = audience;
|
|
470
|
-
this.summaryStateUpdateMethod = this.mc.config.getString("Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2");
|
|
471
461
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
472
462
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
473
463
|
this.validateSummaryBeforeUpload =
|
|
474
|
-
this.mc.config.getBoolean("Fluid.
|
|
475
|
-
false;
|
|
464
|
+
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
476
465
|
this.summaryCollection = new summary_1.SummaryCollection(this.deltaManager, this.logger);
|
|
477
466
|
this.dirtyContainer =
|
|
478
|
-
this.attachState !== container_definitions_1.AttachState.Attached ||
|
|
479
|
-
this.pendingStateManager.hasPendingMessages();
|
|
467
|
+
this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
|
|
480
468
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
481
469
|
if (this.summariesDisabled) {
|
|
482
470
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
@@ -524,6 +512,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
524
512
|
(0, throttler_1.formExponentialFn)({ coefficient: 20, initialDelay: 0 })), {
|
|
525
513
|
initialDelayMs: this.initialSummarizerDelayMs,
|
|
526
514
|
}, this.heuristicsDisabled);
|
|
515
|
+
this.summaryManager.on("summarize", (eventProps) => {
|
|
516
|
+
this.emit("summarize", eventProps);
|
|
517
|
+
});
|
|
527
518
|
this.summaryManager.start();
|
|
528
519
|
}
|
|
529
520
|
}
|
|
@@ -531,7 +522,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
531
522
|
// we accumulate ops while being in read-only state.
|
|
532
523
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
533
524
|
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
534
|
-
(0,
|
|
525
|
+
(0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
535
526
|
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
536
527
|
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
537
528
|
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
@@ -544,7 +535,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
544
535
|
// can rely on same safety mechanism and resend ops only when we establish new connection.
|
|
545
536
|
// This is applicable for read-only permissions (event is raised before connection is properly registered),
|
|
546
537
|
// but it's an extra requirement for Container.forceReadonly() API
|
|
547
|
-
(0,
|
|
538
|
+
(0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
|
|
548
539
|
this.replayPendingStates();
|
|
549
540
|
});
|
|
550
541
|
// logging hardware telemetry
|
|
@@ -568,7 +559,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
568
559
|
disableAttachReorder: this.disableAttachReorder,
|
|
569
560
|
disablePartialFlush,
|
|
570
561
|
idCompressorEnabled: this.idCompressorEnabled,
|
|
571
|
-
summaryStateUpdateMethod: this.summaryStateUpdateMethod,
|
|
572
562
|
closeSummarizerDelayOverride,
|
|
573
563
|
}),
|
|
574
564
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
@@ -578,7 +568,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
578
568
|
(0, batchTracker_1.BindBatchTracker)(this, this.logger);
|
|
579
569
|
this.entryPoint = new core_utils_1.LazyPromise(async () => {
|
|
580
570
|
if (this.isSummarizerClient) {
|
|
581
|
-
(0,
|
|
571
|
+
(0, core_utils_1.assert)(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
582
572
|
return this._summarizer;
|
|
583
573
|
}
|
|
584
574
|
return initializeEntryPoint?.(this);
|
|
@@ -632,11 +622,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
632
622
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
633
623
|
*/
|
|
634
624
|
static async loadRuntime(params) {
|
|
635
|
-
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime,
|
|
625
|
+
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime, } = params;
|
|
626
|
+
const initializeEntryPoint = params.initializeEntryPoint ??
|
|
627
|
+
(async (containerRuntime) => ({
|
|
628
|
+
get IFluidRouter() {
|
|
629
|
+
return this;
|
|
630
|
+
},
|
|
631
|
+
async request(req) {
|
|
632
|
+
return containerRuntime.request(req);
|
|
633
|
+
},
|
|
634
|
+
}));
|
|
636
635
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
637
636
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
638
637
|
const backCompatContext = context;
|
|
639
638
|
const passLogger = backCompatContext.taggedLogger ??
|
|
639
|
+
// eslint-disable-next-line import/no-deprecated
|
|
640
640
|
new telemetry_utils_1.TaggedLoggerAdapter(backCompatContext.logger);
|
|
641
641
|
const logger = (0, telemetry_utils_1.createChildLogger)({
|
|
642
642
|
logger: passLogger,
|
|
@@ -653,7 +653,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
653
653
|
if (context.baseSnapshot && blobId) {
|
|
654
654
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
655
655
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
656
|
-
(0,
|
|
656
|
+
(0, core_utils_1.assert)(context.storage !== undefined, 0x1f5 /* "Attached state should have storage" */);
|
|
657
657
|
return (0, driver_utils_1.readAndParse)(context.storage, blobId);
|
|
658
658
|
}
|
|
659
659
|
};
|
|
@@ -668,7 +668,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
668
668
|
const blobManagerSnapshot = await blobManager_1.BlobManager.load(context.baseSnapshot?.trees[summary_1.blobsTreeName], async (id) => {
|
|
669
669
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
670
670
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
671
|
-
(0,
|
|
671
|
+
(0, core_utils_1.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
672
672
|
return (0, driver_utils_1.readAndParse)(context.storage, id);
|
|
673
673
|
});
|
|
674
674
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
@@ -680,7 +680,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
680
680
|
if (loadSequenceNumberVerification !== "bypass" &&
|
|
681
681
|
runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
682
682
|
// "Load from summary, runtime metadata sequenceNumber !== initialSequenceNumber"
|
|
683
|
-
const error = new
|
|
683
|
+
const error = new telemetry_utils_1.DataCorruptionError(
|
|
684
684
|
// pre-0.58 error message: SummaryMetadataMismatch
|
|
685
685
|
"Summary metadata mismatch", { runtimeVersion: packageVersion_1.pkgVersion, runtimeSequenceNumber, protocolSequenceNumber });
|
|
686
686
|
if (loadSequenceNumberVerification === "log") {
|
|
@@ -698,7 +698,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
698
698
|
idCompressor =
|
|
699
699
|
serializedIdCompressor !== undefined
|
|
700
700
|
? IdCompressor.deserialize(serializedIdCompressor, createSessionId())
|
|
701
|
-
:
|
|
701
|
+
: IdCompressor.create(logger);
|
|
702
702
|
}
|
|
703
703
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
704
704
|
summaryOptions,
|
|
@@ -713,6 +713,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
713
713
|
enableGroupedBatching,
|
|
714
714
|
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
|
|
715
715
|
initializeEntryPoint);
|
|
716
|
+
await runtime.blobManager.processStashedChanges();
|
|
716
717
|
// It's possible to have ops with a reference sequence number of 0. Op sequence numbers start
|
|
717
718
|
// at 1, so we won't see a replayed saved op with a sequence number of 0.
|
|
718
719
|
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
@@ -729,6 +730,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
729
730
|
/** @deprecated - The functionality is no longer exposed publicly */
|
|
730
731
|
get reSubmitFn() {
|
|
731
732
|
return (type, contents, localOpMetadata, opMetadata) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
733
|
+
// Note: compatDetails is not included in this deprecated API
|
|
732
734
|
}
|
|
733
735
|
get flushMode() {
|
|
734
736
|
return this._flushMode;
|
|
@@ -773,7 +775,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
773
775
|
return this._disposed;
|
|
774
776
|
}
|
|
775
777
|
get summarizer() {
|
|
776
|
-
(0,
|
|
778
|
+
(0, core_utils_1.assert)(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
777
779
|
return this._summarizer;
|
|
778
780
|
}
|
|
779
781
|
isSummariesDisabled() {
|
|
@@ -878,8 +880,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
878
880
|
const subRequest = requestParser.createSubRequest(1);
|
|
879
881
|
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
880
882
|
// unintentionally modifying the url if that changes.
|
|
881
|
-
(0,
|
|
882
|
-
return dataStore.
|
|
883
|
+
(0, core_utils_1.assert)(subRequest.url.startsWith("/"), 0x126 /* "Expected createSubRequest url to include a leading slash" */);
|
|
884
|
+
return dataStore.request(subRequest);
|
|
883
885
|
}
|
|
884
886
|
return (0, runtime_utils_1.create404Response)(request);
|
|
885
887
|
}
|
|
@@ -937,7 +939,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
937
939
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
938
940
|
this.addMetadataToSummary(summaryTree);
|
|
939
941
|
if (this.idCompressorEnabled) {
|
|
940
|
-
(0,
|
|
942
|
+
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67a /* IdCompressor should be defined if enabled */);
|
|
941
943
|
const idCompressorState = JSON.stringify(this.idCompressor.serialize(false));
|
|
942
944
|
(0, runtime_utils_1.addBlobToSummary)(summaryTree, summary_1.idCompressorBlobName, idCompressorState);
|
|
943
945
|
}
|
|
@@ -987,7 +989,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
987
989
|
this.mc.logger.sendTelemetryEvent({
|
|
988
990
|
eventName: "ReconnectsWithNoProgress",
|
|
989
991
|
attempts: this.consecutiveReconnects,
|
|
990
|
-
pendingMessages: this.
|
|
992
|
+
pendingMessages: this.pendingMessagesCount,
|
|
991
993
|
});
|
|
992
994
|
}
|
|
993
995
|
return this.consecutiveReconnects < this.maxConsecutiveReconnects;
|
|
@@ -1012,7 +1014,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1012
1014
|
// Save the old state, reset to false, disable event emit
|
|
1013
1015
|
const oldState = this.dirtyContainer;
|
|
1014
1016
|
this.dirtyContainer = false;
|
|
1015
|
-
(0,
|
|
1017
|
+
(0, core_utils_1.assert)(this.emitDirtyDocumentEvent, 0x127 /* "dirty document event not set on replay" */);
|
|
1016
1018
|
this.emitDirtyDocumentEvent = false;
|
|
1017
1019
|
let newState;
|
|
1018
1020
|
try {
|
|
@@ -1046,21 +1048,21 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1046
1048
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
1047
1049
|
*/
|
|
1048
1050
|
parseOpContent(serializedContent) {
|
|
1049
|
-
(0,
|
|
1050
|
-
const { type, contents } = JSON.parse(serializedContent);
|
|
1051
|
-
(0,
|
|
1052
|
-
return { type, contents };
|
|
1051
|
+
(0, core_utils_1.assert)(serializedContent !== undefined, 0x6d5 /* content must be defined */);
|
|
1052
|
+
const { type, contents, compatDetails } = JSON.parse(serializedContent);
|
|
1053
|
+
(0, core_utils_1.assert)(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1054
|
+
return { type, contents, compatDetails };
|
|
1053
1055
|
}
|
|
1054
1056
|
async applyStashedOp(op) {
|
|
1055
1057
|
// Need to parse from string for back-compat
|
|
1056
|
-
const { type, contents } = this.parseOpContent(op);
|
|
1058
|
+
const { type, contents, compatDetails } = this.parseOpContent(op);
|
|
1057
1059
|
switch (type) {
|
|
1058
1060
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1059
1061
|
return this.dataStores.applyStashedOp(contents);
|
|
1060
1062
|
case ContainerMessageType.Attach:
|
|
1061
1063
|
return this.dataStores.applyStashedAttachOp(contents);
|
|
1062
1064
|
case ContainerMessageType.IdAllocation:
|
|
1063
|
-
(0,
|
|
1065
|
+
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
|
|
1064
1066
|
return this.applyStashedIdAllocationOp(contents);
|
|
1065
1067
|
case ContainerMessageType.Alias:
|
|
1066
1068
|
case ContainerMessageType.BlobAttach:
|
|
@@ -1069,8 +1071,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1069
1071
|
throw new Error("chunkedOp not expected here");
|
|
1070
1072
|
case ContainerMessageType.Rejoin:
|
|
1071
1073
|
throw new Error("rejoin not expected here");
|
|
1072
|
-
default:
|
|
1073
|
-
|
|
1074
|
+
default: {
|
|
1075
|
+
// This should be extremely rare for stashed ops.
|
|
1076
|
+
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
1077
|
+
// e.g. if an app rolled back its container version
|
|
1078
|
+
const compatBehavior = compatDetails?.behavior;
|
|
1079
|
+
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
1080
|
+
const error = telemetry_utils_1.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1081
|
+
messageDetails: JSON.stringify({
|
|
1082
|
+
type,
|
|
1083
|
+
compatBehavior,
|
|
1084
|
+
}),
|
|
1085
|
+
});
|
|
1086
|
+
this.closeFn(error);
|
|
1087
|
+
throw error;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1074
1090
|
}
|
|
1075
1091
|
}
|
|
1076
1092
|
setConnectionState(connected, clientId) {
|
|
@@ -1082,28 +1098,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1082
1098
|
// Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
|
|
1083
1099
|
return;
|
|
1084
1100
|
}
|
|
1085
|
-
// If attachment blobs were added while disconnected, we need to delay
|
|
1086
|
-
// propagation of the "connected" event until we have uploaded them to
|
|
1087
|
-
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1088
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1089
|
-
const connecting = connected && !this._connected && !this.innerDeltaManager.readOnlyInfo.readonly;
|
|
1090
|
-
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
1091
|
-
(0, common_utils_1.assert)(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
|
|
1092
|
-
(0, common_utils_1.assert)(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
1093
|
-
this.delayConnectClientId = clientId;
|
|
1094
|
-
this.blobManager.onConnected().then(() => {
|
|
1095
|
-
// make sure we didn't reconnect before the promise resolved
|
|
1096
|
-
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
1097
|
-
this.delayConnectClientId = undefined;
|
|
1098
|
-
this.setConnectionStateCore(connected, clientId);
|
|
1099
|
-
}
|
|
1100
|
-
}, (error) => this.closeFn(error));
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
1101
|
this.setConnectionStateCore(connected, clientId);
|
|
1104
1102
|
}
|
|
1105
1103
|
setConnectionStateCore(connected, clientId) {
|
|
1106
|
-
(0,
|
|
1104
|
+
(0, core_utils_1.assert)(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
|
|
1107
1105
|
this.verifyNotClosed();
|
|
1108
1106
|
// There might be no change of state due to Container calling this API after loading runtime.
|
|
1109
1107
|
const changeOfState = this._connected !== connected;
|
|
@@ -1121,16 +1119,16 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1121
1119
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
1122
1120
|
}
|
|
1123
1121
|
else {
|
|
1124
|
-
(0,
|
|
1122
|
+
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x3cd /* Connection is possible only if container exists in storage */);
|
|
1125
1123
|
}
|
|
1126
1124
|
// Fail while disconnected
|
|
1127
1125
|
if (reconnection) {
|
|
1128
1126
|
this.consecutiveReconnects++;
|
|
1129
1127
|
if (!this.shouldContinueReconnecting()) {
|
|
1130
|
-
this.closeFn(
|
|
1128
|
+
this.closeFn(telemetry_utils_1.DataProcessingError.create("Runtime detected too many reconnects with no progress syncing local ops.", "setConnectionState", undefined, {
|
|
1131
1129
|
dataLoss: 1,
|
|
1132
1130
|
attempts: this.consecutiveReconnects,
|
|
1133
|
-
pendingMessages: this.
|
|
1131
|
+
pendingMessages: this.pendingMessagesCount,
|
|
1134
1132
|
}));
|
|
1135
1133
|
return;
|
|
1136
1134
|
}
|
|
@@ -1147,23 +1145,23 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1147
1145
|
}
|
|
1148
1146
|
process(messageArg, local) {
|
|
1149
1147
|
this.verifyNotClosed();
|
|
1150
|
-
// Whether or not the message
|
|
1148
|
+
// Whether or not the message appears to be a runtime message from an up-to-date client.
|
|
1151
1149
|
// It may be a legacy runtime message (ie already unpacked and ContainerMessageType)
|
|
1152
1150
|
// or something different, like a system message.
|
|
1153
|
-
const
|
|
1151
|
+
const modernRuntimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
|
|
1154
1152
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
1155
1153
|
const messageCopy = { ...messageArg };
|
|
1156
1154
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1157
|
-
this.processCore(message, local,
|
|
1155
|
+
this.processCore(message, local, modernRuntimeMessage);
|
|
1158
1156
|
}
|
|
1159
1157
|
}
|
|
1160
1158
|
/**
|
|
1161
1159
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
1162
1160
|
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
1163
1161
|
* @param local - Did this client send the op?
|
|
1164
|
-
* @param
|
|
1162
|
+
* @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
|
|
1165
1163
|
*/
|
|
1166
|
-
processCore(message, local,
|
|
1164
|
+
processCore(message, local, modernRuntimeMessage) {
|
|
1167
1165
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1168
1166
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1169
1167
|
// messages once a batch has been fully processed.
|
|
@@ -1171,7 +1169,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1171
1169
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1172
1170
|
try {
|
|
1173
1171
|
let localOpMetadata;
|
|
1174
|
-
if (local &&
|
|
1172
|
+
if (local && modernRuntimeMessage && message.type !== ContainerMessageType.ChunkedOp) {
|
|
1175
1173
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(message);
|
|
1176
1174
|
}
|
|
1177
1175
|
// If there are no more pending messages after processing a local message,
|
|
@@ -1179,43 +1177,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1179
1177
|
if (!this.hasPendingMessages()) {
|
|
1180
1178
|
this.updateDocumentDirtyState(false);
|
|
1181
1179
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
case ContainerMessageType.Attach:
|
|
1185
|
-
this.dataStores.processAttachMessage(message, local);
|
|
1186
|
-
break;
|
|
1187
|
-
case ContainerMessageType.Alias:
|
|
1188
|
-
this.processAliasMessage(message, localOpMetadata, local);
|
|
1189
|
-
break;
|
|
1190
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
1191
|
-
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1192
|
-
break;
|
|
1193
|
-
case ContainerMessageType.BlobAttach:
|
|
1194
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
1195
|
-
break;
|
|
1196
|
-
case ContainerMessageType.IdAllocation:
|
|
1197
|
-
(0, common_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1198
|
-
this.idCompressor.finalizeCreationRange(message.contents);
|
|
1199
|
-
break;
|
|
1200
|
-
case ContainerMessageType.ChunkedOp:
|
|
1201
|
-
case ContainerMessageType.Rejoin:
|
|
1202
|
-
break;
|
|
1203
|
-
default:
|
|
1204
|
-
if (runtimeMessage) {
|
|
1205
|
-
const error = container_utils_1.DataProcessingError.create(
|
|
1206
|
-
// Former assert 0x3ce
|
|
1207
|
-
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1208
|
-
local,
|
|
1209
|
-
type: message.type,
|
|
1210
|
-
contentType: typeof message.contents,
|
|
1211
|
-
batch: message.metadata?.batch,
|
|
1212
|
-
compression: message.compression,
|
|
1213
|
-
});
|
|
1214
|
-
this.closeFn(error);
|
|
1215
|
-
throw error;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
this.emit("op", message, runtimeMessage);
|
|
1180
|
+
this.validateAndProcessRuntimeMessage(message, localOpMetadata, local, modernRuntimeMessage);
|
|
1181
|
+
this.emit("op", message, modernRuntimeMessage);
|
|
1219
1182
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
1220
1183
|
if (local) {
|
|
1221
1184
|
// If we have processed a local op, this means that the container is
|
|
@@ -1229,8 +1192,59 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1229
1192
|
throw e;
|
|
1230
1193
|
}
|
|
1231
1194
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
1195
|
+
/**
|
|
1196
|
+
* Assuming the given message is also a ContainerRuntimeMessage,
|
|
1197
|
+
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
1198
|
+
* Throws a DataProcessingError if the message doesn't conform to the ContainerRuntimeMessage type.
|
|
1199
|
+
*/
|
|
1200
|
+
validateAndProcessRuntimeMessage(message, localOpMetadata, local, expectRuntimeMessageType) {
|
|
1201
|
+
// Optimistically extract ContainerRuntimeMessage-specific props from the message
|
|
1202
|
+
const { type: maybeContainerMessageType, compatDetails } = message;
|
|
1203
|
+
switch (maybeContainerMessageType) {
|
|
1204
|
+
case ContainerMessageType.Attach:
|
|
1205
|
+
this.dataStores.processAttachMessage(message, local);
|
|
1206
|
+
break;
|
|
1207
|
+
case ContainerMessageType.Alias:
|
|
1208
|
+
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
1209
|
+
break;
|
|
1210
|
+
case ContainerMessageType.FluidDataStoreOp:
|
|
1211
|
+
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1212
|
+
break;
|
|
1213
|
+
case ContainerMessageType.BlobAttach:
|
|
1214
|
+
this.blobManager.processBlobAttachOp(message, local);
|
|
1215
|
+
break;
|
|
1216
|
+
case ContainerMessageType.IdAllocation:
|
|
1217
|
+
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1218
|
+
this.idCompressor.finalizeCreationRange(message.contents);
|
|
1219
|
+
break;
|
|
1220
|
+
case ContainerMessageType.ChunkedOp:
|
|
1221
|
+
case ContainerMessageType.Rejoin:
|
|
1222
|
+
break;
|
|
1223
|
+
default: {
|
|
1224
|
+
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
1225
|
+
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
1226
|
+
if (!expectRuntimeMessageType) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const compatBehavior = compatDetails?.behavior;
|
|
1230
|
+
if (!compatBehaviorAllowsMessageType(maybeContainerMessageType, compatBehavior)) {
|
|
1231
|
+
const error = telemetry_utils_1.DataProcessingError.create(
|
|
1232
|
+
// Former assert 0x3ce
|
|
1233
|
+
"Runtime message of unknown type", "OpProcessing", message, {
|
|
1234
|
+
local,
|
|
1235
|
+
messageDetails: JSON.stringify({
|
|
1236
|
+
type: message.type,
|
|
1237
|
+
contentType: typeof message.contents,
|
|
1238
|
+
compatBehavior,
|
|
1239
|
+
batch: message.metadata?.batch,
|
|
1240
|
+
compression: message.compression,
|
|
1241
|
+
}),
|
|
1242
|
+
});
|
|
1243
|
+
this.closeFn(error);
|
|
1244
|
+
throw error;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1234
1248
|
}
|
|
1235
1249
|
/**
|
|
1236
1250
|
* Emits the Signal event and update the perf signal data.
|
|
@@ -1298,7 +1312,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1298
1312
|
await this.dataStores.waitIfPendingAlias(id);
|
|
1299
1313
|
const internalId = this.internalId(id);
|
|
1300
1314
|
const context = await this.dataStores.getDataStore(internalId, { wait });
|
|
1301
|
-
(0,
|
|
1315
|
+
(0, core_utils_1.assert)(await context.isRoot(), 0x12b /* "did not get root data store" */);
|
|
1302
1316
|
return context.realize();
|
|
1303
1317
|
}
|
|
1304
1318
|
/**
|
|
@@ -1306,9 +1320,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1306
1320
|
* This method is expected to be called at the end of a batch.
|
|
1307
1321
|
*/
|
|
1308
1322
|
flush() {
|
|
1309
|
-
(0,
|
|
1323
|
+
(0, core_utils_1.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
|
|
1310
1324
|
this.outbox.flush();
|
|
1311
|
-
(0,
|
|
1325
|
+
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
1312
1326
|
}
|
|
1313
1327
|
orderSequentially(callback) {
|
|
1314
1328
|
let checkpoint;
|
|
@@ -1331,7 +1345,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1331
1345
|
}
|
|
1332
1346
|
catch (err) {
|
|
1333
1347
|
const error2 = (0, telemetry_utils_1.wrapError)(err, (message) => {
|
|
1334
|
-
return
|
|
1348
|
+
return telemetry_utils_1.DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
|
|
1335
1349
|
});
|
|
1336
1350
|
this.closeFn(error2);
|
|
1337
1351
|
throw error2;
|
|
@@ -1339,7 +1353,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1339
1353
|
}
|
|
1340
1354
|
else {
|
|
1341
1355
|
// pre-0.58 error message: orderSequentiallyCallbackException
|
|
1342
|
-
this.closeFn(new
|
|
1356
|
+
this.closeFn(new telemetry_utils_1.GenericError("orderSequentially callback exception", error));
|
|
1343
1357
|
}
|
|
1344
1358
|
throw error; // throw the original error for the consumer of the runtime
|
|
1345
1359
|
}
|
|
@@ -1368,13 +1382,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1368
1382
|
}
|
|
1369
1383
|
const channel = await context.realize();
|
|
1370
1384
|
if (channel.entryPoint === undefined) {
|
|
1371
|
-
throw new
|
|
1385
|
+
throw new telemetry_utils_1.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
|
|
1372
1386
|
}
|
|
1373
1387
|
return channel.entryPoint;
|
|
1374
1388
|
}
|
|
1375
1389
|
createDetachedRootDataStore(pkg, rootDataStoreId) {
|
|
1376
1390
|
if (rootDataStoreId.includes("/")) {
|
|
1377
|
-
throw new
|
|
1391
|
+
throw new telemetry_utils_1.UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
1378
1392
|
}
|
|
1379
1393
|
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
1380
1394
|
}
|
|
@@ -1468,10 +1482,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1468
1482
|
}
|
|
1469
1483
|
setAttachState(attachState) {
|
|
1470
1484
|
if (attachState === container_definitions_1.AttachState.Attaching) {
|
|
1471
|
-
(0,
|
|
1485
|
+
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attaching, 0x12d /* "Container Context should already be in attaching state" */);
|
|
1472
1486
|
}
|
|
1473
1487
|
else {
|
|
1474
|
-
(0,
|
|
1488
|
+
(0, core_utils_1.assert)(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
|
|
1475
1489
|
this.emit("attached");
|
|
1476
1490
|
}
|
|
1477
1491
|
if (attachState === container_definitions_1.AttachState.Attached && !this.hasPendingMessages()) {
|
|
@@ -1529,7 +1543,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1529
1543
|
await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC }, telemetryContext);
|
|
1530
1544
|
}
|
|
1531
1545
|
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState, telemetryContext);
|
|
1532
|
-
(0,
|
|
1546
|
+
(0, core_utils_1.assert)(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1533
1547
|
return { stats, summary };
|
|
1534
1548
|
}
|
|
1535
1549
|
finally {
|
|
@@ -1641,7 +1655,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1641
1655
|
case gc_1.GCNodeType.SubDataStore:
|
|
1642
1656
|
return this.dataStores.getDataStorePackagePath(nodePath);
|
|
1643
1657
|
default:
|
|
1644
|
-
(0,
|
|
1658
|
+
(0, core_utils_1.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
1645
1659
|
}
|
|
1646
1660
|
}
|
|
1647
1661
|
/**
|
|
@@ -1698,7 +1712,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1698
1712
|
* @param options - options controlling how the summary is generated or submitted
|
|
1699
1713
|
*/
|
|
1700
1714
|
async submitSummary(options) {
|
|
1701
|
-
const { fullTree = false, refreshLatestAck, summaryLogger } = options;
|
|
1715
|
+
const { fullTree = false, finalAttempt = false, refreshLatestAck, summaryLogger } = options;
|
|
1702
1716
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1703
1717
|
// use it for all events logged during this summary.
|
|
1704
1718
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -1708,7 +1722,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1708
1722
|
all: { summaryNumber },
|
|
1709
1723
|
},
|
|
1710
1724
|
});
|
|
1711
|
-
(0,
|
|
1725
|
+
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
1712
1726
|
let latestSnapshotVersionId;
|
|
1713
1727
|
if (refreshLatestAck) {
|
|
1714
1728
|
const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer((0, telemetry_utils_1.createChildLogger)({
|
|
@@ -1720,6 +1734,40 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1720
1734
|
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
1721
1735
|
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
1722
1736
|
}
|
|
1737
|
+
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
1738
|
+
// incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
|
|
1739
|
+
// within the timeout, check if it should be failed or can continue.
|
|
1740
|
+
if (this.validateSummaryBeforeUpload && this.hasPendingMessages()) {
|
|
1741
|
+
const countBefore = this.pendingMessagesCount;
|
|
1742
|
+
// The timeout for waiting for pending ops can be overridden via configurations.
|
|
1743
|
+
const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
|
|
1744
|
+
exports.defaultPendingOpsWaitTimeoutMs;
|
|
1745
|
+
await new Promise((resolve, reject) => {
|
|
1746
|
+
const timeoutId = setTimeout(() => resolve(), pendingOpsTimeout);
|
|
1747
|
+
this.once("saved", () => {
|
|
1748
|
+
clearTimeout(timeoutId);
|
|
1749
|
+
resolve();
|
|
1750
|
+
});
|
|
1751
|
+
this.once("dispose", () => {
|
|
1752
|
+
clearTimeout(timeoutId);
|
|
1753
|
+
reject(new Error("Runtime is disposed while summarizing"));
|
|
1754
|
+
});
|
|
1755
|
+
});
|
|
1756
|
+
// Log that there are pending ops while summarizing. This will help us gather data on how often this
|
|
1757
|
+
// happens, whether we attempted to wait for these ops to be acked and what was the result.
|
|
1758
|
+
summaryNumberLogger.sendTelemetryEvent({
|
|
1759
|
+
eventName: "PendingOpsWhileSummarizing",
|
|
1760
|
+
saved: this.hasPendingMessages() ? false : true,
|
|
1761
|
+
timeout: pendingOpsTimeout,
|
|
1762
|
+
countBefore,
|
|
1763
|
+
countAfter: this.pendingMessagesCount,
|
|
1764
|
+
});
|
|
1765
|
+
// There could still be pending ops. Check if summary should fail or continue.
|
|
1766
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, this.deltaManager.lastSequenceNumber, this.deltaManager.minimumSequenceNumber, finalAttempt, true /* beforeSummaryGeneration */);
|
|
1767
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
1768
|
+
return pendingMessagesFailResult;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1723
1771
|
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
1724
1772
|
let summaryRefSeqNum;
|
|
1725
1773
|
try {
|
|
@@ -1746,7 +1794,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1746
1794
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
1747
1795
|
// So if we fail here, it either means that RunWhileConnectedCoordinator does not work correctly,
|
|
1748
1796
|
// OR that design changed and we need to remove this check and fix submitSystemMessage.
|
|
1749
|
-
(0,
|
|
1797
|
+
(0, core_utils_1.assert)(this.connected, 0x258 /* "connected" */);
|
|
1750
1798
|
// Ensure that lastSequenceNumber has not changed after pausing.
|
|
1751
1799
|
// We need the summary op's reference sequence number to match our summary sequence number,
|
|
1752
1800
|
// otherwise we'll get the wrong sequence number stamped on the summary's .protocol attributes.
|
|
@@ -1756,7 +1804,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1756
1804
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
1757
1805
|
};
|
|
1758
1806
|
}
|
|
1759
|
-
(0,
|
|
1807
|
+
(0, core_utils_1.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
|
|
1760
1808
|
if (lastAck !== this.summaryCollection.latestAck) {
|
|
1761
1809
|
return {
|
|
1762
1810
|
continue: false,
|
|
@@ -1774,7 +1822,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1774
1822
|
error: continueResult.error,
|
|
1775
1823
|
};
|
|
1776
1824
|
}
|
|
1777
|
-
const trace =
|
|
1825
|
+
const trace = client_utils_1.Trace.start();
|
|
1778
1826
|
let summarizeResult;
|
|
1779
1827
|
// If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
|
|
1780
1828
|
// state of all the nodes.
|
|
@@ -1795,9 +1843,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1795
1843
|
error,
|
|
1796
1844
|
};
|
|
1797
1845
|
}
|
|
1798
|
-
// If validateSummaryBeforeUpload is true, validate that the summary generated
|
|
1799
|
-
// correct before this summary is uploaded.
|
|
1846
|
+
// If validateSummaryBeforeUpload is true, validate that the summary generated is correct before uploading.
|
|
1800
1847
|
if (this.validateSummaryBeforeUpload) {
|
|
1848
|
+
// Validate that the summaries generated by summarize nodes is correct.
|
|
1801
1849
|
const validateResult = this.summarizerNode.validateSummary();
|
|
1802
1850
|
if (!validateResult.success) {
|
|
1803
1851
|
const { success, ...loggingProps } = validateResult;
|
|
@@ -1809,6 +1857,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1809
1857
|
error,
|
|
1810
1858
|
};
|
|
1811
1859
|
}
|
|
1860
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
|
|
1861
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
1862
|
+
return pendingMessagesFailResult;
|
|
1863
|
+
}
|
|
1812
1864
|
}
|
|
1813
1865
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
1814
1866
|
// Now that we have generated the summary, update the message at last summary to the last message processed.
|
|
@@ -1817,7 +1869,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1817
1869
|
// Because handles are unchanged dataStores in the current logic,
|
|
1818
1870
|
// summarized dataStore count is total dataStore count minus handle count
|
|
1819
1871
|
const dataStoreTree = summaryTree.tree[runtime_definitions_1.channelsTreeName];
|
|
1820
|
-
(0,
|
|
1872
|
+
(0, core_utils_1.assert)(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
1821
1873
|
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
|
|
1822
1874
|
const gcSummaryTreeStats = summaryTree.tree[runtime_definitions_1.gcTreeKey]
|
|
1823
1875
|
? (0, runtime_utils_1.calculateStats)(summaryTree.tree[runtime_definitions_1.gcTreeKey])
|
|
@@ -1929,16 +1981,63 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1929
1981
|
}
|
|
1930
1982
|
}
|
|
1931
1983
|
}
|
|
1984
|
+
/**
|
|
1985
|
+
* This helper is called during summarization. If there are pending ops, it will return a failed summarize result
|
|
1986
|
+
* (IBaseSummarizeResult) unless this is the final summarize attempt and SkipFailingIncorrectSummary option is set.
|
|
1987
|
+
* @param logger - The logger to be used for sending telemetry.
|
|
1988
|
+
* @param referenceSequenceNumber - The reference sequence number of the summary attempt.
|
|
1989
|
+
* @param minimumSequenceNumber - The minimum sequence number of the summary attempt.
|
|
1990
|
+
* @param finalAttempt - Whether this is the final summary attempt.
|
|
1991
|
+
* @param beforeSummaryGeneration - Whether this is called before summary generation or after.
|
|
1992
|
+
* @returns failed summarize result (IBaseSummarizeResult) if summary should be failed, undefined otherwise.
|
|
1993
|
+
*/
|
|
1994
|
+
async shouldFailSummaryOnPendingOps(logger, referenceSequenceNumber, minimumSequenceNumber, finalAttempt, beforeSummaryGeneration) {
|
|
1995
|
+
if (!this.hasPendingMessages()) {
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
// If "SkipFailingIncorrectSummary" option is true, don't fail the summary in the last attempt.
|
|
1999
|
+
// This is a fallback to make progress in documents where there are consistently pending ops in
|
|
2000
|
+
// the summarizer.
|
|
2001
|
+
if (finalAttempt &&
|
|
2002
|
+
this.mc.config.getBoolean("Fluid.Summarizer.SkipFailingIncorrectSummary")) {
|
|
2003
|
+
const error = telemetry_utils_1.DataProcessingError.create("Pending ops during summarization", "submitSummary", undefined, { pendingMessages: this.pendingMessagesCount });
|
|
2004
|
+
logger.sendErrorEvent({
|
|
2005
|
+
eventName: "SkipFailingIncorrectSummary",
|
|
2006
|
+
referenceSequenceNumber,
|
|
2007
|
+
minimumSequenceNumber,
|
|
2008
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
2009
|
+
}, error);
|
|
2010
|
+
}
|
|
2011
|
+
else {
|
|
2012
|
+
// The retry delay when there are pending ops can be overridden via config so that we can adjust it
|
|
2013
|
+
// based on telemetry while we decide on a stable number.
|
|
2014
|
+
const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
2015
|
+
exports.defaultPendingOpsRetryDelayMs;
|
|
2016
|
+
const error = new summary_1.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
|
|
2017
|
+
count: this.pendingMessagesCount,
|
|
2018
|
+
beforeGenerate: beforeSummaryGeneration,
|
|
2019
|
+
});
|
|
2020
|
+
return {
|
|
2021
|
+
stage: "base",
|
|
2022
|
+
referenceSequenceNumber,
|
|
2023
|
+
minimumSequenceNumber,
|
|
2024
|
+
error,
|
|
2025
|
+
};
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
get pendingMessagesCount() {
|
|
2029
|
+
return this.pendingStateManager.pendingMessagesCount + this.outbox.messageCount;
|
|
2030
|
+
}
|
|
1932
2031
|
hasPendingMessages() {
|
|
1933
|
-
return this.
|
|
2032
|
+
return this.pendingMessagesCount !== 0;
|
|
1934
2033
|
}
|
|
1935
2034
|
updateDocumentDirtyState(dirty) {
|
|
1936
2035
|
if (this.attachState !== container_definitions_1.AttachState.Attached) {
|
|
1937
|
-
(0,
|
|
2036
|
+
(0, core_utils_1.assert)(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
1938
2037
|
}
|
|
1939
2038
|
else {
|
|
1940
2039
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
1941
|
-
(0,
|
|
2040
|
+
(0, core_utils_1.assert)(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
|
|
1942
2041
|
}
|
|
1943
2042
|
if (this.dirtyContainer === dirty) {
|
|
1944
2043
|
return;
|
|
@@ -1958,7 +2057,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1958
2057
|
submitDataStoreAliasOp(contents, localOpMetadata) {
|
|
1959
2058
|
const aliasMessage = contents;
|
|
1960
2059
|
if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
|
|
1961
|
-
throw new
|
|
2060
|
+
throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
|
|
1962
2061
|
}
|
|
1963
2062
|
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
1964
2063
|
}
|
|
@@ -1971,10 +2070,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1971
2070
|
let idAllocationBatchMessage;
|
|
1972
2071
|
let idRange;
|
|
1973
2072
|
if (this.idCompressorEnabled) {
|
|
1974
|
-
(0,
|
|
2073
|
+
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67d /* IdCompressor should be defined if enabled */);
|
|
1975
2074
|
idRange = this.idCompressor.takeNextCreationRange();
|
|
1976
2075
|
// Don't include the idRange if there weren't any Ids allocated
|
|
1977
|
-
idRange = idRange?.ids
|
|
2076
|
+
idRange = idRange?.ids !== undefined ? idRange : undefined;
|
|
1978
2077
|
}
|
|
1979
2078
|
if (idRange !== undefined) {
|
|
1980
2079
|
const idAllocationMessage = {
|
|
@@ -1998,7 +2097,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1998
2097
|
this.verifyNotClosed();
|
|
1999
2098
|
this.verifyCanSubmitOps();
|
|
2000
2099
|
// There should be no ops in detached container state!
|
|
2001
|
-
(0,
|
|
2100
|
+
(0, core_utils_1.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
2002
2101
|
const serializedContent = JSON.stringify(containerRuntimeMessage);
|
|
2003
2102
|
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
2004
2103
|
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
@@ -2098,15 +2197,15 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2098
2197
|
setTimeout(flush, 0);
|
|
2099
2198
|
break;
|
|
2100
2199
|
default:
|
|
2101
|
-
(0,
|
|
2200
|
+
(0, core_utils_1.assert)(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
2102
2201
|
break;
|
|
2103
2202
|
}
|
|
2104
2203
|
}
|
|
2105
2204
|
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
2106
2205
|
this.verifyNotClosed();
|
|
2107
|
-
(0,
|
|
2206
|
+
(0, core_utils_1.assert)(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
2108
2207
|
// System message should not be sent in the middle of the batch.
|
|
2109
|
-
(0,
|
|
2208
|
+
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
2110
2209
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
2111
2210
|
return this.submitSummaryFn !== undefined
|
|
2112
2211
|
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
@@ -2127,7 +2226,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2127
2226
|
if (this.opReentryCallsToReport > 0) {
|
|
2128
2227
|
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
2129
2228
|
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
2130
|
-
(0, opLifecycle_1.getLongStack)(() => new
|
|
2229
|
+
(0, opLifecycle_1.getLongStack)(() => new telemetry_utils_1.UsageError(errorMessage)));
|
|
2131
2230
|
this.opReentryCallsToReport--;
|
|
2132
2231
|
}
|
|
2133
2232
|
// Creating ops while processing ops can lead
|
|
@@ -2143,7 +2242,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2143
2242
|
// The runtime must enforce op coherence by not allowing ops to be submitted
|
|
2144
2243
|
// while ops are being processed.
|
|
2145
2244
|
if (this.enableOpReentryCheck) {
|
|
2146
|
-
throw new
|
|
2245
|
+
throw new telemetry_utils_1.UsageError(errorMessage);
|
|
2147
2246
|
}
|
|
2148
2247
|
}
|
|
2149
2248
|
}
|
|
@@ -2193,8 +2292,27 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2193
2292
|
case ContainerMessageType.Rejoin:
|
|
2194
2293
|
this.submit(message);
|
|
2195
2294
|
break;
|
|
2196
|
-
default:
|
|
2197
|
-
|
|
2295
|
+
default: {
|
|
2296
|
+
// This case should be very rare - it would imply an op was stashed from a
|
|
2297
|
+
// future version of runtime code and now is being applied on an older version
|
|
2298
|
+
const compatBehavior = message.compatDetails?.behavior;
|
|
2299
|
+
if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
|
|
2300
|
+
this.logger.sendTelemetryEvent({
|
|
2301
|
+
eventName: "resubmitUnrecognizedMessageTypeAllowed",
|
|
2302
|
+
messageDetails: { type: message.type, compatBehavior },
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
else {
|
|
2306
|
+
const error = telemetry_utils_1.DataProcessingError.create("Resubmitting runtime message of unknown type", "reSubmitCore", undefined /* sequencedMessage */, {
|
|
2307
|
+
messageDetails: JSON.stringify({
|
|
2308
|
+
type: message.type,
|
|
2309
|
+
compatBehavior,
|
|
2310
|
+
}),
|
|
2311
|
+
});
|
|
2312
|
+
this.closeFn(error);
|
|
2313
|
+
throw error;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2198
2316
|
}
|
|
2199
2317
|
}
|
|
2200
2318
|
rollback(content, localOpMetadata) {
|
|
@@ -2207,6 +2325,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2207
2325
|
this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
|
|
2208
2326
|
break;
|
|
2209
2327
|
default:
|
|
2328
|
+
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
2210
2329
|
throw new Error(`Can't rollback ${type}`);
|
|
2211
2330
|
}
|
|
2212
2331
|
}
|
|
@@ -2224,29 +2343,22 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2224
2343
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
2225
2344
|
async refreshLatestSummaryAck(options) {
|
|
2226
2345
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2346
|
+
// proposalHandle is always passed from RunningSummarizer.
|
|
2347
|
+
(0, core_utils_1.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
2227
2348
|
const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2349
|
+
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
|
|
2350
|
+
/**
|
|
2351
|
+
* When refreshing a summary ack, this check indicates a new ack of a summary that is newer than the
|
|
2352
|
+
* current summary that is tracked, but this summarizer runtime did not produce/track that summary. Thus
|
|
2353
|
+
* it needs to refresh its state. Today refresh is done by fetching the latest snapshot to update the cache
|
|
2354
|
+
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
2355
|
+
*/
|
|
2356
|
+
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
2357
|
+
const fetchResult = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
2233
2358
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
2234
2359
|
ackHandle,
|
|
2235
2360
|
targetSequenceNumber: summaryRefSeq,
|
|
2236
|
-
}, readAndParseBlob);
|
|
2237
|
-
/**
|
|
2238
|
-
* back-compat - Older loaders and drivers (pre 2.0.0-internal.1.4) don't have fetchSource as a param in the
|
|
2239
|
-
* getVersions API. So, they will not fetch the latest snapshot from network in the previous fetch call. For
|
|
2240
|
-
* these scenarios, fetch the snapshot corresponding to the ack handle to have the same behavior before the
|
|
2241
|
-
* change that started fetching latest snapshot always.
|
|
2242
|
-
*/
|
|
2243
|
-
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
2244
|
-
fetchResult = await this.fetchSnapshotFromStorageAndClose(summaryLogger, {
|
|
2245
|
-
eventName: "RefreshLatestSummaryAckFetchBackCompat",
|
|
2246
|
-
ackHandle,
|
|
2247
|
-
targetSequenceNumber: summaryRefSeq,
|
|
2248
|
-
}, readAndParseBlob, ackHandle);
|
|
2249
|
-
}
|
|
2361
|
+
}, readAndParseBlob, null);
|
|
2250
2362
|
/**
|
|
2251
2363
|
* If the fetched snapshot is older than the one for which the ack was received, close the container.
|
|
2252
2364
|
* This should never happen because an ack should be sent after the latest summary is updated in the server.
|
|
@@ -2258,7 +2370,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2258
2370
|
* state.
|
|
2259
2371
|
*/
|
|
2260
2372
|
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
2261
|
-
const error =
|
|
2373
|
+
const error = telemetry_utils_1.DataProcessingError.create("Fetched snapshot is older than the received ack", "RefreshLatestSummaryAck", undefined /* sequencedMessage */, {
|
|
2262
2374
|
ackHandle,
|
|
2263
2375
|
summaryRefSeq,
|
|
2264
2376
|
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
@@ -2266,17 +2378,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2266
2378
|
this.disposeFn(error);
|
|
2267
2379
|
throw error;
|
|
2268
2380
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
return {
|
|
2273
|
-
snapshotTree: fetchResult.snapshotTree,
|
|
2274
|
-
snapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
2275
|
-
};
|
|
2276
|
-
};
|
|
2277
|
-
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
2381
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryAckFetch");
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2278
2384
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2279
|
-
await this.garbageCollector.refreshLatestSummary(
|
|
2385
|
+
await this.garbageCollector.refreshLatestSummary(result);
|
|
2280
2386
|
}
|
|
2281
2387
|
/**
|
|
2282
2388
|
* Fetches the latest snapshot from storage and uses it to refresh SummarizerNode's
|
|
@@ -2286,30 +2392,38 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2286
2392
|
*/
|
|
2287
2393
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
2288
2394
|
const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
|
|
2289
|
-
const {
|
|
2395
|
+
const { versionId, latestSnapshotRefSeq } = await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
2290
2396
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2291
|
-
}, readAndParseBlob);
|
|
2292
|
-
|
|
2293
|
-
snapshotTree,
|
|
2294
|
-
snapshotRefSeq: latestSnapshotRefSeq,
|
|
2295
|
-
};
|
|
2296
|
-
const result = await this.summarizerNode.refreshLatestSummary(undefined /* proposalHandle */, latestSnapshotRefSeq, async () => fetchLatestSnapshot, readAndParseBlob, summaryLogger);
|
|
2297
|
-
// Notify the garbage collector so it can update its latest summary state.
|
|
2298
|
-
await this.garbageCollector.refreshLatestSummary(undefined /* proposalHandle */, result, readAndParseBlob);
|
|
2397
|
+
}, readAndParseBlob, null);
|
|
2398
|
+
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
2299
2399
|
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
2300
2400
|
}
|
|
2301
|
-
async
|
|
2302
|
-
|
|
2401
|
+
async closeStaleSummarizer(codePath) {
|
|
2402
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2403
|
+
eventName: "ClosingSummarizerOnSummaryStale",
|
|
2404
|
+
codePath,
|
|
2405
|
+
message: "Stopping fetch from storage",
|
|
2406
|
+
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
2407
|
+
}, new telemetry_utils_1.GenericError("Restarting summarizer instead of refreshing"));
|
|
2408
|
+
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2409
|
+
await (0, core_utils_1.delay)(this.closeSummarizerDelayMs);
|
|
2410
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
2411
|
+
this.disposeFn();
|
|
2303
2412
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2413
|
+
/**
|
|
2414
|
+
* Downloads snapshot from storage with the given versionId or latest if versionId is null.
|
|
2415
|
+
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
2416
|
+
* overridden via options.
|
|
2417
|
+
*/
|
|
2418
|
+
async fetchSnapshotFromStorage(logger, event, readAndParseBlob, versionId) {
|
|
2419
|
+
return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2306
2420
|
const stats = {};
|
|
2307
|
-
const trace =
|
|
2421
|
+
const trace = client_utils_1.Trace.start();
|
|
2308
2422
|
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
|
|
2309
|
-
(0,
|
|
2423
|
+
(0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
2310
2424
|
stats.getVersionDuration = trace.trace().duration;
|
|
2311
2425
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
2312
|
-
(0,
|
|
2426
|
+
(0, core_utils_1.assert)(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
2313
2427
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
2314
2428
|
const latestSnapshotRefSeq = await (0, runtime_utils_1.seqFromTree)(maybeSnapshot, readAndParseBlob);
|
|
2315
2429
|
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
@@ -2321,41 +2435,65 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2321
2435
|
latestSnapshotRefSeq,
|
|
2322
2436
|
};
|
|
2323
2437
|
});
|
|
2324
|
-
// We choose to close the summarizer after the snapshot cache is updated to avoid
|
|
2325
|
-
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
2326
|
-
// loads the summarizer from cache.
|
|
2327
|
-
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
2328
|
-
this.mc.logger.sendTelemetryEvent({
|
|
2329
|
-
...event,
|
|
2330
|
-
eventName: "ClosingSummarizerOnSummaryStale",
|
|
2331
|
-
codePath: event.eventName,
|
|
2332
|
-
message: "Stopping fetch from storage",
|
|
2333
|
-
versionId: versionId != null ? versionId : undefined,
|
|
2334
|
-
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
2335
|
-
}, new container_utils_1.GenericError("Restarting summarizer instead of refreshing"));
|
|
2336
|
-
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2337
|
-
await (0, common_utils_1.delay)(this.closeSummarizerDelayMs);
|
|
2338
|
-
this._summarizer?.stop("latestSummaryStateStale");
|
|
2339
|
-
this.disposeFn();
|
|
2340
|
-
}
|
|
2341
|
-
return snapshotResults;
|
|
2342
2438
|
}
|
|
2343
2439
|
notifyAttaching() { } // do nothing (deprecated method)
|
|
2344
2440
|
async getPendingLocalState(props) {
|
|
2345
|
-
this.
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2441
|
+
return telemetry_utils_1.PerformanceEvent.timedExecAsync(this.mc.logger, {
|
|
2442
|
+
eventName: "getPendingLocalState",
|
|
2443
|
+
notifyImminentClosure: props?.notifyImminentClosure,
|
|
2444
|
+
}, async (event) => {
|
|
2445
|
+
this.verifyNotClosed();
|
|
2446
|
+
const waitBlobsToAttach = props?.notifyImminentClosure;
|
|
2447
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
2448
|
+
throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
|
|
2449
|
+
}
|
|
2450
|
+
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
|
|
2451
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
2452
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
2453
|
+
return; // no pending state to save
|
|
2454
|
+
}
|
|
2455
|
+
// Flush pending batch.
|
|
2456
|
+
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2457
|
+
// to close current batch.
|
|
2458
|
+
this.flush();
|
|
2459
|
+
const pendingState = {
|
|
2460
|
+
pending,
|
|
2461
|
+
pendingAttachmentBlobs,
|
|
2462
|
+
};
|
|
2463
|
+
event.end({
|
|
2464
|
+
attachmentBlobsSize: Object.keys(pendingAttachmentBlobs ?? {}).length,
|
|
2465
|
+
pendingOpsSize: pending?.pendingStates.length,
|
|
2466
|
+
});
|
|
2467
|
+
return pendingState;
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
summarizeOnDemand(options) {
|
|
2471
|
+
if (this.isSummarizerClient) {
|
|
2472
|
+
return this.summarizer.summarizeOnDemand(options);
|
|
2473
|
+
}
|
|
2474
|
+
else if (this.summaryManager !== undefined) {
|
|
2475
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
2476
|
+
}
|
|
2477
|
+
else {
|
|
2478
|
+
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2479
|
+
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
2480
|
+
// because it is a misuse of the API rather than an expected failure.
|
|
2481
|
+
throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
enqueueSummarize(options) {
|
|
2485
|
+
if (this.isSummarizerClient) {
|
|
2486
|
+
return this.summarizer.enqueueSummarize(options);
|
|
2487
|
+
}
|
|
2488
|
+
else if (this.summaryManager !== undefined) {
|
|
2489
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
2490
|
+
}
|
|
2491
|
+
else {
|
|
2492
|
+
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2493
|
+
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
2494
|
+
// because it is a misuse of the API rather than an expected failure.
|
|
2495
|
+
throw new telemetry_utils_1.UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
2496
|
+
}
|
|
2359
2497
|
}
|
|
2360
2498
|
/**
|
|
2361
2499
|
* * Forms a function that will request a Summarizer.
|
|
@@ -2378,7 +2516,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2378
2516
|
const fluidObject = await (0, runtime_utils_1.requestFluidObject)(loaderRouter, request);
|
|
2379
2517
|
const summarizer = fluidObject.ISummarizer;
|
|
2380
2518
|
if (!summarizer) {
|
|
2381
|
-
throw new
|
|
2519
|
+
throw new telemetry_utils_1.UsageError("Fluid object does not implement ISummarizer");
|
|
2382
2520
|
}
|
|
2383
2521
|
return summarizer;
|
|
2384
2522
|
};
|
|
@@ -2387,11 +2525,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
2387
2525
|
// eslint-disable-next-line no-restricted-syntax
|
|
2388
2526
|
for (const prop in configuration) {
|
|
2389
2527
|
if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
|
|
2390
|
-
throw new
|
|
2528
|
+
throw new telemetry_utils_1.UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
|
|
2391
2529
|
}
|
|
2392
2530
|
}
|
|
2393
2531
|
if (configuration.minIdleTime > configuration.maxIdleTime) {
|
|
2394
|
-
throw new
|
|
2532
|
+
throw new telemetry_utils_1.UsageError(`"minIdleTime" [${configuration.minIdleTime}] cannot be greater than "maxIdleTime" [${configuration.maxIdleTime}]`);
|
|
2395
2533
|
}
|
|
2396
2534
|
}
|
|
2397
2535
|
get groupedBatchingEnabled() {
|