@fluidframework/container-runtime 2.0.0-dev-rc.4.0.0.261659 → 2.0.0-dev-rc.5.0.0.265721
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 +46 -0
- package/api-report/container-runtime.api.md +60 -29
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +9 -9
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +3 -5
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +8 -6
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +22 -11
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.d.ts +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerHandleContext.d.ts +2 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +14 -24
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +125 -140
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +13 -10
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +21 -8
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
- package/dist/deltaManagerProxies.d.ts.map +1 -0
- package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +38 -2
- package/dist/deltaManagerProxies.js.map +1 -0
- package/dist/deltaScheduler.d.ts +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +1 -2
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +1 -1
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.d.ts.map +1 -1
- package/dist/gc/gcConfigs.js +14 -19
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -22
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +3 -3
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +1 -2
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/dist/gc/gcSummaryDefinitions.d.ts +1 -1
- package/dist/gc/gcSummaryDefinitions.d.ts.map +1 -1
- package/dist/gc/gcSummaryDefinitions.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
- package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +2 -2
- package/dist/gc/gcTelemetry.js.map +1 -1
- 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 +2 -2
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +6 -1
- package/dist/messageTypes.d.ts +5 -2
- package/dist/messageTypes.d.ts.map +1 -1
- package/dist/messageTypes.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +4 -0
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +1 -0
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -20
- package/dist/opLifecycle/outbox.js.map +1 -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 +6 -0
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +10 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.js.map +1 -1
- package/dist/summary/documentSchema.js +2 -2
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/index.d.ts +2 -2
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +4 -2
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +35 -13
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +0 -5
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +28 -113
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +1 -1
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +4 -1
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -2
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +16 -28
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +1 -1
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js +2 -2
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +26 -6
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +7 -8
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +30 -25
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.js +5 -5
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.js.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +9 -9
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +4 -6
- package/lib/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +8 -6
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +23 -12
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerHandleContext.d.ts +2 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +14 -24
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +125 -140
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +13 -10
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +23 -10
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/{deltaManagerSummarizerProxy.d.ts → deltaManagerProxies.d.ts} +28 -3
- package/lib/deltaManagerProxies.d.ts.map +1 -0
- package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +36 -1
- package/lib/deltaManagerProxies.js.map +1 -0
- package/lib/deltaScheduler.d.ts +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +1 -2
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +1 -1
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.d.ts.map +1 -1
- package/lib/gc/gcConfigs.js +15 -20
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -22
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +2 -2
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +1 -2
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts +1 -1
- package/lib/gc/gcSummaryDefinitions.d.ts.map +1 -1
- package/lib/gc/gcSummaryDefinitions.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
- package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +2 -2
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/gc/index.d.ts +1 -1
- package/lib/gc/index.d.ts.map +1 -1
- package/lib/gc/index.js +1 -1
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +6 -1
- package/lib/messageTypes.d.ts +5 -2
- package/lib/messageTypes.d.ts.map +1 -1
- package/lib/messageTypes.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +4 -0
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +1 -0
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -20
- package/lib/opLifecycle/outbox.js.map +1 -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 +6 -0
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +10 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.d.ts +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.js.map +1 -1
- package/lib/summary/documentSchema.js +2 -2
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/index.d.ts +2 -2
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +4 -2
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +35 -13
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +0 -5
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +21 -106
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +1 -1
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +4 -1
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -2
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +1 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +16 -28
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +1 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js +2 -2
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +26 -6
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +7 -8
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +24 -19
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.js +1 -1
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +65 -26
- package/src/blobManager.ts +14 -13
- package/src/channelCollection.ts +34 -20
- package/src/connectionTelemetry.ts +1 -1
- package/src/containerHandleContext.ts +2 -1
- package/src/containerRuntime.ts +161 -170
- package/src/dataStore.ts +3 -2
- package/src/dataStoreContext.ts +62 -23
- package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +55 -3
- package/src/deltaScheduler.ts +1 -1
- package/src/gc/garbageCollection.md +0 -8
- package/src/gc/garbageCollection.ts +2 -1
- package/src/gc/gcConfigs.ts +12 -19
- package/src/gc/gcDefinitions.ts +5 -23
- package/src/gc/gcHelpers.ts +1 -1
- package/src/gc/gcSummaryDefinitions.ts +1 -1
- package/src/gc/gcSummaryStateTracker.ts +1 -1
- package/src/gc/gcTelemetry.ts +1 -1
- package/src/gc/index.ts +1 -1
- package/src/index.ts +6 -1
- package/src/messageTypes.ts +4 -2
- package/src/opLifecycle/batchManager.ts +5 -0
- package/src/opLifecycle/outbox.ts +7 -30
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +11 -1
- package/src/scheduleManager.ts +1 -1
- package/src/summary/documentSchema.ts +1 -1
- package/src/summary/index.ts +5 -1
- package/src/summary/orderedClientElection.ts +83 -12
- package/src/summary/runningSummarizer.ts +30 -114
- package/src/summary/summarizer.ts +5 -2
- package/src/summary/summarizerNode/summarizerNode.ts +0 -2
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -3
- package/src/summary/summarizerTypes.ts +22 -29
- package/src/summary/summaryCollection.ts +1 -1
- package/src/summary/summaryFormat.ts +35 -6
- package/src/summary/summaryGenerator.ts +50 -27
- package/src/summary/summaryManager.ts +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
- package/dist/deltaManagerSummarizerProxy.js.map +0 -1
- package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
- package/lib/deltaManagerSummarizerProxy.js.map +0 -1
package/lib/containerRuntime.js
CHANGED
|
@@ -22,7 +22,7 @@ import { ReportOpPerfTelemetry } from "./connectionTelemetry.js";
|
|
|
22
22
|
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
23
23
|
import { channelToDataStore } from "./dataStore.js";
|
|
24
24
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
25
|
-
import { DeltaManagerSummarizerProxy } from "./
|
|
25
|
+
import { DeltaManagerPendingOpsProxy, DeltaManagerSummarizerProxy } from "./deltaManagerProxies.js";
|
|
26
26
|
import { GCNodeType, GarbageCollector, gcGenerationOptionName, } from "./gc/index.js";
|
|
27
27
|
import { ContainerMessageType, } from "./messageTypes.js";
|
|
28
28
|
import { OpCompressor, OpDecompressor, OpGroupingManager, OpSplitter, Outbox, RemoteMessageProcessor, } from "./opLifecycle/index.js";
|
|
@@ -49,13 +49,13 @@ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, co
|
|
|
49
49
|
export const DefaultSummaryConfiguration = {
|
|
50
50
|
state: "enabled",
|
|
51
51
|
minIdleTime: 0,
|
|
52
|
-
maxIdleTime: 30 * 1000,
|
|
53
|
-
maxTime: 60 * 1000,
|
|
54
|
-
maxOps: 100,
|
|
52
|
+
maxIdleTime: 30 * 1000, // 30 secs.
|
|
53
|
+
maxTime: 60 * 1000, // 1 min.
|
|
54
|
+
maxOps: 100, // Summarize if 100 weighted ops received since last snapshot.
|
|
55
55
|
minOpsForLastSummaryAttempt: 10,
|
|
56
|
-
maxAckWaitTime: 3 * 60 * 1000,
|
|
56
|
+
maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
|
|
57
57
|
maxOpsSinceLastSummary: 7000,
|
|
58
|
-
initialSummarizerDelayMs: 5 * 1000,
|
|
58
|
+
initialSummarizerDelayMs: 5 * 1000, // 5 secs.
|
|
59
59
|
nonRuntimeOpWeight: 0.1,
|
|
60
60
|
runtimeOpWeight: 1.0,
|
|
61
61
|
nonRuntimeHeuristicThreshold: 20,
|
|
@@ -246,7 +246,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
246
246
|
},
|
|
247
247
|
});
|
|
248
248
|
const mc = loggerToMonitoringContext(logger);
|
|
249
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching =
|
|
249
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching = true, explicitSchemaControl = false, } = runtimeOptions;
|
|
250
250
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
251
251
|
const tryFetchBlob = async (blobName) => {
|
|
252
252
|
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
@@ -368,23 +368,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
368
368
|
return createIdCompressor(compressorLogger);
|
|
369
369
|
}
|
|
370
370
|
};
|
|
371
|
-
const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
|
|
372
371
|
const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
373
372
|
const compressionLz4 = disableCompression !== true &&
|
|
374
373
|
compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
375
374
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
376
|
-
const opGroupingEnabled = disableGroupedBatching !== true && enableGroupedBatching;
|
|
377
375
|
const documentSchemaController = new DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
|
|
378
376
|
explicitSchemaControl,
|
|
379
377
|
compressionLz4,
|
|
380
378
|
idCompressorMode,
|
|
381
|
-
opGroupingEnabled,
|
|
379
|
+
opGroupingEnabled: enableGroupedBatching,
|
|
382
380
|
disallowedVersions: [],
|
|
383
381
|
}, (schema) => {
|
|
384
382
|
runtime.onSchemaChange(schema);
|
|
385
383
|
});
|
|
386
384
|
const featureGatesForTelemetry = {
|
|
387
|
-
disableGroupedBatching,
|
|
388
385
|
disableCompression,
|
|
389
386
|
};
|
|
390
387
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
@@ -531,7 +528,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
531
528
|
return this.garbageCollector.throwOnTombstoneUsage;
|
|
532
529
|
}
|
|
533
530
|
/***/
|
|
534
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope,
|
|
531
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope,
|
|
532
|
+
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
533
|
+
baseLogger, existing, blobManagerSnapshot, _storage, createIdCompressor, documentsSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, summaryConfiguration = {
|
|
535
534
|
// the defaults
|
|
536
535
|
...DefaultSummaryConfiguration,
|
|
537
536
|
// the runtime configuration overrides
|
|
@@ -542,7 +541,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
542
541
|
this.metadata = metadata;
|
|
543
542
|
this.runtimeOptions = runtimeOptions;
|
|
544
543
|
this.containerScope = containerScope;
|
|
545
|
-
this.
|
|
544
|
+
this.baseLogger = baseLogger;
|
|
546
545
|
this._storage = _storage;
|
|
547
546
|
this.createIdCompressor = createIdCompressor;
|
|
548
547
|
this.documentsSchemaController = documentsSchemaController;
|
|
@@ -573,7 +572,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
573
572
|
this.snapshotCacheForLoadingGroupIds = new PromiseCache({
|
|
574
573
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
575
574
|
});
|
|
576
|
-
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
575
|
+
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, snapshotWithContents, } = context;
|
|
576
|
+
this.logger = createChildLogger({ logger: this.baseLogger });
|
|
577
577
|
this.mc = createChildMonitoringContext({
|
|
578
578
|
logger: this.logger,
|
|
579
579
|
namespace: "ContainerRuntime",
|
|
@@ -589,7 +589,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
589
589
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
590
590
|
};
|
|
591
591
|
this.innerDeltaManager = deltaManager;
|
|
592
|
-
this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
593
592
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
594
593
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
595
594
|
this.submitFn = submitFn;
|
|
@@ -663,6 +662,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
663
662
|
}, this.mc.logger);
|
|
664
663
|
const opSplitter = new OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
665
664
|
this.remoteMessageProcessor = new RemoteMessageProcessor(opSplitter, new OpDecompressor(this.mc.logger), opGroupingManager);
|
|
665
|
+
const pendingRuntimeState = pendingLocalState;
|
|
666
|
+
this.pendingStateManager = new PendingStateManager({
|
|
667
|
+
applyStashedOp: this.applyStashedOp.bind(this),
|
|
668
|
+
clientId: () => this.clientId,
|
|
669
|
+
close: this.closeFn,
|
|
670
|
+
connected: () => this.connected,
|
|
671
|
+
reSubmit: (message) => {
|
|
672
|
+
this.reSubmit(message);
|
|
673
|
+
this.flush();
|
|
674
|
+
},
|
|
675
|
+
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
676
|
+
isActiveConnection: () => this.innerDeltaManager.active,
|
|
677
|
+
isAttached: () => this.attachState !== AttachState.Detached,
|
|
678
|
+
}, pendingRuntimeState?.pending, this.logger);
|
|
679
|
+
let outerDeltaManager;
|
|
680
|
+
const useDeltaManagerOpsProxy = this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
|
|
681
|
+
// The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
|
|
682
|
+
const summarizerDeltaManagerProxy = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
683
|
+
outerDeltaManager = summarizerDeltaManagerProxy;
|
|
684
|
+
// The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
|
|
685
|
+
// It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
|
|
686
|
+
if (useDeltaManagerOpsProxy) {
|
|
687
|
+
const pendingOpsDeltaManagerProxy = new DeltaManagerPendingOpsProxy(summarizerDeltaManagerProxy, this.pendingStateManager);
|
|
688
|
+
outerDeltaManager = pendingOpsDeltaManagerProxy;
|
|
689
|
+
}
|
|
690
|
+
this.deltaManager = outerDeltaManager;
|
|
666
691
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
667
692
|
if (this.summaryConfiguration.state === "enabled") {
|
|
668
693
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
@@ -682,7 +707,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
682
707
|
else {
|
|
683
708
|
this._flushMode = runtimeOptions.flushMode;
|
|
684
709
|
}
|
|
685
|
-
const pendingRuntimeState = pendingLocalState;
|
|
686
710
|
if (context.attachState === AttachState.Attached) {
|
|
687
711
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
688
712
|
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
@@ -738,7 +762,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
738
762
|
const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
|
|
739
763
|
return this.submitSignalFn(envelope2, targetClientId);
|
|
740
764
|
};
|
|
741
|
-
|
|
765
|
+
let snapshot = getSummaryForDatastores(baseSnapshot, metadata);
|
|
766
|
+
if (snapshot !== undefined && snapshotWithContents !== undefined) {
|
|
767
|
+
snapshot = {
|
|
768
|
+
...snapshotWithContents,
|
|
769
|
+
snapshotTree: snapshot,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
this.channelCollection = new ChannelCollection(snapshot, parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
742
773
|
this.blobManager = new BlobManager({
|
|
743
774
|
routeContext: this.handleContext,
|
|
744
775
|
snapshot: blobManagerSnapshot,
|
|
@@ -761,19 +792,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
761
792
|
closeContainer: (error) => this.closeFn(error),
|
|
762
793
|
});
|
|
763
794
|
this.scheduleManager = new ScheduleManager(this.innerDeltaManager, this, () => this.clientId, createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
764
|
-
this.pendingStateManager = new PendingStateManager({
|
|
765
|
-
applyStashedOp: this.applyStashedOp.bind(this),
|
|
766
|
-
clientId: () => this.clientId,
|
|
767
|
-
close: this.closeFn,
|
|
768
|
-
connected: () => this.connected,
|
|
769
|
-
reSubmit: (message) => {
|
|
770
|
-
this.reSubmit(message);
|
|
771
|
-
this.flush();
|
|
772
|
-
},
|
|
773
|
-
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
774
|
-
isActiveConnection: () => this.innerDeltaManager.active,
|
|
775
|
-
isAttached: () => this.attachState !== AttachState.Detached,
|
|
776
|
-
}, pendingRuntimeState?.pending, this.logger);
|
|
777
795
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
778
796
|
const legacySendBatchFn = makeLegacySendBatchFn(this.submitFn, this.innerDeltaManager);
|
|
779
797
|
this.outbox = new Outbox({
|
|
@@ -818,7 +836,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
818
836
|
let oldClientId = this.clientId;
|
|
819
837
|
this.on("connected", () => {
|
|
820
838
|
const clientId = this.clientId;
|
|
821
|
-
assert(clientId !== undefined,
|
|
839
|
+
assert(clientId !== undefined, 0x975 /* can't be undefined */);
|
|
822
840
|
audience.emit("selfChanged", { clientId: oldClientId }, { clientId, client: audience.getMember(clientId) });
|
|
823
841
|
oldClientId = clientId;
|
|
824
842
|
});
|
|
@@ -838,7 +856,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
838
856
|
namespace: "OrderedClientElection",
|
|
839
857
|
});
|
|
840
858
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
841
|
-
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
859
|
+
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible, this.mc.config.getBoolean("Fluid.ContainerRuntime.OrderedClientElection.EnablePerformanceEvents"));
|
|
842
860
|
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
843
861
|
if (this.isSummarizerClient) {
|
|
844
862
|
this._summarizer = new Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime,
|
|
@@ -882,7 +900,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
882
900
|
}
|
|
883
901
|
}
|
|
884
902
|
// logging hardware telemetry
|
|
885
|
-
logger.sendTelemetryEvent({
|
|
903
|
+
this.logger.sendTelemetryEvent({
|
|
886
904
|
eventName: "DeviceSpec",
|
|
887
905
|
...getDeviceSpec(),
|
|
888
906
|
});
|
|
@@ -1045,7 +1063,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1045
1063
|
const props = {
|
|
1046
1064
|
eventName: "GroupIdSnapshotCatchup",
|
|
1047
1065
|
loadingGroupIds: sortedLoadingGroupIds.join(","),
|
|
1048
|
-
targetSequenceNumber: snapshotSeqNumber,
|
|
1066
|
+
targetSequenceNumber: snapshotSeqNumber, // This is so we reuse some columns in telemetry
|
|
1049
1067
|
sequenceNumber: this.deltaManager.lastSequenceNumber, // This is so we reuse some columns in telemetry
|
|
1050
1068
|
};
|
|
1051
1069
|
const event = PerformanceEvent.start(this.mc.logger, {
|
|
@@ -1259,6 +1277,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1259
1277
|
this.emitDirtyDocumentEvent = false;
|
|
1260
1278
|
let newState;
|
|
1261
1279
|
try {
|
|
1280
|
+
this.submitIdAllocationOpIfNeeded(true);
|
|
1262
1281
|
// replay the ops
|
|
1263
1282
|
this.pendingStateManager.replayPendingStates();
|
|
1264
1283
|
}
|
|
@@ -1306,8 +1325,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1306
1325
|
return;
|
|
1307
1326
|
case ContainerMessageType.BlobAttach:
|
|
1308
1327
|
return;
|
|
1309
|
-
case ContainerMessageType.ChunkedOp:
|
|
1310
|
-
throw new Error("chunkedOp not expected here");
|
|
1311
1328
|
case ContainerMessageType.Rejoin:
|
|
1312
1329
|
throw new Error("rejoin not expected here");
|
|
1313
1330
|
case ContainerMessageType.GC:
|
|
@@ -1319,7 +1336,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1319
1336
|
// e.g. if an app rolled back its container version
|
|
1320
1337
|
const compatBehavior = opContents.compatDetails?.behavior;
|
|
1321
1338
|
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
1322
|
-
const error = DataProcessingError.create("Stashed runtime message of
|
|
1339
|
+
const error = DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1323
1340
|
messageDetails: JSON.stringify({
|
|
1324
1341
|
type: opContents.type,
|
|
1325
1342
|
compatBehavior,
|
|
@@ -1345,7 +1362,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1345
1362
|
for (const range of ops) {
|
|
1346
1363
|
compressor.finalizeCreationRange(range);
|
|
1347
1364
|
}
|
|
1348
|
-
assert(this.pendingIdCompressorOps.length === 0,
|
|
1365
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
|
|
1349
1366
|
this._idCompressor = compressor;
|
|
1350
1367
|
})
|
|
1351
1368
|
.catch((error) => {
|
|
@@ -1358,8 +1375,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1358
1375
|
setConnectionState(connected, clientId) {
|
|
1359
1376
|
// Validate we have consistent state
|
|
1360
1377
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
1361
|
-
assert(clientId === currentClientId,
|
|
1362
|
-
assert(this.clientId === currentClientId,
|
|
1378
|
+
assert(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
1379
|
+
assert(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
|
|
1363
1380
|
if (connected && this.idCompressorMode === "delayed") {
|
|
1364
1381
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1365
1382
|
this.loadIdCompressor();
|
|
@@ -1469,6 +1486,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1469
1486
|
*/
|
|
1470
1487
|
processCore(messageWithContext) {
|
|
1471
1488
|
const { message, local } = messageWithContext;
|
|
1489
|
+
// Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
|
|
1490
|
+
// Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
|
|
1491
|
+
if (this.deltaManager.minimumSequenceNumber <
|
|
1492
|
+
messageWithContext.message.minimumSequenceNumber) {
|
|
1493
|
+
messageWithContext.message.minimumSequenceNumber =
|
|
1494
|
+
this.deltaManager.minimumSequenceNumber;
|
|
1495
|
+
}
|
|
1472
1496
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1473
1497
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1474
1498
|
// messages once a batch has been fully processed.
|
|
@@ -1535,7 +1559,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1535
1559
|
this.pendingIdCompressorOps.push(range);
|
|
1536
1560
|
}
|
|
1537
1561
|
else {
|
|
1538
|
-
assert(this.pendingIdCompressorOps.length === 0,
|
|
1562
|
+
assert(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
|
|
1539
1563
|
this._idCompressor.finalizeCreationRange(range);
|
|
1540
1564
|
}
|
|
1541
1565
|
}
|
|
@@ -1896,7 +1920,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1896
1920
|
return { stats, summary };
|
|
1897
1921
|
}
|
|
1898
1922
|
finally {
|
|
1899
|
-
|
|
1923
|
+
summaryLogger.sendTelemetryEvent({
|
|
1900
1924
|
eventName: "SummarizeTelemetry",
|
|
1901
1925
|
details: telemetryContext.serialize(),
|
|
1902
1926
|
});
|
|
@@ -2055,7 +2079,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2055
2079
|
* @param options - options controlling how the summary is generated or submitted
|
|
2056
2080
|
*/
|
|
2057
2081
|
async submitSummary(options) {
|
|
2058
|
-
const { fullTree = false, finalAttempt = false,
|
|
2082
|
+
const { fullTree = false, finalAttempt = false, summaryLogger, latestSummaryRefSeqNum, } = options;
|
|
2059
2083
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2060
2084
|
// use it for all events logged during this summary.
|
|
2061
2085
|
const summaryNumber = this.nextSummaryNumber;
|
|
@@ -2070,13 +2094,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2070
2094
|
},
|
|
2071
2095
|
});
|
|
2072
2096
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
2073
|
-
// We close the summarizer and download a new snapshot and reload the container
|
|
2074
|
-
if (refreshLatestAck === true) {
|
|
2075
|
-
return this.prefetchLatestSummaryThenClose(createChildLogger({
|
|
2076
|
-
logger: summaryNumberLogger,
|
|
2077
|
-
properties: { all: { safeSummary: true } },
|
|
2078
|
-
}));
|
|
2079
|
-
}
|
|
2080
2097
|
// If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
|
|
2081
2098
|
// and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
|
|
2082
2099
|
// saved within the timeout, check if it should be failed or can continue.
|
|
@@ -2145,7 +2162,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2145
2162
|
stage: "base",
|
|
2146
2163
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2147
2164
|
minimumSequenceNumber,
|
|
2148
|
-
error: new
|
|
2165
|
+
error: new RetriableSummaryError(`Summarizer node state inconsistent with summarizer state.`),
|
|
2149
2166
|
};
|
|
2150
2167
|
}
|
|
2151
2168
|
}
|
|
@@ -2188,7 +2205,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2188
2205
|
stage: "base",
|
|
2189
2206
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2190
2207
|
minimumSequenceNumber,
|
|
2191
|
-
error: new
|
|
2208
|
+
error: new RetriableSummaryError(continueResult.error),
|
|
2192
2209
|
};
|
|
2193
2210
|
}
|
|
2194
2211
|
const trace = Trace.start();
|
|
@@ -2209,7 +2226,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2209
2226
|
stage: "base",
|
|
2210
2227
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2211
2228
|
minimumSequenceNumber,
|
|
2212
|
-
error: wrapError(error, (msg) => new
|
|
2229
|
+
error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
|
|
2213
2230
|
};
|
|
2214
2231
|
}
|
|
2215
2232
|
// Validate that the summary generated by summarizer nodes is correct before uploading.
|
|
@@ -2264,7 +2281,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2264
2281
|
return {
|
|
2265
2282
|
stage: "generate",
|
|
2266
2283
|
...generateSummaryData,
|
|
2267
|
-
error: new
|
|
2284
|
+
error: new RetriableSummaryError(continueResult.error),
|
|
2268
2285
|
};
|
|
2269
2286
|
}
|
|
2270
2287
|
const summaryContext = lastAck === undefined
|
|
@@ -2286,7 +2303,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2286
2303
|
return {
|
|
2287
2304
|
stage: "generate",
|
|
2288
2305
|
...generateSummaryData,
|
|
2289
|
-
error: wrapError(error, (msg) => new
|
|
2306
|
+
error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
|
|
2290
2307
|
};
|
|
2291
2308
|
}
|
|
2292
2309
|
const parent = summaryContext.ackHandle;
|
|
@@ -2307,7 +2324,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2307
2324
|
return {
|
|
2308
2325
|
stage: "upload",
|
|
2309
2326
|
...uploadData,
|
|
2310
|
-
error: new
|
|
2327
|
+
error: new RetriableSummaryError(continueResult.error),
|
|
2311
2328
|
};
|
|
2312
2329
|
}
|
|
2313
2330
|
let clientSequenceNumber;
|
|
@@ -2318,7 +2335,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2318
2335
|
return {
|
|
2319
2336
|
stage: "upload",
|
|
2320
2337
|
...uploadData,
|
|
2321
|
-
error: wrapError(error, (msg) => new
|
|
2338
|
+
error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
|
|
2322
2339
|
};
|
|
2323
2340
|
}
|
|
2324
2341
|
const submitData = {
|
|
@@ -2334,7 +2351,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2334
2351
|
return {
|
|
2335
2352
|
stage: "upload",
|
|
2336
2353
|
...uploadData,
|
|
2337
|
-
error: wrapError(error, (msg) => new
|
|
2354
|
+
error: wrapError(error, (msg) => new RetriableSummaryError(msg)),
|
|
2338
2355
|
};
|
|
2339
2356
|
}
|
|
2340
2357
|
return submitData;
|
|
@@ -2424,11 +2441,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2424
2441
|
this.verifyNotClosed();
|
|
2425
2442
|
return this.blobManager.createBlob(blob, signal);
|
|
2426
2443
|
}
|
|
2427
|
-
submitIdAllocationOpIfNeeded() {
|
|
2444
|
+
submitIdAllocationOpIfNeeded(resubmitOutstandingRanges) {
|
|
2428
2445
|
if (this._idCompressor) {
|
|
2429
|
-
const idRange =
|
|
2446
|
+
const idRange = resubmitOutstandingRanges
|
|
2447
|
+
? this._idCompressor.takeUnfinalizedCreationRange()
|
|
2448
|
+
: this._idCompressor.takeNextCreationRange();
|
|
2430
2449
|
// Don't include the idRange if there weren't any Ids allocated
|
|
2431
|
-
if (idRange
|
|
2450
|
+
if (idRange.ids !== undefined) {
|
|
2432
2451
|
const idAllocationMessage = {
|
|
2433
2452
|
type: ContainerMessageType.IdAllocation,
|
|
2434
2453
|
contents: idRange,
|
|
@@ -2457,6 +2476,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2457
2476
|
});
|
|
2458
2477
|
}
|
|
2459
2478
|
const type = containerRuntimeMessage.type;
|
|
2479
|
+
assert(type !== ContainerMessageType.IdAllocation, "IdAllocation should be submitted directly to outbox.");
|
|
2460
2480
|
const message = {
|
|
2461
2481
|
contents: serializedContent,
|
|
2462
2482
|
metadata,
|
|
@@ -2464,44 +2484,35 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2464
2484
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2465
2485
|
};
|
|
2466
2486
|
try {
|
|
2467
|
-
|
|
2468
|
-
//
|
|
2469
|
-
//
|
|
2470
|
-
//
|
|
2471
|
-
|
|
2472
|
-
|
|
2487
|
+
this.submitIdAllocationOpIfNeeded(false);
|
|
2488
|
+
// Allow document schema controller to send a message if it needs to propose change in document schema.
|
|
2489
|
+
// If it needs to send a message, it will call provided callback with payload of such message and rely
|
|
2490
|
+
// on this callback to do actual sending.
|
|
2491
|
+
const contents = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2492
|
+
if (contents) {
|
|
2493
|
+
this.logger.sendTelemetryEvent({
|
|
2494
|
+
eventName: "SchemaChangeProposal",
|
|
2495
|
+
refSeq: contents.refSeq,
|
|
2496
|
+
version: contents.version,
|
|
2497
|
+
newRuntimeSchema: JSON.stringify(contents.runtime),
|
|
2498
|
+
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
2499
|
+
oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
|
|
2500
|
+
});
|
|
2501
|
+
const msg = {
|
|
2502
|
+
type: ContainerMessageType.DocumentSchemaChange,
|
|
2503
|
+
contents,
|
|
2504
|
+
};
|
|
2505
|
+
this.outbox.submit({
|
|
2506
|
+
contents: JSON.stringify(msg),
|
|
2507
|
+
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
if (type === ContainerMessageType.BlobAttach) {
|
|
2511
|
+
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2512
|
+
this.outbox.submitBlobAttach(message);
|
|
2473
2513
|
}
|
|
2474
2514
|
else {
|
|
2475
|
-
this.
|
|
2476
|
-
// Allow document schema controller to send a message if it needs to propose change in document schema.
|
|
2477
|
-
// If it needs to send a message, it will call provided callback with payload of such message and rely
|
|
2478
|
-
// on this callback to do actual sending.
|
|
2479
|
-
const contents = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2480
|
-
if (contents) {
|
|
2481
|
-
this.logger.sendTelemetryEvent({
|
|
2482
|
-
eventName: "SchemaChangeProposal",
|
|
2483
|
-
refSeq: contents.refSeq,
|
|
2484
|
-
version: contents.version,
|
|
2485
|
-
newRuntimeSchema: JSON.stringify(contents.runtime),
|
|
2486
|
-
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
2487
|
-
oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
|
|
2488
|
-
});
|
|
2489
|
-
const msg = {
|
|
2490
|
-
type: ContainerMessageType.DocumentSchemaChange,
|
|
2491
|
-
contents,
|
|
2492
|
-
};
|
|
2493
|
-
this.outbox.submit({
|
|
2494
|
-
contents: JSON.stringify(msg),
|
|
2495
|
-
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2496
|
-
});
|
|
2497
|
-
}
|
|
2498
|
-
if (type === ContainerMessageType.BlobAttach) {
|
|
2499
|
-
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2500
|
-
this.outbox.submitBlobAttach(message);
|
|
2501
|
-
}
|
|
2502
|
-
else {
|
|
2503
|
-
this.outbox.submit(message);
|
|
2504
|
-
}
|
|
2515
|
+
this.outbox.submit(message);
|
|
2505
2516
|
}
|
|
2506
2517
|
if (!this.currentlyBatching()) {
|
|
2507
2518
|
this.flush();
|
|
@@ -2601,11 +2612,15 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2601
2612
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2602
2613
|
break;
|
|
2603
2614
|
case ContainerMessageType.IdAllocation: {
|
|
2604
|
-
|
|
2615
|
+
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
2616
|
+
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
2617
|
+
// [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
|
|
2618
|
+
// placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
|
|
2619
|
+
// To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
|
|
2620
|
+
// manager to replay pending ops, the runtime will always submit a new allocation range that includes
|
|
2621
|
+
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
2605
2622
|
break;
|
|
2606
2623
|
}
|
|
2607
|
-
case ContainerMessageType.ChunkedOp:
|
|
2608
|
-
throw new Error(`chunkedOp not expected here`);
|
|
2609
2624
|
case ContainerMessageType.BlobAttach:
|
|
2610
2625
|
this.blobManager.reSubmit(opMetadata);
|
|
2611
2626
|
break;
|
|
@@ -2632,7 +2647,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2632
2647
|
});
|
|
2633
2648
|
}
|
|
2634
2649
|
else {
|
|
2635
|
-
const error = DataProcessingError.create("Resubmitting runtime message of
|
|
2650
|
+
const error = DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
|
|
2636
2651
|
messageDetails: JSON.stringify({
|
|
2637
2652
|
type: message.type,
|
|
2638
2653
|
compatBehavior,
|
|
@@ -2672,51 +2687,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2672
2687
|
* and then close as the current main client is likely to be re-elected as the parent summarizer again.
|
|
2673
2688
|
*/
|
|
2674
2689
|
if (!result.isSummaryTracked && result.isSummaryNewer) {
|
|
2675
|
-
await this.
|
|
2690
|
+
await this.fetchLatestSnapshotAndClose(summaryLogger, {
|
|
2676
2691
|
eventName: "RefreshLatestSummaryAckFetch",
|
|
2677
2692
|
ackHandle,
|
|
2678
2693
|
targetSequenceNumber: summaryRefSeq,
|
|
2679
2694
|
}, readAndParseBlob);
|
|
2680
|
-
await this.closeStaleSummarizer();
|
|
2681
2695
|
return;
|
|
2682
2696
|
}
|
|
2683
2697
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2684
2698
|
await this.garbageCollector.refreshLatestSummary(result);
|
|
2685
2699
|
}
|
|
2686
2700
|
/**
|
|
2687
|
-
* Fetches the latest snapshot from storage
|
|
2688
|
-
*
|
|
2689
|
-
*
|
|
2690
|
-
* @returns a generic summarization error
|
|
2701
|
+
* Fetches the latest snapshot from storage and closes the container. This is done in cases where
|
|
2702
|
+
* the last known snapshot is older than the latest one. This will ensure that the latest snapshot
|
|
2703
|
+
* is downloaded and we don't end up loading snapshot from cache.
|
|
2691
2704
|
*/
|
|
2692
|
-
async
|
|
2693
|
-
|
|
2694
|
-
// This is a performance optimization as the same parent is likely to be elected again, and would use its
|
|
2695
|
-
// cache to fetch the snapshot instead of the network.
|
|
2696
|
-
await this.fetchLatestSnapshotFromStorage(summaryLogger, {
|
|
2697
|
-
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2698
|
-
}, readAndParseBlob);
|
|
2699
|
-
await this.closeStaleSummarizer();
|
|
2700
|
-
return {
|
|
2701
|
-
stage: "base",
|
|
2702
|
-
error: new LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
|
|
2703
|
-
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2704
|
-
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
2705
|
-
};
|
|
2706
|
-
}
|
|
2707
|
-
async closeStaleSummarizer() {
|
|
2708
|
-
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
2709
|
-
await delay(this.closeSummarizerDelayMs);
|
|
2710
|
-
this._summarizer?.stop("latestSummaryStateStale");
|
|
2711
|
-
this.disposeFn();
|
|
2712
|
-
}
|
|
2713
|
-
/**
|
|
2714
|
-
* Downloads the latest snapshot from storage.
|
|
2715
|
-
* By default, it also closes the container after downloading the snapshot. However, this may be
|
|
2716
|
-
* overridden via options.
|
|
2717
|
-
*/
|
|
2718
|
-
async fetchLatestSnapshotFromStorage(logger, event, readAndParseBlob) {
|
|
2719
|
-
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2705
|
+
async fetchLatestSnapshotAndClose(logger, event, readAndParseBlob) {
|
|
2706
|
+
await PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2720
2707
|
const stats = {};
|
|
2721
2708
|
const trace = Trace.start();
|
|
2722
2709
|
const versions = await this.storage.getVersions(null, 1, "prefetchLatestSummaryBeforeClose", FetchSource.noCache);
|
|
@@ -2729,12 +2716,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2729
2716
|
stats.snapshotRefSeq = latestSnapshotRefSeq;
|
|
2730
2717
|
stats.snapshotVersion = versions[0].id;
|
|
2731
2718
|
perfEvent.end(stats);
|
|
2732
|
-
return {
|
|
2733
|
-
snapshotTree: maybeSnapshot,
|
|
2734
|
-
versionId: versions[0].id,
|
|
2735
|
-
latestSnapshotRefSeq,
|
|
2736
|
-
};
|
|
2737
2719
|
});
|
|
2720
|
+
await delay(this.closeSummarizerDelayMs);
|
|
2721
|
+
this._summarizer?.stop("latestSummaryStateStale");
|
|
2722
|
+
this.disposeFn();
|
|
2738
2723
|
}
|
|
2739
2724
|
getPendingLocalState(props) {
|
|
2740
2725
|
this.verifyNotClosed();
|