@fluidframework/container-runtime 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.203917
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +119 -0
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.api.md +864 -0
- package/dist/blobManager.d.ts +4 -4
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +55 -71
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +75 -42
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/container-runtime-alpha.d.ts +1742 -0
- package/dist/container-runtime-beta.d.ts +1742 -0
- package/dist/container-runtime-public.d.ts +1742 -0
- package/dist/container-runtime-untrimmed.d.ts +1803 -0
- package/dist/containerHandleContext.js +3 -3
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +88 -98
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +466 -453
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +11 -11
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +2 -4
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +60 -59
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts +3 -0
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +6 -3
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.js +1 -1
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerProxyBase.js +4 -4
- package/dist/deltaManagerProxyBase.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +6 -6
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +23 -24
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +1 -1
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +34 -24
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +10 -7
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
- package/dist/gc/gcSummaryDefinitions.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +2 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +5 -5
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +3 -3
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/gc/index.d.ts +1 -1
- package/dist/gc/index.d.ts.map +1 -1
- package/dist/gc/index.js +3 -3
- package/dist/gc/index.js.map +1 -1
- package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/id-compressor/identifiers.d.ts +3 -3
- package/dist/id-compressor/identifiers.d.ts.map +1 -1
- package/dist/id-compressor/utilities.d.ts +3 -0
- package/dist/id-compressor/utilities.d.ts.map +1 -1
- package/dist/id-compressor/utilities.js +3 -0
- package/dist/id-compressor/utilities.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +137 -0
- package/dist/messageTypes.d.ts.map +1 -0
- package/dist/messageTypes.js +32 -0
- package/dist/messageTypes.js.map +1 -0
- package/dist/opLifecycle/batchManager.js +6 -6
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +7 -3
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +0 -4
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js +3 -3
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -2
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
- 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 +4 -20
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +36 -46
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.js +6 -2
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +7 -4
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +54 -54
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.d.ts +5 -0
- package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +7 -6
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +40 -38
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +2 -0
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +18 -8
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.js +6 -6
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +9 -9
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +8 -8
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +107 -22
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +18 -2
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +23 -21
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +15 -6
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +3 -3
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +2 -2
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +10 -10
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.js +16 -16
- package/dist/throttler.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/blobManager.d.ts +4 -4
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +56 -72
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +76 -43
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.js +3 -3
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +88 -98
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +424 -416
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +11 -11
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +2 -4
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +60 -59
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts +3 -0
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +6 -3
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.js +1 -1
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerProxyBase.js +4 -4
- package/lib/deltaManagerProxyBase.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js +6 -6
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +23 -24
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.js +2 -2
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +34 -24
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +9 -6
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
- package/lib/gc/gcSummaryDefinitions.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +2 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +5 -5
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js +3 -3
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/gc/index.d.ts +1 -1
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/id-compressor/identifiers.d.ts +3 -3
- package/lib/id-compressor/identifiers.d.ts.map +1 -1
- package/lib/id-compressor/utilities.d.ts +3 -0
- package/lib/id-compressor/utilities.d.ts.map +1 -1
- package/lib/id-compressor/utilities.js +3 -0
- package/lib/id-compressor/utilities.js.map +1 -1
- package/lib/index.d.ts +5 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/messageTypes.d.ts +137 -0
- package/lib/messageTypes.d.ts.map +1 -0
- package/lib/messageTypes.js +29 -0
- package/lib/messageTypes.js.map +1 -0
- package/lib/opLifecycle/batchManager.js +6 -6
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +7 -3
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +0 -4
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -2
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +17 -3
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
- 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 +4 -20
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +35 -45
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.js +6 -2
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +7 -4
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +54 -54
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.d.ts +5 -0
- package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +7 -6
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +40 -38
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +2 -0
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +19 -9
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.js +6 -6
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +9 -9
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +8 -8
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +107 -22
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +18 -2
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +23 -21
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +15 -6
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +3 -3
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +2 -2
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +9 -9
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.js +16 -16
- package/lib/throttler.js.map +1 -1
- package/package.json +27 -28
- package/src/blobManager.ts +64 -77
- package/src/connectionTelemetry.ts +97 -52
- package/src/containerRuntime.ts +337 -341
- package/src/dataStore.ts +3 -3
- package/src/dataStoreContext.ts +7 -7
- package/src/dataStoreRegistry.ts +3 -0
- package/src/dataStores.ts +1 -1
- package/src/error.ts +4 -1
- package/src/gc/garbageCollection.ts +12 -11
- package/src/gc/gcConfigs.ts +3 -3
- package/src/gc/gcDefinitions.ts +35 -25
- package/src/gc/gcSummaryDefinitions.ts +1 -1
- package/src/gc/gcTelemetry.ts +6 -5
- package/src/gc/index.ts +2 -2
- package/src/id-compressor/utilities.ts +3 -0
- package/src/index.ts +21 -5
- package/src/messageTypes.ts +228 -0
- package/src/opLifecycle/README.md +93 -68
- package/src/opLifecycle/definitions.ts +5 -1
- package/src/opLifecycle/opDecompressor.ts +0 -8
- package/src/opLifecycle/opGroupingManager.ts +2 -4
- package/src/opLifecycle/opSplitter.ts +2 -2
- package/src/opLifecycle/outbox.ts +3 -0
- package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +31 -52
- package/src/scheduleManager.ts +2 -0
- package/src/summary/orderedClientElection.ts +4 -1
- package/src/summary/runWhileConnectedCoordinator.ts +5 -1
- package/src/summary/runningSummarizer.ts +3 -1
- package/src/summary/summarizer.ts +21 -7
- package/src/summary/summarizerNode/summarizerNode.ts +1 -1
- package/src/summary/summarizerTypes.ts +96 -11
- package/src/summary/summaryCollection.ts +19 -1
- package/src/summary/summaryFormat.ts +11 -1
- package/src/summary/summaryGenerator.ts +3 -3
- package/src/summary/summaryManager.ts +2 -2
- package/src/gc/gcEarlyAdoption.md +0 -145
package/src/containerRuntime.ts
CHANGED
|
@@ -8,9 +8,11 @@ import {
|
|
|
8
8
|
FluidObject,
|
|
9
9
|
IFluidHandle,
|
|
10
10
|
IFluidHandleContext,
|
|
11
|
+
// eslint-disable-next-line import/no-deprecated
|
|
11
12
|
IFluidRouter,
|
|
12
13
|
IRequest,
|
|
13
14
|
IResponse,
|
|
15
|
+
IProvideFluidHandleContext,
|
|
14
16
|
} from "@fluidframework/core-interfaces";
|
|
15
17
|
import {
|
|
16
18
|
IAudience,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
ICriticalContainerError,
|
|
22
24
|
AttachState,
|
|
23
25
|
ILoaderOptions,
|
|
26
|
+
ILoader,
|
|
24
27
|
LoaderHeader,
|
|
25
28
|
} from "@fluidframework/container-definitions";
|
|
26
29
|
import {
|
|
@@ -88,7 +91,6 @@ import {
|
|
|
88
91
|
IIdCompressorCore,
|
|
89
92
|
IdCreationRange,
|
|
90
93
|
IdCreationRangeWithStashedState,
|
|
91
|
-
IAttachMessage,
|
|
92
94
|
} from "@fluidframework/runtime-definitions";
|
|
93
95
|
import {
|
|
94
96
|
addBlobToSummary,
|
|
@@ -98,11 +100,11 @@ import {
|
|
|
98
100
|
create404Response,
|
|
99
101
|
exceptionToResponse,
|
|
100
102
|
GCDataBuilder,
|
|
101
|
-
requestFluidObject,
|
|
102
103
|
seqFromTree,
|
|
103
104
|
calculateStats,
|
|
104
105
|
TelemetryContext,
|
|
105
106
|
ReadAndParseBlob,
|
|
107
|
+
responseToException,
|
|
106
108
|
} from "@fluidframework/runtime-utils";
|
|
107
109
|
import { v4 as uuid } from "uuid";
|
|
108
110
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
@@ -142,7 +144,6 @@ import {
|
|
|
142
144
|
IConnectableRuntime,
|
|
143
145
|
IGeneratedSummaryStats,
|
|
144
146
|
ISubmitSummaryOptions,
|
|
145
|
-
ISummarizer,
|
|
146
147
|
ISummarizerInternalsProvider,
|
|
147
148
|
ISummarizerRuntime,
|
|
148
149
|
IRefreshSummaryAckOptions,
|
|
@@ -155,6 +156,7 @@ import {
|
|
|
155
156
|
EnqueueSummarizeResult,
|
|
156
157
|
ISummarizerEvents,
|
|
157
158
|
IBaseSummarizeResult,
|
|
159
|
+
ISummarizer,
|
|
158
160
|
} from "./summary";
|
|
159
161
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
160
162
|
import {
|
|
@@ -184,92 +186,45 @@ import {
|
|
|
184
186
|
} from "./opLifecycle";
|
|
185
187
|
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
186
188
|
import { IBatchMetadata } from "./metadata";
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Signifies that a blob has been attached and should not be garbage collected by storage
|
|
199
|
-
BlobAttach = "blobAttach",
|
|
200
|
-
|
|
201
|
-
// Ties our new clientId to our old one on reconnect
|
|
202
|
-
Rejoin = "rejoin",
|
|
203
|
-
|
|
204
|
-
// Sets the alias of a root data store
|
|
205
|
-
Alias = "alias",
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
|
|
209
|
-
* the last allocation op was sent.
|
|
210
|
-
* See the [IdCompressor README](./id-compressor/README.md) for more details.
|
|
211
|
-
*/
|
|
212
|
-
IdAllocation = "idAllocation",
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* How should an older client handle an unrecognized remote op type?
|
|
217
|
-
*
|
|
218
|
-
* @internal
|
|
219
|
-
*/
|
|
220
|
-
export type CompatModeBehavior =
|
|
221
|
-
/** Ignore the op. It won't be persisted if this client summarizes */
|
|
222
|
-
| "Ignore"
|
|
223
|
-
/** Fail processing immediately. (The container will close) */
|
|
224
|
-
| "FailToProcess";
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* All the info an older client would need to know how to handle an unrecognized remote op type
|
|
228
|
-
*
|
|
229
|
-
* @internal
|
|
230
|
-
*/
|
|
231
|
-
export interface IContainerRuntimeMessageCompatDetails {
|
|
232
|
-
/** How should an older client handle an unrecognized remote op type? */
|
|
233
|
-
behavior: CompatModeBehavior;
|
|
234
|
-
}
|
|
189
|
+
import {
|
|
190
|
+
ContainerMessageType,
|
|
191
|
+
type InboundSequencedContainerRuntimeMessage,
|
|
192
|
+
type InboundSequencedContainerRuntimeMessageOrSystemMessage,
|
|
193
|
+
type ContainerRuntimeIdAllocationMessage,
|
|
194
|
+
type LocalContainerRuntimeIdAllocationMessage,
|
|
195
|
+
type LocalContainerRuntimeMessage,
|
|
196
|
+
type OutboundContainerRuntimeMessage,
|
|
197
|
+
type UnknownContainerRuntimeMessage,
|
|
198
|
+
} from "./messageTypes";
|
|
235
199
|
|
|
236
200
|
/**
|
|
237
201
|
* Utility to implement compat behaviors given an unknown message type
|
|
238
202
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
239
203
|
*
|
|
240
|
-
* @param _unknownContainerRuntimeMessageType - Typed as
|
|
204
|
+
* @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
|
|
241
205
|
* handled before calling this function (e.g. in a switch statement).
|
|
242
206
|
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
243
207
|
*/
|
|
244
208
|
function compatBehaviorAllowsMessageType(
|
|
245
|
-
_unknownContainerRuntimeMessageType:
|
|
209
|
+
_unknownContainerRuntimeMessageType: UnknownContainerRuntimeMessage["type"],
|
|
246
210
|
compatBehavior: "Ignore" | "FailToProcess" | undefined,
|
|
247
211
|
): boolean {
|
|
248
212
|
// undefined defaults to same behavior as "FailToProcess"
|
|
249
213
|
return compatBehavior === "Ignore";
|
|
250
214
|
}
|
|
251
215
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
/** Type of the op, within the ContainerRuntime's domain */
|
|
260
|
-
type: ContainerMessageType;
|
|
261
|
-
/** Domain-specific contents, interpreted according to the type */
|
|
262
|
-
contents: any;
|
|
263
|
-
/** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
|
|
264
|
-
compatDetails?: IContainerRuntimeMessageCompatDetails;
|
|
216
|
+
function prepareLocalContainerRuntimeIdAllocationMessageForTransit(
|
|
217
|
+
message: LocalContainerRuntimeIdAllocationMessage | ContainerRuntimeIdAllocationMessage,
|
|
218
|
+
): asserts message is ContainerRuntimeIdAllocationMessage {
|
|
219
|
+
// Remove the stashedState from the op if it's a stashed op
|
|
220
|
+
if ("stashedState" in message.contents) {
|
|
221
|
+
delete message.contents.stashedState;
|
|
222
|
+
}
|
|
265
223
|
}
|
|
266
224
|
|
|
267
225
|
/**
|
|
268
|
-
*
|
|
269
|
-
* promoted up to the outer object
|
|
226
|
+
* @public
|
|
270
227
|
*/
|
|
271
|
-
export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
|
|
272
|
-
|
|
273
228
|
export interface ISummaryBaseConfiguration {
|
|
274
229
|
/**
|
|
275
230
|
* Delay before first attempt to spawn summarizing container.
|
|
@@ -289,6 +244,9 @@ export interface ISummaryBaseConfiguration {
|
|
|
289
244
|
maxOpsSinceLastSummary: number;
|
|
290
245
|
}
|
|
291
246
|
|
|
247
|
+
/**
|
|
248
|
+
* @public
|
|
249
|
+
*/
|
|
292
250
|
export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfiguration {
|
|
293
251
|
state: "enabled";
|
|
294
252
|
/**
|
|
@@ -349,19 +307,31 @@ export interface ISummaryConfigurationHeuristics extends ISummaryBaseConfigurati
|
|
|
349
307
|
nonRuntimeHeuristicThreshold?: number;
|
|
350
308
|
}
|
|
351
309
|
|
|
310
|
+
/**
|
|
311
|
+
* @public
|
|
312
|
+
*/
|
|
352
313
|
export interface ISummaryConfigurationDisableSummarizer {
|
|
353
314
|
state: "disabled";
|
|
354
315
|
}
|
|
355
316
|
|
|
317
|
+
/**
|
|
318
|
+
* @public
|
|
319
|
+
*/
|
|
356
320
|
export interface ISummaryConfigurationDisableHeuristics extends ISummaryBaseConfiguration {
|
|
357
321
|
state: "disableHeuristics";
|
|
358
322
|
}
|
|
359
323
|
|
|
324
|
+
/**
|
|
325
|
+
* @public
|
|
326
|
+
*/
|
|
360
327
|
export type ISummaryConfiguration =
|
|
361
328
|
| ISummaryConfigurationDisableSummarizer
|
|
362
329
|
| ISummaryConfigurationDisableHeuristics
|
|
363
330
|
| ISummaryConfigurationHeuristics;
|
|
364
331
|
|
|
332
|
+
/**
|
|
333
|
+
* @public
|
|
334
|
+
*/
|
|
365
335
|
export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
366
336
|
state: "enabled",
|
|
367
337
|
|
|
@@ -388,6 +358,9 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
388
358
|
nonRuntimeHeuristicThreshold: 20,
|
|
389
359
|
};
|
|
390
360
|
|
|
361
|
+
/**
|
|
362
|
+
* @public
|
|
363
|
+
*/
|
|
391
364
|
export interface ISummaryRuntimeOptions {
|
|
392
365
|
/** Override summary configurations set by the server. */
|
|
393
366
|
summaryConfigOverrides?: ISummaryConfiguration;
|
|
@@ -403,22 +376,25 @@ export interface ISummaryRuntimeOptions {
|
|
|
403
376
|
|
|
404
377
|
/**
|
|
405
378
|
* Options for op compression.
|
|
406
|
-
* @
|
|
379
|
+
* @public
|
|
407
380
|
*/
|
|
408
381
|
export interface ICompressionRuntimeOptions {
|
|
409
382
|
/**
|
|
410
|
-
* The
|
|
383
|
+
* The value the batch's content size must exceed for the batch to be compressed.
|
|
384
|
+
* By default the value is 600 * 1024 = 614400 bytes. If the value is set to `Infinity`, compression will be disabled.
|
|
411
385
|
*/
|
|
412
386
|
readonly minimumBatchSizeInBytes: number;
|
|
413
387
|
|
|
414
388
|
/**
|
|
415
389
|
* The compression algorithm that will be used to compress the op.
|
|
390
|
+
* By default the value is `lz4` which is the only compression algorithm currently supported.
|
|
416
391
|
*/
|
|
417
392
|
readonly compressionAlgorithm: CompressionAlgorithms;
|
|
418
393
|
}
|
|
419
394
|
|
|
420
395
|
/**
|
|
421
396
|
* Options for container runtime.
|
|
397
|
+
* @public
|
|
422
398
|
*/
|
|
423
399
|
export interface IContainerRuntimeOptions {
|
|
424
400
|
readonly summaryOptions?: ISummaryRuntimeOptions;
|
|
@@ -440,8 +416,7 @@ export interface IContainerRuntimeOptions {
|
|
|
440
416
|
*/
|
|
441
417
|
readonly flushMode?: FlushMode;
|
|
442
418
|
/**
|
|
443
|
-
* Enables the runtime to compress ops.
|
|
444
|
-
* @experimental Not ready for use.
|
|
419
|
+
* Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
|
|
445
420
|
*/
|
|
446
421
|
readonly compressionOptions?: ICompressionRuntimeOptions;
|
|
447
422
|
/**
|
|
@@ -458,12 +433,15 @@ export interface IContainerRuntimeOptions {
|
|
|
458
433
|
/**
|
|
459
434
|
* If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
|
|
460
435
|
* how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
|
|
461
|
-
* batch size exceeds this value, it will be chunked into smaller ops of this size.
|
|
436
|
+
* batch content size exceeds this value, it will be chunked into smaller ops of this exact size.
|
|
462
437
|
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
438
|
+
* This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use
|
|
439
|
+
* 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link IContainerRuntimeOptions.maxBatchSizeInBytes}
|
|
440
|
+
* regardless of the overhead of an individual op.
|
|
465
441
|
*
|
|
466
|
-
* @
|
|
442
|
+
* Any value of `chunkSizeInBytes` exceeding {@link IContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content
|
|
443
|
+
* size exceeds {@link IContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `GenericError` with
|
|
444
|
+
* the `BatchTooLarge` message.
|
|
467
445
|
*/
|
|
468
446
|
readonly chunkSizeInBytes?: number;
|
|
469
447
|
|
|
@@ -498,6 +476,7 @@ export interface IContainerRuntimeOptions {
|
|
|
498
476
|
|
|
499
477
|
/**
|
|
500
478
|
* Accepted header keys for requests coming to the runtime.
|
|
479
|
+
* @public
|
|
501
480
|
*/
|
|
502
481
|
export enum RuntimeHeaders {
|
|
503
482
|
/** True to wait for a data store to be created and loaded before returning it. */
|
|
@@ -506,14 +485,25 @@ export enum RuntimeHeaders {
|
|
|
506
485
|
viaHandle = "viaHandle",
|
|
507
486
|
}
|
|
508
487
|
|
|
509
|
-
/** True if a tombstoned object should be returned without erroring
|
|
488
|
+
/** True if a tombstoned object should be returned without erroring
|
|
489
|
+
* @public
|
|
490
|
+
*/
|
|
510
491
|
export const AllowTombstoneRequestHeaderKey = "allowTombstone"; // Belongs in the enum above, but avoiding the breaking change
|
|
511
|
-
/**
|
|
492
|
+
/**
|
|
493
|
+
* [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
|
|
494
|
+
* @public
|
|
495
|
+
*/
|
|
512
496
|
export const AllowInactiveRequestHeaderKey = "allowInactive"; // Belongs in the enum above, but avoiding the breaking change
|
|
513
497
|
|
|
514
|
-
/**
|
|
498
|
+
/**
|
|
499
|
+
* Tombstone error responses will have this header set to true
|
|
500
|
+
* @public
|
|
501
|
+
*/
|
|
515
502
|
export const TombstoneResponseHeaderKey = "isTombstoned";
|
|
516
|
-
/**
|
|
503
|
+
/**
|
|
504
|
+
* Inactive error responses will have this header set to true
|
|
505
|
+
* @public
|
|
506
|
+
*/
|
|
517
507
|
export const InactiveResponseHeaderKey = "isInactive";
|
|
518
508
|
|
|
519
509
|
/**
|
|
@@ -534,6 +524,7 @@ export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
|
|
|
534
524
|
|
|
535
525
|
/**
|
|
536
526
|
* Available compression algorithms for op compression.
|
|
527
|
+
* @public
|
|
537
528
|
*/
|
|
538
529
|
export enum CompressionAlgorithms {
|
|
539
530
|
lz4 = "lz4",
|
|
@@ -597,7 +588,8 @@ export const defaultPendingOpsRetryDelayMs = 1000;
|
|
|
597
588
|
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
598
589
|
|
|
599
590
|
/**
|
|
600
|
-
* @deprecated
|
|
591
|
+
* @deprecated use ContainerRuntimeMessageType instead
|
|
592
|
+
* @public
|
|
601
593
|
*/
|
|
602
594
|
export enum RuntimeMessage {
|
|
603
595
|
FluidDataStoreOp = "component",
|
|
@@ -610,7 +602,8 @@ export enum RuntimeMessage {
|
|
|
610
602
|
}
|
|
611
603
|
|
|
612
604
|
/**
|
|
613
|
-
* @deprecated
|
|
605
|
+
* @deprecated please use version in driver-utils
|
|
606
|
+
* @public
|
|
614
607
|
*/
|
|
615
608
|
export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
616
609
|
return (Object.values(RuntimeMessage) as string[]).includes(message.type);
|
|
@@ -620,6 +613,7 @@ export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
|
620
613
|
* Legacy ID for the built-in AgentScheduler. To minimize disruption while removing it, retaining this as a
|
|
621
614
|
* special-case for document dirty state. Ultimately we should have no special-cases from the
|
|
622
615
|
* ContainerRuntime's perspective.
|
|
616
|
+
* @public
|
|
623
617
|
*/
|
|
624
618
|
export const agentSchedulerId = "_scheduler";
|
|
625
619
|
|
|
@@ -660,23 +654,94 @@ export const makeLegacySendBatchFn =
|
|
|
660
654
|
deltaManager.flush();
|
|
661
655
|
};
|
|
662
656
|
|
|
657
|
+
/** Helper type for type constraints passed through several functions.
|
|
658
|
+
* message - The unpacked message. Likely a TypedContainerRuntimeMessage, but could also be a system op
|
|
659
|
+
* modernRuntimeMessage - Does this appear like a current TypedContainerRuntimeMessage?
|
|
660
|
+
* local - Did this client send the op?
|
|
661
|
+
*/
|
|
662
|
+
type MessageWithContext =
|
|
663
|
+
| {
|
|
664
|
+
message: InboundSequencedContainerRuntimeMessage;
|
|
665
|
+
modernRuntimeMessage: true;
|
|
666
|
+
local: boolean;
|
|
667
|
+
}
|
|
668
|
+
| {
|
|
669
|
+
message: InboundSequencedContainerRuntimeMessageOrSystemMessage;
|
|
670
|
+
modernRuntimeMessage: false;
|
|
671
|
+
local: boolean;
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
const summarizerRequestUrl = "_summarizer";
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Create and retrieve the summmarizer
|
|
678
|
+
*/
|
|
679
|
+
async function createSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
|
|
680
|
+
const request: IRequest = {
|
|
681
|
+
headers: {
|
|
682
|
+
[LoaderHeader.cache]: false,
|
|
683
|
+
[LoaderHeader.clientDetails]: {
|
|
684
|
+
capabilities: { interactive: false },
|
|
685
|
+
type: summarizerClientType,
|
|
686
|
+
},
|
|
687
|
+
[DriverHeader.summarizingClient]: true,
|
|
688
|
+
[LoaderHeader.reconnect]: false,
|
|
689
|
+
},
|
|
690
|
+
url,
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const resolvedContainer = await loader.resolve(request);
|
|
694
|
+
let fluidObject: FluidObject<ISummarizer> | undefined;
|
|
695
|
+
|
|
696
|
+
// Older containers may not have the "getEntryPoint" API
|
|
697
|
+
// ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
|
|
698
|
+
if (resolvedContainer.getEntryPoint !== undefined) {
|
|
699
|
+
fluidObject = await resolvedContainer.getEntryPoint();
|
|
700
|
+
} else {
|
|
701
|
+
const response = await resolvedContainer.request({ url: `/${summarizerRequestUrl}` });
|
|
702
|
+
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
703
|
+
throw responseToException(response, request);
|
|
704
|
+
}
|
|
705
|
+
fluidObject = response.value;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (fluidObject?.ISummarizer === undefined) {
|
|
709
|
+
throw new UsageError("Fluid object does not implement ISummarizer");
|
|
710
|
+
}
|
|
711
|
+
return fluidObject.ISummarizer;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* This function is not supported publicly and exists for e2e testing
|
|
716
|
+
* @internal
|
|
717
|
+
*/
|
|
718
|
+
export async function TEST_requestSummarizer(loader: ILoader, url: string): Promise<ISummarizer> {
|
|
719
|
+
return createSummarizer(loader, url);
|
|
720
|
+
}
|
|
721
|
+
|
|
663
722
|
/**
|
|
664
723
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
665
724
|
* It will define the store level mappings.
|
|
725
|
+
* @public
|
|
666
726
|
*/
|
|
667
727
|
export class ContainerRuntime
|
|
668
728
|
extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
|
|
669
|
-
implements
|
|
729
|
+
implements
|
|
730
|
+
IContainerRuntime,
|
|
731
|
+
IRuntime,
|
|
732
|
+
ISummarizerRuntime,
|
|
733
|
+
ISummarizerInternalsProvider,
|
|
734
|
+
IProvideFluidHandleContext
|
|
670
735
|
{
|
|
671
736
|
/**
|
|
672
|
-
* @deprecated
|
|
737
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
673
738
|
*/
|
|
674
739
|
public get IFluidRouter() {
|
|
675
740
|
return this;
|
|
676
741
|
}
|
|
677
742
|
|
|
678
743
|
/**
|
|
679
|
-
* @deprecated
|
|
744
|
+
* @deprecated use loadRuntime instead.
|
|
680
745
|
* Load the stores from a snapshot and returns the runtime.
|
|
681
746
|
* @param context - Context of the container.
|
|
682
747
|
* @param registryEntries - Mapping to the stores.
|
|
@@ -703,10 +768,15 @@ export class ContainerRuntime
|
|
|
703
768
|
context,
|
|
704
769
|
registryEntries,
|
|
705
770
|
existing: existingFlag,
|
|
706
|
-
requestHandler,
|
|
707
771
|
runtimeOptions,
|
|
708
772
|
containerScope,
|
|
709
773
|
containerRuntimeCtor,
|
|
774
|
+
requestHandler,
|
|
775
|
+
provideEntryPoint: () => {
|
|
776
|
+
throw new UsageError(
|
|
777
|
+
"ContainerRuntime.load is deprecated and should no longer be used",
|
|
778
|
+
);
|
|
779
|
+
},
|
|
710
780
|
});
|
|
711
781
|
}
|
|
712
782
|
|
|
@@ -722,7 +792,7 @@ export class ContainerRuntime
|
|
|
722
792
|
* - containerScope - runtime services provided with context
|
|
723
793
|
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
724
794
|
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
725
|
-
* -
|
|
795
|
+
* - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
726
796
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
727
797
|
*/
|
|
728
798
|
public static async loadRuntime(params: {
|
|
@@ -732,30 +802,21 @@ export class ContainerRuntime
|
|
|
732
802
|
runtimeOptions?: IContainerRuntimeOptions;
|
|
733
803
|
containerScope?: FluidObject;
|
|
734
804
|
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
805
|
+
/** @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */
|
|
735
806
|
requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
|
|
736
|
-
|
|
807
|
+
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
|
|
737
808
|
}): Promise<ContainerRuntime> {
|
|
738
809
|
const {
|
|
739
810
|
context,
|
|
740
811
|
registryEntries,
|
|
741
812
|
existing,
|
|
742
813
|
requestHandler,
|
|
814
|
+
provideEntryPoint,
|
|
743
815
|
runtimeOptions = {},
|
|
744
816
|
containerScope = {},
|
|
745
817
|
containerRuntimeCtor = ContainerRuntime,
|
|
746
818
|
} = params;
|
|
747
819
|
|
|
748
|
-
const initializeEntryPoint =
|
|
749
|
-
params.initializeEntryPoint ??
|
|
750
|
-
(async (containerRuntime: IContainerRuntime) => ({
|
|
751
|
-
get IFluidRouter() {
|
|
752
|
-
return this;
|
|
753
|
-
},
|
|
754
|
-
async request(req) {
|
|
755
|
-
return containerRuntime.request(req);
|
|
756
|
-
},
|
|
757
|
-
}));
|
|
758
|
-
|
|
759
820
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
760
821
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
761
822
|
const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
|
|
@@ -884,15 +945,14 @@ export class ContainerRuntime
|
|
|
884
945
|
blobManagerSnapshot,
|
|
885
946
|
context.storage,
|
|
886
947
|
idCompressor,
|
|
948
|
+
provideEntryPoint,
|
|
887
949
|
requestHandler,
|
|
888
950
|
undefined, // summaryConfiguration
|
|
889
|
-
initializeEntryPoint,
|
|
890
951
|
);
|
|
891
952
|
|
|
892
|
-
|
|
893
|
-
//
|
|
894
|
-
|
|
895
|
-
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
953
|
+
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
954
|
+
// or zero. This must be done before Container replays saved ops.
|
|
955
|
+
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
896
956
|
|
|
897
957
|
// Initialize the base state of the runtime before it's returned.
|
|
898
958
|
await runtime.initializeBaseState();
|
|
@@ -913,17 +973,6 @@ export class ContainerRuntime
|
|
|
913
973
|
return this._storage;
|
|
914
974
|
}
|
|
915
975
|
|
|
916
|
-
/** @deprecated - The functionality is no longer exposed publicly */
|
|
917
|
-
public get reSubmitFn() {
|
|
918
|
-
return (
|
|
919
|
-
type: ContainerMessageType,
|
|
920
|
-
contents: any,
|
|
921
|
-
localOpMetadata: unknown,
|
|
922
|
-
opMetadata: Record<string, unknown> | undefined,
|
|
923
|
-
) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
924
|
-
// Note: compatDetails is not included in this deprecated API
|
|
925
|
-
}
|
|
926
|
-
|
|
927
976
|
private readonly submitFn: (
|
|
928
977
|
type: MessageType,
|
|
929
978
|
contents: any,
|
|
@@ -1175,6 +1224,7 @@ export class ContainerRuntime
|
|
|
1175
1224
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1176
1225
|
private readonly _storage: IDocumentStorageService,
|
|
1177
1226
|
idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
|
|
1227
|
+
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1178
1228
|
private readonly requestHandler?: (
|
|
1179
1229
|
request: IRequest,
|
|
1180
1230
|
runtime: IContainerRuntime,
|
|
@@ -1185,7 +1235,6 @@ export class ContainerRuntime
|
|
|
1185
1235
|
// the runtime configuration overrides
|
|
1186
1236
|
...runtimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1187
1237
|
},
|
|
1188
|
-
initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1189
1238
|
) {
|
|
1190
1239
|
super();
|
|
1191
1240
|
|
|
@@ -1619,7 +1668,7 @@ export class ContainerRuntime
|
|
|
1619
1668
|
this, // IConnectedState
|
|
1620
1669
|
this.summaryCollection,
|
|
1621
1670
|
this.logger,
|
|
1622
|
-
this.
|
|
1671
|
+
this.formCreateSummarizerFn(loader),
|
|
1623
1672
|
new Throttler(
|
|
1624
1673
|
60 * 1000, // 60 sec delay window
|
|
1625
1674
|
30 * 1000, // 30 sec max delay
|
|
@@ -1638,35 +1687,6 @@ export class ContainerRuntime
|
|
|
1638
1687
|
}
|
|
1639
1688
|
}
|
|
1640
1689
|
|
|
1641
|
-
this.deltaManager.on("readonly", (readonly: boolean) => {
|
|
1642
|
-
// we accumulate ops while being in read-only state.
|
|
1643
|
-
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
1644
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1645
|
-
assert(
|
|
1646
|
-
readonly === this.innerDeltaManager.readOnlyInfo.readonly,
|
|
1647
|
-
0x124 /* "inconsistent readonly property/event state" */,
|
|
1648
|
-
);
|
|
1649
|
-
|
|
1650
|
-
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
1651
|
-
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
1652
|
-
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
1653
|
-
// For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
|
|
1654
|
-
// ops that made it from previous connection, before switching clientId and raising "connected" event
|
|
1655
|
-
// But with read-only permissions, if we transition between read-only and r/w states while on same
|
|
1656
|
-
// connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
|
|
1657
|
-
// being in read-only state.
|
|
1658
|
-
// For that reason, we support getting to read-only state only when disconnected. This ensures that we
|
|
1659
|
-
// can rely on same safety mechanism and resend ops only when we establish new connection.
|
|
1660
|
-
// This is applicable for read-only permissions (event is raised before connection is properly registered),
|
|
1661
|
-
// but it's an extra requirement for Container.forceReadonly() API
|
|
1662
|
-
assert(
|
|
1663
|
-
!readonly || !this.connected,
|
|
1664
|
-
0x125 /* "Unsafe to transition to read-only state!" */,
|
|
1665
|
-
);
|
|
1666
|
-
|
|
1667
|
-
this.replayPendingStates();
|
|
1668
|
-
});
|
|
1669
|
-
|
|
1670
1690
|
// logging hardware telemetry
|
|
1671
1691
|
logger.sendTelemetryEvent({
|
|
1672
1692
|
eventName: "DeviceSpec",
|
|
@@ -1706,7 +1726,7 @@ export class ContainerRuntime
|
|
|
1706
1726
|
);
|
|
1707
1727
|
return this._summarizer;
|
|
1708
1728
|
}
|
|
1709
|
-
return
|
|
1729
|
+
return provideEntryPoint(this);
|
|
1710
1730
|
});
|
|
1711
1731
|
}
|
|
1712
1732
|
|
|
@@ -1747,14 +1767,14 @@ export class ContainerRuntime
|
|
|
1747
1767
|
/**
|
|
1748
1768
|
* Notifies this object about the request made to the container.
|
|
1749
1769
|
* @param request - Request made to the handler.
|
|
1750
|
-
* @deprecated
|
|
1770
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
1751
1771
|
*/
|
|
1752
1772
|
public async request(request: IRequest): Promise<IResponse> {
|
|
1753
1773
|
try {
|
|
1754
1774
|
const parser = RequestParser.create(request);
|
|
1755
1775
|
const id = parser.pathParts[0];
|
|
1756
1776
|
|
|
1757
|
-
if (id ===
|
|
1777
|
+
if (id === summarizerRequestUrl && parser.pathParts.length === 1) {
|
|
1758
1778
|
if (this._summarizer !== undefined) {
|
|
1759
1779
|
return {
|
|
1760
1780
|
status: 200,
|
|
@@ -1765,6 +1785,7 @@ export class ContainerRuntime
|
|
|
1765
1785
|
return create404Response(request);
|
|
1766
1786
|
}
|
|
1767
1787
|
if (this.requestHandler !== undefined) {
|
|
1788
|
+
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1768
1789
|
return this.requestHandler(parser, this);
|
|
1769
1790
|
}
|
|
1770
1791
|
|
|
@@ -1784,6 +1805,7 @@ export class ContainerRuntime
|
|
|
1784
1805
|
const id = requestParser.pathParts[0];
|
|
1785
1806
|
|
|
1786
1807
|
if (id === "_channels") {
|
|
1808
|
+
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1787
1809
|
return this.resolveHandle(requestParser.createSubRequest(1));
|
|
1788
1810
|
}
|
|
1789
1811
|
|
|
@@ -1797,7 +1819,10 @@ export class ContainerRuntime
|
|
|
1797
1819
|
}
|
|
1798
1820
|
: create404Response(request);
|
|
1799
1821
|
} else if (requestParser.pathParts.length > 0) {
|
|
1800
|
-
|
|
1822
|
+
// Differentiate between requesting the dataStore directly, or one of its children
|
|
1823
|
+
const requestForChild = !requestParser.isLeaf(1);
|
|
1824
|
+
const dataStore = await this.getDataStoreFromRequest(id, request, requestForChild);
|
|
1825
|
+
|
|
1801
1826
|
const subRequest = requestParser.createSubRequest(1);
|
|
1802
1827
|
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
1803
1828
|
// unintentionally modifying the url if that changes.
|
|
@@ -1805,6 +1830,7 @@ export class ContainerRuntime
|
|
|
1805
1830
|
subRequest.url.startsWith("/"),
|
|
1806
1831
|
0x126 /* "Expected createSubRequest url to include a leading slash" */,
|
|
1807
1832
|
);
|
|
1833
|
+
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1808
1834
|
return dataStore.request(subRequest);
|
|
1809
1835
|
}
|
|
1810
1836
|
|
|
@@ -1817,16 +1843,20 @@ export class ContainerRuntime
|
|
|
1817
1843
|
/**
|
|
1818
1844
|
* {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
|
|
1819
1845
|
*/
|
|
1820
|
-
public async getEntryPoint
|
|
1846
|
+
public async getEntryPoint(): Promise<FluidObject> {
|
|
1821
1847
|
return this.entryPoint;
|
|
1822
1848
|
}
|
|
1823
|
-
private readonly entryPoint: LazyPromise<FluidObject
|
|
1849
|
+
private readonly entryPoint: LazyPromise<FluidObject>;
|
|
1824
1850
|
|
|
1825
1851
|
private internalId(maybeAlias: string): string {
|
|
1826
1852
|
return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
|
|
1827
1853
|
}
|
|
1828
1854
|
|
|
1829
|
-
private async getDataStoreFromRequest(
|
|
1855
|
+
private async getDataStoreFromRequest(
|
|
1856
|
+
id: string,
|
|
1857
|
+
request: IRequest,
|
|
1858
|
+
requestForChild: boolean,
|
|
1859
|
+
): Promise<IFluidDataStoreChannel> {
|
|
1830
1860
|
const headerData: RuntimeHeaderData = {};
|
|
1831
1861
|
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
1832
1862
|
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
@@ -1838,6 +1868,11 @@ export class ContainerRuntime
|
|
|
1838
1868
|
headerData.allowTombstone = request.headers[AllowTombstoneRequestHeaderKey];
|
|
1839
1869
|
}
|
|
1840
1870
|
|
|
1871
|
+
// We allow Tombstone requests for sub-DataStore objects
|
|
1872
|
+
if (requestForChild) {
|
|
1873
|
+
headerData.allowTombstone = true;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1841
1876
|
await this.dataStores.waitIfPendingAlias(id);
|
|
1842
1877
|
const internalId = this.internalId(id);
|
|
1843
1878
|
const dataStoreContext = await this.dataStores.getDataStore(internalId, headerData);
|
|
@@ -2015,28 +2050,28 @@ export class ContainerRuntime
|
|
|
2015
2050
|
* Parse an op's type and actual content from given serialized content
|
|
2016
2051
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
2017
2052
|
*/
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
2023
|
-
return
|
|
2053
|
+
// TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
|
|
2054
|
+
private parseLocalOpContent(serializedContents?: string): LocalContainerRuntimeMessage {
|
|
2055
|
+
assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
|
|
2056
|
+
const message: LocalContainerRuntimeMessage = JSON.parse(serializedContents);
|
|
2057
|
+
assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
2058
|
+
return message;
|
|
2024
2059
|
}
|
|
2025
2060
|
|
|
2026
|
-
private async applyStashedOp(
|
|
2061
|
+
private async applyStashedOp(serializedOpContent: string): Promise<unknown> {
|
|
2027
2062
|
// Need to parse from string for back-compat
|
|
2028
|
-
const
|
|
2029
|
-
switch (type) {
|
|
2063
|
+
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
2064
|
+
switch (opContents.type) {
|
|
2030
2065
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2031
|
-
return this.dataStores.applyStashedOp(contents
|
|
2066
|
+
return this.dataStores.applyStashedOp(opContents.contents);
|
|
2032
2067
|
case ContainerMessageType.Attach:
|
|
2033
|
-
return this.dataStores.applyStashedAttachOp(contents
|
|
2068
|
+
return this.dataStores.applyStashedAttachOp(opContents.contents);
|
|
2034
2069
|
case ContainerMessageType.IdAllocation:
|
|
2035
2070
|
assert(
|
|
2036
2071
|
this.idCompressor !== undefined,
|
|
2037
2072
|
0x67b /* IdCompressor should be defined if enabled */,
|
|
2038
2073
|
);
|
|
2039
|
-
return this.applyStashedIdAllocationOp(contents
|
|
2074
|
+
return this.applyStashedIdAllocationOp(opContents.contents);
|
|
2040
2075
|
case ContainerMessageType.Alias:
|
|
2041
2076
|
case ContainerMessageType.BlobAttach:
|
|
2042
2077
|
return;
|
|
@@ -2048,15 +2083,15 @@ export class ContainerRuntime
|
|
|
2048
2083
|
// This should be extremely rare for stashed ops.
|
|
2049
2084
|
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
2050
2085
|
// e.g. if an app rolled back its container version
|
|
2051
|
-
const compatBehavior = compatDetails?.behavior;
|
|
2052
|
-
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
2086
|
+
const compatBehavior = opContents.compatDetails?.behavior;
|
|
2087
|
+
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
2053
2088
|
const error = DataProcessingError.create(
|
|
2054
2089
|
"Stashed runtime message of unknown type",
|
|
2055
2090
|
"applyStashedOp",
|
|
2056
2091
|
undefined /* sequencedMessage */,
|
|
2057
2092
|
{
|
|
2058
2093
|
messageDetails: JSON.stringify({
|
|
2059
|
-
type,
|
|
2094
|
+
type: opContents.type,
|
|
2060
2095
|
compatBehavior,
|
|
2061
2096
|
}),
|
|
2062
2097
|
},
|
|
@@ -2078,6 +2113,30 @@ export class ContainerRuntime
|
|
|
2078
2113
|
return;
|
|
2079
2114
|
}
|
|
2080
2115
|
|
|
2116
|
+
// If there are stashed blobs in the pending state, we need to delay
|
|
2117
|
+
// propagation of the "connected" event until we have uploaded them to
|
|
2118
|
+
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
2119
|
+
const connecting = connected && !this._connected;
|
|
2120
|
+
if (connecting && this.blobManager.hasPendingStashedBlobs()) {
|
|
2121
|
+
assert(
|
|
2122
|
+
!this.delayConnectClientId,
|
|
2123
|
+
0x791 /* Connect event delay must be canceled before subsequent connect event */,
|
|
2124
|
+
);
|
|
2125
|
+
assert(!!clientId, 0x792 /* Must have clientId when connecting */);
|
|
2126
|
+
this.delayConnectClientId = clientId;
|
|
2127
|
+
this.blobManager.processStashedChanges().then(
|
|
2128
|
+
() => {
|
|
2129
|
+
// make sure we didn't reconnect before the promise resolved
|
|
2130
|
+
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
2131
|
+
this.delayConnectClientId = undefined;
|
|
2132
|
+
this.setConnectionStateCore(connected, clientId);
|
|
2133
|
+
}
|
|
2134
|
+
},
|
|
2135
|
+
(error) => this.closeFn(error),
|
|
2136
|
+
);
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2081
2140
|
this.setConnectionStateCore(connected, clientId);
|
|
2082
2141
|
}
|
|
2083
2142
|
|
|
@@ -2156,9 +2215,25 @@ export class ContainerRuntime
|
|
|
2156
2215
|
const modernRuntimeMessage = messageArg.type === MessageType.Operation;
|
|
2157
2216
|
|
|
2158
2217
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
2218
|
+
// There might be multiple container instances receiving the same message.
|
|
2219
|
+
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
2220
|
+
// but will not modify the contents object (likely it will replace it on the message).
|
|
2159
2221
|
const messageCopy = { ...messageArg };
|
|
2160
2222
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
2161
|
-
|
|
2223
|
+
if (modernRuntimeMessage) {
|
|
2224
|
+
this.processCore({
|
|
2225
|
+
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
2226
|
+
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
2227
|
+
// the result messages will be so. In the end modern bool being true only directs to
|
|
2228
|
+
// throw error if ultimately unrecognized without compat details saying otherwise.
|
|
2229
|
+
message: message as InboundSequencedContainerRuntimeMessage,
|
|
2230
|
+
local,
|
|
2231
|
+
modernRuntimeMessage,
|
|
2232
|
+
});
|
|
2233
|
+
} else {
|
|
2234
|
+
// Unrecognized message will be ignored.
|
|
2235
|
+
this.processCore({ message, local, modernRuntimeMessage });
|
|
2236
|
+
}
|
|
2162
2237
|
}
|
|
2163
2238
|
}
|
|
2164
2239
|
|
|
@@ -2166,15 +2241,9 @@ export class ContainerRuntime
|
|
|
2166
2241
|
|
|
2167
2242
|
/**
|
|
2168
2243
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
*/
|
|
2173
|
-
private processCore(
|
|
2174
|
-
message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
|
|
2175
|
-
local: boolean,
|
|
2176
|
-
modernRuntimeMessage: boolean,
|
|
2177
|
-
) {
|
|
2244
|
+
*/
|
|
2245
|
+
private processCore(messageWithContext: MessageWithContext) {
|
|
2246
|
+
const { message, local } = messageWithContext;
|
|
2178
2247
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
2179
2248
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
2180
2249
|
// messages once a batch has been fully processed.
|
|
@@ -2184,9 +2253,13 @@ export class ContainerRuntime
|
|
|
2184
2253
|
|
|
2185
2254
|
try {
|
|
2186
2255
|
let localOpMetadata: unknown;
|
|
2187
|
-
if (
|
|
2256
|
+
if (
|
|
2257
|
+
local &&
|
|
2258
|
+
messageWithContext.modernRuntimeMessage &&
|
|
2259
|
+
message.type !== ContainerMessageType.ChunkedOp
|
|
2260
|
+
) {
|
|
2188
2261
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2189
|
-
message
|
|
2262
|
+
messageWithContext.message,
|
|
2190
2263
|
);
|
|
2191
2264
|
}
|
|
2192
2265
|
|
|
@@ -2196,14 +2269,9 @@ export class ContainerRuntime
|
|
|
2196
2269
|
this.updateDocumentDirtyState(false);
|
|
2197
2270
|
}
|
|
2198
2271
|
|
|
2199
|
-
this.validateAndProcessRuntimeMessage(
|
|
2200
|
-
message,
|
|
2201
|
-
localOpMetadata,
|
|
2202
|
-
local,
|
|
2203
|
-
modernRuntimeMessage,
|
|
2204
|
-
);
|
|
2272
|
+
this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
|
|
2205
2273
|
|
|
2206
|
-
this.emit("op", message, modernRuntimeMessage);
|
|
2274
|
+
this.emit("op", message, messageWithContext.modernRuntimeMessage);
|
|
2207
2275
|
|
|
2208
2276
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
2209
2277
|
|
|
@@ -2219,39 +2287,43 @@ export class ContainerRuntime
|
|
|
2219
2287
|
}
|
|
2220
2288
|
}
|
|
2221
2289
|
/**
|
|
2222
|
-
* Assuming the given message is also a
|
|
2290
|
+
* Assuming the given message is also a TypedContainerRuntimeMessage,
|
|
2223
2291
|
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
2224
|
-
* Throws a DataProcessingError if the message doesn't conform to
|
|
2292
|
+
* Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
|
|
2225
2293
|
*/
|
|
2226
2294
|
private validateAndProcessRuntimeMessage(
|
|
2227
|
-
|
|
2295
|
+
messageWithContext: MessageWithContext,
|
|
2228
2296
|
localOpMetadata: unknown,
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const { type: maybeContainerMessageType, compatDetails } =
|
|
2234
|
-
message as ContainerRuntimeMessage;
|
|
2235
|
-
|
|
2236
|
-
switch (maybeContainerMessageType) {
|
|
2297
|
+
): void {
|
|
2298
|
+
// TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
|
|
2299
|
+
const { local } = messageWithContext;
|
|
2300
|
+
switch (messageWithContext.message.type) {
|
|
2237
2301
|
case ContainerMessageType.Attach:
|
|
2238
|
-
this.dataStores.processAttachMessage(message, local);
|
|
2302
|
+
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
2239
2303
|
break;
|
|
2240
2304
|
case ContainerMessageType.Alias:
|
|
2241
|
-
this.dataStores.processAliasMessage(
|
|
2305
|
+
this.dataStores.processAliasMessage(
|
|
2306
|
+
messageWithContext.message,
|
|
2307
|
+
localOpMetadata,
|
|
2308
|
+
local,
|
|
2309
|
+
);
|
|
2242
2310
|
break;
|
|
2243
2311
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2244
|
-
this.dataStores.processFluidDataStoreOp(
|
|
2312
|
+
this.dataStores.processFluidDataStoreOp(
|
|
2313
|
+
messageWithContext.message,
|
|
2314
|
+
local,
|
|
2315
|
+
localOpMetadata,
|
|
2316
|
+
);
|
|
2245
2317
|
break;
|
|
2246
2318
|
case ContainerMessageType.BlobAttach:
|
|
2247
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
2319
|
+
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
2248
2320
|
break;
|
|
2249
2321
|
case ContainerMessageType.IdAllocation:
|
|
2250
2322
|
assert(
|
|
2251
2323
|
this.idCompressor !== undefined,
|
|
2252
2324
|
0x67c /* IdCompressor should be defined if enabled */,
|
|
2253
2325
|
);
|
|
2254
|
-
this.idCompressor.finalizeCreationRange(message.contents
|
|
2326
|
+
this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
|
|
2255
2327
|
break;
|
|
2256
2328
|
case ContainerMessageType.ChunkedOp:
|
|
2257
2329
|
case ContainerMessageType.Rejoin:
|
|
@@ -2259,12 +2331,18 @@ export class ContainerRuntime
|
|
|
2259
2331
|
default: {
|
|
2260
2332
|
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
2261
2333
|
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
2262
|
-
if (!
|
|
2334
|
+
if (!messageWithContext.modernRuntimeMessage) {
|
|
2263
2335
|
return;
|
|
2264
2336
|
}
|
|
2265
2337
|
|
|
2266
|
-
const compatBehavior = compatDetails?.behavior;
|
|
2267
|
-
if (
|
|
2338
|
+
const compatBehavior = messageWithContext.message.compatDetails?.behavior;
|
|
2339
|
+
if (
|
|
2340
|
+
!compatBehaviorAllowsMessageType(
|
|
2341
|
+
messageWithContext.message.type,
|
|
2342
|
+
compatBehavior,
|
|
2343
|
+
)
|
|
2344
|
+
) {
|
|
2345
|
+
const { message } = messageWithContext;
|
|
2268
2346
|
const error = DataProcessingError.create(
|
|
2269
2347
|
// Former assert 0x3ce
|
|
2270
2348
|
"Runtime message of unknown type",
|
|
@@ -2354,8 +2432,9 @@ export class ContainerRuntime
|
|
|
2354
2432
|
* Returns the runtime of the data store.
|
|
2355
2433
|
* @param id - Id supplied during creating the data store.
|
|
2356
2434
|
* @param wait - True if you want to wait for it.
|
|
2357
|
-
* @deprecated
|
|
2435
|
+
* @deprecated Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
2358
2436
|
*/
|
|
2437
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2359
2438
|
public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
|
|
2360
2439
|
return this.getRootDataStoreChannel(id, wait);
|
|
2361
2440
|
}
|
|
@@ -2535,7 +2614,7 @@ export class ContainerRuntime
|
|
|
2535
2614
|
return this.dirtyContainer;
|
|
2536
2615
|
}
|
|
2537
2616
|
|
|
2538
|
-
private isContainerMessageDirtyable({ type, contents }:
|
|
2617
|
+
private isContainerMessageDirtyable({ type, contents }: OutboundContainerRuntimeMessage) {
|
|
2539
2618
|
// For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
|
|
2540
2619
|
// Ultimately we should have no special-cases from the ContainerRuntime's perspective.
|
|
2541
2620
|
if (type === ContainerMessageType.Attach) {
|
|
@@ -2544,7 +2623,7 @@ export class ContainerRuntime
|
|
|
2544
2623
|
return false;
|
|
2545
2624
|
}
|
|
2546
2625
|
} else if (type === ContainerMessageType.FluidDataStoreOp) {
|
|
2547
|
-
const envelope = contents
|
|
2626
|
+
const envelope = contents;
|
|
2548
2627
|
if (envelope.address === agentSchedulerId) {
|
|
2549
2628
|
return false;
|
|
2550
2629
|
}
|
|
@@ -2788,7 +2867,7 @@ export class ContainerRuntime
|
|
|
2788
2867
|
}
|
|
2789
2868
|
|
|
2790
2869
|
/**
|
|
2791
|
-
* @deprecated
|
|
2870
|
+
* @deprecated Replaced by deleteSweepReadyNodes.
|
|
2792
2871
|
*/
|
|
2793
2872
|
public deleteUnusedNodes(unusedRoutes: string[]): string[] {
|
|
2794
2873
|
throw new Error("deleteUnusedRoutes should not be called");
|
|
@@ -2937,19 +3016,15 @@ export class ContainerRuntime
|
|
|
2937
3016
|
|
|
2938
3017
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
2939
3018
|
|
|
3019
|
+
// We close the summarizer and download a new snapshot and reload the container
|
|
2940
3020
|
let latestSnapshotVersionId: string | undefined;
|
|
2941
|
-
if (refreshLatestAck) {
|
|
2942
|
-
|
|
3021
|
+
if (refreshLatestAck === true) {
|
|
3022
|
+
return this.prefetchLatestSummaryThenClose(
|
|
2943
3023
|
createChildLogger({
|
|
2944
3024
|
logger: summaryNumberLogger,
|
|
2945
3025
|
properties: { all: { safeSummary: true } },
|
|
2946
3026
|
}),
|
|
2947
3027
|
);
|
|
2948
|
-
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
2949
|
-
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
2950
|
-
|
|
2951
|
-
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
2952
|
-
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
2953
3028
|
}
|
|
2954
3029
|
|
|
2955
3030
|
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
@@ -3397,7 +3472,7 @@ export class ContainerRuntime
|
|
|
3397
3472
|
}
|
|
3398
3473
|
|
|
3399
3474
|
if (idRange !== undefined) {
|
|
3400
|
-
const idAllocationMessage:
|
|
3475
|
+
const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
|
|
3401
3476
|
type: ContainerMessageType.IdAllocation,
|
|
3402
3477
|
contents: idRange,
|
|
3403
3478
|
};
|
|
@@ -3417,7 +3492,7 @@ export class ContainerRuntime
|
|
|
3417
3492
|
}
|
|
3418
3493
|
|
|
3419
3494
|
private submit(
|
|
3420
|
-
containerRuntimeMessage:
|
|
3495
|
+
containerRuntimeMessage: OutboundContainerRuntimeMessage,
|
|
3421
3496
|
localOpMetadata: unknown = undefined,
|
|
3422
3497
|
metadata: Record<string, unknown> | undefined = undefined,
|
|
3423
3498
|
): void {
|
|
@@ -3613,39 +3688,36 @@ export class ContainerRuntime
|
|
|
3613
3688
|
|
|
3614
3689
|
private reSubmit(message: IPendingBatchMessage) {
|
|
3615
3690
|
// Need to parse from string for back-compat
|
|
3616
|
-
const containerRuntimeMessage = this.
|
|
3691
|
+
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
3617
3692
|
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
3618
3693
|
}
|
|
3619
3694
|
|
|
3620
3695
|
/**
|
|
3621
3696
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
3622
3697
|
* reconnect and there are pending messages.
|
|
3623
|
-
* @param message - The original
|
|
3698
|
+
* @param message - The original LocalContainerRuntimeMessage.
|
|
3624
3699
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
3625
3700
|
*/
|
|
3626
3701
|
private reSubmitCore(
|
|
3627
|
-
message:
|
|
3702
|
+
message: LocalContainerRuntimeMessage,
|
|
3628
3703
|
localOpMetadata: unknown,
|
|
3629
3704
|
opMetadata: Record<string, unknown> | undefined,
|
|
3630
3705
|
) {
|
|
3631
|
-
const contents = message.contents;
|
|
3632
3706
|
switch (message.type) {
|
|
3633
3707
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3634
3708
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3635
3709
|
// and trigger resubmission on it.
|
|
3636
|
-
this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
|
|
3710
|
+
this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
|
|
3637
3711
|
break;
|
|
3638
3712
|
case ContainerMessageType.Attach:
|
|
3639
3713
|
case ContainerMessageType.Alias:
|
|
3640
3714
|
this.submit(message, localOpMetadata);
|
|
3641
3715
|
break;
|
|
3642
|
-
case ContainerMessageType.IdAllocation:
|
|
3643
|
-
|
|
3644
|
-
if (contents.stashedState !== undefined) {
|
|
3645
|
-
delete contents.stashedState;
|
|
3646
|
-
}
|
|
3716
|
+
case ContainerMessageType.IdAllocation: {
|
|
3717
|
+
prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
|
|
3647
3718
|
this.submit(message, localOpMetadata);
|
|
3648
3719
|
break;
|
|
3720
|
+
}
|
|
3649
3721
|
case ContainerMessageType.ChunkedOp:
|
|
3650
3722
|
throw new Error(`chunkedOp not expected here`);
|
|
3651
3723
|
case ContainerMessageType.BlobAttach:
|
|
@@ -3684,12 +3756,12 @@ export class ContainerRuntime
|
|
|
3684
3756
|
|
|
3685
3757
|
private rollback(content: string | undefined, localOpMetadata: unknown) {
|
|
3686
3758
|
// Need to parse from string for back-compat
|
|
3687
|
-
const { type, contents } = this.
|
|
3759
|
+
const { type, contents } = this.parseLocalOpContent(content);
|
|
3688
3760
|
switch (type) {
|
|
3689
3761
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3690
3762
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
3691
3763
|
// and trigger rollback on it.
|
|
3692
|
-
this.dataStores.rollbackDataStoreOp(contents
|
|
3764
|
+
this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
|
|
3693
3765
|
break;
|
|
3694
3766
|
default:
|
|
3695
3767
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -3697,26 +3769,6 @@ export class ContainerRuntime
|
|
|
3697
3769
|
}
|
|
3698
3770
|
}
|
|
3699
3771
|
|
|
3700
|
-
private async waitForDeltaManagerToCatchup(
|
|
3701
|
-
latestSnapshotRefSeq: number,
|
|
3702
|
-
summaryLogger: ITelemetryLoggerExt,
|
|
3703
|
-
): Promise<void> {
|
|
3704
|
-
if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
|
|
3705
|
-
// We need to catch up to the latest summary's reference sequence number before proceeding.
|
|
3706
|
-
await PerformanceEvent.timedExecAsync(
|
|
3707
|
-
summaryLogger,
|
|
3708
|
-
{
|
|
3709
|
-
eventName: "WaitingForSeq",
|
|
3710
|
-
lastSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3711
|
-
targetSequenceNumber: latestSnapshotRefSeq,
|
|
3712
|
-
lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
|
|
3713
|
-
},
|
|
3714
|
-
async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq),
|
|
3715
|
-
{ start: true, end: true, cancel: "error" }, // definitely want start event
|
|
3716
|
-
);
|
|
3717
|
-
}
|
|
3718
|
-
}
|
|
3719
|
-
|
|
3720
3772
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
3721
3773
|
public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
|
|
3722
3774
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
@@ -3735,7 +3787,7 @@ export class ContainerRuntime
|
|
|
3735
3787
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
3736
3788
|
*/
|
|
3737
3789
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
3738
|
-
const fetchResult = await this.
|
|
3790
|
+
const fetchResult = await this.fetchLatestSnapshotFromStorage(
|
|
3739
3791
|
summaryLogger,
|
|
3740
3792
|
{
|
|
3741
3793
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
@@ -3743,7 +3795,6 @@ export class ContainerRuntime
|
|
|
3743
3795
|
targetSequenceNumber: summaryRefSeq,
|
|
3744
3796
|
},
|
|
3745
3797
|
readAndParseBlob,
|
|
3746
|
-
null,
|
|
3747
3798
|
);
|
|
3748
3799
|
|
|
3749
3800
|
/**
|
|
@@ -3780,40 +3831,37 @@ export class ContainerRuntime
|
|
|
3780
3831
|
}
|
|
3781
3832
|
|
|
3782
3833
|
/**
|
|
3783
|
-
* Fetches the latest snapshot from storage
|
|
3784
|
-
*
|
|
3834
|
+
* Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
|
|
3835
|
+
* summarizer to reload from new state.
|
|
3785
3836
|
* @param summaryLogger - logger to use when fetching snapshot from storage
|
|
3786
|
-
* @returns
|
|
3837
|
+
* @returns a generic summarization error
|
|
3787
3838
|
*/
|
|
3788
|
-
private async
|
|
3839
|
+
private async prefetchLatestSummaryThenClose(
|
|
3789
3840
|
summaryLogger: ITelemetryLoggerExt,
|
|
3790
|
-
): Promise<
|
|
3841
|
+
): Promise<IBaseSummarizeResult> {
|
|
3791
3842
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
3792
|
-
|
|
3843
|
+
|
|
3844
|
+
// This is a performance optimization as the same parent is likely to be elected again, and would use its
|
|
3845
|
+
// cache to fetch the snapshot instead of the network.
|
|
3846
|
+
await this.fetchLatestSnapshotFromStorage(
|
|
3793
3847
|
summaryLogger,
|
|
3794
3848
|
{
|
|
3795
3849
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
3796
3850
|
},
|
|
3797
3851
|
readAndParseBlob,
|
|
3798
|
-
null,
|
|
3799
3852
|
);
|
|
3800
3853
|
|
|
3801
3854
|
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
3802
3855
|
|
|
3803
|
-
return {
|
|
3856
|
+
return {
|
|
3857
|
+
stage: "base",
|
|
3858
|
+
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
3859
|
+
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3860
|
+
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
3861
|
+
};
|
|
3804
3862
|
}
|
|
3805
3863
|
|
|
3806
3864
|
private async closeStaleSummarizer(codePath: string): Promise<void> {
|
|
3807
|
-
this.mc.logger.sendTelemetryEvent(
|
|
3808
|
-
{
|
|
3809
|
-
eventName: "ClosingSummarizerOnSummaryStale",
|
|
3810
|
-
codePath,
|
|
3811
|
-
message: "Stopping fetch from storage",
|
|
3812
|
-
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
3813
|
-
},
|
|
3814
|
-
new GenericError("Restarting summarizer instead of refreshing"),
|
|
3815
|
-
);
|
|
3816
|
-
|
|
3817
3865
|
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3818
3866
|
await delay(this.closeSummarizerDelayMs);
|
|
3819
3867
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
@@ -3821,15 +3869,14 @@ export class ContainerRuntime
|
|
|
3821
3869
|
}
|
|
3822
3870
|
|
|
3823
3871
|
/**
|
|
3824
|
-
* Downloads
|
|
3872
|
+
* Downloads the latest snapshot from storage.
|
|
3825
3873
|
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
3826
3874
|
* overridden via options.
|
|
3827
3875
|
*/
|
|
3828
|
-
private async
|
|
3876
|
+
private async fetchLatestSnapshotFromStorage(
|
|
3829
3877
|
logger: ITelemetryLoggerExt,
|
|
3830
3878
|
event: ITelemetryGenericEvent,
|
|
3831
3879
|
readAndParseBlob: ReadAndParseBlob,
|
|
3832
|
-
versionId: string | null,
|
|
3833
3880
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3834
3881
|
return PerformanceEvent.timedExecAsync(
|
|
3835
3882
|
logger,
|
|
@@ -3851,10 +3898,10 @@ export class ContainerRuntime
|
|
|
3851
3898
|
const trace = Trace.start();
|
|
3852
3899
|
|
|
3853
3900
|
const versions = await this.storage.getVersions(
|
|
3854
|
-
|
|
3901
|
+
null,
|
|
3855
3902
|
1,
|
|
3856
|
-
"
|
|
3857
|
-
|
|
3903
|
+
"prefetchLatestSummaryBeforeClose",
|
|
3904
|
+
FetchSource.noCache,
|
|
3858
3905
|
);
|
|
3859
3906
|
assert(
|
|
3860
3907
|
!!versions && !!versions[0],
|
|
@@ -3896,17 +3943,17 @@ export class ContainerRuntime
|
|
|
3896
3943
|
if (this._orderSequentiallyCalls !== 0) {
|
|
3897
3944
|
throw new UsageError("can't get state during orderSequentially");
|
|
3898
3945
|
}
|
|
3899
|
-
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(
|
|
3900
|
-
waitBlobsToAttach,
|
|
3901
|
-
);
|
|
3902
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
3903
|
-
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3904
|
-
return; // no pending state to save
|
|
3905
|
-
}
|
|
3906
3946
|
// Flush pending batch.
|
|
3907
3947
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3908
3948
|
// to close current batch.
|
|
3909
3949
|
this.flush();
|
|
3950
|
+
const pendingAttachmentBlobs = waitBlobsToAttach
|
|
3951
|
+
? await this.blobManager.attachAndGetPendingBlobs()
|
|
3952
|
+
: undefined;
|
|
3953
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
3954
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3955
|
+
return; // no pending state to save
|
|
3956
|
+
}
|
|
3910
3957
|
|
|
3911
3958
|
const pendingState: IPendingRuntimeState = {
|
|
3912
3959
|
pending,
|
|
@@ -3948,35 +3995,11 @@ export class ContainerRuntime
|
|
|
3948
3995
|
}
|
|
3949
3996
|
|
|
3950
3997
|
/**
|
|
3951
|
-
*
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
private formRequestSummarizerFn(loaderRouter: IFluidRouter) {
|
|
3998
|
+
* Forms a function that will create and retrieve a Summarizer.
|
|
3999
|
+
*/
|
|
4000
|
+
private formCreateSummarizerFn(loader: ILoader) {
|
|
3955
4001
|
return async () => {
|
|
3956
|
-
|
|
3957
|
-
headers: {
|
|
3958
|
-
[LoaderHeader.cache]: false,
|
|
3959
|
-
[LoaderHeader.clientDetails]: {
|
|
3960
|
-
capabilities: { interactive: false },
|
|
3961
|
-
type: summarizerClientType,
|
|
3962
|
-
},
|
|
3963
|
-
[DriverHeader.summarizingClient]: true,
|
|
3964
|
-
[LoaderHeader.reconnect]: false,
|
|
3965
|
-
},
|
|
3966
|
-
url: "/_summarizer",
|
|
3967
|
-
};
|
|
3968
|
-
|
|
3969
|
-
const fluidObject = await requestFluidObject<FluidObject<ISummarizer>>(
|
|
3970
|
-
loaderRouter,
|
|
3971
|
-
request,
|
|
3972
|
-
);
|
|
3973
|
-
const summarizer = fluidObject.ISummarizer;
|
|
3974
|
-
|
|
3975
|
-
if (!summarizer) {
|
|
3976
|
-
throw new UsageError("Fluid object does not implement ISummarizer");
|
|
3977
|
-
}
|
|
3978
|
-
|
|
3979
|
-
return summarizer;
|
|
4002
|
+
return createSummarizer(loader, `/${summarizerRequestUrl}`);
|
|
3980
4003
|
};
|
|
3981
4004
|
}
|
|
3982
4005
|
|
|
@@ -4003,30 +4026,3 @@ export class ContainerRuntime
|
|
|
4003
4026
|
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
4004
4027
|
}
|
|
4005
4028
|
}
|
|
4006
|
-
|
|
4007
|
-
/**
|
|
4008
|
-
* Wait for a specific sequence number. Promise should resolve when we reach that number,
|
|
4009
|
-
* or reject if closed.
|
|
4010
|
-
*/
|
|
4011
|
-
const waitForSeq = async (
|
|
4012
|
-
deltaManager: IDeltaManager<Pick<ISequencedDocumentMessage, "sequenceNumber">, unknown>,
|
|
4013
|
-
targetSeq: number,
|
|
4014
|
-
): Promise<void> =>
|
|
4015
|
-
new Promise<void>((resolve, reject) => {
|
|
4016
|
-
// TODO: remove cast to any when actual event is determined
|
|
4017
|
-
deltaManager.on("closed" as any, reject);
|
|
4018
|
-
deltaManager.on("disposed" as any, reject);
|
|
4019
|
-
|
|
4020
|
-
// If we already reached target sequence number, simply resolve the promise.
|
|
4021
|
-
if (deltaManager.lastSequenceNumber >= targetSeq) {
|
|
4022
|
-
resolve();
|
|
4023
|
-
} else {
|
|
4024
|
-
const handleOp = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
|
|
4025
|
-
if (message.sequenceNumber >= targetSeq) {
|
|
4026
|
-
resolve();
|
|
4027
|
-
deltaManager.off("op", handleOp);
|
|
4028
|
-
}
|
|
4029
|
-
};
|
|
4030
|
-
deltaManager.on("op", handleOp);
|
|
4031
|
-
}
|
|
4032
|
-
});
|