@fluidframework/container-runtime 2.20.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +36 -6
- package/CHANGELOG.md +38 -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.map +1 -1
- package/dist/blobManager/blobManager.js +14 -11
- 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 +264 -194
- 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.map +1 -1
- package/lib/blobManager/blobManager.js +14 -11
- 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 +271 -196
- 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 +21 -43
- package/src/batchTracker.ts +3 -3
- package/src/blobManager/blobManager.ts +16 -14
- package/src/blobManager/blobManagerSnapSum.ts +8 -8
- package/src/channelCollection.ts +63 -44
- package/src/connectionTelemetry.ts +12 -6
- package/src/containerRuntime.ts +306 -235
- 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
|
|
@@ -891,14 +916,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
891
916
|
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
892
917
|
closeContainer: (error) => this.closeFn(error),
|
|
893
918
|
});
|
|
894
|
-
this.deltaScheduler = new DeltaScheduler(this.innerDeltaManager, this, createChildLogger({ logger: this.
|
|
895
|
-
this.inboundBatchAggregator = new InboundBatchAggregator(this.innerDeltaManager, () => this.clientId, createChildLogger({ logger: this.
|
|
919
|
+
this.deltaScheduler = new DeltaScheduler(this.innerDeltaManager, this, createChildLogger({ logger: this.baseLogger, namespace: "DeltaScheduler" }));
|
|
920
|
+
this.inboundBatchAggregator = new InboundBatchAggregator(this.innerDeltaManager, () => this.clientId, createChildLogger({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }));
|
|
896
921
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
897
|
-
const legacySendBatchFn = makeLegacySendBatchFn(
|
|
922
|
+
const legacySendBatchFn = makeLegacySendBatchFn(submitFn, this.innerDeltaManager);
|
|
898
923
|
this.outbox = new Outbox({
|
|
899
924
|
shouldSend: () => this.canSendOps(),
|
|
900
925
|
pendingStateManager: this.pendingStateManager,
|
|
901
|
-
submitBatchFn
|
|
926
|
+
submitBatchFn,
|
|
902
927
|
legacySendBatchFn,
|
|
903
928
|
compressor: new OpCompressor(this.mc.logger),
|
|
904
929
|
splitter: opSplitter,
|
|
@@ -945,7 +970,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
945
970
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
946
971
|
this.closeSummarizerDelayMs =
|
|
947
972
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
948
|
-
|
|
973
|
+
const summaryCollection = new SummaryCollection(this.deltaManager, this.baseLogger);
|
|
949
974
|
this.dirtyContainer =
|
|
950
975
|
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
951
976
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
@@ -954,14 +979,17 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
954
979
|
}
|
|
955
980
|
else {
|
|
956
981
|
const orderedClientLogger = createChildLogger({
|
|
957
|
-
logger: this.
|
|
982
|
+
logger: this.baseLogger,
|
|
958
983
|
namespace: "OrderedClientElection",
|
|
959
984
|
});
|
|
960
985
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
961
986
|
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
|
-
|
|
987
|
+
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary);
|
|
988
|
+
if (isSummarizerClient) {
|
|
989
|
+
// eslint-disable-next-line import/no-deprecated
|
|
990
|
+
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, summaryCollection,
|
|
991
|
+
// eslint-disable-next-line import/no-deprecated
|
|
992
|
+
async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
965
993
|
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
966
994
|
// information. The proxy delta manager would always return false for summarizer client.
|
|
967
995
|
() => this.innerDeltaManager.active));
|
|
@@ -970,48 +998,49 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
970
998
|
// Only create a SummaryManager and SummarizerClientElection
|
|
971
999
|
// if summaries are enabled and we are not the summarizer client.
|
|
972
1000
|
const defaultAction = () => {
|
|
973
|
-
if (
|
|
1001
|
+
if (summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
974
1002
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
975
1003
|
// unregister default to no log on every op after falling behind
|
|
976
1004
|
// and register summary ack handler to re-register this handler
|
|
977
1005
|
// after successful summary
|
|
978
|
-
|
|
1006
|
+
summaryCollection.once(MessageType.SummaryAck, () => {
|
|
979
1007
|
this.mc.logger.sendTelemetryEvent({
|
|
980
1008
|
eventName: "SummaryStatus:CaughtUp",
|
|
981
1009
|
});
|
|
982
1010
|
// we've caught up, so re-register the default action to monitor for
|
|
983
1011
|
// falling behind, and unregister ourself
|
|
984
|
-
|
|
1012
|
+
summaryCollection.on("default", defaultAction);
|
|
985
1013
|
});
|
|
986
|
-
|
|
1014
|
+
summaryCollection.off("default", defaultAction);
|
|
987
1015
|
}
|
|
988
1016
|
};
|
|
989
|
-
|
|
1017
|
+
summaryCollection.on("default", defaultAction);
|
|
990
1018
|
// Create the SummaryManager and mark the initial state
|
|
991
1019
|
this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
992
|
-
|
|
1020
|
+
summaryCollection, this.baseLogger, this.formCreateSummarizerFn(loader), new Throttler(60 * 1000, // 60 sec delay window
|
|
993
1021
|
30 * 1000, // 30 sec max delay
|
|
994
1022
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
995
1023
|
formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
|
|
996
|
-
initialDelayMs:
|
|
1024
|
+
initialDelayMs: initialSummarizerDelayMs,
|
|
997
1025
|
});
|
|
998
1026
|
// Forward events from SummaryManager
|
|
999
|
-
[
|
|
1027
|
+
for (const eventName of [
|
|
1000
1028
|
"summarize",
|
|
1001
1029
|
"summarizeAllAttemptsFailed",
|
|
1002
1030
|
"summarizerStop",
|
|
1003
1031
|
"summarizerStart",
|
|
1004
1032
|
"summarizerStartupFailed",
|
|
1005
|
-
]
|
|
1033
|
+
]) {
|
|
1006
1034
|
this.summaryManager?.on(eventName, (...args) => {
|
|
1007
1035
|
this.emit(eventName, ...args);
|
|
1008
1036
|
});
|
|
1009
|
-
}
|
|
1037
|
+
}
|
|
1010
1038
|
this.summaryManager.start();
|
|
1011
1039
|
}
|
|
1012
1040
|
}
|
|
1013
1041
|
// logging hardware telemetry
|
|
1014
|
-
this.
|
|
1042
|
+
this.baseLogger.send({
|
|
1043
|
+
category: "generic",
|
|
1015
1044
|
eventName: "DeviceSpec",
|
|
1016
1045
|
...getDeviceSpec(),
|
|
1017
1046
|
});
|
|
@@ -1023,13 +1052,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1023
1052
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
1024
1053
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
1025
1054
|
gcVersion: metadata?.gcFeature,
|
|
1026
|
-
options: JSON.stringify(
|
|
1055
|
+
options: JSON.stringify(baseRuntimeOptions),
|
|
1027
1056
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
1028
|
-
idCompressorMode: this.idCompressorMode,
|
|
1057
|
+
idCompressorMode: this.sessionSchema.idCompressorMode,
|
|
1029
1058
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
1030
1059
|
featureGates: JSON.stringify({
|
|
1031
1060
|
...featureGatesForTelemetry,
|
|
1032
|
-
disableAttachReorder: this.disableAttachReorder,
|
|
1033
1061
|
disablePartialFlush,
|
|
1034
1062
|
closeSummarizerDelayOverride,
|
|
1035
1063
|
}),
|
|
@@ -1037,11 +1065,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1037
1065
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1038
1066
|
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
1039
1067
|
});
|
|
1040
|
-
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.
|
|
1041
|
-
BindBatchTracker(this, this.
|
|
1068
|
+
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.baseLogger);
|
|
1069
|
+
BindBatchTracker(this, this.baseLogger);
|
|
1042
1070
|
this.entryPoint = new LazyPromise(async () => {
|
|
1043
|
-
if (this.
|
|
1044
|
-
assert(this._summarizer !== undefined, 0x5bf /* Summarizer object is undefined in a summarizer client */);
|
|
1071
|
+
if (this._summarizer !== undefined) {
|
|
1045
1072
|
return this._summarizer;
|
|
1046
1073
|
}
|
|
1047
1074
|
return provideEntryPoint(this);
|
|
@@ -1050,8 +1077,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1050
1077
|
// saved state, i.e. all the ops marked by Loader layer sa savedOp === true.
|
|
1051
1078
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
1052
1079
|
}
|
|
1080
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1053
1081
|
onSchemaChange(schema) {
|
|
1054
|
-
this.logger.sendTelemetryEvent({
|
|
1082
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1055
1083
|
eventName: "SchemaChangeAccept",
|
|
1056
1084
|
sessionRuntimeSchema: JSON.stringify(schema),
|
|
1057
1085
|
});
|
|
@@ -1086,8 +1114,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1086
1114
|
* Initializes the state from the base snapshot this container runtime loaded from.
|
|
1087
1115
|
*/
|
|
1088
1116
|
async initializeBaseState() {
|
|
1089
|
-
if (this.idCompressorMode === "on" ||
|
|
1090
|
-
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
1117
|
+
if (this.sessionSchema.idCompressorMode === "on" ||
|
|
1118
|
+
(this.sessionSchema.idCompressorMode === "delayed" && this.connected)) {
|
|
1091
1119
|
this._idCompressor = await this.createIdCompressor();
|
|
1092
1120
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
1093
1121
|
assert(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
@@ -1130,7 +1158,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1130
1158
|
// Lookup up in the cache, if not present then make the network call as multiple datastores could
|
|
1131
1159
|
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
1132
1160
|
// any request, then cache that as same group could be requested in future too.
|
|
1133
|
-
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(), async () => {
|
|
1161
|
+
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(sortedLoadingGroupIds.join(","), async () => {
|
|
1134
1162
|
assert(this.storage.getSnapshot !== undefined, 0x8ee /* getSnapshot api should be defined if used */);
|
|
1135
1163
|
loadedFromCache = false;
|
|
1136
1164
|
return this.storage.getSnapshot({
|
|
@@ -1139,7 +1167,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1139
1167
|
loadingGroupIds: sortedLoadingGroupIds,
|
|
1140
1168
|
});
|
|
1141
1169
|
});
|
|
1142
|
-
this.logger.sendTelemetryEvent({
|
|
1170
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1143
1171
|
eventName: "GroupIdSnapshotFetched",
|
|
1144
1172
|
details: JSON.stringify({
|
|
1145
1173
|
fromCache: loadedFromCache,
|
|
@@ -1169,7 +1197,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1169
1197
|
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
1170
1198
|
// the summarizer state is not up to date.
|
|
1171
1199
|
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
1172
|
-
if (this.
|
|
1200
|
+
if (this._summarizer !== undefined) {
|
|
1173
1201
|
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
1174
1202
|
}
|
|
1175
1203
|
// We want to catchup from sequenceNumber to targetSequenceNumber
|
|
@@ -1231,7 +1259,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1231
1259
|
return {
|
|
1232
1260
|
status: 200,
|
|
1233
1261
|
mimeType: "fluid/object",
|
|
1234
|
-
value: this.
|
|
1262
|
+
value: this._summarizer,
|
|
1235
1263
|
};
|
|
1236
1264
|
}
|
|
1237
1265
|
return create404Response(request);
|
|
@@ -1297,6 +1325,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1297
1325
|
const documentSchema = this.documentsSchemaController.summarizeDocumentSchema(this.deltaManager.lastSequenceNumber);
|
|
1298
1326
|
// Is document schema explicit control on?
|
|
1299
1327
|
const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
|
|
1328
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1300
1329
|
const metadata = {
|
|
1301
1330
|
...this.createContainerMetadata,
|
|
1302
1331
|
// Increment the summary number for the next summary that will be generated.
|
|
@@ -1310,7 +1339,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1310
1339
|
// last message's sequence number.
|
|
1311
1340
|
// See also lastMessageFromMetadata()
|
|
1312
1341
|
message: explicitSchemaControl
|
|
1313
|
-
?
|
|
1342
|
+
? // eslint-disable-next-line import/no-deprecated
|
|
1343
|
+
{ sequenceNumber: -1 }
|
|
1314
1344
|
: message,
|
|
1315
1345
|
lastMessage: explicitSchemaControl ? message : undefined,
|
|
1316
1346
|
documentSchema,
|
|
@@ -1426,9 +1456,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1426
1456
|
switch (opContents.type) {
|
|
1427
1457
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1428
1458
|
case ContainerMessageType.Attach:
|
|
1429
|
-
case ContainerMessageType.Alias:
|
|
1459
|
+
case ContainerMessageType.Alias: {
|
|
1430
1460
|
return this.channelCollection.applyStashedOp(opContents);
|
|
1431
|
-
|
|
1461
|
+
}
|
|
1462
|
+
case ContainerMessageType.IdAllocation: {
|
|
1432
1463
|
// IDs allocation ops in stashed state are ignored because the tip state of the compressor
|
|
1433
1464
|
// is serialized into the pending state. This is done because generation of new IDs during
|
|
1434
1465
|
// stashed op application (or, later, resubmit) must generate new IDs and if the compressor
|
|
@@ -1438,17 +1469,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1438
1469
|
// and the runtime could filter out all ID allocation ops from the stashed state and apply them
|
|
1439
1470
|
// before applying the rest of the stashed ops. This would accomplish the same thing but with
|
|
1440
1471
|
// better performance in future incremental stashed state creation.
|
|
1441
|
-
assert(this.idCompressorMode !== undefined, 0x8f1 /* ID compressor should be in use */);
|
|
1472
|
+
assert(this.sessionSchema.idCompressorMode !== undefined, 0x8f1 /* ID compressor should be in use */);
|
|
1442
1473
|
return;
|
|
1443
|
-
|
|
1474
|
+
}
|
|
1475
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
1444
1476
|
return;
|
|
1445
|
-
|
|
1477
|
+
}
|
|
1478
|
+
case ContainerMessageType.BlobAttach: {
|
|
1446
1479
|
return;
|
|
1447
|
-
|
|
1480
|
+
}
|
|
1481
|
+
case ContainerMessageType.Rejoin: {
|
|
1448
1482
|
throw new Error("rejoin not expected here");
|
|
1449
|
-
|
|
1483
|
+
}
|
|
1484
|
+
case ContainerMessageType.GC: {
|
|
1450
1485
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
1451
1486
|
throw new LoggingError("GC op not expected to be stashed in summarizer");
|
|
1487
|
+
}
|
|
1452
1488
|
default: {
|
|
1453
1489
|
const error = getUnknownMessageTypeError(opContents.type, "applyStashedOp" /* codePath */);
|
|
1454
1490
|
this.closeFn(error);
|
|
@@ -1458,7 +1494,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1458
1494
|
}
|
|
1459
1495
|
async loadIdCompressor() {
|
|
1460
1496
|
if (this._idCompressor === undefined &&
|
|
1461
|
-
this.idCompressorMode !== undefined &&
|
|
1497
|
+
this.sessionSchema.idCompressorMode !== undefined &&
|
|
1462
1498
|
this._loadIdCompressor === undefined) {
|
|
1463
1499
|
this._loadIdCompressor = this.createIdCompressor()
|
|
1464
1500
|
.then((compressor) => {
|
|
@@ -1472,7 +1508,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1472
1508
|
this._idCompressor = compressor;
|
|
1473
1509
|
})
|
|
1474
1510
|
.catch((error) => {
|
|
1475
|
-
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1511
|
+
this.mc.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
1476
1512
|
throw error;
|
|
1477
1513
|
});
|
|
1478
1514
|
}
|
|
@@ -1483,7 +1519,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1483
1519
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
1484
1520
|
assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
1485
1521
|
assert(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
|
|
1486
|
-
if (connected && this.idCompressorMode === "delayed") {
|
|
1522
|
+
if (connected && this.sessionSchema.idCompressorMode === "delayed") {
|
|
1487
1523
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1488
1524
|
this.loadIdCompressor();
|
|
1489
1525
|
}
|
|
@@ -1572,7 +1608,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1572
1608
|
// or something different, like a system message.
|
|
1573
1609
|
const hasModernRuntimeMessageEnvelope = messageCopy.type === MessageType.Operation;
|
|
1574
1610
|
const savedOp = messageCopy.metadata?.savedOp;
|
|
1575
|
-
const logLegacyCase = getSingleUseLegacyLogCallback(this.logger, messageCopy.type);
|
|
1611
|
+
const logLegacyCase = getSingleUseLegacyLogCallback(this.mc.logger, messageCopy.type);
|
|
1576
1612
|
let runtimeBatch = hasModernRuntimeMessageEnvelope || isUnpackedRuntimeMessage(messageCopy);
|
|
1577
1613
|
if (runtimeBatch) {
|
|
1578
1614
|
// We expect runtime messages to have JSON contents - deserialize it in place.
|
|
@@ -1674,11 +1710,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1674
1710
|
let error;
|
|
1675
1711
|
try {
|
|
1676
1712
|
if (!runtimeBatch) {
|
|
1677
|
-
|
|
1713
|
+
for (const { message } of messagesWithMetadata) {
|
|
1678
1714
|
this.ensureNoDataModelChanges(() => {
|
|
1679
1715
|
this.observeNonRuntimeMessage(message);
|
|
1680
1716
|
});
|
|
1681
|
-
}
|
|
1717
|
+
}
|
|
1682
1718
|
return;
|
|
1683
1719
|
}
|
|
1684
1720
|
// Updates a message's minimum sequence number to the minimum sequence number that container
|
|
@@ -1746,8 +1782,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1746
1782
|
this.emit("op", message, true /* runtimeMessage */);
|
|
1747
1783
|
}
|
|
1748
1784
|
}
|
|
1749
|
-
catch (
|
|
1750
|
-
error =
|
|
1785
|
+
catch (error_) {
|
|
1786
|
+
error = error_;
|
|
1751
1787
|
throw error;
|
|
1752
1788
|
}
|
|
1753
1789
|
finally {
|
|
@@ -1804,30 +1840,39 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1804
1840
|
switch (message.type) {
|
|
1805
1841
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1806
1842
|
case ContainerMessageType.Attach:
|
|
1807
|
-
case ContainerMessageType.Alias:
|
|
1843
|
+
case ContainerMessageType.Alias: {
|
|
1808
1844
|
// Remove the metadata from the message before sending it to the channel collection. The metadata
|
|
1809
1845
|
// is added by the container runtime and is not part of the message that the channel collection and
|
|
1810
1846
|
// layers below it expect.
|
|
1811
1847
|
this.channelCollection.processMessages({ envelope: message, messagesContent, local });
|
|
1812
1848
|
break;
|
|
1813
|
-
|
|
1849
|
+
}
|
|
1850
|
+
case ContainerMessageType.BlobAttach: {
|
|
1814
1851
|
this.blobManager.processBlobAttachMessage(message, local);
|
|
1815
1852
|
break;
|
|
1816
|
-
|
|
1853
|
+
}
|
|
1854
|
+
case ContainerMessageType.IdAllocation: {
|
|
1817
1855
|
this.processIdCompressorMessages(contents, savedOp);
|
|
1818
1856
|
break;
|
|
1819
|
-
|
|
1857
|
+
}
|
|
1858
|
+
case ContainerMessageType.GC: {
|
|
1820
1859
|
this.garbageCollector.processMessages(contents, message.timestamp, local);
|
|
1821
1860
|
break;
|
|
1822
|
-
|
|
1861
|
+
}
|
|
1862
|
+
case ContainerMessageType.ChunkedOp: {
|
|
1823
1863
|
// From observability POV, we should not expose the rest of the system (including "op" events on object) to these messages.
|
|
1824
1864
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
1825
1865
|
assert(false, 0x93d /* should not even get here */);
|
|
1826
|
-
|
|
1866
|
+
}
|
|
1867
|
+
case ContainerMessageType.Rejoin: {
|
|
1827
1868
|
break;
|
|
1828
|
-
|
|
1829
|
-
|
|
1869
|
+
}
|
|
1870
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
1871
|
+
this.documentsSchemaController.processDocumentSchemaMessages(
|
|
1872
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1873
|
+
contents, local, message.sequenceNumber);
|
|
1830
1874
|
break;
|
|
1875
|
+
}
|
|
1831
1876
|
default: {
|
|
1832
1877
|
const error = getUnknownMessageTypeError(message.type, "validateAndProcessRuntimeMessage" /* codePath */, message);
|
|
1833
1878
|
this.closeFn(error);
|
|
@@ -1845,7 +1890,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1845
1890
|
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1846
1891
|
// put it in a pending queue and delay finalization.
|
|
1847
1892
|
if (this._idCompressor === undefined) {
|
|
1848
|
-
assert(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1893
|
+
assert(this.sessionSchema.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1849
1894
|
this.pendingIdCompressorOps.push(range);
|
|
1850
1895
|
}
|
|
1851
1896
|
else {
|
|
@@ -1879,7 +1924,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1879
1924
|
* Updates signal telemetry including emitting telemetry events.
|
|
1880
1925
|
*/
|
|
1881
1926
|
processSignalForTelemetry(envelope) {
|
|
1882
|
-
const { clientBroadcastSignalSequenceNumber } = envelope;
|
|
1927
|
+
const { clientBroadcastSignalSequenceNumber, contents: envelopeContents, address: envelopeAddress, } = envelope;
|
|
1883
1928
|
if (clientBroadcastSignalSequenceNumber === undefined) {
|
|
1884
1929
|
return;
|
|
1885
1930
|
}
|
|
@@ -1917,8 +1962,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1917
1962
|
};
|
|
1918
1963
|
// Only log `contents.type` when address is for container to avoid
|
|
1919
1964
|
// chance that contents type is customer data.
|
|
1920
|
-
if (
|
|
1921
|
-
details.contentsType =
|
|
1965
|
+
if (envelopeAddress === undefined) {
|
|
1966
|
+
details.contentsType = envelopeContents.type; // Type of signal that was received out of order.
|
|
1922
1967
|
}
|
|
1923
1968
|
this.mc.logger.sendTelemetryEvent({
|
|
1924
1969
|
eventName: "SignalOutOfOrder",
|
|
@@ -1999,8 +2044,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1999
2044
|
try {
|
|
2000
2045
|
checkpoint.rollback((message) => this.rollback(message.contents, message.localOpMetadata));
|
|
2001
2046
|
}
|
|
2002
|
-
catch (
|
|
2003
|
-
const error2 = wrapError(
|
|
2047
|
+
catch (error_) {
|
|
2048
|
+
const error2 = wrapError(error_, (message) => {
|
|
2004
2049
|
return DataProcessingError.create(`RollbackError: ${message}`, "checkpointRollback", undefined);
|
|
2005
2050
|
});
|
|
2006
2051
|
this.closeFn(error2);
|
|
@@ -2111,8 +2156,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2111
2156
|
case ContainerMessageType.GC: {
|
|
2112
2157
|
return false;
|
|
2113
2158
|
}
|
|
2114
|
-
default:
|
|
2159
|
+
default: {
|
|
2115
2160
|
break;
|
|
2161
|
+
}
|
|
2116
2162
|
}
|
|
2117
2163
|
return true;
|
|
2118
2164
|
}
|
|
@@ -2141,7 +2187,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2141
2187
|
clientBroadcastSignalSequenceNumber;
|
|
2142
2188
|
}
|
|
2143
2189
|
// We should not track the round trip of a new signal in the case we are already tracking one.
|
|
2144
|
-
if (clientBroadcastSignalSequenceNumber %
|
|
2190
|
+
if (clientBroadcastSignalSequenceNumber % defaultTelemetrySignalSampleCount === 1 &&
|
|
2145
2191
|
this._signalTracking.roundTripSignalSequenceNumber === undefined) {
|
|
2146
2192
|
this._signalTracking.signalTimestamp = Date.now();
|
|
2147
2193
|
this._signalTracking.roundTripSignalSequenceNumber =
|
|
@@ -2207,6 +2253,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2207
2253
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
2208
2254
|
return summarizeResult.summary;
|
|
2209
2255
|
}
|
|
2256
|
+
/**
|
|
2257
|
+
* Builds the Summary tree including all the channels and the container state.
|
|
2258
|
+
*
|
|
2259
|
+
* @remarks - Unfortunately, this function is accessed in a non-typesafe way by a legacy first-party partner,
|
|
2260
|
+
* so until we can provide a proper API for their scenario, we need to ensure this function doesn't change.
|
|
2261
|
+
*/
|
|
2210
2262
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
2211
2263
|
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
2212
2264
|
// Wrap data store summaries in .channels subtree.
|
|
@@ -2287,8 +2339,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2287
2339
|
*/
|
|
2288
2340
|
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
2289
2341
|
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
2290
|
-
|
|
2291
|
-
|
|
2342
|
+
return [
|
|
2343
|
+
...this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes),
|
|
2344
|
+
...this.blobManager.deleteSweepReadyNodes(blobManagerRoutes),
|
|
2345
|
+
];
|
|
2292
2346
|
}
|
|
2293
2347
|
/**
|
|
2294
2348
|
* This is called to update objects that are tombstones.
|
|
@@ -2314,10 +2368,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2314
2368
|
* Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
|
|
2315
2369
|
* blob manager.
|
|
2316
2370
|
*/
|
|
2371
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2317
2372
|
getNodeType(nodePath) {
|
|
2318
2373
|
if (isBlobPath(nodePath)) {
|
|
2374
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2319
2375
|
return GCNodeType.Blob;
|
|
2320
2376
|
}
|
|
2377
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2321
2378
|
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
2322
2379
|
}
|
|
2323
2380
|
/**
|
|
@@ -2331,13 +2388,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2331
2388
|
return ["_gcRoot"];
|
|
2332
2389
|
}
|
|
2333
2390
|
switch (this.getNodeType(nodePath)) {
|
|
2334
|
-
|
|
2391
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2392
|
+
case GCNodeType.Blob: {
|
|
2335
2393
|
return [blobManagerBasePath];
|
|
2394
|
+
}
|
|
2395
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2336
2396
|
case GCNodeType.DataStore:
|
|
2337
|
-
|
|
2397
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2398
|
+
case GCNodeType.SubDataStore: {
|
|
2338
2399
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
2339
|
-
|
|
2400
|
+
}
|
|
2401
|
+
default: {
|
|
2340
2402
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
2403
|
+
}
|
|
2341
2404
|
}
|
|
2342
2405
|
}
|
|
2343
2406
|
/**
|
|
@@ -2399,8 +2462,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2399
2462
|
* op processing, updating SummarizerNode state tracking, and garbage collection.
|
|
2400
2463
|
* @param options - options controlling how the summary is generated or submitted
|
|
2401
2464
|
*/
|
|
2465
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2402
2466
|
async submitSummary(options) {
|
|
2403
|
-
const { fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
2467
|
+
const { cancellationToken, fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
2404
2468
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2405
2469
|
// use it for all events logged during this summary.
|
|
2406
2470
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -2484,7 +2548,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2484
2548
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
2485
2549
|
details: {
|
|
2486
2550
|
...startSummaryResult,
|
|
2487
|
-
mismatchNumbers:
|
|
2551
|
+
mismatchNumbers: [...startSummaryResult.mismatchNumbers],
|
|
2488
2552
|
},
|
|
2489
2553
|
});
|
|
2490
2554
|
if (shouldValidatePreSummaryState && !finalAttempt) {
|
|
@@ -2504,7 +2568,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2504
2568
|
// summarizer to reconnect in the future.
|
|
2505
2569
|
// Also checking for cancellation is a must as summary process may be abandoned for other reasons,
|
|
2506
2570
|
// like loss of connectivity for main (interactive) client.
|
|
2507
|
-
if (
|
|
2571
|
+
if (cancellationToken.cancelled) {
|
|
2508
2572
|
return { continue: false, error: "disconnected" };
|
|
2509
2573
|
}
|
|
2510
2574
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
@@ -2617,7 +2681,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2617
2681
|
};
|
|
2618
2682
|
let handle;
|
|
2619
2683
|
try {
|
|
2620
|
-
handle = await this.storage.uploadSummaryWithContext(
|
|
2684
|
+
handle = await this.storage.uploadSummaryWithContext(summaryTree, summaryContext);
|
|
2621
2685
|
}
|
|
2622
2686
|
catch (error) {
|
|
2623
2687
|
return {
|
|
@@ -2739,13 +2803,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2739
2803
|
return this.pendingMessagesCount !== 0;
|
|
2740
2804
|
}
|
|
2741
2805
|
updateDocumentDirtyState(dirty) {
|
|
2742
|
-
if (this.attachState
|
|
2743
|
-
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
2744
|
-
}
|
|
2745
|
-
else {
|
|
2806
|
+
if (this.attachState === AttachState.Attached) {
|
|
2746
2807
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
2747
2808
|
assert(!dirty || this.hasPendingMessages(), 0x3d3 /* if doc is dirty, there has to be pending ops */);
|
|
2748
2809
|
}
|
|
2810
|
+
else {
|
|
2811
|
+
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
2812
|
+
}
|
|
2749
2813
|
if (this.dirtyContainer === dirty) {
|
|
2750
2814
|
return;
|
|
2751
2815
|
}
|
|
@@ -2807,7 +2871,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2807
2871
|
// on this callback to do actual sending.
|
|
2808
2872
|
const schemaChangeMessage = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2809
2873
|
if (schemaChangeMessage) {
|
|
2810
|
-
this.logger.sendTelemetryEvent({
|
|
2874
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2811
2875
|
eventName: "SchemaChangeProposal",
|
|
2812
2876
|
refSeq: schemaChangeMessage.refSeq,
|
|
2813
2877
|
version: schemaChangeMessage.version,
|
|
@@ -2859,6 +2923,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2859
2923
|
return;
|
|
2860
2924
|
}
|
|
2861
2925
|
this.flushTaskExists = true;
|
|
2926
|
+
// TODO: hoist this out of the function scope to save unnecessary allocations
|
|
2927
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping -- Separate `flush` method already exists in outer scope
|
|
2862
2928
|
const flush = () => {
|
|
2863
2929
|
this.flushTaskExists = false;
|
|
2864
2930
|
try {
|
|
@@ -2869,22 +2935,25 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2869
2935
|
}
|
|
2870
2936
|
};
|
|
2871
2937
|
switch (this.flushMode) {
|
|
2872
|
-
case FlushMode.TurnBased:
|
|
2938
|
+
case FlushMode.TurnBased: {
|
|
2873
2939
|
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
2874
2940
|
// batch at the end of the turn
|
|
2875
2941
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2876
2942
|
Promise.resolve().then(flush);
|
|
2877
2943
|
break;
|
|
2944
|
+
}
|
|
2878
2945
|
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
2879
|
-
case FlushModeExperimental.Async:
|
|
2946
|
+
case FlushModeExperimental.Async: {
|
|
2880
2947
|
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
2881
2948
|
// batch when all micro-tasks are complete.
|
|
2882
2949
|
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
2883
2950
|
setTimeout(flush, 0);
|
|
2884
2951
|
break;
|
|
2885
|
-
|
|
2952
|
+
}
|
|
2953
|
+
default: {
|
|
2886
2954
|
assert(this._orderSequentiallyCalls > 0, 0x587 /* Unreachable unless running under orderSequentially */);
|
|
2887
2955
|
break;
|
|
2956
|
+
}
|
|
2888
2957
|
}
|
|
2889
2958
|
}
|
|
2890
2959
|
submitSummaryMessage(contents, referenceSequenceNumber) {
|
|
@@ -2892,10 +2961,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2892
2961
|
assert(this.connected, 0x133 /* "Container disconnected when trying to submit system message" */);
|
|
2893
2962
|
// System message should not be sent in the middle of the batch.
|
|
2894
2963
|
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);
|
|
2964
|
+
return this.submitSummaryFn(contents, referenceSequenceNumber);
|
|
2899
2965
|
}
|
|
2900
2966
|
/**
|
|
2901
2967
|
* Throw an error if the runtime is closed. Methods that are expected to potentially
|
|
@@ -2935,15 +3001,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2935
3001
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2936
3002
|
*/
|
|
2937
3003
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2938
|
-
assert(
|
|
3004
|
+
assert(this._summarizer === undefined, 0x8f2 /* Summarizer never reconnects so should never resubmit */);
|
|
2939
3005
|
switch (message.type) {
|
|
2940
3006
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2941
3007
|
case ContainerMessageType.Attach:
|
|
2942
|
-
case ContainerMessageType.Alias:
|
|
3008
|
+
case ContainerMessageType.Alias: {
|
|
2943
3009
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
2944
3010
|
// and trigger resubmission on it.
|
|
2945
3011
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2946
3012
|
break;
|
|
3013
|
+
}
|
|
2947
3014
|
case ContainerMessageType.IdAllocation: {
|
|
2948
3015
|
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
2949
3016
|
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
@@ -2954,20 +3021,24 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2954
3021
|
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
2955
3022
|
break;
|
|
2956
3023
|
}
|
|
2957
|
-
case ContainerMessageType.BlobAttach:
|
|
3024
|
+
case ContainerMessageType.BlobAttach: {
|
|
2958
3025
|
this.blobManager.reSubmit(opMetadata);
|
|
2959
3026
|
break;
|
|
2960
|
-
|
|
3027
|
+
}
|
|
3028
|
+
case ContainerMessageType.Rejoin: {
|
|
2961
3029
|
this.submit(message);
|
|
2962
3030
|
break;
|
|
2963
|
-
|
|
3031
|
+
}
|
|
3032
|
+
case ContainerMessageType.GC: {
|
|
2964
3033
|
this.submit(message);
|
|
2965
3034
|
break;
|
|
2966
|
-
|
|
3035
|
+
}
|
|
3036
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
2967
3037
|
// There is no need to resend this message. Document schema controller will properly resend it again (if needed)
|
|
2968
3038
|
// on a first occasion (any ops sent after reconnect). There is a good chance, though, that it will not want to
|
|
2969
3039
|
// send any ops, as some other client already changed schema.
|
|
2970
3040
|
break;
|
|
3041
|
+
}
|
|
2971
3042
|
default: {
|
|
2972
3043
|
const error = getUnknownMessageTypeError(message.type, "reSubmitCore" /* codePath */);
|
|
2973
3044
|
this.closeFn(error);
|
|
@@ -2979,18 +3050,21 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2979
3050
|
// Need to parse from string for back-compat
|
|
2980
3051
|
const { type, contents } = this.parseLocalOpContent(content);
|
|
2981
3052
|
switch (type) {
|
|
2982
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
3053
|
+
case ContainerMessageType.FluidDataStoreOp: {
|
|
2983
3054
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
2984
3055
|
// and trigger rollback on it.
|
|
2985
3056
|
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
2986
3057
|
break;
|
|
2987
|
-
|
|
3058
|
+
}
|
|
3059
|
+
default: {
|
|
2988
3060
|
throw new Error(`Can't rollback ${type}`);
|
|
3061
|
+
}
|
|
2989
3062
|
}
|
|
2990
3063
|
}
|
|
2991
3064
|
/**
|
|
2992
3065
|
* Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck
|
|
2993
3066
|
*/
|
|
3067
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2994
3068
|
async refreshLatestSummaryAck(options) {
|
|
2995
3069
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2996
3070
|
// proposalHandle is always passed from RunningSummarizer.
|
|
@@ -3060,15 +3134,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
3060
3134
|
snapshotTree = snapshot.snapshotTree;
|
|
3061
3135
|
}
|
|
3062
3136
|
else {
|
|
3063
|
-
const versions = await this.storage.getVersions(
|
|
3137
|
+
const versions = await this.storage.getVersions(
|
|
3138
|
+
// eslint-disable-next-line unicorn/no-null
|
|
3139
|
+
null, 1, scenarioName, FetchSource.noCache);
|
|
3064
3140
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
3065
3141
|
snapshotTree = await this.storage.getSnapshotTree(versions[0]);
|
|
3066
3142
|
assert(!!snapshotTree, 0x138 /* "Failed to get snapshot from storage" */);
|
|
3067
3143
|
props.snapshotVersion = versions[0].id;
|
|
3068
3144
|
}
|
|
3069
3145
|
props.getSnapshotDuration = trace.trace().duration;
|
|
3070
|
-
const
|
|
3071
|
-
const snapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
3146
|
+
const snapshotRefSeq = await seqFromTree(snapshotTree, this.readAndParseBlob);
|
|
3072
3147
|
props.snapshotRefSeq = snapshotRefSeq;
|
|
3073
3148
|
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
3074
3149
|
perfEvent.end({ details: props });
|
|
@@ -3121,32 +3196,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
3121
3196
|
: PerformanceEvent.timedExec(this.mc.logger, perfEvent, (event) => logAndReturnPendingState(event, getSyncState()));
|
|
3122
3197
|
}
|
|
3123
3198
|
summarizeOnDemand(options) {
|
|
3124
|
-
if (this.
|
|
3125
|
-
return this.
|
|
3126
|
-
}
|
|
3127
|
-
else if (this.summaryManager !== undefined) {
|
|
3128
|
-
return this.summaryManager.summarizeOnDemand(options);
|
|
3199
|
+
if (this._summarizer !== undefined) {
|
|
3200
|
+
return this._summarizer.summarizeOnDemand(options);
|
|
3129
3201
|
}
|
|
3130
|
-
else {
|
|
3202
|
+
else if (this.summaryManager === undefined) {
|
|
3131
3203
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3132
3204
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
3133
3205
|
// because it is a misuse of the API rather than an expected failure.
|
|
3134
3206
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3135
3207
|
}
|
|
3208
|
+
else {
|
|
3209
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
3210
|
+
}
|
|
3136
3211
|
}
|
|
3137
3212
|
enqueueSummarize(options) {
|
|
3138
|
-
if (this.
|
|
3139
|
-
return this.
|
|
3140
|
-
}
|
|
3141
|
-
else if (this.summaryManager !== undefined) {
|
|
3142
|
-
return this.summaryManager.enqueueSummarize(options);
|
|
3213
|
+
if (this._summarizer !== undefined) {
|
|
3214
|
+
return this._summarizer.enqueueSummarize(options);
|
|
3143
3215
|
}
|
|
3144
|
-
else {
|
|
3216
|
+
else if (this.summaryManager === undefined) {
|
|
3145
3217
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
3146
3218
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
3147
3219
|
// because it is a misuse of the API rather than an expected failure.
|
|
3148
3220
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
3149
3221
|
}
|
|
3222
|
+
else {
|
|
3223
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
3224
|
+
}
|
|
3150
3225
|
}
|
|
3151
3226
|
/**
|
|
3152
3227
|
* Forms a function that will create and retrieve a Summarizer.
|