@fluidframework/container-runtime 2.20.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +36 -6
- package/.mocharc.cjs +3 -0
- package/CHANGELOG.md +42 -0
- package/README.md +1 -0
- package/api-report/container-runtime.legacy.alpha.api.md +31 -31
- package/dist/batchTracker.d.ts +1 -2
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager/blobManager.d.ts +0 -3
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +25 -19
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.d.ts +1 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.js +7 -5
- package/dist/blobManager/blobManagerSnapSum.js.map +1 -1
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +63 -41
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts +2 -2
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +4 -4
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +14 -30
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +265 -196
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +6 -3
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +16 -11
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +1 -0
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +5 -5
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +36 -14
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +2 -0
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +8 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +1 -0
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +8 -5
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +2 -1
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +29 -15
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/inboundBatchAggregator.js +3 -3
- package/dist/inboundBatchAggregator.js.map +1 -1
- package/dist/layerCompatState.d.ts +19 -0
- package/dist/layerCompatState.d.ts.map +1 -0
- package/dist/layerCompatState.js +64 -0
- package/dist/layerCompatState.js.map +1 -0
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.js +2 -2
- package/dist/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +3 -2
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +13 -19
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +3 -0
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +4 -1
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +5 -3
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +13 -10
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +14 -11
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +3 -3
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +11 -15
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +3 -1
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +3 -4
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +11 -10
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +7 -0
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +6 -4
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +1 -0
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +13 -11
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts +1 -0
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +7 -2
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +2 -2
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +38 -17
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +1 -0
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +18 -9
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js +1 -0
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/index.d.ts.map +1 -1
- package/dist/summary/summarizerNode/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +30 -31
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +7 -0
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +3 -4
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +9 -6
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +4 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +3 -2
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +19 -8
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +12 -9
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -2
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -2
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts +0 -3
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +26 -20
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.d.ts +1 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.js +7 -5
- package/lib/blobManager/blobManagerSnapSum.js.map +1 -1
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +66 -42
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +2 -2
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +5 -5
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +14 -30
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +272 -198
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +6 -3
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +16 -11
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +1 -0
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +6 -6
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +39 -15
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +2 -0
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +8 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +1 -0
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +8 -5
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +2 -1
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +32 -16
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/inboundBatchAggregator.js +4 -4
- package/lib/inboundBatchAggregator.js.map +1 -1
- package/lib/layerCompatState.d.ts +19 -0
- package/lib/layerCompatState.d.ts.map +1 -0
- package/lib/layerCompatState.js +60 -0
- package/lib/layerCompatState.js.map +1 -0
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.js +2 -2
- package/lib/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +3 -2
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +13 -19
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +3 -0
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +4 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +5 -3
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +13 -10
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +14 -11
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +3 -3
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +11 -15
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +3 -1
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +3 -4
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +12 -11
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +7 -0
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +6 -4
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +1 -0
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +13 -11
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts +1 -0
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +7 -2
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +2 -2
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +38 -17
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +1 -0
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +18 -9
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js +1 -0
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/index.d.ts.map +1 -1
- package/lib/summary/summarizerNode/index.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +30 -31
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +7 -0
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +3 -4
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +9 -6
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +4 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +2 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +19 -8
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +12 -9
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +24 -46
- package/src/batchTracker.ts +3 -3
- package/src/blobManager/blobManager.ts +27 -28
- package/src/blobManager/blobManagerSnapSum.ts +8 -8
- package/src/channelCollection.ts +63 -44
- package/src/connectionTelemetry.ts +12 -6
- package/src/containerRuntime.ts +306 -236
- package/src/dataStore.ts +6 -3
- package/src/dataStoreContext.ts +16 -16
- package/src/dataStoreContexts.ts +1 -0
- package/src/deltaScheduler.ts +6 -6
- package/src/gc/garbageCollection.ts +47 -20
- package/src/gc/gcConfigs.ts +9 -1
- package/src/gc/gcDefinitions.ts +12 -0
- package/src/gc/gcHelpers.ts +9 -4
- package/src/gc/gcSummaryStateTracker.ts +3 -1
- package/src/gc/gcTelemetry.ts +26 -11
- package/src/inboundBatchAggregator.ts +4 -4
- package/src/layerCompatState.ts +75 -0
- package/src/messageTypes.ts +2 -0
- package/src/opLifecycle/README.md +43 -34
- package/src/opLifecycle/duplicateBatchDetector.ts +2 -2
- package/src/opLifecycle/opCompressor.ts +16 -23
- package/src/opLifecycle/opDecompressor.ts +4 -1
- package/src/opLifecycle/opGroupingManager.ts +5 -4
- package/src/opLifecycle/opSplitter.ts +14 -11
- package/src/opLifecycle/outbox.ts +13 -20
- package/src/opLifecycle/remoteMessageProcessor.ts +3 -1
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +15 -10
- package/src/summary/documentSchema.ts +11 -4
- package/src/summary/orderedClientElection.ts +14 -11
- package/src/summary/runWhileConnectedCoordinator.ts +6 -0
- package/src/summary/runningSummarizer.ts +43 -19
- package/src/summary/summarizer.ts +24 -11
- package/src/summary/summarizerClientElection.ts +2 -0
- package/src/summary/summarizerHeuristics.ts +1 -1
- package/src/summary/summarizerNode/index.ts +1 -0
- package/src/summary/summarizerNode/summarizerNode.ts +32 -31
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +4 -4
- package/src/summary/summarizerTypes.ts +7 -0
- package/src/summary/summaryCollection.ts +19 -8
- package/src/summary/summaryFormat.ts +10 -5
- package/src/summary/summaryGenerator.ts +25 -10
- package/src/summary/summaryManager.ts +14 -12
- package/container-runtime.test-files.tar +0 -0
package/lib/containerRuntime.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { Trace, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
5
|
+
import { Trace, TypedEventEmitter, } from "@fluid-internal/client-utils";
|
|
6
6
|
import { AttachState, } from "@fluidframework/container-definitions";
|
|
7
7
|
import { LoaderHeader, isIDeltaManagerFull, } from "@fluidframework/container-definitions/internal";
|
|
8
8
|
import { assert, Deferred, LazyPromise, PromiseCache, delay, } from "@fluidframework/core-utils/internal";
|
|
@@ -24,13 +24,20 @@ import { channelToDataStore } from "./dataStore.js";
|
|
|
24
24
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
25
25
|
import { DeltaManagerPendingOpsProxy, DeltaManagerSummarizerProxy, } from "./deltaManagerProxies.js";
|
|
26
26
|
import { DeltaScheduler } from "./deltaScheduler.js";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
// eslint-disable-next-line import/no-deprecated
|
|
29
|
+
GCNodeType, GarbageCollector, gcGenerationOptionName, } from "./gc/index.js";
|
|
28
30
|
import { InboundBatchAggregator } from "./inboundBatchAggregator.js";
|
|
31
|
+
import { RuntimeCompatDetails, validateLoaderCompatibility } from "./layerCompatState.js";
|
|
29
32
|
import { ContainerMessageType, } from "./messageTypes.js";
|
|
30
33
|
import { DuplicateBatchDetector, ensureContentsDeserialized, OpCompressor, OpDecompressor, OpGroupingManager, OpSplitter, Outbox, RemoteMessageProcessor, serializeOpContents, } from "./opLifecycle/index.js";
|
|
31
34
|
import { pkgVersion } from "./packageVersion.js";
|
|
32
35
|
import { PendingStateManager, } from "./pendingStateManager.js";
|
|
33
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
// eslint-disable-next-line import/no-deprecated
|
|
38
|
+
DocumentsSchemaController, OrderedClientCollection, OrderedClientElection, RetriableSummaryError, RunWhileConnectedCoordinator,
|
|
39
|
+
// eslint-disable-next-line import/no-deprecated
|
|
40
|
+
Summarizer, SummarizerClientElection, SummaryCollection, SummaryManager, aliasBlobName, chunksBlobName, recentBatchInfoBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, idCompressorBlobName, metadataBlobName, rootHasIsolatedChannels, summarizerClientType, wrapSummaryInChannelsTree, } from "./summary/index.js";
|
|
34
41
|
import { Throttler, formExponentialFn } from "./throttler.js";
|
|
35
42
|
/**
|
|
36
43
|
* Creates an error object to be thrown / passed to Container's close fn in case of an unknown message type.
|
|
@@ -51,6 +58,9 @@ function getUnknownMessageTypeError(unknownContainerRuntimeMessageType, codePath
|
|
|
51
58
|
},
|
|
52
59
|
});
|
|
53
60
|
}
|
|
61
|
+
export function isSummariesDisabled(config) {
|
|
62
|
+
return config.state === "disabled";
|
|
63
|
+
}
|
|
54
64
|
/**
|
|
55
65
|
* @legacy
|
|
56
66
|
* @alpha
|
|
@@ -66,13 +76,14 @@ export const DefaultSummaryConfiguration = {
|
|
|
66
76
|
maxOpsSinceLastSummary: 7000,
|
|
67
77
|
initialSummarizerDelayMs: 5 * 1000, // 5 secs.
|
|
68
78
|
nonRuntimeOpWeight: 0.1,
|
|
69
|
-
runtimeOpWeight: 1
|
|
79
|
+
runtimeOpWeight: 1,
|
|
70
80
|
nonRuntimeHeuristicThreshold: 20,
|
|
71
81
|
};
|
|
72
82
|
/**
|
|
73
83
|
* Error responses when requesting a deleted object will have this header set to true
|
|
74
84
|
* @legacy
|
|
75
85
|
* @alpha
|
|
86
|
+
* @deprecated This type will be moved to internal in 2.30. External usage is not necessary or supported.
|
|
76
87
|
*/
|
|
77
88
|
export const DeletedResponseHeaderKey = "wasDeleted";
|
|
78
89
|
/**
|
|
@@ -112,7 +123,7 @@ export var CompressionAlgorithms;
|
|
|
112
123
|
* @alpha
|
|
113
124
|
*/
|
|
114
125
|
export const disabledCompressionConfig = {
|
|
115
|
-
minimumBatchSizeInBytes:
|
|
126
|
+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
116
127
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
117
128
|
};
|
|
118
129
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
@@ -166,7 +177,9 @@ export function getDeviceSpec() {
|
|
|
166
177
|
};
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
|
-
catch {
|
|
180
|
+
catch {
|
|
181
|
+
// Eat the error
|
|
182
|
+
}
|
|
170
183
|
return {};
|
|
171
184
|
}
|
|
172
185
|
/**
|
|
@@ -207,21 +220,20 @@ async function createSummarizer(loader, url) {
|
|
|
207
220
|
let fluidObject;
|
|
208
221
|
// Older containers may not have the "getEntryPoint" API
|
|
209
222
|
// ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
|
|
210
|
-
if (resolvedContainer.getEntryPoint
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
else {
|
|
214
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment
|
|
215
|
-
const response = await resolvedContainer.request({
|
|
223
|
+
if (resolvedContainer.getEntryPoint === undefined) {
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
225
|
+
const response = (await resolvedContainer.request({
|
|
216
226
|
url: `/${summarizerRequestUrl}`,
|
|
217
|
-
});
|
|
218
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
227
|
+
}));
|
|
219
228
|
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
220
229
|
throw responseToException(response, request);
|
|
221
230
|
}
|
|
222
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
223
232
|
fluidObject = response.value;
|
|
224
233
|
}
|
|
234
|
+
else {
|
|
235
|
+
fluidObject = await resolvedContainer.getEntryPoint();
|
|
236
|
+
}
|
|
225
237
|
if (fluidObject?.ISummarizer === undefined) {
|
|
226
238
|
throw new UsageError("Fluid object does not implement ISummarizer");
|
|
227
239
|
}
|
|
@@ -233,7 +245,9 @@ async function createSummarizer(loader, url) {
|
|
|
233
245
|
* This allows new runtime to make documents not openable for old runtimes, one explicit document schema control is enabled.
|
|
234
246
|
* Please see addMetadataToSummary() as well
|
|
235
247
|
*/
|
|
236
|
-
function lastMessageFromMetadata(
|
|
248
|
+
function lastMessageFromMetadata(
|
|
249
|
+
// eslint-disable-next-line import/no-deprecated
|
|
250
|
+
metadata) {
|
|
237
251
|
return metadata?.documentSchema?.runtime?.explicitSchemaControl
|
|
238
252
|
? metadata?.lastMessage
|
|
239
253
|
: metadata?.message;
|
|
@@ -250,6 +264,7 @@ export let getSingleUseLegacyLogCallback = (logger, type) => {
|
|
|
250
264
|
details: { codePath, type },
|
|
251
265
|
});
|
|
252
266
|
// Now that we've logged, prevent future logging (globally).
|
|
267
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
253
268
|
getSingleUseLegacyLogCallback = () => () => { };
|
|
254
269
|
};
|
|
255
270
|
};
|
|
@@ -263,6 +278,8 @@ export let getSingleUseLegacyLogCallback = (logger, type) => {
|
|
|
263
278
|
export async function loadContainerRuntime(params) {
|
|
264
279
|
return ContainerRuntime.loadRuntime(params);
|
|
265
280
|
}
|
|
281
|
+
const defaultMaxConsecutiveReconnects = 7;
|
|
282
|
+
const defaultTelemetrySignalSampleCount = 100;
|
|
266
283
|
/**
|
|
267
284
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
268
285
|
* It will define the store level mappings.
|
|
@@ -318,7 +335,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
318
335
|
const [chunks, recentBatchInfo, metadata, electedSummarizerData, aliases, serializedIdCompressor,] = await Promise.all([
|
|
319
336
|
tryFetchBlob(chunksBlobName),
|
|
320
337
|
tryFetchBlob(recentBatchInfoBlobName),
|
|
338
|
+
// eslint-disable-next-line import/no-deprecated
|
|
321
339
|
tryFetchBlob(metadataBlobName),
|
|
340
|
+
// eslint-disable-next-line import/no-deprecated
|
|
322
341
|
tryFetchBlob(electedSummarizerBlobName),
|
|
323
342
|
tryFetchBlob(aliasBlobName),
|
|
324
343
|
tryFetchBlob(idCompressorBlobName),
|
|
@@ -332,6 +351,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
332
351
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
333
352
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
334
353
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
354
|
+
// eslint-disable-next-line unicorn/no-lonely-if -- Separate if statements make flow easier to parse
|
|
335
355
|
if (loadSequenceNumberVerification !== "bypass" &&
|
|
336
356
|
runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
337
357
|
// Message to OCEs:
|
|
@@ -354,15 +374,18 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
354
374
|
}
|
|
355
375
|
let desiredIdCompressorMode;
|
|
356
376
|
switch (mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) {
|
|
357
|
-
case true:
|
|
377
|
+
case true: {
|
|
358
378
|
desiredIdCompressorMode = "on";
|
|
359
379
|
break;
|
|
360
|
-
|
|
380
|
+
}
|
|
381
|
+
case false: {
|
|
361
382
|
desiredIdCompressorMode = undefined;
|
|
362
383
|
break;
|
|
363
|
-
|
|
384
|
+
}
|
|
385
|
+
default: {
|
|
364
386
|
desiredIdCompressorMode = enableRuntimeIdCompressor;
|
|
365
387
|
break;
|
|
388
|
+
}
|
|
366
389
|
}
|
|
367
390
|
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
368
391
|
// allow new containers to turn it on.
|
|
@@ -415,15 +438,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
415
438
|
if (pendingLocalState?.pendingIdCompressorState !== undefined) {
|
|
416
439
|
return deserializeIdCompressor(pendingLocalState.pendingIdCompressorState, compressorLogger);
|
|
417
440
|
}
|
|
418
|
-
else if (serializedIdCompressor
|
|
419
|
-
return
|
|
441
|
+
else if (serializedIdCompressor === undefined) {
|
|
442
|
+
return createIdCompressor(compressorLogger);
|
|
420
443
|
}
|
|
421
444
|
else {
|
|
422
|
-
return
|
|
445
|
+
return deserializeIdCompressor(serializedIdCompressor, createSessionId(), compressorLogger);
|
|
423
446
|
}
|
|
424
447
|
};
|
|
425
|
-
const compressionLz4 = compressionOptions.minimumBatchSizeInBytes !==
|
|
448
|
+
const compressionLz4 = compressionOptions.minimumBatchSizeInBytes !== Number.POSITIVE_INFINITY &&
|
|
426
449
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
450
|
+
// eslint-disable-next-line import/no-deprecated
|
|
427
451
|
const documentSchemaController = new DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
|
|
428
452
|
explicitSchemaControl,
|
|
429
453
|
compressionLz4,
|
|
@@ -501,9 +525,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
501
525
|
get sessionSchema() {
|
|
502
526
|
return this.documentsSchemaController.sessionSchema.runtime;
|
|
503
527
|
}
|
|
504
|
-
get idCompressorMode() {
|
|
505
|
-
return this.sessionSchema.idCompressorMode;
|
|
506
|
-
}
|
|
507
528
|
/**
|
|
508
529
|
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor}
|
|
509
530
|
*/
|
|
@@ -512,7 +533,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
512
533
|
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
513
534
|
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
514
535
|
// to reason over such things as session ID space.
|
|
515
|
-
if (this.idCompressorMode === "on") {
|
|
536
|
+
if (this.sessionSchema.idCompressorMode === "on") {
|
|
516
537
|
assert(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
517
538
|
return this._idCompressor;
|
|
518
539
|
}
|
|
@@ -563,28 +584,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
563
584
|
get disposed() {
|
|
564
585
|
return this._disposed;
|
|
565
586
|
}
|
|
566
|
-
get summarizer() {
|
|
567
|
-
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
568
|
-
return this._summarizer;
|
|
569
|
-
}
|
|
570
|
-
isSummariesDisabled() {
|
|
571
|
-
return this.summaryConfiguration.state === "disabled";
|
|
572
|
-
}
|
|
573
|
-
getMaxOpsSinceLastSummary() {
|
|
574
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
575
|
-
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
576
|
-
: 0;
|
|
577
|
-
}
|
|
578
|
-
getInitialSummarizerDelayMs() {
|
|
579
|
-
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
580
|
-
// to ISummaryConfiguration in 0.60.
|
|
581
|
-
if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
|
|
582
|
-
return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
|
|
583
|
-
}
|
|
584
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
585
|
-
? this.summaryConfiguration.initialSummarizerDelayMs
|
|
586
|
-
: 0;
|
|
587
|
-
}
|
|
588
587
|
/**
|
|
589
588
|
* If false, loading or using a Tombstoned object should merely log, not fail.
|
|
590
589
|
* @deprecated NOT SUPPORTED - hardcoded to return false since it's deprecated.
|
|
@@ -601,14 +600,27 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
601
600
|
get gcThrowOnTombstoneUsage() {
|
|
602
601
|
return false;
|
|
603
602
|
}
|
|
603
|
+
get ILayerCompatDetails() {
|
|
604
|
+
return RuntimeCompatDetails;
|
|
605
|
+
}
|
|
604
606
|
/***/
|
|
605
|
-
constructor(context, registry,
|
|
607
|
+
constructor(context, registry,
|
|
608
|
+
// eslint-disable-next-line import/no-deprecated
|
|
609
|
+
metadata,
|
|
610
|
+
// eslint-disable-next-line import/no-deprecated
|
|
611
|
+
electedSummarizerData, chunks, dataStoreAliasMap, baseRuntimeOptions, containerScope,
|
|
606
612
|
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
607
|
-
baseLogger, existing,
|
|
613
|
+
baseLogger, existing,
|
|
614
|
+
// eslint-disable-next-line import/no-deprecated
|
|
615
|
+
blobManagerSnapshot, _storage, createIdCompressor,
|
|
616
|
+
// eslint-disable-next-line import/no-deprecated
|
|
617
|
+
documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler,
|
|
618
|
+
// eslint-disable-next-line unicorn/no-object-as-default-parameter
|
|
619
|
+
summaryConfiguration = {
|
|
608
620
|
// the defaults
|
|
609
621
|
...DefaultSummaryConfiguration,
|
|
610
622
|
// the runtime configuration overrides
|
|
611
|
-
...
|
|
623
|
+
...baseRuntimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
612
624
|
}, recentBatchInfo) {
|
|
613
625
|
super();
|
|
614
626
|
this.registry = registry;
|
|
@@ -619,19 +631,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
619
631
|
this.createIdCompressor = createIdCompressor;
|
|
620
632
|
this.documentsSchemaController = documentsSchemaController;
|
|
621
633
|
this.requestHandler = requestHandler;
|
|
622
|
-
this.summaryConfiguration = summaryConfiguration;
|
|
623
634
|
this.imminentClosure = false;
|
|
624
635
|
// We accumulate Id compressor Ops while Id compressor is not loaded yet (only for "delayed" mode)
|
|
625
636
|
// Once it loads, it will process all such ops and we will stop accumulating further ops - ops will be processes as they come in.
|
|
626
637
|
this.pendingIdCompressorOps = [];
|
|
627
|
-
this.defaultMaxConsecutiveReconnects = 7;
|
|
628
638
|
this._orderSequentiallyCalls = 0;
|
|
629
639
|
this.flushTaskExists = false;
|
|
630
640
|
this.consecutiveReconnects = 0;
|
|
631
641
|
this.ensureNoDataModelChangesCalls = 0;
|
|
632
642
|
this._disposed = false;
|
|
633
643
|
this.emitDirtyDocumentEvent = true;
|
|
634
|
-
this.defaultTelemetrySignalSampleCount = 100;
|
|
635
644
|
this._signalTracking = {
|
|
636
645
|
totalSignalsSentInLatencyWindow: 0,
|
|
637
646
|
signalsLost: 0,
|
|
@@ -650,15 +659,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
650
659
|
this.snapshotCacheForLoadingGroupIds = new PromiseCache({
|
|
651
660
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
652
661
|
});
|
|
662
|
+
this.readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
653
663
|
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, snapshotWithContents, } = context;
|
|
664
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
665
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
666
|
+
const maybeLoaderCompatDetails = context;
|
|
667
|
+
validateLoaderCompatibility(maybeLoaderCompatDetails.ILayerCompatDetails, this.disposeFn);
|
|
654
668
|
// Backfill in defaults for the internal runtimeOptions, since they may not be present on the provided runtimeOptions object
|
|
655
|
-
|
|
669
|
+
const runtimeOptions = {
|
|
656
670
|
flushMode: defaultFlushMode,
|
|
657
|
-
...
|
|
671
|
+
...baseRuntimeOptions,
|
|
658
672
|
};
|
|
659
|
-
this.logger = createChildLogger({ logger: this.baseLogger });
|
|
660
673
|
this.mc = createChildMonitoringContext({
|
|
661
|
-
logger: this.
|
|
674
|
+
logger: this.baseLogger,
|
|
662
675
|
namespace: "ContainerRuntime",
|
|
663
676
|
});
|
|
664
677
|
// If we support multiple algorithms in the future, then we would need to manage it here carefully.
|
|
@@ -675,19 +688,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
675
688
|
this.innerDeltaManager = deltaManager;
|
|
676
689
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
677
690
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
678
|
-
this
|
|
679
|
-
this.
|
|
680
|
-
|
|
691
|
+
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
692
|
+
this.submitSummaryFn =
|
|
693
|
+
submitSummaryFn ??
|
|
694
|
+
((summaryOp, refseq) => submitFn(MessageType.Summarize, summaryOp, false));
|
|
681
695
|
this.submitSignalFn = submitSignalFn;
|
|
682
696
|
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
683
697
|
// Values are generally expected to be set from the runtime side.
|
|
684
698
|
this.options = options ?? {};
|
|
685
699
|
this.clientDetails = clientDetails;
|
|
686
|
-
|
|
700
|
+
const isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
687
701
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
702
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
688
703
|
this._getClientId = () => context.clientId;
|
|
704
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
689
705
|
this._getAttachState = () => context.attachState;
|
|
690
706
|
this.getAbsoluteUrl = async (relativeUrl) => {
|
|
707
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
691
708
|
if (context.getAbsoluteUrl === undefined) {
|
|
692
709
|
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
693
710
|
}
|
|
@@ -700,10 +717,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
700
717
|
// customer should observe dirty state on the runtime (the owner of dirty state) directly, rather than on the IContainer.
|
|
701
718
|
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
702
719
|
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
703
|
-
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
704
|
-
this.disposeFn = disposeFn ?? closeFn;
|
|
705
720
|
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
706
|
-
this.closeFn =
|
|
721
|
+
this.closeFn = isSummarizerClient ? this.disposeFn : closeFn;
|
|
707
722
|
let loadSummaryNumber;
|
|
708
723
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
709
724
|
// get the values from the metadata blob.
|
|
@@ -733,16 +748,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
733
748
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
734
749
|
inputs: JSON.stringify({
|
|
735
750
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
736
|
-
gcOptions_gcGeneration:
|
|
751
|
+
gcOptions_gcGeneration: runtimeOptions.gcOptions[gcGenerationOptionName],
|
|
737
752
|
}),
|
|
738
753
|
});
|
|
739
754
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
|
|
740
|
-
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
741
755
|
const opGroupingManager = new OpGroupingManager({
|
|
742
756
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
743
|
-
opCountThreshold: this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
744
757
|
}, this.mc.logger);
|
|
745
|
-
const opSplitter = new OpSplitter(chunks,
|
|
758
|
+
const opSplitter = new OpSplitter(chunks, submitBatchFn, runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
746
759
|
this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
|
|
747
760
|
const pendingRuntimeState = pendingLocalState;
|
|
748
761
|
this.pendingStateManager = new PendingStateManager({
|
|
@@ -752,7 +765,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
752
765
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
753
766
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
754
767
|
isAttached: () => this.attachState !== AttachState.Detached,
|
|
755
|
-
}, pendingRuntimeState?.pending, this.
|
|
768
|
+
}, pendingRuntimeState?.pending, this.baseLogger);
|
|
756
769
|
let outerDeltaManager;
|
|
757
770
|
this.useDeltaManagerOpsProxy =
|
|
758
771
|
this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") === true;
|
|
@@ -767,24 +780,35 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
767
780
|
}
|
|
768
781
|
this._deltaManager = outerDeltaManager;
|
|
769
782
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
770
|
-
if (
|
|
771
|
-
this.validateSummaryHeuristicConfiguration(
|
|
772
|
-
}
|
|
773
|
-
this.summariesDisabled =
|
|
774
|
-
|
|
775
|
-
|
|
783
|
+
if (summaryConfiguration.state === "enabled") {
|
|
784
|
+
this.validateSummaryHeuristicConfiguration(summaryConfiguration);
|
|
785
|
+
}
|
|
786
|
+
this.summariesDisabled = isSummariesDisabled(summaryConfiguration);
|
|
787
|
+
const { maxOpsSinceLastSummary = 0, initialSummarizerDelayMs = 0 } = isSummariesDisabled(summaryConfiguration)
|
|
788
|
+
? {}
|
|
789
|
+
: {
|
|
790
|
+
...summaryConfiguration,
|
|
791
|
+
initialSummarizerDelayMs:
|
|
792
|
+
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
793
|
+
// to ISummaryConfiguration in 0.60.
|
|
794
|
+
runtimeOptions.summaryOptions.initialSummarizerDelayMs ??
|
|
795
|
+
summaryConfiguration.initialSummarizerDelayMs,
|
|
796
|
+
};
|
|
776
797
|
this.maxConsecutiveReconnects =
|
|
777
|
-
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
supportedFeatures?.get("referenceSequenceNumbers")
|
|
798
|
+
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ?? defaultMaxConsecutiveReconnects;
|
|
799
|
+
// If the context has ILayerCompatDetails, it supports referenceSequenceNumbers since that features
|
|
800
|
+
// predates ILayerCompatDetails.
|
|
801
|
+
const referenceSequenceNumbersSupported = maybeLoaderCompatDetails.ILayerCompatDetails === undefined
|
|
802
|
+
? supportedFeatures?.get("referenceSequenceNumbers") === true
|
|
803
|
+
: true;
|
|
804
|
+
if (runtimeOptions.flushMode === FlushModeExperimental.Async &&
|
|
805
|
+
!referenceSequenceNumbersSupported) {
|
|
782
806
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
783
807
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
784
808
|
this._flushMode = FlushMode.TurnBased;
|
|
785
809
|
}
|
|
786
810
|
else {
|
|
787
|
-
this._flushMode =
|
|
811
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
788
812
|
}
|
|
789
813
|
this.offlineEnabled =
|
|
790
814
|
this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ?? false;
|
|
@@ -799,6 +823,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
799
823
|
if (this.offlineEnabled) {
|
|
800
824
|
this.duplicateBatchDetector = new DuplicateBatchDetector(recentBatchInfo);
|
|
801
825
|
}
|
|
826
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
802
827
|
if (context.attachState === AttachState.Attached) {
|
|
803
828
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
804
829
|
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
@@ -811,13 +836,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
811
836
|
}
|
|
812
837
|
this.garbageCollector = GarbageCollector.create({
|
|
813
838
|
runtime: this,
|
|
814
|
-
gcOptions:
|
|
839
|
+
gcOptions: runtimeOptions.gcOptions,
|
|
815
840
|
baseSnapshot,
|
|
816
841
|
baseLogger: this.mc.logger,
|
|
817
842
|
existing,
|
|
818
843
|
metadata,
|
|
819
844
|
createContainerMetadata: this.createContainerMetadata,
|
|
820
|
-
isSummarizerClient
|
|
845
|
+
isSummarizerClient,
|
|
821
846
|
getNodePackagePath: async (nodePath) => this.getGCNodePackagePath(nodePath),
|
|
822
847
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
823
848
|
readAndParseBlob: async (id) => readAndParse(this.storage, id),
|
|
@@ -831,7 +856,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
831
856
|
const summaryReferenceSequenceNumber = baseSnapshot === undefined || metadata?.disableIsolatedChannels === true
|
|
832
857
|
? undefined
|
|
833
858
|
: loadedFromSequenceNumber;
|
|
834
|
-
this.summarizerNode = createRootSummarizerNodeWithGC(createChildLogger({ logger: this.
|
|
859
|
+
this.summarizerNode = createRootSummarizerNodeWithGC(createChildLogger({ logger: this.baseLogger, namespace: "SummarizerNode" }),
|
|
835
860
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
836
861
|
async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
837
862
|
// Latest change sequence number, no changes since summary applied yet
|
|
@@ -889,16 +914,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
889
914
|
isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
890
915
|
runtime: this,
|
|
891
916
|
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
892
|
-
closeContainer: (error) => this.closeFn(error),
|
|
893
917
|
});
|
|
894
|
-
this.deltaScheduler = new DeltaScheduler(this.innerDeltaManager, this, createChildLogger({ logger: this.
|
|
895
|
-
this.inboundBatchAggregator = new InboundBatchAggregator(this.innerDeltaManager, () => this.clientId, createChildLogger({ logger: this.
|
|
918
|
+
this.deltaScheduler = new DeltaScheduler(this.innerDeltaManager, this, createChildLogger({ logger: this.baseLogger, namespace: "DeltaScheduler" }));
|
|
919
|
+
this.inboundBatchAggregator = new InboundBatchAggregator(this.innerDeltaManager, () => this.clientId, createChildLogger({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }));
|
|
896
920
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
897
|
-
const legacySendBatchFn = makeLegacySendBatchFn(
|
|
921
|
+
const legacySendBatchFn = makeLegacySendBatchFn(submitFn, this.innerDeltaManager);
|
|
898
922
|
this.outbox = new Outbox({
|
|
899
923
|
shouldSend: () => this.canSendOps(),
|
|
900
924
|
pendingStateManager: this.pendingStateManager,
|
|
901
|
-
submitBatchFn
|
|
925
|
+
submitBatchFn,
|
|
902
926
|
legacySendBatchFn,
|
|
903
927
|
compressor: new OpCompressor(this.mc.logger),
|
|
904
928
|
splitter: opSplitter,
|
|
@@ -945,7 +969,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
945
969
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
946
970
|
this.closeSummarizerDelayMs =
|
|
947
971
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
948
|
-
|
|
972
|
+
const summaryCollection = new SummaryCollection(this.deltaManager, this.baseLogger);
|
|
949
973
|
this.dirtyContainer =
|
|
950
974
|
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
951
975
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
@@ -954,14 +978,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
954
978
|
}
|
|
955
979
|
else {
|
|
956
980
|
const orderedClientLogger = createChildLogger({
|
|
957
|
-
logger: this.
|
|
981
|
+
logger: this.baseLogger,
|
|
958
982
|
namespace: "OrderedClientElection",
|
|
959
983
|
});
|
|
960
984
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
961
985
|
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible, this.mc.config.getBoolean("Fluid.ContainerRuntime.OrderedClientElection.EnablePerformanceEvents"));
|
|
962
|
-
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger,
|
|
963
|
-
if (
|
|
964
|
-
|
|
986
|
+
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary);
|
|
987
|
+
if (isSummarizerClient) {
|
|
988
|
+
// eslint-disable-next-line import/no-deprecated
|
|
989
|
+
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, summaryCollection,
|
|
990
|
+
// eslint-disable-next-line import/no-deprecated
|
|
991
|
+
async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
965
992
|
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
966
993
|
// information. The proxy delta manager would always return false for summarizer client.
|
|
967
994
|
() => this.innerDeltaManager.active));
|
|
@@ -970,48 +997,49 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
970
997
|
// Only create a SummaryManager and SummarizerClientElection
|
|
971
998
|
// if summaries are enabled and we are not the summarizer client.
|
|
972
999
|
const defaultAction = () => {
|
|
973
|
-
if (
|
|
1000
|
+
if (summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
974
1001
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
975
1002
|
// unregister default to no log on every op after falling behind
|
|
976
1003
|
// and register summary ack handler to re-register this handler
|
|
977
1004
|
// after successful summary
|
|
978
|
-
|
|
1005
|
+
summaryCollection.once(MessageType.SummaryAck, () => {
|
|
979
1006
|
this.mc.logger.sendTelemetryEvent({
|
|
980
1007
|
eventName: "SummaryStatus:CaughtUp",
|
|
981
1008
|
});
|
|
982
1009
|
// we've caught up, so re-register the default action to monitor for
|
|
983
1010
|
// falling behind, and unregister ourself
|
|
984
|
-
|
|
1011
|
+
summaryCollection.on("default", defaultAction);
|
|
985
1012
|
});
|
|
986
|
-
|
|
1013
|
+
summaryCollection.off("default", defaultAction);
|
|
987
1014
|
}
|
|
988
1015
|
};
|
|
989
|
-
|
|
1016
|
+
summaryCollection.on("default", defaultAction);
|
|
990
1017
|
// Create the SummaryManager and mark the initial state
|
|
991
1018
|
this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
992
|
-
|
|
1019
|
+
summaryCollection, this.baseLogger, this.formCreateSummarizerFn(loader), new Throttler(60 * 1000, // 60 sec delay window
|
|
993
1020
|
30 * 1000, // 30 sec max delay
|
|
994
1021
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
995
1022
|
formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
|
|
996
|
-
initialDelayMs:
|
|
1023
|
+
initialDelayMs: initialSummarizerDelayMs,
|
|
997
1024
|
});
|
|
998
1025
|
// Forward events from SummaryManager
|
|
999
|
-
[
|
|
1026
|
+
for (const eventName of [
|
|
1000
1027
|
"summarize",
|
|
1001
1028
|
"summarizeAllAttemptsFailed",
|
|
1002
1029
|
"summarizerStop",
|
|
1003
1030
|
"summarizerStart",
|
|
1004
1031
|
"summarizerStartupFailed",
|
|
1005
|
-
]
|
|
1032
|
+
]) {
|
|
1006
1033
|
this.summaryManager?.on(eventName, (...args) => {
|
|
1007
1034
|
this.emit(eventName, ...args);
|
|
1008
1035
|
});
|
|
1009
|
-
}
|
|
1036
|
+
}
|
|
1010
1037
|
this.summaryManager.start();
|
|
1011
1038
|
}
|
|
1012
1039
|
}
|
|
1013
1040
|
// logging hardware telemetry
|
|
1014
|
-
this.
|
|
1041
|
+
this.baseLogger.send({
|
|
1042
|
+
category: "generic",
|
|
1015
1043
|
eventName: "DeviceSpec",
|
|
1016
1044
|
...getDeviceSpec(),
|
|
1017
1045
|
});
|
|
@@ -1023,13 +1051,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1023
1051
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1024
1052
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1025
1053
|
gcVersion: metadata?.gcFeature,
|
|
1026
|
-
options: JSON.stringify(
|
|
1054
|
+
options: JSON.stringify(baseRuntimeOptions),
|
|
1027
1055
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
1028
|
-
idCompressorMode: this.idCompressorMode,
|
|
1056
|
+
idCompressorMode: this.sessionSchema.idCompressorMode,
|
|
1029
1057
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
1030
1058
|
featureGates: JSON.stringify({
|
|
1031
1059
|
...featureGatesForTelemetry,
|
|
1032
|
-
disableAttachReorder: this.disableAttachReorder,
|
|
1033
1060
|
disablePartialFlush,
|
|
1034
1061
|
closeSummarizerDelayOverride,
|
|
1035
1062
|
}),
|
|
@@ -1037,11 +1064,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1037
1064
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1038
1065
|
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
1039
1066
|
});
|
|
1040
|
-
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.
|
|
1041
|
-
BindBatchTracker(this, this.
|
|
1067
|
+
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.baseLogger);
|
|
1068
|
+
BindBatchTracker(this, this.baseLogger);
|
|
1042
1069
|
this.entryPoint = new LazyPromise(async () => {
|
|
1043
|
-
if (this.
|
|
1044
|
-
assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
1070
|
+
if (this._summarizer !== undefined) {
|
|
1045
1071
|
return this._summarizer;
|
|
1046
1072
|
}
|
|
1047
1073
|
return provideEntryPoint(this);
|
|
@@ -1050,8 +1076,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1050
1076
|
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
1051
1077
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
1052
1078
|
}
|
|
1079
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1053
1080
|
onSchemaChange(schema) {
|
|
1054
|
-
this.logger.sendTelemetryEvent({
|
|
1081
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1055
1082
|
eventName: "SchemaChangeAccept",
|
|
1056
1083
|
sessionRuntimeSchema: JSON.stringify(schema),
|
|
1057
1084
|
});
|
|
@@ -1086,8 +1113,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1086
1113
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
1087
1114
|
*/
|
|
1088
1115
|
async initializeBaseState() {
|
|
1089
|
-
if (this.idCompressorMode === "on" ||
|
|
1090
|
-
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
1116
|
+
if (this.sessionSchema.idCompressorMode === "on" ||
|
|
1117
|
+
(this.sessionSchema.idCompressorMode === "delayed" && this.connected)) {
|
|
1091
1118
|
this._idCompressor = await this.createIdCompressor();
|
|
1092
1119
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
1093
1120
|
assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
@@ -1130,7 +1157,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1130
1157
|
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
1131
1158
|
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
1132
1159
|
// any request, then cache that as same group could be requested in future too.
|
|
1133
|
-
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(), async () => {
|
|
1160
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(","), async () => {
|
|
1134
1161
|
assert(this.storage.getSnapshot !== undefined, 0x8ee /* getSnapshot api should be defined if used */);
|
|
1135
1162
|
loadedFromCache = false;
|
|
1136
1163
|
return this.storage.getSnapshot({
|
|
@@ -1139,7 +1166,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1139
1166
|
loadingGroupIds: sortedLoadingGroupIds,
|
|
1140
1167
|
});
|
|
1141
1168
|
});
|
|
1142
|
-
this.logger.sendTelemetryEvent({
|
|
1169
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1143
1170
|
eventName: "GroupIdSnapshotFetched",
|
|
1144
1171
|
details: JSON.stringify({
|
|
1145
1172
|
fromCache: loadedFromCache,
|
|
@@ -1169,7 +1196,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1169
1196
|
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
1170
1197
|
// the summarizer state is not up to date.
|
|
1171
1198
|
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
1172
|
-
if (this.
|
|
1199
|
+
if (this._summarizer !== undefined) {
|
|
1173
1200
|
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
1174
1201
|
}
|
|
1175
1202
|
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
@@ -1231,7 +1258,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1231
1258
|
return {
|
|
1232
1259
|
status: 200,
|
|
1233
1260
|
mimeType: "fluid/object",
|
|
1234
|
-
value: this.
|
|
1261
|
+
value: this._summarizer,
|
|
1235
1262
|
};
|
|
1236
1263
|
}
|
|
1237
1264
|
return create404Response(request);
|
|
@@ -1297,6 +1324,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1297
1324
|
const documentSchema = this.documentsSchemaController.summarizeDocumentSchema(this.deltaManager.lastSequenceNumber);
|
|
1298
1325
|
// Is document schema explicit control on?
|
|
1299
1326
|
const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
|
|
1327
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1300
1328
|
const metadata = {
|
|
1301
1329
|
...this.createContainerMetadata,
|
|
1302
1330
|
// Increment the summary number for the next summary that will be generated.
|
|
@@ -1310,7 +1338,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1310
1338
|
// last message's sequence number.
|
|
1311
1339
|
// See also lastMessageFromMetadata()
|
|
1312
1340
|
message: explicitSchemaControl
|
|
1313
|
-
?
|
|
1341
|
+
? // eslint-disable-next-line import/no-deprecated
|
|
1342
|
+
{ sequenceNumber: -1 }
|
|
1314
1343
|
: message,
|
|
1315
1344
|
lastMessage: explicitSchemaControl ? message : undefined,
|
|
1316
1345
|
documentSchema,
|
|
@@ -1426,9 +1455,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1426
1455
|
switch (opContents.type) {
|
|
1427
1456
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1428
1457
|
case ContainerMessageType.Attach:
|
|
1429
|
-
case ContainerMessageType.Alias:
|
|
1458
|
+
case ContainerMessageType.Alias: {
|
|
1430
1459
|
return this.channelCollection.applyStashedOp(opContents);
|
|
1431
|
-
|
|
1460
|
+
}
|
|
1461
|
+
case ContainerMessageType.IdAllocation: {
|
|
1432
1462
|
// IDs allocation ops in stashed state are ignored because the tip state of the compressor
|
|
1433
1463
|
// is serialized into the pending state. This is done because generation of new IDs during
|
|
1434
1464
|
// stashed op application (or, later, resubmit) must generate new IDs and if the compressor
|
|
@@ -1438,17 +1468,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1438
1468
|
// and the runtime could filter out all ID allocation ops from the stashed state and apply them
|
|
1439
1469
|
// before applying the rest of the stashed ops. This would accomplish the same thing but with
|
|
1440
1470
|
// better performance in future incremental stashed state creation.
|
|
1441
|
-
assert(this.idCompressorMode !== undefined, 0x8f1 /* ID compressor should be in use */);
|
|
1471
|
+
assert(this.sessionSchema.idCompressorMode !== undefined, 0x8f1 /* ID compressor should be in use */);
|
|
1442
1472
|
return;
|
|
1443
|
-
|
|
1473
|
+
}
|
|
1474
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
1444
1475
|
return;
|
|
1445
|
-
|
|
1476
|
+
}
|
|
1477
|
+
case ContainerMessageType.BlobAttach: {
|
|
1446
1478
|
return;
|
|
1447
|
-
|
|
1479
|
+
}
|
|
1480
|
+
case ContainerMessageType.Rejoin: {
|
|
1448
1481
|
throw new Error("rejoin not expected here");
|
|
1449
|
-
|
|
1482
|
+
}
|
|
1483
|
+
case ContainerMessageType.GC: {
|
|
1450
1484
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
1451
1485
|
throw new LoggingError("GC op not expected to be stashed in summarizer");
|
|
1486
|
+
}
|
|
1452
1487
|
default: {
|
|
1453
1488
|
const error = getUnknownMessageTypeError(opContents.type, "applyStashedOp" /* codePath */);
|
|
1454
1489
|
this.closeFn(error);
|
|
@@ -1458,7 +1493,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1458
1493
|
}
|
|
1459
1494
|
async loadIdCompressor() {
|
|
1460
1495
|
if (this._idCompressor === undefined &&
|
|
1461
|
-
this.idCompressorMode !== undefined &&
|
|
1496
|
+
this.sessionSchema.idCompressorMode !== undefined &&
|
|
1462
1497
|
this._loadIdCompressor === undefined) {
|
|
1463
1498
|
this._loadIdCompressor = this.createIdCompressor()
|
|
1464
1499
|
.then((compressor) => {
|
|
@@ -1472,7 +1507,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1472
1507
|
this._idCompressor = compressor;
|
|
1473
1508
|
})
|
|
1474
1509
|
.catch((error) => {
|
|
1475
|
-
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1510
|
+
this.mc.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1476
1511
|
throw error;
|
|
1477
1512
|
});
|
|
1478
1513
|
}
|
|
@@ -1483,7 +1518,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1483
1518
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
1484
1519
|
assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
1485
1520
|
assert(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
|
|
1486
|
-
if (connected && this.idCompressorMode === "delayed") {
|
|
1521
|
+
if (connected && this.sessionSchema.idCompressorMode === "delayed") {
|
|
1487
1522
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1488
1523
|
this.loadIdCompressor();
|
|
1489
1524
|
}
|
|
@@ -1572,7 +1607,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1572
1607
|
// or something different, like a system message.
|
|
1573
1608
|
const hasModernRuntimeMessageEnvelope = messageCopy.type === MessageType.Operation;
|
|
1574
1609
|
const savedOp = messageCopy.metadata?.savedOp;
|
|
1575
|
-
const logLegacyCase = getSingleUseLegacyLogCallback(this.logger, messageCopy.type);
|
|
1610
|
+
const logLegacyCase = getSingleUseLegacyLogCallback(this.mc.logger, messageCopy.type);
|
|
1576
1611
|
let runtimeBatch = hasModernRuntimeMessageEnvelope || isUnpackedRuntimeMessage(messageCopy);
|
|
1577
1612
|
if (runtimeBatch) {
|
|
1578
1613
|
// We expect runtime messages to have JSON contents - deserialize it in place.
|
|
@@ -1674,11 +1709,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1674
1709
|
let error;
|
|
1675
1710
|
try {
|
|
1676
1711
|
if (!runtimeBatch) {
|
|
1677
|
-
|
|
1712
|
+
for (const { message } of messagesWithMetadata) {
|
|
1678
1713
|
this.ensureNoDataModelChanges(() => {
|
|
1679
1714
|
this.observeNonRuntimeMessage(message);
|
|
1680
1715
|
});
|
|
1681
|
-
}
|
|
1716
|
+
}
|
|
1682
1717
|
return;
|
|
1683
1718
|
}
|
|
1684
1719
|
// Updates a message's minimum sequence number to the minimum sequence number that container
|
|
@@ -1746,8 +1781,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1746
1781
|
this.emit("op", message, true /* runtimeMessage */);
|
|
1747
1782
|
}
|
|
1748
1783
|
}
|
|
1749
|
-
catch (
|
|
1750
|
-
error =
|
|
1784
|
+
catch (error_) {
|
|
1785
|
+
error = error_;
|
|
1751
1786
|
throw error;
|
|
1752
1787
|
}
|
|
1753
1788
|
finally {
|
|
@@ -1804,30 +1839,39 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1804
1839
|
switch (message.type) {
|
|
1805
1840
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1806
1841
|
case ContainerMessageType.Attach:
|
|
1807
|
-
case ContainerMessageType.Alias:
|
|
1842
|
+
case ContainerMessageType.Alias: {
|
|
1808
1843
|
// Remove the metadata from the message before sending it to the channel collection. The metadata
|
|
1809
1844
|
// is added by the container runtime and is not part of the message that the channel collection and
|
|
1810
1845
|
// layers below it expect.
|
|
1811
1846
|
this.channelCollection.processMessages({ envelope: message, messagesContent, local });
|
|
1812
1847
|
break;
|
|
1813
|
-
|
|
1848
|
+
}
|
|
1849
|
+
case ContainerMessageType.BlobAttach: {
|
|
1814
1850
|
this.blobManager.processBlobAttachMessage(message, local);
|
|
1815
1851
|
break;
|
|
1816
|
-
|
|
1852
|
+
}
|
|
1853
|
+
case ContainerMessageType.IdAllocation: {
|
|
1817
1854
|
this.processIdCompressorMessages(contents, savedOp);
|
|
1818
1855
|
break;
|
|
1819
|
-
|
|
1856
|
+
}
|
|
1857
|
+
case ContainerMessageType.GC: {
|
|
1820
1858
|
this.garbageCollector.processMessages(contents, message.timestamp, local);
|
|
1821
1859
|
break;
|
|
1822
|
-
|
|
1860
|
+
}
|
|
1861
|
+
case ContainerMessageType.ChunkedOp: {
|
|
1823
1862
|
// From observability POV, we should not expose the rest of the system (including "op" events on object) to these messages.
|
|
1824
1863
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
1825
1864
|
assert(false, 0x93d /* should not even get here */);
|
|
1826
|
-
|
|
1865
|
+
}
|
|
1866
|
+
case ContainerMessageType.Rejoin: {
|
|
1827
1867
|
break;
|
|
1828
|
-
|
|
1829
|
-
|
|
1868
|
+
}
|
|
1869
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
1870
|
+
this.documentsSchemaController.processDocumentSchemaMessages(
|
|
1871
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1872
|
+
contents, local, message.sequenceNumber);
|
|
1830
1873
|
break;
|
|
1874
|
+
}
|
|
1831
1875
|
default: {
|
|
1832
1876
|
const error = getUnknownMessageTypeError(message.type, "validateAndProcessRuntimeMessage" /* codePath */, message);
|
|
1833
1877
|
this.closeFn(error);
|
|
@@ -1845,7 +1889,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1845
1889
|
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1846
1890
|
// put it in a pending queue and delay finalization.
|
|
1847
1891
|
if (this._idCompressor === undefined) {
|
|
1848
|
-
assert(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1892
|
+
assert(this.sessionSchema.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1849
1893
|
this.pendingIdCompressorOps.push(range);
|
|
1850
1894
|
}
|
|
1851
1895
|
else {
|
|
@@ -1879,7 +1923,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1879
1923
|
* Updates signal telemetry including emitting telemetry events.
|
|
1880
1924
|
*/
|
|
1881
1925
|
processSignalForTelemetry(envelope) {
|
|
1882
|
-
const { clientBroadcastSignalSequenceNumber } = envelope;
|
|
1926
|
+
const { clientBroadcastSignalSequenceNumber, contents: envelopeContents, address: envelopeAddress, } = envelope;
|
|
1883
1927
|
if (clientBroadcastSignalSequenceNumber === undefined) {
|
|
1884
1928
|
return;
|
|
1885
1929
|
}
|
|
@@ -1917,8 +1961,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1917
1961
|
};
|
|
1918
1962
|
// Only log `contents.type` when address is for container to avoid
|
|
1919
1963
|
// chance that contents type is customer data.
|
|
1920
|
-
if (
|
|
1921
|
-
details.contentsType =
|
|
1964
|
+
if (envelopeAddress === undefined) {
|
|
1965
|
+
details.contentsType = envelopeContents.type; // Type of signal that was received out of order.
|
|
1922
1966
|
}
|
|
1923
1967
|
this.mc.logger.sendTelemetryEvent({
|
|
1924
1968
|
eventName: "SignalOutOfOrder",
|
|
@@ -1999,8 +2043,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1999
2043
|
try {
|
|
2000
2044
|
checkpoint.rollback((message) => this.rollback(message.contents, message.localOpMetadata));
|
|
2001
2045
|
}
|
|
2002
|
-
catch (
|
|
2003
|
-
const error2 = wrapError(
|
|
2046
|
+
catch (error_) {
|
|
2047
|
+
const error2 = wrapError(error_, (message) => {
|
|
2004
2048
|
return DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
|
|
2005
2049
|
});
|
|
2006
2050
|
this.closeFn(error2);
|
|
@@ -2111,8 +2155,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2111
2155
|
case ContainerMessageType.GC: {
|
|
2112
2156
|
return false;
|
|
2113
2157
|
}
|
|
2114
|
-
default:
|
|
2158
|
+
default: {
|
|
2115
2159
|
break;
|
|
2160
|
+
}
|
|
2116
2161
|
}
|
|
2117
2162
|
return true;
|
|
2118
2163
|
}
|
|
@@ -2141,7 +2186,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2141
2186
|
clientBroadcastSignalSequenceNumber;
|
|
2142
2187
|
}
|
|
2143
2188
|
// We should not track the round trip of a new signal in the case we are already tracking one.
|
|
2144
|
-
if (clientBroadcastSignalSequenceNumber %
|
|
2189
|
+
if (clientBroadcastSignalSequenceNumber % defaultTelemetrySignalSampleCount === 1 &&
|
|
2145
2190
|
this._signalTracking.roundTripSignalSequenceNumber === undefined) {
|
|
2146
2191
|
this._signalTracking.signalTimestamp = Date.now();
|
|
2147
2192
|
this._signalTracking.roundTripSignalSequenceNumber =
|
|
@@ -2207,6 +2252,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2207
2252
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
2208
2253
|
return summarizeResult.summary;
|
|
2209
2254
|
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Builds the Summary tree including all the channels and the container state.
|
|
2257
|
+
*
|
|
2258
|
+
* @remarks - Unfortunately, this function is accessed in a non-typesafe way by a legacy first-party partner,
|
|
2259
|
+
* so until we can provide a proper API for their scenario, we need to ensure this function doesn't change.
|
|
2260
|
+
*/
|
|
2210
2261
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
2211
2262
|
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
2212
2263
|
// Wrap data store summaries in .channels subtree.
|
|
@@ -2287,8 +2338,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2287
2338
|
*/
|
|
2288
2339
|
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
2289
2340
|
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
2290
|
-
|
|
2291
|
-
|
|
2341
|
+
return [
|
|
2342
|
+
...this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes),
|
|
2343
|
+
...this.blobManager.deleteSweepReadyNodes(blobManagerRoutes),
|
|
2344
|
+
];
|
|
2292
2345
|
}
|
|
2293
2346
|
/**
|
|
2294
2347
|
* This is called to update objects that are tombstones.
|
|
@@ -2314,10 +2367,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2314
2367
|
* Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
|
|
2315
2368
|
* blob manager.
|
|
2316
2369
|
*/
|
|
2370
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2317
2371
|
getNodeType(nodePath) {
|
|
2318
2372
|
if (isBlobPath(nodePath)) {
|
|
2373
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2319
2374
|
return GCNodeType.Blob;
|
|
2320
2375
|
}
|
|
2376
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2321
2377
|
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
2322
2378
|
}
|
|
2323
2379
|
/**
|
|
@@ -2331,13 +2387,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2331
2387
|
return ["_gcRoot"];
|
|
2332
2388
|
}
|
|
2333
2389
|
switch (this.getNodeType(nodePath)) {
|
|
2334
|
-
|
|
2390
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2391
|
+
case GCNodeType.Blob: {
|
|
2335
2392
|
return [blobManagerBasePath];
|
|
2393
|
+
}
|
|
2394
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2336
2395
|
case GCNodeType.DataStore:
|
|
2337
|
-
|
|
2396
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2397
|
+
case GCNodeType.SubDataStore: {
|
|
2338
2398
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
2339
|
-
|
|
2399
|
+
}
|
|
2400
|
+
default: {
|
|
2340
2401
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
2402
|
+
}
|
|
2341
2403
|
}
|
|
2342
2404
|
}
|
|
2343
2405
|
/**
|
|
@@ -2399,8 +2461,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2399
2461
|
* op processing, updating SummarizerNode state tracking, and garbage collection.
|
|
2400
2462
|
* @param options - options controlling how the summary is generated or submitted
|
|
2401
2463
|
*/
|
|
2464
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2402
2465
|
async submitSummary(options) {
|
|
2403
|
-
const { fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
2466
|
+
const { cancellationToken, fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
2404
2467
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2405
2468
|
// use it for all events logged during this summary.
|
|
2406
2469
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -2484,7 +2547,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2484
2547
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
2485
2548
|
details: {
|
|
2486
2549
|
...startSummaryResult,
|
|
2487
|
-
mismatchNumbers:
|
|
2550
|
+
mismatchNumbers: [...startSummaryResult.mismatchNumbers],
|
|
2488
2551
|
},
|
|
2489
2552
|
});
|
|
2490
2553
|
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
@@ -2504,7 +2567,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2504
2567
|
// summarizer to reconnect in the future.
|
|
2505
2568
|
// Also checking for cancellation is a must as summary process may be abandoned for other reasons,
|
|
2506
2569
|
// like loss of connectivity for main (interactive) client.
|
|
2507
|
-
if (
|
|
2570
|
+
if (cancellationToken.cancelled) {
|
|
2508
2571
|
return { continue: false, error: "disconnected" };
|
|
2509
2572
|
}
|
|
2510
2573
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
@@ -2617,7 +2680,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2617
2680
|
};
|
|
2618
2681
|
let handle;
|
|
2619
2682
|
try {
|
|
2620
|
-
handle = await this.storage.uploadSummaryWithContext(
|
|
2683
|
+
handle = await this.storage.uploadSummaryWithContext(summaryTree, summaryContext);
|
|
2621
2684
|
}
|
|
2622
2685
|
catch (error) {
|
|
2623
2686
|
return {
|
|
@@ -2739,13 +2802,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2739
2802
|
return this.pendingMessagesCount !== 0;
|
|
2740
2803
|
}
|
|
2741
2804
|
updateDocumentDirtyState(dirty) {
|
|
2742
|
-
if (this.attachState
|
|
2743
|
-
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
2744
|
-
}
|
|
2745
|
-
else {
|
|
2805
|
+
if (this.attachState === AttachState.Attached) {
|
|
2746
2806
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
2747
2807
|
assert(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
|
|
2748
2808
|
}
|
|
2809
|
+
else {
|
|
2810
|
+
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
2811
|
+
}
|
|
2749
2812
|
if (this.dirtyContainer === dirty) {
|
|
2750
2813
|
return;
|
|
2751
2814
|
}
|
|
@@ -2807,7 +2870,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2807
2870
|
// on this callback to do actual sending.
|
|
2808
2871
|
const schemaChangeMessage = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2809
2872
|
if (schemaChangeMessage) {
|
|
2810
|
-
this.logger.sendTelemetryEvent({
|
|
2873
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2811
2874
|
eventName: "SchemaChangeProposal",
|
|
2812
2875
|
refSeq: schemaChangeMessage.refSeq,
|
|
2813
2876
|
version: schemaChangeMessage.version,
|
|
@@ -2859,6 +2922,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2859
2922
|
return;
|
|
2860
2923
|
}
|
|
2861
2924
|
this.flushTaskExists = true;
|
|
2925
|
+
// TODO: hoist this out of the function scope to save unnecessary allocations
|
|
2926
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping -- Separate `flush` method already exists in outer scope
|
|
2862
2927
|
const flush = () => {
|
|
2863
2928
|
this.flushTaskExists = false;
|
|
2864
2929
|
try {
|
|
@@ -2869,22 +2934,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2869
2934
|
}
|
|
2870
2935
|
};
|
|
2871
2936
|
switch (this.flushMode) {
|
|
2872
|
-
case FlushMode.TurnBased:
|
|
2937
|
+
case FlushMode.TurnBased: {
|
|
2873
2938
|
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
2874
2939
|
// batch at the end of the turn
|
|
2875
2940
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2876
2941
|
Promise.resolve().then(flush);
|
|
2877
2942
|
break;
|
|
2943
|
+
}
|
|
2878
2944
|
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
2879
|
-
case FlushModeExperimental.Async:
|
|
2945
|
+
case FlushModeExperimental.Async: {
|
|
2880
2946
|
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
2881
2947
|
// batch when all micro-tasks are complete.
|
|
2882
2948
|
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
2883
2949
|
setTimeout(flush, 0);
|
|
2884
2950
|
break;
|
|
2885
|
-
|
|
2951
|
+
}
|
|
2952
|
+
default: {
|
|
2886
2953
|
assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
2887
2954
|
break;
|
|
2955
|
+
}
|
|
2888
2956
|
}
|
|
2889
2957
|
}
|
|
2890
2958
|
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
@@ -2892,10 +2960,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2892
2960
|
assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
2893
2961
|
// System message should not be sent in the middle of the batch.
|
|
2894
2962
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
2895
|
-
|
|
2896
|
-
return this.submitSummaryFn !== undefined
|
|
2897
|
-
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
2898
|
-
: this.submitFn(MessageType.Summarize, contents, false);
|
|
2963
|
+
return this.submitSummaryFn(contents, referenceSequenceNumber);
|
|
2899
2964
|
}
|
|
2900
2965
|
/**
|
|
2901
2966
|
* Throw an error if the runtime is closed. Methods that are expected to potentially
|
|
@@ -2935,15 +3000,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2935
3000
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2936
3001
|
*/
|
|
2937
3002
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2938
|
-
assert(
|
|
3003
|
+
assert(this._summarizer === undefined, 0x8f2 /* Summarizer never reconnects so should never resubmit */);
|
|
2939
3004
|
switch (message.type) {
|
|
2940
3005
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2941
3006
|
case ContainerMessageType.Attach:
|
|
2942
|
-
case ContainerMessageType.Alias:
|
|
3007
|
+
case ContainerMessageType.Alias: {
|
|
2943
3008
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
2944
3009
|
// and trigger resubmission on it.
|
|
2945
3010
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2946
3011
|
break;
|
|
3012
|
+
}
|
|
2947
3013
|
case ContainerMessageType.IdAllocation: {
|
|
2948
3014
|
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
2949
3015
|
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
@@ -2954,20 +3020,24 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2954
3020
|
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
2955
3021
|
break;
|
|
2956
3022
|
}
|
|
2957
|
-
case ContainerMessageType.BlobAttach:
|
|
3023
|
+
case ContainerMessageType.BlobAttach: {
|
|
2958
3024
|
this.blobManager.reSubmit(opMetadata);
|
|
2959
3025
|
break;
|
|
2960
|
-
|
|
3026
|
+
}
|
|
3027
|
+
case ContainerMessageType.Rejoin: {
|
|
2961
3028
|
this.submit(message);
|
|
2962
3029
|
break;
|
|
2963
|
-
|
|
3030
|
+
}
|
|
3031
|
+
case ContainerMessageType.GC: {
|
|
2964
3032
|
this.submit(message);
|
|
2965
3033
|
break;
|
|
2966
|
-
|
|
3034
|
+
}
|
|
3035
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
2967
3036
|
// There is no need to resend this message. Document schema controller will properly resend it again (if needed)
|
|
2968
3037
|
// on a first occasion (any ops sent after reconnect). There is a good chance, though, that it will not want to
|
|
2969
3038
|
// send any ops, as some other client already changed schema.
|
|
2970
3039
|
break;
|
|
3040
|
+
}
|
|
2971
3041
|
default: {
|
|
2972
3042
|
const error = getUnknownMessageTypeError(message.type, "reSubmitCore" /* codePath */);
|
|
2973
3043
|
this.closeFn(error);
|
|
@@ -2979,18 +3049,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2979
3049
|
// Need to parse from string for back-compat
|
|
2980
3050
|
const { type, contents } = this.parseLocalOpContent(content);
|
|
2981
3051
|
switch (type) {
|
|
2982
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
3052
|
+
case ContainerMessageType.FluidDataStoreOp: {
|
|
2983
3053
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
2984
3054
|
// and trigger rollback on it.
|
|
2985
3055
|
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
2986
3056
|
break;
|
|
2987
|
-
|
|
3057
|
+
}
|
|
3058
|
+
default: {
|
|
2988
3059
|
throw new Error(`Can't rollback ${type}`);
|
|
3060
|
+
}
|
|
2989
3061
|
}
|
|
2990
3062
|
}
|
|
2991
3063
|
/**
|
|
2992
3064
|
* Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck
|
|
2993
3065
|
*/
|
|
3066
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2994
3067
|
async refreshLatestSummaryAck(options) {
|
|
2995
3068
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2996
3069
|
// proposalHandle is always passed from RunningSummarizer.
|
|
@@ -3060,15 +3133,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
3060
3133
|
snapshotTree = snapshot.snapshotTree;
|
|
3061
3134
|
}
|
|
3062
3135
|
else {
|
|
3063
|
-
const versions = await this.storage.getVersions(
|
|
3136
|
+
const versions = await this.storage.getVersions(
|
|
3137
|
+
// eslint-disable-next-line unicorn/no-null
|
|
3138
|
+
null, 1, scenarioName, FetchSource.noCache);
|
|
3064
3139
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
3065
3140
|
snapshotTree = await this.storage.getSnapshotTree(versions[0]);
|
|
3066
3141
|
assert(!!snapshotTree, 0x138 /* "Failed to get snapshot from storage" */);
|
|
3067
3142
|
props.snapshotVersion = versions[0].id;
|
|
3068
3143
|
}
|
|
3069
3144
|
props.getSnapshotDuration = trace.trace().duration;
|
|
3070
|
-
const
|
|
3071
|
-
const snapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
3145
|
+
const snapshotRefSeq = await seqFromTree(snapshotTree, this.readAndParseBlob);
|
|
3072
3146
|
props.snapshotRefSeq = snapshotRefSeq;
|
|
3073
3147
|
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
3074
3148
|
perfEvent.end({ details: props });
|
|
@@ -3089,7 +3163,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
3089
3163
|
if (this._orderSequentiallyCalls !== 0) {
|
|
3090
3164
|
throw new UsageError("can't get state during orderSequentially");
|
|
3091
3165
|
}
|
|
3092
|
-
this.imminentClosure
|
|
3166
|
+
this.imminentClosure ||= props?.notifyImminentClosure ?? false;
|
|
3093
3167
|
const getSyncState = (pendingAttachmentBlobs) => {
|
|
3094
3168
|
const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
|
|
3095
3169
|
const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
|
|
@@ -3121,32 +3195,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
3121
3195
|
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) => logAndReturnPendingState(event, getSyncState()));
|
|
3122
3196
|
}
|
|
3123
3197
|
summarizeOnDemand(options) {
|
|
3124
|
-
if (this.
|
|
3125
|
-
return this.
|
|
3126
|
-
}
|
|
3127
|
-
else if (this.summaryManager !== undefined) {
|
|
3128
|
-
return this.summaryManager.summarizeOnDemand(options);
|
|
3198
|
+
if (this._summarizer !== undefined) {
|
|
3199
|
+
return this._summarizer.summarizeOnDemand(options);
|
|
3129
3200
|
}
|
|
3130
|
-
else {
|
|
3201
|
+
else if (this.summaryManager === undefined) {
|
|
3131
3202
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3132
3203
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
3133
3204
|
// because it is a misuse of the API rather than an expected failure.
|
|
3134
3205
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3135
3206
|
}
|
|
3207
|
+
else {
|
|
3208
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
3209
|
+
}
|
|
3136
3210
|
}
|
|
3137
3211
|
enqueueSummarize(options) {
|
|
3138
|
-
if (this.
|
|
3139
|
-
return this.
|
|
3140
|
-
}
|
|
3141
|
-
else if (this.summaryManager !== undefined) {
|
|
3142
|
-
return this.summaryManager.enqueueSummarize(options);
|
|
3212
|
+
if (this._summarizer !== undefined) {
|
|
3213
|
+
return this._summarizer.enqueueSummarize(options);
|
|
3143
3214
|
}
|
|
3144
|
-
else {
|
|
3215
|
+
else if (this.summaryManager === undefined) {
|
|
3145
3216
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3146
3217
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
3147
3218
|
// because it is a misuse of the API rather than an expected failure.
|
|
3148
3219
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3149
3220
|
}
|
|
3221
|
+
else {
|
|
3222
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
3223
|
+
}
|
|
3150
3224
|
}
|
|
3151
3225
|
/**
|
|
3152
3226
|
* Forms a function that will create and retrieve a Summarizer.
|