@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/src/containerRuntime.ts
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Trace,
|
|
8
|
+
TypedEventEmitter,
|
|
9
|
+
type ILayerCompatDetails,
|
|
10
|
+
type IProvideLayerCompatDetails,
|
|
11
|
+
} from "@fluid-internal/client-utils";
|
|
7
12
|
import {
|
|
8
13
|
AttachState,
|
|
9
14
|
IAudience,
|
|
@@ -12,7 +17,6 @@ import {
|
|
|
12
17
|
type IAudienceEvents,
|
|
13
18
|
} from "@fluidframework/container-definitions";
|
|
14
19
|
import {
|
|
15
|
-
IBatchMessage,
|
|
16
20
|
IContainerContext,
|
|
17
21
|
IGetPendingLocalStateProps,
|
|
18
22
|
ILoader,
|
|
@@ -34,6 +38,7 @@ import {
|
|
|
34
38
|
ITelemetryBaseLogger,
|
|
35
39
|
} from "@fluidframework/core-interfaces";
|
|
36
40
|
import {
|
|
41
|
+
type IErrorBase,
|
|
37
42
|
IFluidHandleContext,
|
|
38
43
|
type IFluidHandleInternal,
|
|
39
44
|
IProvideFluidHandleContext,
|
|
@@ -142,6 +147,7 @@ import {
|
|
|
142
147
|
blobsTreeName,
|
|
143
148
|
isBlobPath,
|
|
144
149
|
loadBlobManagerLoadInfo,
|
|
150
|
+
// eslint-disable-next-line import/no-deprecated
|
|
145
151
|
type IBlobManagerLoadInfo,
|
|
146
152
|
} from "./blobManager/index.js";
|
|
147
153
|
import {
|
|
@@ -159,15 +165,18 @@ import {
|
|
|
159
165
|
} from "./deltaManagerProxies.js";
|
|
160
166
|
import { DeltaScheduler } from "./deltaScheduler.js";
|
|
161
167
|
import {
|
|
168
|
+
// eslint-disable-next-line import/no-deprecated
|
|
162
169
|
GCNodeType,
|
|
163
170
|
GarbageCollector,
|
|
164
171
|
IGCRuntimeOptions,
|
|
172
|
+
// eslint-disable-next-line import/no-deprecated
|
|
165
173
|
IGCStats,
|
|
166
174
|
IGarbageCollector,
|
|
167
175
|
gcGenerationOptionName,
|
|
168
176
|
type GarbageCollectionMessage,
|
|
169
177
|
} from "./gc/index.js";
|
|
170
178
|
import { InboundBatchAggregator } from "./inboundBatchAggregator.js";
|
|
179
|
+
import { RuntimeCompatDetails, validateLoaderCompatibility } from "./layerCompatState.js";
|
|
171
180
|
import {
|
|
172
181
|
ContainerMessageType,
|
|
173
182
|
type ContainerRuntimeDocumentSchemaMessage,
|
|
@@ -202,26 +211,38 @@ import {
|
|
|
202
211
|
PendingStateManager,
|
|
203
212
|
} from "./pendingStateManager.js";
|
|
204
213
|
import {
|
|
214
|
+
// eslint-disable-next-line import/no-deprecated
|
|
205
215
|
DocumentsSchemaController,
|
|
206
216
|
EnqueueSummarizeResult,
|
|
207
217
|
IBaseSummarizeResult,
|
|
218
|
+
// eslint-disable-next-line import/no-deprecated
|
|
208
219
|
IConnectableRuntime,
|
|
220
|
+
// eslint-disable-next-line import/no-deprecated
|
|
209
221
|
IContainerRuntimeMetadata,
|
|
222
|
+
// eslint-disable-next-line import/no-deprecated
|
|
210
223
|
ICreateContainerMetadata,
|
|
224
|
+
// eslint-disable-next-line import/no-deprecated
|
|
211
225
|
type IDocumentSchemaChangeMessage,
|
|
226
|
+
// eslint-disable-next-line import/no-deprecated
|
|
212
227
|
type IDocumentSchemaCurrent,
|
|
213
228
|
IEnqueueSummarizeOptions,
|
|
214
229
|
IGenerateSummaryTreeResult,
|
|
215
230
|
IGeneratedSummaryStats,
|
|
216
231
|
IOnDemandSummarizeOptions,
|
|
232
|
+
// eslint-disable-next-line import/no-deprecated
|
|
217
233
|
IRefreshSummaryAckOptions,
|
|
218
234
|
IRootSummarizerNodeWithGC,
|
|
235
|
+
// eslint-disable-next-line import/no-deprecated
|
|
219
236
|
ISerializedElection,
|
|
237
|
+
// eslint-disable-next-line import/no-deprecated
|
|
220
238
|
ISubmitSummaryOptions,
|
|
221
239
|
ISummarizeResults,
|
|
222
240
|
ISummarizer,
|
|
241
|
+
// eslint-disable-next-line import/no-deprecated
|
|
223
242
|
ISummarizerInternalsProvider,
|
|
243
|
+
// eslint-disable-next-line import/no-deprecated
|
|
224
244
|
ISummarizerRuntime,
|
|
245
|
+
// eslint-disable-next-line import/no-deprecated
|
|
225
246
|
ISummaryMetadataMessage,
|
|
226
247
|
IdCompressorMode,
|
|
227
248
|
OrderedClientCollection,
|
|
@@ -229,6 +250,7 @@ import {
|
|
|
229
250
|
RetriableSummaryError,
|
|
230
251
|
RunWhileConnectedCoordinator,
|
|
231
252
|
SubmitSummaryResult,
|
|
253
|
+
// eslint-disable-next-line import/no-deprecated
|
|
232
254
|
Summarizer,
|
|
233
255
|
SummarizerClientElection,
|
|
234
256
|
SummaryCollection,
|
|
@@ -244,6 +266,7 @@ import {
|
|
|
244
266
|
rootHasIsolatedChannels,
|
|
245
267
|
summarizerClientType,
|
|
246
268
|
wrapSummaryInChannelsTree,
|
|
269
|
+
// eslint-disable-next-line import/no-deprecated
|
|
247
270
|
type IDocumentSchemaFeatures,
|
|
248
271
|
} from "./summary/index.js";
|
|
249
272
|
import { Throttler, formExponentialFn } from "./throttler.js";
|
|
@@ -389,6 +412,12 @@ export type ISummaryConfiguration =
|
|
|
389
412
|
| ISummaryConfigurationDisableHeuristics
|
|
390
413
|
| ISummaryConfigurationHeuristics;
|
|
391
414
|
|
|
415
|
+
export function isSummariesDisabled(
|
|
416
|
+
config: ISummaryConfiguration,
|
|
417
|
+
): config is ISummaryConfigurationDisableSummarizer {
|
|
418
|
+
return config.state === "disabled";
|
|
419
|
+
}
|
|
420
|
+
|
|
392
421
|
/**
|
|
393
422
|
* @legacy
|
|
394
423
|
* @alpha
|
|
@@ -414,7 +443,7 @@ export const DefaultSummaryConfiguration: ISummaryConfiguration = {
|
|
|
414
443
|
|
|
415
444
|
nonRuntimeOpWeight: 0.1,
|
|
416
445
|
|
|
417
|
-
runtimeOpWeight: 1
|
|
446
|
+
runtimeOpWeight: 1,
|
|
418
447
|
|
|
419
448
|
nonRuntimeHeuristicThreshold: 20,
|
|
420
449
|
};
|
|
@@ -560,6 +589,7 @@ export interface IContainerRuntimeOptionsInternal extends IContainerRuntimeOptio
|
|
|
560
589
|
* Error responses when requesting a deleted object will have this header set to true
|
|
561
590
|
* @legacy
|
|
562
591
|
* @alpha
|
|
592
|
+
* @deprecated This type will be moved to internal in 2.30. External usage is not necessary or supported.
|
|
563
593
|
*/
|
|
564
594
|
export const DeletedResponseHeaderKey = "wasDeleted";
|
|
565
595
|
/**
|
|
@@ -611,7 +641,7 @@ export enum CompressionAlgorithms {
|
|
|
611
641
|
* @alpha
|
|
612
642
|
*/
|
|
613
643
|
export const disabledCompressionConfig: ICompressionRuntimeOptions = {
|
|
614
|
-
minimumBatchSizeInBytes:
|
|
644
|
+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
615
645
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
616
646
|
};
|
|
617
647
|
|
|
@@ -713,7 +743,9 @@ export function getDeviceSpec(): {
|
|
|
713
743
|
hardwareConcurrency: navigator.hardwareConcurrency,
|
|
714
744
|
};
|
|
715
745
|
}
|
|
716
|
-
} catch {
|
|
746
|
+
} catch {
|
|
747
|
+
// Eat the error
|
|
748
|
+
}
|
|
717
749
|
return {};
|
|
718
750
|
}
|
|
719
751
|
|
|
@@ -774,19 +806,18 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
774
806
|
|
|
775
807
|
// Older containers may not have the "getEntryPoint" API
|
|
776
808
|
// ! This check will need to stay until LTS of loader moves past 2.0.0-internal.7.0.0
|
|
777
|
-
if (resolvedContainer.getEntryPoint
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
// 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
|
|
781
|
-
const response = await (resolvedContainer as any).request({
|
|
809
|
+
if (resolvedContainer.getEntryPoint === undefined) {
|
|
810
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any
|
|
811
|
+
const response = (await (resolvedContainer as any).request({
|
|
782
812
|
url: `/${summarizerRequestUrl}`,
|
|
783
|
-
});
|
|
784
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
813
|
+
})) as IResponse;
|
|
785
814
|
if (response.status !== 200 || response.mimeType !== "fluid/object") {
|
|
786
815
|
throw responseToException(response, request);
|
|
787
816
|
}
|
|
788
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-
|
|
817
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
789
818
|
fluidObject = response.value;
|
|
819
|
+
} else {
|
|
820
|
+
fluidObject = await resolvedContainer.getEntryPoint();
|
|
790
821
|
}
|
|
791
822
|
|
|
792
823
|
if (fluidObject?.ISummarizer === undefined) {
|
|
@@ -802,7 +833,9 @@ async function createSummarizer(loader: ILoader, url: string): Promise<ISummariz
|
|
|
802
833
|
* Please see addMetadataToSummary() as well
|
|
803
834
|
*/
|
|
804
835
|
function lastMessageFromMetadata(
|
|
836
|
+
// eslint-disable-next-line import/no-deprecated
|
|
805
837
|
metadata: IContainerRuntimeMetadata | undefined,
|
|
838
|
+
// eslint-disable-next-line import/no-deprecated
|
|
806
839
|
): ISummaryMetadataMessage | undefined {
|
|
807
840
|
return metadata?.documentSchema?.runtime?.explicitSchemaControl
|
|
808
841
|
? metadata?.lastMessage
|
|
@@ -822,6 +855,7 @@ export let getSingleUseLegacyLogCallback = (logger: ITelemetryLoggerExt, type: s
|
|
|
822
855
|
});
|
|
823
856
|
|
|
824
857
|
// Now that we've logged, prevent future logging (globally).
|
|
858
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
825
859
|
getSingleUseLegacyLogCallback = () => () => {};
|
|
826
860
|
};
|
|
827
861
|
};
|
|
@@ -877,6 +911,10 @@ export async function loadContainerRuntime(
|
|
|
877
911
|
return ContainerRuntime.loadRuntime(params);
|
|
878
912
|
}
|
|
879
913
|
|
|
914
|
+
const defaultMaxConsecutiveReconnects = 7;
|
|
915
|
+
|
|
916
|
+
const defaultTelemetrySignalSampleCount = 100;
|
|
917
|
+
|
|
880
918
|
/**
|
|
881
919
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
882
920
|
* It will define the store level mappings.
|
|
@@ -888,9 +926,12 @@ export class ContainerRuntime
|
|
|
888
926
|
implements
|
|
889
927
|
IContainerRuntime,
|
|
890
928
|
IRuntime,
|
|
929
|
+
// eslint-disable-next-line import/no-deprecated
|
|
891
930
|
ISummarizerRuntime,
|
|
931
|
+
// eslint-disable-next-line import/no-deprecated
|
|
892
932
|
ISummarizerInternalsProvider,
|
|
893
|
-
IProvideFluidHandleContext
|
|
933
|
+
IProvideFluidHandleContext,
|
|
934
|
+
IProvideLayerCompatDetails
|
|
894
935
|
{
|
|
895
936
|
/**
|
|
896
937
|
* Load the stores from a snapshot and returns the runtime.
|
|
@@ -991,7 +1032,9 @@ export class ContainerRuntime
|
|
|
991
1032
|
tryFetchBlob<ReturnType<DuplicateBatchDetector["getRecentBatchInfoForSummary"]>>(
|
|
992
1033
|
recentBatchInfoBlobName,
|
|
993
1034
|
),
|
|
1035
|
+
// eslint-disable-next-line import/no-deprecated
|
|
994
1036
|
tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
|
|
1037
|
+
// eslint-disable-next-line import/no-deprecated
|
|
995
1038
|
tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
|
|
996
1039
|
tryFetchBlob<[string, string][]>(aliasBlobName),
|
|
997
1040
|
tryFetchBlob<SerializedIdCompressorWithNoSession>(idCompressorBlobName),
|
|
@@ -1008,6 +1051,7 @@ export class ContainerRuntime
|
|
|
1008
1051
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
1009
1052
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
1010
1053
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
1054
|
+
// eslint-disable-next-line unicorn/no-lonely-if -- Separate if statements make flow easier to parse
|
|
1011
1055
|
if (
|
|
1012
1056
|
loadSequenceNumberVerification !== "bypass" &&
|
|
1013
1057
|
runtimeSequenceNumber !== protocolSequenceNumber
|
|
@@ -1036,15 +1080,18 @@ export class ContainerRuntime
|
|
|
1036
1080
|
|
|
1037
1081
|
let desiredIdCompressorMode: IdCompressorMode;
|
|
1038
1082
|
switch (mc.config.getBoolean("Fluid.ContainerRuntime.IdCompressorEnabled")) {
|
|
1039
|
-
case true:
|
|
1083
|
+
case true: {
|
|
1040
1084
|
desiredIdCompressorMode = "on";
|
|
1041
1085
|
break;
|
|
1042
|
-
|
|
1086
|
+
}
|
|
1087
|
+
case false: {
|
|
1043
1088
|
desiredIdCompressorMode = undefined;
|
|
1044
1089
|
break;
|
|
1045
|
-
|
|
1090
|
+
}
|
|
1091
|
+
default: {
|
|
1046
1092
|
desiredIdCompressorMode = enableRuntimeIdCompressor;
|
|
1047
1093
|
break;
|
|
1094
|
+
}
|
|
1048
1095
|
}
|
|
1049
1096
|
|
|
1050
1097
|
// Enabling the IdCompressor is a one-way operation and we only want to
|
|
@@ -1108,21 +1155,22 @@ export class ContainerRuntime
|
|
|
1108
1155
|
pendingLocalState.pendingIdCompressorState,
|
|
1109
1156
|
compressorLogger,
|
|
1110
1157
|
);
|
|
1111
|
-
} else if (serializedIdCompressor
|
|
1158
|
+
} else if (serializedIdCompressor === undefined) {
|
|
1159
|
+
return createIdCompressor(compressorLogger);
|
|
1160
|
+
} else {
|
|
1112
1161
|
return deserializeIdCompressor(
|
|
1113
1162
|
serializedIdCompressor,
|
|
1114
1163
|
createSessionId(),
|
|
1115
1164
|
compressorLogger,
|
|
1116
1165
|
);
|
|
1117
|
-
} else {
|
|
1118
|
-
return createIdCompressor(compressorLogger);
|
|
1119
1166
|
}
|
|
1120
1167
|
};
|
|
1121
1168
|
|
|
1122
1169
|
const compressionLz4 =
|
|
1123
|
-
compressionOptions.minimumBatchSizeInBytes !==
|
|
1170
|
+
compressionOptions.minimumBatchSizeInBytes !== Number.POSITIVE_INFINITY &&
|
|
1124
1171
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
1125
1172
|
|
|
1173
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1126
1174
|
const documentSchemaController = new DocumentsSchemaController(
|
|
1127
1175
|
existing,
|
|
1128
1176
|
protocolSequenceNumber,
|
|
@@ -1190,7 +1238,7 @@ export class ContainerRuntime
|
|
|
1190
1238
|
runtime.setConnectionStateCore(true, runtime.delayConnectClientId);
|
|
1191
1239
|
}
|
|
1192
1240
|
},
|
|
1193
|
-
(error) => runtime.closeFn(error),
|
|
1241
|
+
(error: IErrorBase) => runtime.closeFn(error),
|
|
1194
1242
|
);
|
|
1195
1243
|
|
|
1196
1244
|
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
@@ -1221,18 +1269,6 @@ export class ContainerRuntime
|
|
|
1221
1269
|
return this;
|
|
1222
1270
|
}
|
|
1223
1271
|
|
|
1224
|
-
private readonly submitFn: (
|
|
1225
|
-
type: MessageType,
|
|
1226
|
-
contents: unknown,
|
|
1227
|
-
batch: boolean,
|
|
1228
|
-
appData?: unknown,
|
|
1229
|
-
) => number;
|
|
1230
|
-
/**
|
|
1231
|
-
* Although current IContainerContext guarantees submitBatchFn, it is not available on older loaders.
|
|
1232
|
-
*/
|
|
1233
|
-
private readonly submitBatchFn:
|
|
1234
|
-
| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)
|
|
1235
|
-
| undefined;
|
|
1236
1272
|
private readonly submitSummaryFn: (
|
|
1237
1273
|
summaryOp: ISummaryContent,
|
|
1238
1274
|
referenceSequenceNumber?: number,
|
|
@@ -1272,9 +1308,11 @@ export class ContainerRuntime
|
|
|
1272
1308
|
* this op roundtrips, compression will be On. Client can't send compressed ops until it's change in schema.
|
|
1273
1309
|
*/
|
|
1274
1310
|
public get sessionSchema(): {
|
|
1311
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1275
1312
|
[P in keyof IDocumentSchemaFeatures]?: IDocumentSchemaFeatures[P] extends boolean
|
|
1276
1313
|
? true
|
|
1277
|
-
:
|
|
1314
|
+
: // eslint-disable-next-line import/no-deprecated
|
|
1315
|
+
IDocumentSchemaFeatures[P];
|
|
1278
1316
|
} {
|
|
1279
1317
|
return this.documentsSchemaController.sessionSchema.runtime;
|
|
1280
1318
|
}
|
|
@@ -1291,9 +1329,6 @@ export class ContainerRuntime
|
|
|
1291
1329
|
// In such case we have to process all ops, including those marked with savedOp === true.
|
|
1292
1330
|
private readonly skipSavedCompressorOps: boolean;
|
|
1293
1331
|
|
|
1294
|
-
public get idCompressorMode(): IdCompressorMode {
|
|
1295
|
-
return this.sessionSchema.idCompressorMode;
|
|
1296
|
-
}
|
|
1297
1332
|
/**
|
|
1298
1333
|
* {@inheritDoc @fluidframework/runtime-definitions#IContainerRuntimeBase.idCompressor}
|
|
1299
1334
|
*/
|
|
@@ -1302,7 +1337,7 @@ export class ContainerRuntime
|
|
|
1302
1337
|
// If container uses delayed mode, then we can only expose generateDocumentUniqueId() and nothing else.
|
|
1303
1338
|
// That's because any other usage will require immidiate loading of ID Compressor in next sessions in order
|
|
1304
1339
|
// to reason over such things as session ID space.
|
|
1305
|
-
if (this.idCompressorMode === "on") {
|
|
1340
|
+
if (this.sessionSchema.idCompressorMode === "on") {
|
|
1306
1341
|
assert(this._idCompressor !== undefined, 0x8ea /* compressor should have been loaded */);
|
|
1307
1342
|
return this._idCompressor;
|
|
1308
1343
|
}
|
|
@@ -1310,7 +1345,7 @@ export class ContainerRuntime
|
|
|
1310
1345
|
|
|
1311
1346
|
/**
|
|
1312
1347
|
* True if we have ID compressor loading in-flight (async operation). Useful only for
|
|
1313
|
-
* this.idCompressorMode === "delayed" mode
|
|
1348
|
+
* this.sessionSchema.idCompressorMode === "delayed" mode
|
|
1314
1349
|
*/
|
|
1315
1350
|
protected _loadIdCompressor: Promise<void> | undefined;
|
|
1316
1351
|
|
|
@@ -1354,14 +1389,10 @@ export class ContainerRuntime
|
|
|
1354
1389
|
* do not create it (see SummarizerClientElection.clientDetailsPermitElection() for details)
|
|
1355
1390
|
*/
|
|
1356
1391
|
private readonly summaryManager?: SummaryManager;
|
|
1357
|
-
private readonly summaryCollection: SummaryCollection;
|
|
1358
1392
|
|
|
1359
1393
|
private readonly summarizerNode: IRootSummarizerNodeWithGC;
|
|
1360
1394
|
|
|
1361
|
-
private readonly logger: ITelemetryLoggerExt;
|
|
1362
|
-
|
|
1363
1395
|
private readonly maxConsecutiveReconnects: number;
|
|
1364
|
-
private readonly defaultMaxConsecutiveReconnects = 7;
|
|
1365
1396
|
|
|
1366
1397
|
private _orderSequentiallyCalls: number = 0;
|
|
1367
1398
|
private readonly _flushMode: FlushMode;
|
|
@@ -1415,10 +1446,8 @@ export class ContainerRuntime
|
|
|
1415
1446
|
|
|
1416
1447
|
private dirtyContainer: boolean;
|
|
1417
1448
|
private emitDirtyDocumentEvent = true;
|
|
1418
|
-
private readonly disableAttachReorder: boolean | undefined;
|
|
1419
1449
|
private readonly useDeltaManagerOpsProxy: boolean;
|
|
1420
1450
|
private readonly closeSummarizerDelayMs: number;
|
|
1421
|
-
private readonly defaultTelemetrySignalSampleCount = 100;
|
|
1422
1451
|
private readonly _signalTracking: IPerfSignalReport = {
|
|
1423
1452
|
totalSignalsSentInLatencyWindow: 0,
|
|
1424
1453
|
signalsLost: 0,
|
|
@@ -1436,6 +1465,7 @@ export class ContainerRuntime
|
|
|
1436
1465
|
* It is the main entry point for summary work.
|
|
1437
1466
|
* It is created only by summarizing container (i.e. one with clientType === "summarizer")
|
|
1438
1467
|
*/
|
|
1468
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1439
1469
|
private readonly _summarizer?: Summarizer;
|
|
1440
1470
|
private readonly deltaScheduler: DeltaScheduler;
|
|
1441
1471
|
private readonly inboundBatchAggregator: InboundBatchAggregator;
|
|
@@ -1451,37 +1481,12 @@ export class ContainerRuntime
|
|
|
1451
1481
|
/**
|
|
1452
1482
|
* The last message processed at the time of the last summary.
|
|
1453
1483
|
*/
|
|
1484
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1454
1485
|
private messageAtLastSummary: ISummaryMetadataMessage | undefined;
|
|
1455
1486
|
|
|
1456
|
-
private get summarizer(): Summarizer {
|
|
1457
|
-
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
1458
|
-
return this._summarizer;
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
1487
|
private readonly summariesDisabled: boolean;
|
|
1462
|
-
private isSummariesDisabled(): boolean {
|
|
1463
|
-
return this.summaryConfiguration.state === "disabled";
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
private readonly maxOpsSinceLastSummary: number;
|
|
1467
|
-
private getMaxOpsSinceLastSummary(): number {
|
|
1468
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
1469
|
-
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
1470
|
-
: 0;
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
private readonly initialSummarizerDelayMs: number;
|
|
1474
|
-
private getInitialSummarizerDelayMs(): number {
|
|
1475
|
-
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
1476
|
-
// to ISummaryConfiguration in 0.60.
|
|
1477
|
-
if (this.runtimeOptions.summaryOptions.initialSummarizerDelayMs !== undefined) {
|
|
1478
|
-
return this.runtimeOptions.summaryOptions.initialSummarizerDelayMs;
|
|
1479
|
-
}
|
|
1480
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
1481
|
-
? this.summaryConfiguration.initialSummarizerDelayMs
|
|
1482
|
-
: 0;
|
|
1483
|
-
}
|
|
1484
1488
|
|
|
1489
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1485
1490
|
private readonly createContainerMetadata: ICreateContainerMetadata;
|
|
1486
1491
|
/**
|
|
1487
1492
|
* The summary number of the next summary that will be generated for this container. This is incremented every time
|
|
@@ -1513,11 +1518,6 @@ export class ContainerRuntime
|
|
|
1513
1518
|
*/
|
|
1514
1519
|
private readonly telemetryDocumentId: string;
|
|
1515
1520
|
|
|
1516
|
-
/**
|
|
1517
|
-
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1518
|
-
*/
|
|
1519
|
-
private readonly isSummarizerClient: boolean;
|
|
1520
|
-
|
|
1521
1521
|
/**
|
|
1522
1522
|
* The id of the version used to initially load this runtime, or undefined if it's newly created.
|
|
1523
1523
|
*/
|
|
@@ -1538,27 +1538,30 @@ export class ContainerRuntime
|
|
|
1538
1538
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
1539
1539
|
});
|
|
1540
1540
|
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
private readonly runtimeOptions: Readonly<Required<IContainerRuntimeOptionsInternal>>;
|
|
1541
|
+
public get ILayerCompatDetails(): ILayerCompatDetails {
|
|
1542
|
+
return RuntimeCompatDetails;
|
|
1543
|
+
}
|
|
1545
1544
|
|
|
1546
1545
|
/***/
|
|
1547
1546
|
protected constructor(
|
|
1548
1547
|
context: IContainerContext,
|
|
1549
1548
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1549
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1550
1550
|
private readonly metadata: IContainerRuntimeMetadata | undefined,
|
|
1551
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1551
1552
|
electedSummarizerData: ISerializedElection | undefined,
|
|
1552
1553
|
chunks: [string, string[]][],
|
|
1553
1554
|
dataStoreAliasMap: [string, string][],
|
|
1554
|
-
|
|
1555
|
+
baseRuntimeOptions: Readonly<Required<IContainerRuntimeOptions>>,
|
|
1555
1556
|
private readonly containerScope: FluidObject,
|
|
1556
1557
|
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
1557
1558
|
public readonly baseLogger: ITelemetryBaseLogger,
|
|
1558
1559
|
existing: boolean,
|
|
1560
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1559
1561
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1560
1562
|
private readonly _storage: IDocumentStorageService,
|
|
1561
1563
|
private readonly createIdCompressor: () => Promise<IIdCompressor & IIdCompressorCore>,
|
|
1564
|
+
// eslint-disable-next-line import/no-deprecated
|
|
1562
1565
|
private readonly documentsSchemaController: DocumentsSchemaController,
|
|
1563
1566
|
featureGatesForTelemetry: Record<string, boolean | number | undefined>,
|
|
1564
1567
|
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
@@ -1566,11 +1569,12 @@ export class ContainerRuntime
|
|
|
1566
1569
|
request: IRequest,
|
|
1567
1570
|
runtime: IContainerRuntime,
|
|
1568
1571
|
) => Promise<IResponse>,
|
|
1569
|
-
|
|
1572
|
+
// eslint-disable-next-line unicorn/no-object-as-default-parameter
|
|
1573
|
+
summaryConfiguration: ISummaryConfiguration = {
|
|
1570
1574
|
// the defaults
|
|
1571
1575
|
...DefaultSummaryConfiguration,
|
|
1572
1576
|
// the runtime configuration overrides
|
|
1573
|
-
...
|
|
1577
|
+
...baseRuntimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1574
1578
|
},
|
|
1575
1579
|
recentBatchInfo?: [number, string][],
|
|
1576
1580
|
) {
|
|
@@ -1596,14 +1600,19 @@ export class ContainerRuntime
|
|
|
1596
1600
|
snapshotWithContents,
|
|
1597
1601
|
} = context;
|
|
1598
1602
|
|
|
1603
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1604
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
1605
|
+
|
|
1606
|
+
const maybeLoaderCompatDetails = context as FluidObject<ILayerCompatDetails>;
|
|
1607
|
+
validateLoaderCompatibility(maybeLoaderCompatDetails.ILayerCompatDetails, this.disposeFn);
|
|
1608
|
+
|
|
1599
1609
|
// Backfill in defaults for the internal runtimeOptions, since they may not be present on the provided runtimeOptions object
|
|
1600
|
-
|
|
1610
|
+
const runtimeOptions = {
|
|
1601
1611
|
flushMode: defaultFlushMode,
|
|
1602
|
-
...
|
|
1612
|
+
...baseRuntimeOptions,
|
|
1603
1613
|
};
|
|
1604
|
-
this.logger = createChildLogger({ logger: this.baseLogger });
|
|
1605
1614
|
this.mc = createChildMonitoringContext({
|
|
1606
|
-
logger: this.
|
|
1615
|
+
logger: this.baseLogger,
|
|
1607
1616
|
namespace: "ContainerRuntime",
|
|
1608
1617
|
});
|
|
1609
1618
|
|
|
@@ -1623,20 +1632,24 @@ export class ContainerRuntime
|
|
|
1623
1632
|
|
|
1624
1633
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
1625
1634
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
1626
|
-
this
|
|
1627
|
-
this.
|
|
1628
|
-
|
|
1635
|
+
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
1636
|
+
this.submitSummaryFn =
|
|
1637
|
+
submitSummaryFn ??
|
|
1638
|
+
((summaryOp, refseq) => submitFn(MessageType.Summarize, summaryOp, false));
|
|
1629
1639
|
this.submitSignalFn = submitSignalFn;
|
|
1630
1640
|
|
|
1631
1641
|
// TODO: After IContainerContext.options is removed, we'll just create a new blank object {} here.
|
|
1632
1642
|
// Values are generally expected to be set from the runtime side.
|
|
1633
1643
|
this.options = options ?? {};
|
|
1634
1644
|
this.clientDetails = clientDetails;
|
|
1635
|
-
|
|
1645
|
+
const isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1636
1646
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
1647
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1637
1648
|
this._getClientId = () => context.clientId;
|
|
1649
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1638
1650
|
this._getAttachState = () => context.attachState;
|
|
1639
1651
|
this.getAbsoluteUrl = async (relativeUrl: string) => {
|
|
1652
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1640
1653
|
if (context.getAbsoluteUrl === undefined) {
|
|
1641
1654
|
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
1642
1655
|
}
|
|
@@ -1650,10 +1663,8 @@ export class ContainerRuntime
|
|
|
1650
1663
|
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
1651
1664
|
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
1652
1665
|
|
|
1653
|
-
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1654
|
-
this.disposeFn = disposeFn ?? closeFn;
|
|
1655
1666
|
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
1656
|
-
this.closeFn =
|
|
1667
|
+
this.closeFn = isSummarizerClient ? this.disposeFn : closeFn;
|
|
1657
1668
|
|
|
1658
1669
|
let loadSummaryNumber: number;
|
|
1659
1670
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
@@ -1686,28 +1697,22 @@ export class ContainerRuntime
|
|
|
1686
1697
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
1687
1698
|
inputs: JSON.stringify({
|
|
1688
1699
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1689
|
-
gcOptions_gcGeneration:
|
|
1700
|
+
gcOptions_gcGeneration: runtimeOptions.gcOptions[gcGenerationOptionName],
|
|
1690
1701
|
}),
|
|
1691
1702
|
});
|
|
1692
1703
|
|
|
1693
1704
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? uuid();
|
|
1694
1705
|
|
|
1695
|
-
this.disableAttachReorder = this.mc.config.getBoolean(
|
|
1696
|
-
"Fluid.ContainerRuntime.disableAttachOpReorder",
|
|
1697
|
-
);
|
|
1698
|
-
|
|
1699
1706
|
const opGroupingManager = new OpGroupingManager(
|
|
1700
1707
|
{
|
|
1701
1708
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1702
|
-
opCountThreshold:
|
|
1703
|
-
this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
1704
1709
|
},
|
|
1705
1710
|
this.mc.logger,
|
|
1706
1711
|
);
|
|
1707
1712
|
|
|
1708
1713
|
const opSplitter = new OpSplitter(
|
|
1709
1714
|
chunks,
|
|
1710
|
-
|
|
1715
|
+
submitBatchFn,
|
|
1711
1716
|
runtimeOptions.chunkSizeInBytes,
|
|
1712
1717
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1713
1718
|
this.mc.logger,
|
|
@@ -1730,7 +1735,7 @@ export class ContainerRuntime
|
|
|
1730
1735
|
isAttached: () => this.attachState !== AttachState.Detached,
|
|
1731
1736
|
},
|
|
1732
1737
|
pendingRuntimeState?.pending,
|
|
1733
|
-
this.
|
|
1738
|
+
this.baseLogger,
|
|
1734
1739
|
);
|
|
1735
1740
|
|
|
1736
1741
|
let outerDeltaManager: IDeltaManagerFull;
|
|
@@ -1756,28 +1761,42 @@ export class ContainerRuntime
|
|
|
1756
1761
|
|
|
1757
1762
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
1758
1763
|
|
|
1759
|
-
if (
|
|
1760
|
-
this.validateSummaryHeuristicConfiguration(
|
|
1764
|
+
if (summaryConfiguration.state === "enabled") {
|
|
1765
|
+
this.validateSummaryHeuristicConfiguration(summaryConfiguration);
|
|
1761
1766
|
}
|
|
1762
1767
|
|
|
1763
|
-
this.summariesDisabled =
|
|
1764
|
-
|
|
1765
|
-
|
|
1768
|
+
this.summariesDisabled = isSummariesDisabled(summaryConfiguration);
|
|
1769
|
+
const { maxOpsSinceLastSummary = 0, initialSummarizerDelayMs = 0 } = isSummariesDisabled(
|
|
1770
|
+
summaryConfiguration,
|
|
1771
|
+
)
|
|
1772
|
+
? {}
|
|
1773
|
+
: {
|
|
1774
|
+
...summaryConfiguration,
|
|
1775
|
+
initialSummarizerDelayMs:
|
|
1776
|
+
// back-compat: initialSummarizerDelayMs was moved from ISummaryRuntimeOptions
|
|
1777
|
+
// to ISummaryConfiguration in 0.60.
|
|
1778
|
+
runtimeOptions.summaryOptions.initialSummarizerDelayMs ??
|
|
1779
|
+
summaryConfiguration.initialSummarizerDelayMs,
|
|
1780
|
+
};
|
|
1766
1781
|
|
|
1767
1782
|
this.maxConsecutiveReconnects =
|
|
1768
|
-
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ??
|
|
1769
|
-
|
|
1770
|
-
|
|
1783
|
+
this.mc.config.getNumber(maxConsecutiveReconnectsKey) ?? defaultMaxConsecutiveReconnects;
|
|
1784
|
+
|
|
1785
|
+
// If the context has ILayerCompatDetails, it supports referenceSequenceNumbers since that features
|
|
1786
|
+
// predates ILayerCompatDetails.
|
|
1787
|
+
const referenceSequenceNumbersSupported =
|
|
1788
|
+
maybeLoaderCompatDetails.ILayerCompatDetails === undefined
|
|
1789
|
+
? supportedFeatures?.get("referenceSequenceNumbers") === true
|
|
1790
|
+
: true;
|
|
1771
1791
|
if (
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
supportedFeatures?.get("referenceSequenceNumbers") !== true
|
|
1792
|
+
runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
|
|
1793
|
+
!referenceSequenceNumbersSupported
|
|
1775
1794
|
) {
|
|
1776
1795
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
1777
1796
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
1778
1797
|
this._flushMode = FlushMode.TurnBased;
|
|
1779
1798
|
} else {
|
|
1780
|
-
this._flushMode =
|
|
1799
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
1781
1800
|
}
|
|
1782
1801
|
this.offlineEnabled =
|
|
1783
1802
|
this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ?? false;
|
|
@@ -1795,6 +1814,7 @@ export class ContainerRuntime
|
|
|
1795
1814
|
this.duplicateBatchDetector = new DuplicateBatchDetector(recentBatchInfo);
|
|
1796
1815
|
}
|
|
1797
1816
|
|
|
1817
|
+
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
1798
1818
|
if (context.attachState === AttachState.Attached) {
|
|
1799
1819
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1800
1820
|
if (
|
|
@@ -1810,13 +1830,13 @@ export class ContainerRuntime
|
|
|
1810
1830
|
|
|
1811
1831
|
this.garbageCollector = GarbageCollector.create({
|
|
1812
1832
|
runtime: this,
|
|
1813
|
-
gcOptions:
|
|
1833
|
+
gcOptions: runtimeOptions.gcOptions,
|
|
1814
1834
|
baseSnapshot,
|
|
1815
1835
|
baseLogger: this.mc.logger,
|
|
1816
1836
|
existing,
|
|
1817
1837
|
metadata,
|
|
1818
1838
|
createContainerMetadata: this.createContainerMetadata,
|
|
1819
|
-
isSummarizerClient
|
|
1839
|
+
isSummarizerClient,
|
|
1820
1840
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1821
1841
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1822
1842
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
@@ -1833,7 +1853,7 @@ export class ContainerRuntime
|
|
|
1833
1853
|
? undefined
|
|
1834
1854
|
: loadedFromSequenceNumber;
|
|
1835
1855
|
this.summarizerNode = createRootSummarizerNodeWithGC(
|
|
1836
|
-
createChildLogger({ logger: this.
|
|
1856
|
+
createChildLogger({ logger: this.baseLogger, namespace: "SummarizerNode" }),
|
|
1837
1857
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
1838
1858
|
async (fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext) =>
|
|
1839
1859
|
this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
@@ -1928,25 +1948,25 @@ export class ContainerRuntime
|
|
|
1928
1948
|
this.deltaScheduler = new DeltaScheduler(
|
|
1929
1949
|
this.innerDeltaManager,
|
|
1930
1950
|
this,
|
|
1931
|
-
createChildLogger({ logger: this.
|
|
1951
|
+
createChildLogger({ logger: this.baseLogger, namespace: "DeltaScheduler" }),
|
|
1932
1952
|
);
|
|
1933
1953
|
|
|
1934
1954
|
this.inboundBatchAggregator = new InboundBatchAggregator(
|
|
1935
1955
|
this.innerDeltaManager,
|
|
1936
1956
|
() => this.clientId,
|
|
1937
|
-
createChildLogger({ logger: this.
|
|
1957
|
+
createChildLogger({ logger: this.baseLogger, namespace: "InboundBatchAggregator" }),
|
|
1938
1958
|
);
|
|
1939
1959
|
|
|
1940
1960
|
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1941
1961
|
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1942
1962
|
);
|
|
1943
1963
|
|
|
1944
|
-
const legacySendBatchFn = makeLegacySendBatchFn(
|
|
1964
|
+
const legacySendBatchFn = makeLegacySendBatchFn(submitFn, this.innerDeltaManager);
|
|
1945
1965
|
|
|
1946
1966
|
this.outbox = new Outbox({
|
|
1947
1967
|
shouldSend: () => this.canSendOps(),
|
|
1948
1968
|
pendingStateManager: this.pendingStateManager,
|
|
1949
|
-
submitBatchFn
|
|
1969
|
+
submitBatchFn,
|
|
1950
1970
|
legacySendBatchFn,
|
|
1951
1971
|
compressor: new OpCompressor(this.mc.logger),
|
|
1952
1972
|
splitter: opSplitter,
|
|
@@ -2003,7 +2023,7 @@ export class ContainerRuntime
|
|
|
2003
2023
|
);
|
|
2004
2024
|
this.closeSummarizerDelayMs =
|
|
2005
2025
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
2006
|
-
|
|
2026
|
+
const summaryCollection = new SummaryCollection(this.deltaManager, this.baseLogger);
|
|
2007
2027
|
|
|
2008
2028
|
this.dirtyContainer =
|
|
2009
2029
|
this.attachState !== AttachState.Attached || this.hasPendingMessages();
|
|
@@ -2013,7 +2033,7 @@ export class ContainerRuntime
|
|
|
2013
2033
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
2014
2034
|
} else {
|
|
2015
2035
|
const orderedClientLogger = createChildLogger({
|
|
2016
|
-
logger: this.
|
|
2036
|
+
logger: this.baseLogger,
|
|
2017
2037
|
namespace: "OrderedClientElection",
|
|
2018
2038
|
});
|
|
2019
2039
|
const orderedClientCollection = new OrderedClientCollection(
|
|
@@ -2033,18 +2053,20 @@ export class ContainerRuntime
|
|
|
2033
2053
|
|
|
2034
2054
|
this.summarizerClientElection = new SummarizerClientElection(
|
|
2035
2055
|
orderedClientLogger,
|
|
2036
|
-
|
|
2056
|
+
summaryCollection,
|
|
2037
2057
|
orderedClientElectionForSummarizer,
|
|
2038
|
-
|
|
2058
|
+
maxOpsSinceLastSummary,
|
|
2039
2059
|
);
|
|
2040
2060
|
|
|
2041
|
-
if (
|
|
2061
|
+
if (isSummarizerClient) {
|
|
2062
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2042
2063
|
this._summarizer = new Summarizer(
|
|
2043
2064
|
this /* ISummarizerRuntime */,
|
|
2044
|
-
() =>
|
|
2065
|
+
() => summaryConfiguration,
|
|
2045
2066
|
this /* ISummarizerInternalsProvider */,
|
|
2046
2067
|
this.handleContext,
|
|
2047
|
-
|
|
2068
|
+
summaryCollection,
|
|
2069
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2048
2070
|
async (runtime: IConnectableRuntime) =>
|
|
2049
2071
|
RunWhileConnectedCoordinator.create(
|
|
2050
2072
|
runtime,
|
|
@@ -2057,31 +2079,31 @@ export class ContainerRuntime
|
|
|
2057
2079
|
// Only create a SummaryManager and SummarizerClientElection
|
|
2058
2080
|
// if summaries are enabled and we are not the summarizer client.
|
|
2059
2081
|
const defaultAction = (): void => {
|
|
2060
|
-
if (
|
|
2082
|
+
if (summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
2061
2083
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
2062
2084
|
// unregister default to no log on every op after falling behind
|
|
2063
2085
|
// and register summary ack handler to re-register this handler
|
|
2064
2086
|
// after successful summary
|
|
2065
|
-
|
|
2087
|
+
summaryCollection.once(MessageType.SummaryAck, () => {
|
|
2066
2088
|
this.mc.logger.sendTelemetryEvent({
|
|
2067
2089
|
eventName: "SummaryStatus:CaughtUp",
|
|
2068
2090
|
});
|
|
2069
2091
|
// we've caught up, so re-register the default action to monitor for
|
|
2070
2092
|
// falling behind, and unregister ourself
|
|
2071
|
-
|
|
2093
|
+
summaryCollection.on("default", defaultAction);
|
|
2072
2094
|
});
|
|
2073
|
-
|
|
2095
|
+
summaryCollection.off("default", defaultAction);
|
|
2074
2096
|
}
|
|
2075
2097
|
};
|
|
2076
2098
|
|
|
2077
|
-
|
|
2099
|
+
summaryCollection.on("default", defaultAction);
|
|
2078
2100
|
|
|
2079
2101
|
// Create the SummaryManager and mark the initial state
|
|
2080
2102
|
this.summaryManager = new SummaryManager(
|
|
2081
2103
|
this.summarizerClientElection,
|
|
2082
2104
|
this, // IConnectedState
|
|
2083
|
-
|
|
2084
|
-
this.
|
|
2105
|
+
summaryCollection,
|
|
2106
|
+
this.baseLogger,
|
|
2085
2107
|
this.formCreateSummarizerFn(loader),
|
|
2086
2108
|
new Throttler(
|
|
2087
2109
|
60 * 1000, // 60 sec delay window
|
|
@@ -2090,28 +2112,29 @@ export class ContainerRuntime
|
|
|
2090
2112
|
formExponentialFn({ coefficient: 20, initialDelay: 0 }),
|
|
2091
2113
|
),
|
|
2092
2114
|
{
|
|
2093
|
-
initialDelayMs:
|
|
2115
|
+
initialDelayMs: initialSummarizerDelayMs,
|
|
2094
2116
|
},
|
|
2095
2117
|
);
|
|
2096
2118
|
// Forward events from SummaryManager
|
|
2097
|
-
[
|
|
2119
|
+
for (const eventName of [
|
|
2098
2120
|
"summarize",
|
|
2099
2121
|
"summarizeAllAttemptsFailed",
|
|
2100
2122
|
"summarizerStop",
|
|
2101
2123
|
"summarizerStart",
|
|
2102
2124
|
"summarizerStartupFailed",
|
|
2103
|
-
]
|
|
2104
|
-
this.summaryManager?.on(eventName, (...args:
|
|
2125
|
+
]) {
|
|
2126
|
+
this.summaryManager?.on(eventName, (...args: unknown[]) => {
|
|
2105
2127
|
this.emit(eventName, ...args);
|
|
2106
2128
|
});
|
|
2107
|
-
}
|
|
2129
|
+
}
|
|
2108
2130
|
|
|
2109
2131
|
this.summaryManager.start();
|
|
2110
2132
|
}
|
|
2111
2133
|
}
|
|
2112
2134
|
|
|
2113
2135
|
// logging hardware telemetry
|
|
2114
|
-
this.
|
|
2136
|
+
this.baseLogger.send({
|
|
2137
|
+
category: "generic",
|
|
2115
2138
|
eventName: "DeviceSpec",
|
|
2116
2139
|
...getDeviceSpec(),
|
|
2117
2140
|
});
|
|
@@ -2124,13 +2147,12 @@ export class ContainerRuntime
|
|
|
2124
2147
|
summaryFormatVersion: metadata?.summaryFormatVersion,
|
|
2125
2148
|
disableIsolatedChannels: metadata?.disableIsolatedChannels,
|
|
2126
2149
|
gcVersion: metadata?.gcFeature,
|
|
2127
|
-
options: JSON.stringify(
|
|
2150
|
+
options: JSON.stringify(baseRuntimeOptions),
|
|
2128
2151
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
2129
|
-
idCompressorMode: this.idCompressorMode,
|
|
2152
|
+
idCompressorMode: this.sessionSchema.idCompressorMode,
|
|
2130
2153
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
2131
2154
|
featureGates: JSON.stringify({
|
|
2132
2155
|
...featureGatesForTelemetry,
|
|
2133
|
-
disableAttachReorder: this.disableAttachReorder,
|
|
2134
2156
|
disablePartialFlush,
|
|
2135
2157
|
closeSummarizerDelayOverride,
|
|
2136
2158
|
}),
|
|
@@ -2139,15 +2161,11 @@ export class ContainerRuntime
|
|
|
2139
2161
|
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
2140
2162
|
});
|
|
2141
2163
|
|
|
2142
|
-
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.
|
|
2143
|
-
BindBatchTracker(this, this.
|
|
2164
|
+
ReportOpPerfTelemetry(this.clientId, this._deltaManager, this, this.baseLogger);
|
|
2165
|
+
BindBatchTracker(this, this.baseLogger);
|
|
2144
2166
|
|
|
2145
2167
|
this.entryPoint = new LazyPromise(async () => {
|
|
2146
|
-
if (this.
|
|
2147
|
-
assert(
|
|
2148
|
-
this._summarizer !== undefined,
|
|
2149
|
-
0x5bf /* Summarizer object is undefined in a summarizer client */,
|
|
2150
|
-
);
|
|
2168
|
+
if (this._summarizer !== undefined) {
|
|
2151
2169
|
return this._summarizer;
|
|
2152
2170
|
}
|
|
2153
2171
|
return provideEntryPoint(this);
|
|
@@ -2158,8 +2176,9 @@ export class ContainerRuntime
|
|
|
2158
2176
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
2159
2177
|
}
|
|
2160
2178
|
|
|
2179
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2161
2180
|
public onSchemaChange(schema: IDocumentSchemaCurrent): void {
|
|
2162
|
-
this.logger.sendTelemetryEvent({
|
|
2181
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2163
2182
|
eventName: "SchemaChangeAccept",
|
|
2164
2183
|
sessionRuntimeSchema: JSON.stringify(schema),
|
|
2165
2184
|
});
|
|
@@ -2216,8 +2235,8 @@ export class ContainerRuntime
|
|
|
2216
2235
|
*/
|
|
2217
2236
|
private async initializeBaseState(): Promise<void> {
|
|
2218
2237
|
if (
|
|
2219
|
-
this.idCompressorMode === "on" ||
|
|
2220
|
-
(this.idCompressorMode === "delayed" && this.connected)
|
|
2238
|
+
this.sessionSchema.idCompressorMode === "on" ||
|
|
2239
|
+
(this.sessionSchema.idCompressorMode === "delayed" && this.connected)
|
|
2221
2240
|
) {
|
|
2222
2241
|
this._idCompressor = await this.createIdCompressor();
|
|
2223
2242
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
@@ -2276,7 +2295,7 @@ export class ContainerRuntime
|
|
|
2276
2295
|
// be in same loading group. So, once we have fetched the snapshot for that loading group on
|
|
2277
2296
|
// any request, then cache that as same group could be requested in future too.
|
|
2278
2297
|
const snapshot = await this.snapshotCacheForLoadingGroupIds.addOrGet(
|
|
2279
|
-
sortedLoadingGroupIds.join(),
|
|
2298
|
+
sortedLoadingGroupIds.join(","),
|
|
2280
2299
|
async () => {
|
|
2281
2300
|
assert(
|
|
2282
2301
|
this.storage.getSnapshot !== undefined,
|
|
@@ -2291,7 +2310,7 @@ export class ContainerRuntime
|
|
|
2291
2310
|
},
|
|
2292
2311
|
);
|
|
2293
2312
|
|
|
2294
|
-
this.logger.sendTelemetryEvent({
|
|
2313
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2295
2314
|
eventName: "GroupIdSnapshotFetched",
|
|
2296
2315
|
details: JSON.stringify({
|
|
2297
2316
|
fromCache: loadedFromCache,
|
|
@@ -2332,7 +2351,7 @@ export class ContainerRuntime
|
|
|
2332
2351
|
// another snapshot from which the summarizer loaded and it is behind, then just give up as
|
|
2333
2352
|
// the summarizer state is not up to date.
|
|
2334
2353
|
// This should be a recoverable scenario and shouldn't happen as we should process the ack first.
|
|
2335
|
-
if (this.
|
|
2354
|
+
if (this._summarizer !== undefined) {
|
|
2336
2355
|
throw new Error("Summarizer client behind, loaded newer snapshot with loadingGroupId");
|
|
2337
2356
|
}
|
|
2338
2357
|
|
|
@@ -2403,7 +2422,7 @@ export class ContainerRuntime
|
|
|
2403
2422
|
return {
|
|
2404
2423
|
status: 200,
|
|
2405
2424
|
mimeType: "fluid/object",
|
|
2406
|
-
value: this.
|
|
2425
|
+
value: this._summarizer,
|
|
2407
2426
|
};
|
|
2408
2427
|
}
|
|
2409
2428
|
return create404Response(request);
|
|
@@ -2481,6 +2500,7 @@ export class ContainerRuntime
|
|
|
2481
2500
|
// Is document schema explicit control on?
|
|
2482
2501
|
const explicitSchemaControl = documentSchema?.runtime.explicitSchemaControl;
|
|
2483
2502
|
|
|
2503
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2484
2504
|
const metadata: IContainerRuntimeMetadata = {
|
|
2485
2505
|
...this.createContainerMetadata,
|
|
2486
2506
|
// Increment the summary number for the next summary that will be generated.
|
|
@@ -2494,7 +2514,8 @@ export class ContainerRuntime
|
|
|
2494
2514
|
// last message's sequence number.
|
|
2495
2515
|
// See also lastMessageFromMetadata()
|
|
2496
2516
|
message: explicitSchemaControl
|
|
2497
|
-
?
|
|
2517
|
+
? // eslint-disable-next-line import/no-deprecated
|
|
2518
|
+
({ sequenceNumber: -1 } as unknown as ISummaryMetadataMessage)
|
|
2498
2519
|
: message,
|
|
2499
2520
|
lastMessage: explicitSchemaControl ? message : undefined,
|
|
2500
2521
|
documentSchema,
|
|
@@ -2639,9 +2660,10 @@ export class ContainerRuntime
|
|
|
2639
2660
|
switch (opContents.type) {
|
|
2640
2661
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2641
2662
|
case ContainerMessageType.Attach:
|
|
2642
|
-
case ContainerMessageType.Alias:
|
|
2663
|
+
case ContainerMessageType.Alias: {
|
|
2643
2664
|
return this.channelCollection.applyStashedOp(opContents);
|
|
2644
|
-
|
|
2665
|
+
}
|
|
2666
|
+
case ContainerMessageType.IdAllocation: {
|
|
2645
2667
|
// IDs allocation ops in stashed state are ignored because the tip state of the compressor
|
|
2646
2668
|
// is serialized into the pending state. This is done because generation of new IDs during
|
|
2647
2669
|
// stashed op application (or, later, resubmit) must generate new IDs and if the compressor
|
|
@@ -2652,19 +2674,24 @@ export class ContainerRuntime
|
|
|
2652
2674
|
// before applying the rest of the stashed ops. This would accomplish the same thing but with
|
|
2653
2675
|
// better performance in future incremental stashed state creation.
|
|
2654
2676
|
assert(
|
|
2655
|
-
this.idCompressorMode !== undefined,
|
|
2677
|
+
this.sessionSchema.idCompressorMode !== undefined,
|
|
2656
2678
|
0x8f1 /* ID compressor should be in use */,
|
|
2657
2679
|
);
|
|
2658
2680
|
return;
|
|
2659
|
-
|
|
2681
|
+
}
|
|
2682
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
2660
2683
|
return;
|
|
2661
|
-
|
|
2684
|
+
}
|
|
2685
|
+
case ContainerMessageType.BlobAttach: {
|
|
2662
2686
|
return;
|
|
2663
|
-
|
|
2687
|
+
}
|
|
2688
|
+
case ContainerMessageType.Rejoin: {
|
|
2664
2689
|
throw new Error("rejoin not expected here");
|
|
2665
|
-
|
|
2690
|
+
}
|
|
2691
|
+
case ContainerMessageType.GC: {
|
|
2666
2692
|
// GC op is only sent in summarizer which should never have stashed ops.
|
|
2667
2693
|
throw new LoggingError("GC op not expected to be stashed in summarizer");
|
|
2694
|
+
}
|
|
2668
2695
|
default: {
|
|
2669
2696
|
const error = getUnknownMessageTypeError(
|
|
2670
2697
|
opContents.type,
|
|
@@ -2679,7 +2706,7 @@ export class ContainerRuntime
|
|
|
2679
2706
|
private async loadIdCompressor(): Promise<void | undefined> {
|
|
2680
2707
|
if (
|
|
2681
2708
|
this._idCompressor === undefined &&
|
|
2682
|
-
this.idCompressorMode !== undefined &&
|
|
2709
|
+
this.sessionSchema.idCompressorMode !== undefined &&
|
|
2683
2710
|
this._loadIdCompressor === undefined
|
|
2684
2711
|
) {
|
|
2685
2712
|
this._loadIdCompressor = this.createIdCompressor()
|
|
@@ -2694,7 +2721,7 @@ export class ContainerRuntime
|
|
|
2694
2721
|
this._idCompressor = compressor;
|
|
2695
2722
|
})
|
|
2696
2723
|
.catch((error) => {
|
|
2697
|
-
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2724
|
+
this.mc.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
2698
2725
|
throw error;
|
|
2699
2726
|
});
|
|
2700
2727
|
}
|
|
@@ -2710,7 +2737,7 @@ export class ContainerRuntime
|
|
|
2710
2737
|
0x978 /* this.clientId does not match Audience */,
|
|
2711
2738
|
);
|
|
2712
2739
|
|
|
2713
|
-
if (connected && this.idCompressorMode === "delayed") {
|
|
2740
|
+
if (connected && this.sessionSchema.idCompressorMode === "delayed") {
|
|
2714
2741
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
2715
2742
|
this.loadIdCompressor();
|
|
2716
2743
|
}
|
|
@@ -2832,7 +2859,7 @@ export class ContainerRuntime
|
|
|
2832
2859
|
// or something different, like a system message.
|
|
2833
2860
|
const hasModernRuntimeMessageEnvelope = messageCopy.type === MessageType.Operation;
|
|
2834
2861
|
const savedOp = (messageCopy.metadata as ISavedOpMetadata)?.savedOp;
|
|
2835
|
-
const logLegacyCase = getSingleUseLegacyLogCallback(this.logger, messageCopy.type);
|
|
2862
|
+
const logLegacyCase = getSingleUseLegacyLogCallback(this.mc.logger, messageCopy.type);
|
|
2836
2863
|
|
|
2837
2864
|
let runtimeBatch: boolean =
|
|
2838
2865
|
hasModernRuntimeMessageEnvelope || isUnpackedRuntimeMessage(messageCopy);
|
|
@@ -2987,11 +3014,11 @@ export class ContainerRuntime
|
|
|
2987
3014
|
let error: unknown;
|
|
2988
3015
|
try {
|
|
2989
3016
|
if (!runtimeBatch) {
|
|
2990
|
-
|
|
3017
|
+
for (const { message } of messagesWithMetadata) {
|
|
2991
3018
|
this.ensureNoDataModelChanges(() => {
|
|
2992
3019
|
this.observeNonRuntimeMessage(message);
|
|
2993
3020
|
});
|
|
2994
|
-
}
|
|
3021
|
+
}
|
|
2995
3022
|
return;
|
|
2996
3023
|
}
|
|
2997
3024
|
|
|
@@ -3076,8 +3103,8 @@ export class ContainerRuntime
|
|
|
3076
3103
|
for (const { message } of messagesWithMetadata) {
|
|
3077
3104
|
this.emit("op", message, true /* runtimeMessage */);
|
|
3078
3105
|
}
|
|
3079
|
-
} catch (
|
|
3080
|
-
error =
|
|
3106
|
+
} catch (error_) {
|
|
3107
|
+
error = error_;
|
|
3081
3108
|
throw error;
|
|
3082
3109
|
} finally {
|
|
3083
3110
|
if (locationInBatch.batchEnd) {
|
|
@@ -3148,38 +3175,46 @@ export class ContainerRuntime
|
|
|
3148
3175
|
switch (message.type) {
|
|
3149
3176
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3150
3177
|
case ContainerMessageType.Attach:
|
|
3151
|
-
case ContainerMessageType.Alias:
|
|
3178
|
+
case ContainerMessageType.Alias: {
|
|
3152
3179
|
// Remove the metadata from the message before sending it to the channel collection. The metadata
|
|
3153
3180
|
// is added by the container runtime and is not part of the message that the channel collection and
|
|
3154
3181
|
// layers below it expect.
|
|
3155
3182
|
this.channelCollection.processMessages({ envelope: message, messagesContent, local });
|
|
3156
3183
|
break;
|
|
3157
|
-
|
|
3184
|
+
}
|
|
3185
|
+
case ContainerMessageType.BlobAttach: {
|
|
3158
3186
|
this.blobManager.processBlobAttachMessage(message, local);
|
|
3159
3187
|
break;
|
|
3160
|
-
|
|
3188
|
+
}
|
|
3189
|
+
case ContainerMessageType.IdAllocation: {
|
|
3161
3190
|
this.processIdCompressorMessages(contents as IdCreationRange[], savedOp);
|
|
3162
3191
|
break;
|
|
3163
|
-
|
|
3192
|
+
}
|
|
3193
|
+
case ContainerMessageType.GC: {
|
|
3164
3194
|
this.garbageCollector.processMessages(
|
|
3165
3195
|
contents as GarbageCollectionMessage[],
|
|
3166
3196
|
message.timestamp,
|
|
3167
3197
|
local,
|
|
3168
3198
|
);
|
|
3169
3199
|
break;
|
|
3170
|
-
|
|
3200
|
+
}
|
|
3201
|
+
case ContainerMessageType.ChunkedOp: {
|
|
3171
3202
|
// From observability POV, we should not expose the rest of the system (including "op" events on object) to these messages.
|
|
3172
3203
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
3173
3204
|
assert(false, 0x93d /* should not even get here */);
|
|
3174
|
-
|
|
3205
|
+
}
|
|
3206
|
+
case ContainerMessageType.Rejoin: {
|
|
3175
3207
|
break;
|
|
3176
|
-
|
|
3208
|
+
}
|
|
3209
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
3177
3210
|
this.documentsSchemaController.processDocumentSchemaMessages(
|
|
3211
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3178
3212
|
contents as IDocumentSchemaChangeMessage[],
|
|
3179
3213
|
local,
|
|
3180
3214
|
message.sequenceNumber,
|
|
3181
3215
|
);
|
|
3182
3216
|
break;
|
|
3217
|
+
}
|
|
3183
3218
|
default: {
|
|
3184
3219
|
const error = getUnknownMessageTypeError(
|
|
3185
3220
|
message.type,
|
|
@@ -3206,7 +3241,7 @@ export class ContainerRuntime
|
|
|
3206
3241
|
// put it in a pending queue and delay finalization.
|
|
3207
3242
|
if (this._idCompressor === undefined) {
|
|
3208
3243
|
assert(
|
|
3209
|
-
this.idCompressorMode !== undefined,
|
|
3244
|
+
this.sessionSchema.idCompressorMode !== undefined,
|
|
3210
3245
|
0x93c /* id compressor should be enabled */,
|
|
3211
3246
|
);
|
|
3212
3247
|
this.pendingIdCompressorOps.push(range);
|
|
@@ -3246,7 +3281,11 @@ export class ContainerRuntime
|
|
|
3246
3281
|
* Updates signal telemetry including emitting telemetry events.
|
|
3247
3282
|
*/
|
|
3248
3283
|
private processSignalForTelemetry(envelope: ISignalEnvelope): void {
|
|
3249
|
-
const {
|
|
3284
|
+
const {
|
|
3285
|
+
clientBroadcastSignalSequenceNumber,
|
|
3286
|
+
contents: envelopeContents,
|
|
3287
|
+
address: envelopeAddress,
|
|
3288
|
+
} = envelope;
|
|
3250
3289
|
if (clientBroadcastSignalSequenceNumber === undefined) {
|
|
3251
3290
|
return;
|
|
3252
3291
|
}
|
|
@@ -3291,8 +3330,8 @@ export class ContainerRuntime
|
|
|
3291
3330
|
};
|
|
3292
3331
|
// Only log `contents.type` when address is for container to avoid
|
|
3293
3332
|
// chance that contents type is customer data.
|
|
3294
|
-
if (
|
|
3295
|
-
details.contentsType =
|
|
3333
|
+
if (envelopeAddress === undefined) {
|
|
3334
|
+
details.contentsType = envelopeContents.type; // Type of signal that was received out of order.
|
|
3296
3335
|
}
|
|
3297
3336
|
this.mc.logger.sendTelemetryEvent({
|
|
3298
3337
|
eventName: "SignalOutOfOrder",
|
|
@@ -3388,8 +3427,8 @@ export class ContainerRuntime
|
|
|
3388
3427
|
checkpoint.rollback((message: BatchMessage) =>
|
|
3389
3428
|
this.rollback(message.contents, message.localOpMetadata),
|
|
3390
3429
|
);
|
|
3391
|
-
} catch (
|
|
3392
|
-
const error2 = wrapError(
|
|
3430
|
+
} catch (error_) {
|
|
3431
|
+
const error2 = wrapError(error_, (message) => {
|
|
3393
3432
|
return DataProcessingError.create(
|
|
3394
3433
|
`RollbackError: ${message}`,
|
|
3395
3434
|
"checkpointRollback",
|
|
@@ -3549,8 +3588,9 @@ export class ContainerRuntime
|
|
|
3549
3588
|
case ContainerMessageType.GC: {
|
|
3550
3589
|
return false;
|
|
3551
3590
|
}
|
|
3552
|
-
default:
|
|
3591
|
+
default: {
|
|
3553
3592
|
break;
|
|
3593
|
+
}
|
|
3554
3594
|
}
|
|
3555
3595
|
return true;
|
|
3556
3596
|
}
|
|
@@ -3593,7 +3633,7 @@ export class ContainerRuntime
|
|
|
3593
3633
|
|
|
3594
3634
|
// We should not track the round trip of a new signal in the case we are already tracking one.
|
|
3595
3635
|
if (
|
|
3596
|
-
clientBroadcastSignalSequenceNumber %
|
|
3636
|
+
clientBroadcastSignalSequenceNumber % defaultTelemetrySignalSampleCount === 1 &&
|
|
3597
3637
|
this._signalTracking.roundTripSignalSequenceNumber === undefined
|
|
3598
3638
|
) {
|
|
3599
3639
|
this._signalTracking.signalTimestamp = Date.now();
|
|
@@ -3687,6 +3727,12 @@ export class ContainerRuntime
|
|
|
3687
3727
|
|
|
3688
3728
|
public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>;
|
|
3689
3729
|
|
|
3730
|
+
/**
|
|
3731
|
+
* Builds the Summary tree including all the channels and the container state.
|
|
3732
|
+
*
|
|
3733
|
+
* @remarks - Unfortunately, this function is accessed in a non-typesafe way by a legacy first-party partner,
|
|
3734
|
+
* so until we can provide a proper API for their scenario, we need to ensure this function doesn't change.
|
|
3735
|
+
*/
|
|
3690
3736
|
private async summarizeInternal(
|
|
3691
3737
|
fullTree: boolean,
|
|
3692
3738
|
trackState: boolean,
|
|
@@ -3834,8 +3880,10 @@ export class ContainerRuntime
|
|
|
3834
3880
|
const { dataStoreRoutes, blobManagerRoutes } =
|
|
3835
3881
|
this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
3836
3882
|
|
|
3837
|
-
|
|
3838
|
-
|
|
3883
|
+
return [
|
|
3884
|
+
...this.channelCollection.deleteSweepReadyNodes(dataStoreRoutes),
|
|
3885
|
+
...this.blobManager.deleteSweepReadyNodes(blobManagerRoutes),
|
|
3886
|
+
];
|
|
3839
3887
|
}
|
|
3840
3888
|
|
|
3841
3889
|
/**
|
|
@@ -3864,10 +3912,13 @@ export class ContainerRuntime
|
|
|
3864
3912
|
* Returns the type of the GC node. Currently, there are nodes that belong to the root ("/"), data stores or
|
|
3865
3913
|
* blob manager.
|
|
3866
3914
|
*/
|
|
3915
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3867
3916
|
public getNodeType(nodePath: string): GCNodeType {
|
|
3868
3917
|
if (isBlobPath(nodePath)) {
|
|
3918
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3869
3919
|
return GCNodeType.Blob;
|
|
3870
3920
|
}
|
|
3921
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3871
3922
|
return this.channelCollection.getGCNodeType(nodePath) ?? GCNodeType.Other;
|
|
3872
3923
|
}
|
|
3873
3924
|
|
|
@@ -3883,13 +3934,19 @@ export class ContainerRuntime
|
|
|
3883
3934
|
}
|
|
3884
3935
|
|
|
3885
3936
|
switch (this.getNodeType(nodePath)) {
|
|
3886
|
-
|
|
3937
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3938
|
+
case GCNodeType.Blob: {
|
|
3887
3939
|
return [blobManagerBasePath];
|
|
3940
|
+
}
|
|
3941
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3888
3942
|
case GCNodeType.DataStore:
|
|
3889
|
-
|
|
3943
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3944
|
+
case GCNodeType.SubDataStore: {
|
|
3890
3945
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
3891
|
-
|
|
3946
|
+
}
|
|
3947
|
+
default: {
|
|
3892
3948
|
assert(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
3949
|
+
}
|
|
3893
3950
|
}
|
|
3894
3951
|
}
|
|
3895
3952
|
|
|
@@ -3935,6 +3992,7 @@ export class ContainerRuntime
|
|
|
3935
3992
|
fullGC?: boolean;
|
|
3936
3993
|
},
|
|
3937
3994
|
telemetryContext?: ITelemetryContext,
|
|
3995
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3938
3996
|
): Promise<IGCStats | undefined> {
|
|
3939
3997
|
return this.garbageCollector.collectGarbage(options, telemetryContext);
|
|
3940
3998
|
}
|
|
@@ -3977,8 +4035,10 @@ export class ContainerRuntime
|
|
|
3977
4035
|
* op processing, updating SummarizerNode state tracking, and garbage collection.
|
|
3978
4036
|
* @param options - options controlling how the summary is generated or submitted
|
|
3979
4037
|
*/
|
|
4038
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3980
4039
|
public async submitSummary(options: ISubmitSummaryOptions): Promise<SubmitSummaryResult> {
|
|
3981
4040
|
const {
|
|
4041
|
+
cancellationToken,
|
|
3982
4042
|
fullTree = false,
|
|
3983
4043
|
finalAttempt = false,
|
|
3984
4044
|
summaryLogger,
|
|
@@ -4098,7 +4158,7 @@ export class ContainerRuntime
|
|
|
4098
4158
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
4099
4159
|
details: {
|
|
4100
4160
|
...startSummaryResult,
|
|
4101
|
-
mismatchNumbers:
|
|
4161
|
+
mismatchNumbers: [...startSummaryResult.mismatchNumbers],
|
|
4102
4162
|
},
|
|
4103
4163
|
});
|
|
4104
4164
|
|
|
@@ -4122,7 +4182,7 @@ export class ContainerRuntime
|
|
|
4122
4182
|
// summarizer to reconnect in the future.
|
|
4123
4183
|
// Also checking for cancellation is a must as summary process may be abandoned for other reasons,
|
|
4124
4184
|
// like loss of connectivity for main (interactive) client.
|
|
4125
|
-
if (
|
|
4185
|
+
if (cancellationToken.cancelled) {
|
|
4126
4186
|
return { continue: false, error: "disconnected" };
|
|
4127
4187
|
}
|
|
4128
4188
|
// That said, we rely on submitSystemMessage() that today only works in connected state.
|
|
@@ -4263,10 +4323,7 @@ export class ContainerRuntime
|
|
|
4263
4323
|
|
|
4264
4324
|
let handle: string;
|
|
4265
4325
|
try {
|
|
4266
|
-
handle = await this.storage.uploadSummaryWithContext(
|
|
4267
|
-
summarizeResult.summary,
|
|
4268
|
-
summaryContext,
|
|
4269
|
-
);
|
|
4326
|
+
handle = await this.storage.uploadSummaryWithContext(summaryTree, summaryContext);
|
|
4270
4327
|
} catch (error) {
|
|
4271
4328
|
return {
|
|
4272
4329
|
stage: "generate",
|
|
@@ -4416,14 +4473,14 @@ export class ContainerRuntime
|
|
|
4416
4473
|
}
|
|
4417
4474
|
|
|
4418
4475
|
private updateDocumentDirtyState(dirty: boolean): void {
|
|
4419
|
-
if (this.attachState
|
|
4420
|
-
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
4421
|
-
} else {
|
|
4476
|
+
if (this.attachState === AttachState.Attached) {
|
|
4422
4477
|
// Other way is not true = see this.isContainerMessageDirtyable()
|
|
4423
4478
|
assert(
|
|
4424
4479
|
!dirty || this.hasPendingMessages(),
|
|
4425
4480
|
0x3d3 /* if doc is dirty, there has to be pending ops */,
|
|
4426
4481
|
);
|
|
4482
|
+
} else {
|
|
4483
|
+
assert(dirty, 0x3d2 /* Non-attached container is dirty */);
|
|
4427
4484
|
}
|
|
4428
4485
|
|
|
4429
4486
|
if (this.dirtyContainer === dirty) {
|
|
@@ -4520,7 +4577,7 @@ export class ContainerRuntime
|
|
|
4520
4577
|
// on this callback to do actual sending.
|
|
4521
4578
|
const schemaChangeMessage = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
4522
4579
|
if (schemaChangeMessage) {
|
|
4523
|
-
this.logger.sendTelemetryEvent({
|
|
4580
|
+
this.mc.logger.sendTelemetryEvent({
|
|
4524
4581
|
eventName: "SchemaChangeProposal",
|
|
4525
4582
|
refSeq: schemaChangeMessage.refSeq,
|
|
4526
4583
|
version: schemaChangeMessage.version,
|
|
@@ -4574,6 +4631,9 @@ export class ContainerRuntime
|
|
|
4574
4631
|
}
|
|
4575
4632
|
|
|
4576
4633
|
this.flushTaskExists = true;
|
|
4634
|
+
|
|
4635
|
+
// TODO: hoist this out of the function scope to save unnecessary allocations
|
|
4636
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping -- Separate `flush` method already exists in outer scope
|
|
4577
4637
|
const flush = (): void => {
|
|
4578
4638
|
this.flushTaskExists = false;
|
|
4579
4639
|
try {
|
|
@@ -4584,27 +4644,30 @@ export class ContainerRuntime
|
|
|
4584
4644
|
};
|
|
4585
4645
|
|
|
4586
4646
|
switch (this.flushMode) {
|
|
4587
|
-
case FlushMode.TurnBased:
|
|
4647
|
+
case FlushMode.TurnBased: {
|
|
4588
4648
|
// When in TurnBased flush mode the runtime will buffer operations in the current turn and send them as a single
|
|
4589
4649
|
// batch at the end of the turn
|
|
4590
4650
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
4591
4651
|
Promise.resolve().then(flush);
|
|
4592
4652
|
break;
|
|
4653
|
+
}
|
|
4593
4654
|
|
|
4594
4655
|
// FlushModeExperimental is experimental and not exposed directly in the runtime APIs
|
|
4595
|
-
case FlushModeExperimental.Async as unknown as FlushMode:
|
|
4656
|
+
case FlushModeExperimental.Async as unknown as FlushMode: {
|
|
4596
4657
|
// When in Async flush mode, the runtime will accumulate all operations across JS turns and send them as a single
|
|
4597
4658
|
// batch when all micro-tasks are complete.
|
|
4598
4659
|
// Compared to TurnBased, this flush mode will capture more ops into the same batch.
|
|
4599
4660
|
setTimeout(flush, 0);
|
|
4600
4661
|
break;
|
|
4662
|
+
}
|
|
4601
4663
|
|
|
4602
|
-
default:
|
|
4664
|
+
default: {
|
|
4603
4665
|
assert(
|
|
4604
4666
|
this._orderSequentiallyCalls > 0,
|
|
4605
4667
|
0x587 /* Unreachable unless running under orderSequentially */,
|
|
4606
4668
|
);
|
|
4607
4669
|
break;
|
|
4670
|
+
}
|
|
4608
4671
|
}
|
|
4609
4672
|
}
|
|
4610
4673
|
|
|
@@ -4621,10 +4684,7 @@ export class ContainerRuntime
|
|
|
4621
4684
|
// System message should not be sent in the middle of the batch.
|
|
4622
4685
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
4623
4686
|
|
|
4624
|
-
|
|
4625
|
-
return this.submitSummaryFn !== undefined
|
|
4626
|
-
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
4627
|
-
: this.submitFn(MessageType.Summarize, contents, false);
|
|
4687
|
+
return this.submitSummaryFn(contents, referenceSequenceNumber);
|
|
4628
4688
|
}
|
|
4629
4689
|
|
|
4630
4690
|
/**
|
|
@@ -4674,17 +4734,18 @@ export class ContainerRuntime
|
|
|
4674
4734
|
opMetadata: Record<string, unknown> | undefined,
|
|
4675
4735
|
): void {
|
|
4676
4736
|
assert(
|
|
4677
|
-
|
|
4737
|
+
this._summarizer === undefined,
|
|
4678
4738
|
0x8f2 /* Summarizer never reconnects so should never resubmit */,
|
|
4679
4739
|
);
|
|
4680
4740
|
switch (message.type) {
|
|
4681
4741
|
case ContainerMessageType.FluidDataStoreOp:
|
|
4682
4742
|
case ContainerMessageType.Attach:
|
|
4683
|
-
case ContainerMessageType.Alias:
|
|
4743
|
+
case ContainerMessageType.Alias: {
|
|
4684
4744
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
4685
4745
|
// and trigger resubmission on it.
|
|
4686
4746
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
4687
4747
|
break;
|
|
4748
|
+
}
|
|
4688
4749
|
case ContainerMessageType.IdAllocation: {
|
|
4689
4750
|
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
4690
4751
|
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
@@ -4695,20 +4756,24 @@ export class ContainerRuntime
|
|
|
4695
4756
|
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
4696
4757
|
break;
|
|
4697
4758
|
}
|
|
4698
|
-
case ContainerMessageType.BlobAttach:
|
|
4759
|
+
case ContainerMessageType.BlobAttach: {
|
|
4699
4760
|
this.blobManager.reSubmit(opMetadata);
|
|
4700
4761
|
break;
|
|
4701
|
-
|
|
4762
|
+
}
|
|
4763
|
+
case ContainerMessageType.Rejoin: {
|
|
4702
4764
|
this.submit(message);
|
|
4703
4765
|
break;
|
|
4704
|
-
|
|
4766
|
+
}
|
|
4767
|
+
case ContainerMessageType.GC: {
|
|
4705
4768
|
this.submit(message);
|
|
4706
4769
|
break;
|
|
4707
|
-
|
|
4770
|
+
}
|
|
4771
|
+
case ContainerMessageType.DocumentSchemaChange: {
|
|
4708
4772
|
// There is no need to resend this message. Document schema controller will properly resend it again (if needed)
|
|
4709
4773
|
// on a first occasion (any ops sent after reconnect). There is a good chance, though, that it will not want to
|
|
4710
4774
|
// send any ops, as some other client already changed schema.
|
|
4711
4775
|
break;
|
|
4776
|
+
}
|
|
4712
4777
|
default: {
|
|
4713
4778
|
const error = getUnknownMessageTypeError(message.type, "reSubmitCore" /* codePath */);
|
|
4714
4779
|
this.closeFn(error);
|
|
@@ -4721,19 +4786,22 @@ export class ContainerRuntime
|
|
|
4721
4786
|
// Need to parse from string for back-compat
|
|
4722
4787
|
const { type, contents } = this.parseLocalOpContent(content);
|
|
4723
4788
|
switch (type) {
|
|
4724
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
4789
|
+
case ContainerMessageType.FluidDataStoreOp: {
|
|
4725
4790
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
4726
4791
|
// and trigger rollback on it.
|
|
4727
4792
|
this.channelCollection.rollback(type, contents, localOpMetadata);
|
|
4728
4793
|
break;
|
|
4729
|
-
|
|
4794
|
+
}
|
|
4795
|
+
default: {
|
|
4730
4796
|
throw new Error(`Can't rollback ${type}`);
|
|
4797
|
+
}
|
|
4731
4798
|
}
|
|
4732
4799
|
}
|
|
4733
4800
|
|
|
4734
4801
|
/**
|
|
4735
4802
|
* Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck
|
|
4736
4803
|
*/
|
|
4804
|
+
// eslint-disable-next-line import/no-deprecated
|
|
4737
4805
|
public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions): Promise<void> {
|
|
4738
4806
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
4739
4807
|
// proposalHandle is always passed from RunningSummarizer.
|
|
@@ -4780,6 +4848,9 @@ export class ContainerRuntime
|
|
|
4780
4848
|
};
|
|
4781
4849
|
}
|
|
4782
4850
|
|
|
4851
|
+
private readonly readAndParseBlob = async <T>(id: string): Promise<T> =>
|
|
4852
|
+
readAndParse<T>(this.storage, id);
|
|
4853
|
+
|
|
4783
4854
|
/**
|
|
4784
4855
|
* Fetches the latest snapshot from storage. If the fetched snapshot is same or newer than the one for which ack
|
|
4785
4856
|
* was received, close this client. Fetching the snapshot will update the cache for this client so if it's
|
|
@@ -4840,6 +4911,7 @@ export class ContainerRuntime
|
|
|
4840
4911
|
snapshotTree = snapshot.snapshotTree;
|
|
4841
4912
|
} else {
|
|
4842
4913
|
const versions = await this.storage.getVersions(
|
|
4914
|
+
// eslint-disable-next-line unicorn/no-null
|
|
4843
4915
|
null,
|
|
4844
4916
|
1,
|
|
4845
4917
|
scenarioName,
|
|
@@ -4855,9 +4927,8 @@ export class ContainerRuntime
|
|
|
4855
4927
|
}
|
|
4856
4928
|
|
|
4857
4929
|
props.getSnapshotDuration = trace.trace().duration;
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
const snapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
4930
|
+
|
|
4931
|
+
const snapshotRefSeq = await seqFromTree(snapshotTree, this.readAndParseBlob);
|
|
4861
4932
|
props.snapshotRefSeq = snapshotRefSeq;
|
|
4862
4933
|
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
4863
4934
|
|
|
@@ -4937,28 +5008,28 @@ export class ContainerRuntime
|
|
|
4937
5008
|
}
|
|
4938
5009
|
|
|
4939
5010
|
public summarizeOnDemand(options: IOnDemandSummarizeOptions): ISummarizeResults {
|
|
4940
|
-
if (this.
|
|
4941
|
-
return this.
|
|
4942
|
-
} else if (this.summaryManager
|
|
4943
|
-
return this.summaryManager.summarizeOnDemand(options);
|
|
4944
|
-
} else {
|
|
5011
|
+
if (this._summarizer !== undefined) {
|
|
5012
|
+
return this._summarizer.summarizeOnDemand(options);
|
|
5013
|
+
} else if (this.summaryManager === undefined) {
|
|
4945
5014
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
4946
5015
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
4947
5016
|
// because it is a misuse of the API rather than an expected failure.
|
|
4948
5017
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
5018
|
+
} else {
|
|
5019
|
+
return this.summaryManager.summarizeOnDemand(options);
|
|
4949
5020
|
}
|
|
4950
5021
|
}
|
|
4951
5022
|
|
|
4952
5023
|
public enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult {
|
|
4953
|
-
if (this.
|
|
4954
|
-
return this.
|
|
4955
|
-
} else if (this.summaryManager
|
|
4956
|
-
return this.summaryManager.enqueueSummarize(options);
|
|
4957
|
-
} else {
|
|
5024
|
+
if (this._summarizer !== undefined) {
|
|
5025
|
+
return this._summarizer.enqueueSummarize(options);
|
|
5026
|
+
} else if (this.summaryManager === undefined) {
|
|
4958
5027
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
4959
5028
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
4960
5029
|
// because it is a misuse of the API rather than an expected failure.
|
|
4961
5030
|
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
5031
|
+
} else {
|
|
5032
|
+
return this.summaryManager.enqueueSummarize(options);
|
|
4962
5033
|
}
|
|
4963
5034
|
}
|
|
4964
5035
|
|