@fluidframework/container-runtime 2.0.0-dev-rc.3.0.0.254866 → 2.0.0-dev-rc.5.0.0.263932
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 +69 -0
- package/api-report/container-runtime.api.md +93 -39
- package/dist/batchTracker.d.ts +1 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +7 -7
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +2 -4
- package/dist/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +10 -6
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +85 -22
- 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 +54 -5
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +22 -35
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +232 -174
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +9 -6
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +19 -5
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts +2 -0
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js +7 -0
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/deltaManagerProxies.d.ts +81 -0
- package/dist/deltaManagerProxies.d.ts.map +1 -0
- package/dist/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +75 -20
- package/dist/deltaManagerProxies.js.map +1 -0
- package/dist/deltaScheduler.d.ts +2 -2
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +5 -12
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +45 -29
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +27 -6
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +5 -4
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +14 -2
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +14 -4
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +24 -21
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/index.d.ts +2 -2
- 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 +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/{alpha.d.ts → legacy.d.ts} +8 -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/metadata.d.ts +2 -2
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +4 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +0 -10
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +6 -6
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +2 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +0 -4
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +7 -38
- package/dist/opLifecycle/outbox.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 +9 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +26 -10
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +3 -0
- package/dist/scheduleManager.d.ts +2 -2
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +3 -1
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +34 -16
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/index.d.ts +1 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -2
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runningSummarizer.js +10 -10
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +1 -2
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.d.ts +1 -1
- package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +4 -3
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +4 -10
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.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 +2 -9
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +3 -5
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts +2 -2
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +25 -5
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts +1 -2
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +12 -11
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +5 -5
- package/dist/summary/summaryManager.js.map +1 -1
- package/{lib/beta.d.ts → internal.d.ts} +2 -0
- package/{dist/beta.d.ts → legacy.d.ts} +2 -0
- package/lib/batchTracker.d.ts +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +7 -7
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +3 -5
- package/lib/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +10 -6
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +88 -25
- 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 +49 -0
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +22 -35
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +232 -174
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +1 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +9 -6
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +21 -7
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts +2 -0
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js +7 -0
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/deltaManagerProxies.d.ts +81 -0
- package/lib/deltaManagerProxies.d.ts.map +1 -0
- package/lib/{deltaManagerSummarizerProxy.js → deltaManagerProxies.js} +72 -19
- package/lib/deltaManagerProxies.js.map +1 -0
- package/lib/deltaScheduler.d.ts +2 -2
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +5 -12
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +47 -31
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +27 -6
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +5 -4
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +12 -1
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +14 -4
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +24 -21
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/index.d.ts +2 -2
- 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 +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/{alpha.d.ts → legacy.d.ts} +8 -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/metadata.d.ts +2 -2
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +4 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +0 -10
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +6 -6
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +2 -2
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.js +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +0 -4
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +7 -38
- package/lib/opLifecycle/outbox.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 +9 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +27 -11
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +3 -0
- package/lib/scheduleManager.d.ts +2 -2
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +3 -1
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +34 -16
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/index.d.ts +1 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -2
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runningSummarizer.js +1 -1
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +1 -2
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.d.ts +1 -1
- package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +4 -3
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +4 -10
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -3
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.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 +2 -9
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +3 -5
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts +2 -2
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +25 -5
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts +1 -2
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +5 -4
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +2 -2
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +37 -59
- package/src/batchTracker.ts +1 -2
- package/src/blobManager.ts +11 -10
- package/src/channelCollection.ts +115 -47
- package/src/connectionTelemetry.ts +59 -4
- package/src/containerRuntime.ts +302 -270
- package/src/dataStore.ts +7 -4
- package/src/dataStoreContext.ts +57 -16
- package/src/dataStoreContexts.ts +13 -2
- package/src/{deltaManagerSummarizerProxy.ts → deltaManagerProxies.ts} +98 -24
- package/src/deltaScheduler.ts +2 -3
- package/src/gc/garbageCollection.ts +64 -42
- package/src/gc/gcDefinitions.ts +22 -10
- package/src/gc/gcHelpers.ts +14 -1
- package/src/gc/gcTelemetry.ts +57 -50
- package/src/gc/index.ts +2 -1
- package/src/index.ts +7 -0
- package/src/messageTypes.ts +4 -2
- package/src/metadata.ts +2 -2
- package/src/opLifecycle/README.md +4 -4
- package/src/opLifecycle/batchManager.ts +5 -14
- package/src/opLifecycle/opDecompressor.ts +12 -6
- package/src/opLifecycle/opGroupingManager.ts +2 -2
- package/src/opLifecycle/opSplitter.ts +1 -1
- package/src/opLifecycle/outbox.ts +7 -53
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +38 -15
- package/src/scheduleManager.ts +2 -2
- package/src/summary/documentSchema.ts +52 -18
- package/src/summary/index.ts +4 -0
- package/src/summary/orderedClientElection.ts +6 -3
- package/src/summary/runningSummarizer.ts +1 -1
- package/src/summary/summarizer.ts +1 -1
- package/src/summary/summarizerClientElection.ts +1 -1
- package/src/summary/summarizerHeuristics.ts +1 -1
- package/src/summary/summarizerNode/summarizerNode.ts +3 -12
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -3
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +1 -10
- package/src/summary/summarizerTypes.ts +6 -5
- package/src/summary/summaryCollection.ts +2 -2
- package/src/summary/summaryFormat.ts +30 -4
- package/src/summary/summaryGenerator.ts +20 -9
- package/src/summary/summaryManager.ts +6 -3
- package/dist/deltaManagerSummarizerProxy.d.ts +0 -44
- package/dist/deltaManagerSummarizerProxy.d.ts.map +0 -1
- package/dist/deltaManagerSummarizerProxy.js.map +0 -1
- package/lib/deltaManagerSummarizerProxy.d.ts +0 -44
- package/lib/deltaManagerSummarizerProxy.d.ts.map +0 -1
- package/lib/deltaManagerSummarizerProxy.js.map +0 -1
package/dist/containerRuntime.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
|
|
7
|
+
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.disabledCompressionConfig = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.DeletedResponseHeaderKey = exports.DefaultSummaryConfiguration = void 0;
|
|
8
8
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
9
9
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
10
10
|
const internal_1 = require("@fluidframework/container-definitions/internal");
|
|
@@ -23,7 +23,7 @@ const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
|
|
|
23
23
|
const containerHandleContext_js_1 = require("./containerHandleContext.js");
|
|
24
24
|
const dataStore_js_1 = require("./dataStore.js");
|
|
25
25
|
const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
|
|
26
|
-
const
|
|
26
|
+
const deltaManagerProxies_js_1 = require("./deltaManagerProxies.js");
|
|
27
27
|
const index_js_1 = require("./gc/index.js");
|
|
28
28
|
const messageTypes_js_1 = require("./messageTypes.js");
|
|
29
29
|
const index_js_2 = require("./opLifecycle/index.js");
|
|
@@ -61,6 +61,11 @@ exports.DefaultSummaryConfiguration = {
|
|
|
61
61
|
runtimeOpWeight: 1.0,
|
|
62
62
|
nonRuntimeHeuristicThreshold: 20,
|
|
63
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* Error responses when requesting a deleted object will have this header set to true
|
|
66
|
+
* @alpha
|
|
67
|
+
*/
|
|
68
|
+
exports.DeletedResponseHeaderKey = "wasDeleted";
|
|
64
69
|
/**
|
|
65
70
|
* Tombstone error responses will have this header set to true
|
|
66
71
|
* @alpha
|
|
@@ -245,7 +250,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
245
250
|
},
|
|
246
251
|
});
|
|
247
252
|
const mc = (0, internal_7.loggerToMonitoringContext)(logger);
|
|
248
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes,
|
|
253
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, compressionOptions = defaultCompressionConfig, maxBatchSizeInBytes = defaultMaxBatchSizeInBytes, enableRuntimeIdCompressor, chunkSizeInBytes = defaultChunkSizeInBytes, enableGroupedBatching = true, explicitSchemaControl = false, } = runtimeOptions;
|
|
249
254
|
const registry = new dataStoreRegistry_js_1.FluidDataStoreRegistry(registryEntries);
|
|
250
255
|
const tryFetchBlob = async (blobName) => {
|
|
251
256
|
const blobId = context.baseSnapshot?.blobs[blobName];
|
|
@@ -273,9 +278,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
273
278
|
const messageAtLastSummary = lastMessageFromMetadata(metadata);
|
|
274
279
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
275
280
|
const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
|
|
281
|
+
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
276
282
|
// When we load with pending state, we reuse an old snapshot so we don't expect these numbers to match
|
|
277
283
|
if (!context.pendingLocalState && runtimeSequenceNumber !== undefined) {
|
|
278
|
-
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
279
284
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
280
285
|
if (loadSequenceNumberVerification !== "bypass" &&
|
|
281
286
|
runtimeSequenceNumber !== protocolSequenceNumber) {
|
|
@@ -327,7 +332,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
327
332
|
?.idCompressorMode;
|
|
328
333
|
// This is the only exception to the rule above - we have proper plumbing to load ID compressor on schema change
|
|
329
334
|
// event. It is loaded async (relative to op processing), so this conversion is only safe for off -> delayed conversion!
|
|
330
|
-
|
|
335
|
+
// Clients do not expect ID compressor ops unless ID compressor is On for them, and that could be achieved only through
|
|
336
|
+
// explicit schema change, i.e. only if explicitSchemaControl is on.
|
|
337
|
+
// Note: it would be better if we throw on combination of options (explicitSchemaControl = off, desiredIdCompressorMode === "delayed")
|
|
338
|
+
// that is not supported. But our service tests are oblivious to these problems and throwing here will cause a ton of failures
|
|
339
|
+
// We ignored incompatible ID compressor changes from the start (they were sticky), so that's not a new problem being introduced...
|
|
340
|
+
if (idCompressorMode === undefined &&
|
|
341
|
+
desiredIdCompressorMode === "delayed" &&
|
|
342
|
+
explicitSchemaControl) {
|
|
331
343
|
idCompressorMode = desiredIdCompressorMode;
|
|
332
344
|
}
|
|
333
345
|
}
|
|
@@ -360,23 +372,20 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
360
372
|
return createIdCompressor(compressorLogger);
|
|
361
373
|
}
|
|
362
374
|
};
|
|
363
|
-
const disableGroupedBatching = mc.config.getBoolean("Fluid.ContainerRuntime.DisableGroupedBatching");
|
|
364
375
|
const disableCompression = mc.config.getBoolean("Fluid.ContainerRuntime.CompressionDisabled");
|
|
365
376
|
const compressionLz4 = disableCompression !== true &&
|
|
366
377
|
compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
367
378
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
368
|
-
const
|
|
369
|
-
const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, metadata?.documentSchema, {
|
|
379
|
+
const documentSchemaController = new index_js_3.DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
|
|
370
380
|
explicitSchemaControl,
|
|
371
381
|
compressionLz4,
|
|
372
382
|
idCompressorMode,
|
|
373
|
-
opGroupingEnabled,
|
|
383
|
+
opGroupingEnabled: enableGroupedBatching,
|
|
374
384
|
disallowedVersions: [],
|
|
375
385
|
}, (schema) => {
|
|
376
386
|
runtime.onSchemaChange(schema);
|
|
377
387
|
});
|
|
378
388
|
const featureGatesForTelemetry = {
|
|
379
|
-
disableGroupedBatching,
|
|
380
389
|
disableCompression,
|
|
381
390
|
};
|
|
382
391
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
@@ -389,7 +398,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
389
398
|
chunkSizeInBytes,
|
|
390
399
|
// Requires<> drops undefined from IdCompressorType
|
|
391
400
|
enableRuntimeIdCompressor: enableRuntimeIdCompressor,
|
|
392
|
-
enableOpReentryCheck,
|
|
393
401
|
enableGroupedBatching,
|
|
394
402
|
explicitSchemaControl,
|
|
395
403
|
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, createIdCompressorFn, documentSchemaController, featureGatesForTelemetry, provideEntryPoint, requestHandler, undefined);
|
|
@@ -428,11 +436,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
428
436
|
get attachState() {
|
|
429
437
|
return this._getAttachState();
|
|
430
438
|
}
|
|
431
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Current session schema - defines what options are on & off.
|
|
441
|
+
* It's overlap of document schema (controlled by summary & ops) and options controlling this session.
|
|
442
|
+
* For example, document schema might have compression ON, but feature gates / runtime options turn it Off.
|
|
443
|
+
* In such case it will be off in session schema (i.e. this session should not use compression), but this client
|
|
444
|
+
* has to deal with compressed ops as other clients might send them.
|
|
445
|
+
* And in reverse, session schema can have compression Off, but feature gates / runtime options want it On.
|
|
446
|
+
* In such case it will be off in session schema, however this client will propose change to schema, and once / if
|
|
447
|
+
* this op rountrips, compression will be On. Client can't send compressed ops until it's change in schema.
|
|
448
|
+
*/
|
|
449
|
+
get sessionSchema() {
|
|
432
450
|
return this.documentsSchemaController.sessionSchema.runtime;
|
|
433
451
|
}
|
|
434
452
|
get idCompressorMode() {
|
|
435
|
-
return this.
|
|
453
|
+
return this.sessionSchema.idCompressorMode;
|
|
436
454
|
}
|
|
437
455
|
/**
|
|
438
456
|
* See IContainerRuntimeBase.idCompressor() for details.
|
|
@@ -540,13 +558,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
540
558
|
this.flushTaskExists = false;
|
|
541
559
|
this.consecutiveReconnects = 0;
|
|
542
560
|
this.ensureNoDataModelChangesCalls = 0;
|
|
543
|
-
/**
|
|
544
|
-
* Tracks the number of detected reentrant ops to report,
|
|
545
|
-
* in order to self-throttle the telemetry events.
|
|
546
|
-
*
|
|
547
|
-
* This should be removed as part of ADO:2322
|
|
548
|
-
*/
|
|
549
|
-
this.opReentryCallsToReport = 5;
|
|
550
561
|
this._disposed = false;
|
|
551
562
|
this.emitDirtyDocumentEvent = true;
|
|
552
563
|
this.defaultTelemetrySignalSampleCount = 100;
|
|
@@ -563,7 +574,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
563
574
|
this.snapshotCacheForLoadingGroupIds = new internal_2.PromiseCache({
|
|
564
575
|
expiry: { policy: "absolute", durationMs: 60000 },
|
|
565
576
|
});
|
|
566
|
-
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, } = context;
|
|
577
|
+
const { options, clientDetails, connected, baseSnapshot, submitFn, submitBatchFn, submitSummaryFn, submitSignalFn, disposeFn, closeFn, deltaManager, quorum, audience, loader, pendingLocalState, supportedFeatures, snapshotWithContents, } = context;
|
|
567
578
|
this.mc = (0, internal_7.createChildMonitoringContext)({
|
|
568
579
|
logger: this.logger,
|
|
569
580
|
namespace: "ContainerRuntime",
|
|
@@ -573,13 +584,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
573
584
|
// If it's not in the list, then we will need to either use no compression, or fallback to some other (supported by format)
|
|
574
585
|
// compression.
|
|
575
586
|
const compressionOptions = {
|
|
576
|
-
minimumBatchSizeInBytes: this.
|
|
587
|
+
minimumBatchSizeInBytes: this.sessionSchema.compressionLz4
|
|
577
588
|
? runtimeOptions.compressionOptions.minimumBatchSizeInBytes
|
|
578
589
|
: Number.POSITIVE_INFINITY,
|
|
579
590
|
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
580
591
|
};
|
|
581
592
|
this.innerDeltaManager = deltaManager;
|
|
582
|
-
this.deltaManager = new deltaManagerSummarizerProxy_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
583
593
|
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
584
594
|
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
585
595
|
this.submitFn = submitFn;
|
|
@@ -653,15 +663,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
653
663
|
}, this.mc.logger);
|
|
654
664
|
const opSplitter = new index_js_2.OpSplitter(chunks, this.submitBatchFn, disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
655
665
|
this.remoteMessageProcessor = new index_js_2.RemoteMessageProcessor(opSplitter, new index_js_2.OpDecompressor(this.mc.logger), opGroupingManager);
|
|
666
|
+
const pendingRuntimeState = pendingLocalState;
|
|
667
|
+
this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
|
|
668
|
+
applyStashedOp: this.applyStashedOp.bind(this),
|
|
669
|
+
clientId: () => this.clientId,
|
|
670
|
+
close: this.closeFn,
|
|
671
|
+
connected: () => this.connected,
|
|
672
|
+
reSubmit: (message) => {
|
|
673
|
+
this.reSubmit(message);
|
|
674
|
+
this.flush();
|
|
675
|
+
},
|
|
676
|
+
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
677
|
+
isActiveConnection: () => this.innerDeltaManager.active,
|
|
678
|
+
isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
|
|
679
|
+
}, pendingRuntimeState?.pending, this.logger);
|
|
680
|
+
let outerDeltaManager;
|
|
681
|
+
const useDeltaManagerOpsProxy = this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") !== false;
|
|
682
|
+
// The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
|
|
683
|
+
const summarizerDeltaManagerProxy = new deltaManagerProxies_js_1.DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
684
|
+
outerDeltaManager = summarizerDeltaManagerProxy;
|
|
685
|
+
// The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
|
|
686
|
+
// It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
|
|
687
|
+
if (useDeltaManagerOpsProxy) {
|
|
688
|
+
const pendingOpsDeltaManagerProxy = new deltaManagerProxies_js_1.DeltaManagerPendingOpsProxy(summarizerDeltaManagerProxy, this.pendingStateManager);
|
|
689
|
+
outerDeltaManager = pendingOpsDeltaManagerProxy;
|
|
690
|
+
}
|
|
691
|
+
this.deltaManager = outerDeltaManager;
|
|
656
692
|
this.handleContext = new containerHandleContext_js_1.ContainerFluidHandleContext("", this);
|
|
657
693
|
if (this.summaryConfiguration.state === "enabled") {
|
|
658
694
|
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
659
695
|
}
|
|
660
|
-
const disableOpReentryCheck = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck");
|
|
661
|
-
this.enableOpReentryCheck =
|
|
662
|
-
runtimeOptions.enableOpReentryCheck === true &&
|
|
663
|
-
// Allow for a break-glass config to override the options
|
|
664
|
-
disableOpReentryCheck !== true;
|
|
665
696
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
666
697
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
667
698
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
@@ -677,7 +708,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
677
708
|
else {
|
|
678
709
|
this._flushMode = runtimeOptions.flushMode;
|
|
679
710
|
}
|
|
680
|
-
const pendingRuntimeState = pendingLocalState;
|
|
681
711
|
if (context.attachState === container_definitions_1.AttachState.Attached) {
|
|
682
712
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
683
713
|
if (maxSnapshotCacheDurationMs !== undefined &&
|
|
@@ -733,7 +763,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
733
763
|
const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
|
|
734
764
|
return this.submitSignalFn(envelope2, targetClientId);
|
|
735
765
|
};
|
|
736
|
-
|
|
766
|
+
let snapshot = (0, channelCollection_js_1.getSummaryForDatastores)(baseSnapshot, metadata);
|
|
767
|
+
if (snapshot !== undefined && snapshotWithContents !== undefined) {
|
|
768
|
+
snapshot = {
|
|
769
|
+
...snapshotWithContents,
|
|
770
|
+
snapshotTree: snapshot,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
this.channelCollection = new channelCollection_js_1.ChannelCollection(snapshot, parentContext, this.mc.logger, (props) => this.garbageCollector.nodeUpdated(props), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
737
774
|
this.blobManager = new blobManager_js_1.BlobManager({
|
|
738
775
|
routeContext: this.handleContext,
|
|
739
776
|
snapshot: blobManagerSnapshot,
|
|
@@ -746,26 +783,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
746
783
|
});
|
|
747
784
|
}
|
|
748
785
|
},
|
|
749
|
-
blobRequested: (blobPath) => this.garbageCollector.nodeUpdated(
|
|
786
|
+
blobRequested: (blobPath) => this.garbageCollector.nodeUpdated({
|
|
787
|
+
node: { type: "Blob", path: blobPath },
|
|
788
|
+
reason: "Loaded",
|
|
789
|
+
}),
|
|
750
790
|
isBlobDeleted: (blobPath) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
751
791
|
runtime: this,
|
|
752
792
|
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
753
793
|
closeContainer: (error) => this.closeFn(error),
|
|
754
794
|
});
|
|
755
795
|
this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, internal_7.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
756
|
-
this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
|
|
757
|
-
applyStashedOp: this.applyStashedOp.bind(this),
|
|
758
|
-
clientId: () => this.clientId,
|
|
759
|
-
close: this.closeFn,
|
|
760
|
-
connected: () => this.connected,
|
|
761
|
-
reSubmit: (message) => {
|
|
762
|
-
this.reSubmit(message);
|
|
763
|
-
this.flush();
|
|
764
|
-
},
|
|
765
|
-
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
766
|
-
isActiveConnection: () => this.innerDeltaManager.active,
|
|
767
|
-
isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
|
|
768
|
-
}, pendingRuntimeState?.pending, this.logger);
|
|
769
796
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
770
797
|
const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
|
|
771
798
|
this.outbox = new index_js_2.Outbox({
|
|
@@ -794,12 +821,29 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
794
821
|
this._quorum.on("removeMember", (clientId) => {
|
|
795
822
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
796
823
|
});
|
|
797
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
798
824
|
this._audience = audience;
|
|
825
|
+
if (audience.getSelf === undefined) {
|
|
826
|
+
// back-compat, added in 2.0 RC3.
|
|
827
|
+
// Purpose: deal with cases when we run against old loader that does not have newly added capabilities
|
|
828
|
+
audience.getSelf = () => {
|
|
829
|
+
const clientId = this._getClientId();
|
|
830
|
+
return clientId === undefined
|
|
831
|
+
? undefined
|
|
832
|
+
: ({
|
|
833
|
+
clientId,
|
|
834
|
+
client: audience.getMember(clientId),
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
let oldClientId = this.clientId;
|
|
838
|
+
this.on("connected", () => {
|
|
839
|
+
const clientId = this.clientId;
|
|
840
|
+
(0, internal_2.assert)(clientId !== undefined, 0x975 /* can't be undefined */);
|
|
841
|
+
audience.emit("selfChanged", { clientId: oldClientId }, { clientId, client: audience.getMember(clientId) });
|
|
842
|
+
oldClientId = clientId;
|
|
843
|
+
});
|
|
844
|
+
}
|
|
799
845
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
800
846
|
this.closeSummarizerDelayMs = closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
801
|
-
this.validateSummaryBeforeUpload =
|
|
802
|
-
this.mc.config.getBoolean("Fluid.Summarizer.ValidateSummaryBeforeUpload") ?? false;
|
|
803
847
|
this.summaryCollection = new index_js_3.SummaryCollection(this.deltaManager, this.logger);
|
|
804
848
|
this.dirtyContainer =
|
|
805
849
|
this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
|
|
@@ -872,9 +916,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
872
916
|
options: JSON.stringify(runtimeOptions),
|
|
873
917
|
idCompressorModeMetadata: metadata?.documentSchema?.runtime?.idCompressorMode,
|
|
874
918
|
idCompressorMode: this.idCompressorMode,
|
|
919
|
+
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
875
920
|
featureGates: JSON.stringify({
|
|
876
921
|
...featureGatesForTelemetry,
|
|
877
|
-
disableOpReentryCheck,
|
|
878
922
|
disableChunking,
|
|
879
923
|
disableAttachReorder: this.disableAttachReorder,
|
|
880
924
|
disablePartialFlush,
|
|
@@ -882,6 +926,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
882
926
|
}),
|
|
883
927
|
telemetryDocumentId: this.telemetryDocumentId,
|
|
884
928
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
929
|
+
initialSequenceNumber: this.deltaManager.initialSequenceNumber,
|
|
885
930
|
});
|
|
886
931
|
(0, connectionTelemetry_js_1.ReportOpPerfTelemetry)(this.clientId, this.deltaManager, this, this.logger);
|
|
887
932
|
(0, batchTracker_js_1.BindBatchTracker)(this, this.logger);
|
|
@@ -897,6 +942,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
897
942
|
this.skipSavedCompressorOps = pendingRuntimeState?.pendingIdCompressorState !== undefined;
|
|
898
943
|
}
|
|
899
944
|
onSchemaChange(schema) {
|
|
945
|
+
this.logger.sendTelemetryEvent({
|
|
946
|
+
eventName: "SchemaChangeAccept",
|
|
947
|
+
sessionRuntimeSchema: JSON.stringify(schema),
|
|
948
|
+
});
|
|
900
949
|
// Most of the settings will be picked up only by new sessions (i.e. after reload).
|
|
901
950
|
// We can make it better in the future (i.e. start to use op compression right away), but for simplicity
|
|
902
951
|
// this is not done.
|
|
@@ -929,9 +978,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
929
978
|
async initializeBaseState() {
|
|
930
979
|
if (this.idCompressorMode === "on" ||
|
|
931
980
|
(this.idCompressorMode === "delayed" && this.connected)) {
|
|
981
|
+
this._idCompressor = await this.createIdCompressor();
|
|
932
982
|
// This is called from loadRuntime(), long before we process any ops, so there should be no ops accumulated yet.
|
|
933
983
|
(0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x8ec /* no pending ops */);
|
|
934
|
-
this._idCompressor = await this.createIdCompressor();
|
|
935
984
|
}
|
|
936
985
|
await this.garbageCollector.initializeBaseState();
|
|
937
986
|
}
|
|
@@ -1229,6 +1278,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1229
1278
|
this.emitDirtyDocumentEvent = false;
|
|
1230
1279
|
let newState;
|
|
1231
1280
|
try {
|
|
1281
|
+
this.submitIdAllocationOpIfNeeded(true);
|
|
1232
1282
|
// replay the ops
|
|
1233
1283
|
this.pendingStateManager.replayPendingStates();
|
|
1234
1284
|
}
|
|
@@ -1276,8 +1326,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1276
1326
|
return;
|
|
1277
1327
|
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
1278
1328
|
return;
|
|
1279
|
-
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
1280
|
-
throw new Error("chunkedOp not expected here");
|
|
1281
1329
|
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
1282
1330
|
throw new Error("rejoin not expected here");
|
|
1283
1331
|
case messageTypes_js_1.ContainerMessageType.GC:
|
|
@@ -1289,7 +1337,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1289
1337
|
// e.g. if an app rolled back its container version
|
|
1290
1338
|
const compatBehavior = opContents.compatDetails?.behavior;
|
|
1291
1339
|
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
1292
|
-
const error = internal_7.DataProcessingError.create("Stashed runtime message of
|
|
1340
|
+
const error = internal_7.DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1293
1341
|
messageDetails: JSON.stringify({
|
|
1294
1342
|
type: opContents.type,
|
|
1295
1343
|
compatBehavior,
|
|
@@ -1309,12 +1357,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1309
1357
|
this._loadIdCompressor === undefined) {
|
|
1310
1358
|
this._loadIdCompressor = this.createIdCompressor()
|
|
1311
1359
|
.then((compressor) => {
|
|
1312
|
-
this._idCompressor = compressor;
|
|
1313
1360
|
// Finalize any ranges we received while the compressor was turned off.
|
|
1314
|
-
|
|
1315
|
-
this._idCompressor.finalizeCreationRange(range);
|
|
1316
|
-
}
|
|
1361
|
+
const ops = this.pendingIdCompressorOps;
|
|
1317
1362
|
this.pendingIdCompressorOps = [];
|
|
1363
|
+
for (const range of ops) {
|
|
1364
|
+
compressor.finalizeCreationRange(range);
|
|
1365
|
+
}
|
|
1366
|
+
(0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x976 /* No new ops added */);
|
|
1367
|
+
this._idCompressor = compressor;
|
|
1318
1368
|
})
|
|
1319
1369
|
.catch((error) => {
|
|
1320
1370
|
this.logger.sendErrorEvent({ eventName: "IdCompressorDelayedLoad" }, error);
|
|
@@ -1324,6 +1374,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1324
1374
|
return this._loadIdCompressor;
|
|
1325
1375
|
}
|
|
1326
1376
|
setConnectionState(connected, clientId) {
|
|
1377
|
+
// Validate we have consistent state
|
|
1378
|
+
const currentClientId = this._audience.getSelf()?.clientId;
|
|
1379
|
+
(0, internal_2.assert)(clientId === currentClientId, 0x977 /* input clientId does not match Audience */);
|
|
1380
|
+
(0, internal_2.assert)(this.clientId === currentClientId, 0x978 /* this.clientId does not match Audience */);
|
|
1327
1381
|
if (connected && this.idCompressorMode === "delayed") {
|
|
1328
1382
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1329
1383
|
this.loadIdCompressor();
|
|
@@ -1405,9 +1459,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1405
1459
|
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
1406
1460
|
// but will not modify the contents object (likely it will replace it on the message).
|
|
1407
1461
|
const messageCopy = { ...messageArg };
|
|
1462
|
+
const savedOp = messageCopy.metadata?.savedOp;
|
|
1408
1463
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1409
|
-
|
|
1410
|
-
|
|
1464
|
+
const msg = modernRuntimeMessage
|
|
1465
|
+
? {
|
|
1411
1466
|
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
1412
1467
|
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
1413
1468
|
// the result messages will be so. In the end modern bool being true only directs to
|
|
@@ -1415,12 +1470,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1415
1470
|
message: message,
|
|
1416
1471
|
local,
|
|
1417
1472
|
modernRuntimeMessage,
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1473
|
+
}
|
|
1474
|
+
: // Unrecognized message will be ignored.
|
|
1475
|
+
{
|
|
1476
|
+
message,
|
|
1477
|
+
local,
|
|
1478
|
+
modernRuntimeMessage,
|
|
1479
|
+
};
|
|
1480
|
+
msg.savedOp = savedOp;
|
|
1481
|
+
// ensure that we observe any re-entrancy, and if needed, rebase ops
|
|
1482
|
+
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
1424
1483
|
}
|
|
1425
1484
|
}
|
|
1426
1485
|
/**
|
|
@@ -1428,6 +1487,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1428
1487
|
*/
|
|
1429
1488
|
processCore(messageWithContext) {
|
|
1430
1489
|
const { message, local } = messageWithContext;
|
|
1490
|
+
// Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
|
|
1491
|
+
// Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
|
|
1492
|
+
if (this.deltaManager.minimumSequenceNumber <
|
|
1493
|
+
messageWithContext.message.minimumSequenceNumber) {
|
|
1494
|
+
messageWithContext.message.minimumSequenceNumber =
|
|
1495
|
+
this.deltaManager.minimumSequenceNumber;
|
|
1496
|
+
}
|
|
1431
1497
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1432
1498
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1433
1499
|
// messages once a batch has been fully processed.
|
|
@@ -1438,7 +1504,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1438
1504
|
// These calls should be made for all but chunked ops:
|
|
1439
1505
|
// 1) this.pendingStateManager.processPendingLocalMessage() below
|
|
1440
1506
|
// 2) this.resetReconnectCount() below
|
|
1441
|
-
(0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp,
|
|
1507
|
+
(0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, 0x93b /* we should never get here with chunked ops */);
|
|
1442
1508
|
let localOpMetadata;
|
|
1443
1509
|
if (local && messageWithContext.modernRuntimeMessage) {
|
|
1444
1510
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
|
|
@@ -1485,17 +1551,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1485
1551
|
// stashed ops flow. The compressor is stashed with these ops already processed.
|
|
1486
1552
|
// That said, in idCompressorMode === "delayed", we might not serialize ID compressor, and
|
|
1487
1553
|
// thus we need to process all the ops.
|
|
1488
|
-
if (!(this.skipSavedCompressorOps &&
|
|
1489
|
-
messageWithContext.message.metadata?.savedOp ===
|
|
1490
|
-
true)) {
|
|
1554
|
+
if (!(this.skipSavedCompressorOps && messageWithContext.savedOp === true)) {
|
|
1491
1555
|
const range = messageWithContext.message.contents;
|
|
1492
1556
|
// Some other client turned on the id compressor. If we have not turned it on,
|
|
1493
1557
|
// put it in a pending queue and delay finalization.
|
|
1494
1558
|
if (this._idCompressor === undefined) {
|
|
1495
|
-
(0, internal_2.assert)(this.idCompressorMode !== undefined,
|
|
1559
|
+
(0, internal_2.assert)(this.idCompressorMode !== undefined, 0x93c /* id compressor should be enabled */);
|
|
1496
1560
|
this.pendingIdCompressorOps.push(range);
|
|
1497
1561
|
}
|
|
1498
1562
|
else {
|
|
1563
|
+
(0, internal_2.assert)(this.pendingIdCompressorOps.length === 0, 0x979 /* there should be no pending ops! */);
|
|
1499
1564
|
this._idCompressor.finalizeCreationRange(range);
|
|
1500
1565
|
}
|
|
1501
1566
|
}
|
|
@@ -1506,7 +1571,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1506
1571
|
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
1507
1572
|
// From observability POV, we should not exppse the rest of the system (including "op" events on object) to these messages.
|
|
1508
1573
|
// Also resetReconnectCount() would be wrong - see comment that was there before this change was made.
|
|
1509
|
-
(0, internal_2.assert)(false,
|
|
1574
|
+
(0, internal_2.assert)(false, 0x93d /* should not even get here */);
|
|
1510
1575
|
case messageTypes_js_1.ContainerMessageType.Rejoin:
|
|
1511
1576
|
break;
|
|
1512
1577
|
case messageTypes_js_1.ContainerMessageType.DocumentSchemaChange:
|
|
@@ -1616,9 +1681,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1616
1681
|
let checkpoint;
|
|
1617
1682
|
let result;
|
|
1618
1683
|
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
|
|
1619
|
-
// Note: we are not touching
|
|
1620
|
-
// 1. It would not help, as
|
|
1621
|
-
// 2. There is no way to undo process of data store creation.
|
|
1684
|
+
// Note: we are not touching any batches other than mainBatch here, for two reasons:
|
|
1685
|
+
// 1. It would not help, as other batches are flushed independently from main batch.
|
|
1686
|
+
// 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
|
|
1622
1687
|
checkpoint = this.outbox.checkpoint().mainBatch;
|
|
1623
1688
|
}
|
|
1624
1689
|
try {
|
|
@@ -1681,7 +1746,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1681
1746
|
if (channel.entryPoint === undefined) {
|
|
1682
1747
|
throw new internal_7.UsageError("entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint");
|
|
1683
1748
|
}
|
|
1684
|
-
this.garbageCollector.nodeUpdated(
|
|
1749
|
+
this.garbageCollector.nodeUpdated({
|
|
1750
|
+
node: { type: "DataStore", path: `/${internalId}` },
|
|
1751
|
+
reason: "Loaded",
|
|
1752
|
+
packagePath: context.packagePath,
|
|
1753
|
+
});
|
|
1685
1754
|
return channel.entryPoint;
|
|
1686
1755
|
}
|
|
1687
1756
|
createDetachedDataStore(pkg, loadingGroupId) {
|
|
@@ -1805,7 +1874,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1805
1874
|
// We can finalize any allocated IDs since we're the only client
|
|
1806
1875
|
const idRange = this._idCompressor?.takeNextCreationRange();
|
|
1807
1876
|
if (idRange !== undefined) {
|
|
1808
|
-
(0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1,
|
|
1877
|
+
(0, internal_2.assert)(idRange.ids === undefined || idRange.ids.firstGenCount === 1, 0x93e /* No other ranges should be taken while container is detached. */);
|
|
1809
1878
|
this._idCompressor?.finalizeCreationRange(idRange);
|
|
1810
1879
|
}
|
|
1811
1880
|
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
@@ -1852,7 +1921,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1852
1921
|
return { stats, summary };
|
|
1853
1922
|
}
|
|
1854
1923
|
finally {
|
|
1855
|
-
|
|
1924
|
+
summaryLogger.sendTelemetryEvent({
|
|
1856
1925
|
eventName: "SummarizeTelemetry",
|
|
1857
1926
|
details: telemetryContext.serialize(),
|
|
1858
1927
|
});
|
|
@@ -2015,10 +2084,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2015
2084
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2016
2085
|
// use it for all events logged during this summary.
|
|
2017
2086
|
const summaryNumber = this.nextSummaryNumber;
|
|
2087
|
+
let summaryRefSeqNum;
|
|
2018
2088
|
const summaryNumberLogger = (0, internal_7.createChildLogger)({
|
|
2019
2089
|
logger: summaryLogger,
|
|
2020
2090
|
properties: {
|
|
2021
|
-
all: {
|
|
2091
|
+
all: {
|
|
2092
|
+
summaryNumber,
|
|
2093
|
+
referenceSequenceNumber: () => summaryRefSeqNum,
|
|
2094
|
+
},
|
|
2022
2095
|
},
|
|
2023
2096
|
});
|
|
2024
2097
|
(0, internal_2.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
@@ -2032,7 +2105,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2032
2105
|
// If the container is dirty, i.e., there are pending unacked ops, the summary will not be eventual consistent
|
|
2033
2106
|
// and it may even be incorrect. So, wait for the container to be saved with a timeout. If the container is not
|
|
2034
2107
|
// saved within the timeout, check if it should be failed or can continue.
|
|
2035
|
-
if (this.
|
|
2108
|
+
if (this.isDirty) {
|
|
2036
2109
|
const countBefore = this.pendingMessagesCount;
|
|
2037
2110
|
// The timeout for waiting for pending ops can be overridden via configurations.
|
|
2038
2111
|
const pendingOpsTimeout = this.mc.config.getNumber("Fluid.Summarizer.waitForPendingOpsTimeoutMs") ??
|
|
@@ -2065,7 +2138,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2065
2138
|
}
|
|
2066
2139
|
const shouldPauseInboundSignal = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.disableInboundSignalPause") !== true;
|
|
2067
2140
|
const shouldValidatePreSummaryState = this.mc.config.getBoolean("Fluid.ContainerRuntime.SubmitSummary.shouldValidatePreSummaryState") === true;
|
|
2068
|
-
let summaryRefSeqNum;
|
|
2069
2141
|
try {
|
|
2070
2142
|
await this.deltaManager.inbound.pause();
|
|
2071
2143
|
if (shouldPauseInboundSignal) {
|
|
@@ -2076,9 +2148,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2076
2148
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
2077
2149
|
const lastAck = this.summaryCollection.latestAck;
|
|
2078
2150
|
const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
|
|
2151
|
+
/**
|
|
2152
|
+
* This was added to validate that the summarizer node tree has the same reference sequence number from the
|
|
2153
|
+
* top running summarizer down to the lowest summarizer node.
|
|
2154
|
+
*
|
|
2155
|
+
* The order of mismatch numbers goes (validate sequence number)-(node sequence number).
|
|
2156
|
+
* Generally the validate sequence number comes from the running summarizer and the node sequence number comes from the
|
|
2157
|
+
* summarizer nodes.
|
|
2158
|
+
*/
|
|
2079
2159
|
if (startSummaryResult.invalidNodes > 0 ||
|
|
2080
2160
|
startSummaryResult.mismatchNumbers.size > 0) {
|
|
2081
|
-
summaryLogger.
|
|
2161
|
+
summaryLogger.sendTelemetryEvent({
|
|
2082
2162
|
eventName: "LatestSummaryRefSeqNumMismatch",
|
|
2083
2163
|
details: {
|
|
2084
2164
|
...startSummaryResult,
|
|
@@ -2090,7 +2170,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2090
2170
|
stage: "base",
|
|
2091
2171
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2092
2172
|
minimumSequenceNumber,
|
|
2093
|
-
error: `Summarizer node state inconsistent with summarizer state
|
|
2173
|
+
error: new internal_7.LoggingError(`Summarizer node state inconsistent with summarizer state.`),
|
|
2094
2174
|
};
|
|
2095
2175
|
}
|
|
2096
2176
|
}
|
|
@@ -2133,7 +2213,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2133
2213
|
stage: "base",
|
|
2134
2214
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2135
2215
|
minimumSequenceNumber,
|
|
2136
|
-
error: continueResult.error,
|
|
2216
|
+
error: new internal_7.LoggingError(continueResult.error),
|
|
2137
2217
|
};
|
|
2138
2218
|
}
|
|
2139
2219
|
const trace = client_utils_1.Trace.start();
|
|
@@ -2150,6 +2230,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2150
2230
|
});
|
|
2151
2231
|
}
|
|
2152
2232
|
catch (error) {
|
|
2233
|
+
return {
|
|
2234
|
+
stage: "base",
|
|
2235
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
2236
|
+
minimumSequenceNumber,
|
|
2237
|
+
error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
// Validate that the summary generated by summarizer nodes is correct before uploading.
|
|
2241
|
+
const validateResult = this.summarizerNode.validateSummary();
|
|
2242
|
+
if (!validateResult.success) {
|
|
2243
|
+
const { success, ...loggingProps } = validateResult;
|
|
2244
|
+
const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
2153
2245
|
return {
|
|
2154
2246
|
stage: "base",
|
|
2155
2247
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
@@ -2157,24 +2249,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2157
2249
|
error,
|
|
2158
2250
|
};
|
|
2159
2251
|
}
|
|
2160
|
-
// If
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
const { success, ...loggingProps } = validateResult;
|
|
2166
|
-
const error = new index_js_3.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
2167
|
-
return {
|
|
2168
|
-
stage: "base",
|
|
2169
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
2170
|
-
minimumSequenceNumber,
|
|
2171
|
-
error,
|
|
2172
|
-
};
|
|
2173
|
-
}
|
|
2174
|
-
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
|
|
2175
|
-
if (pendingMessagesFailResult !== undefined) {
|
|
2176
|
-
return pendingMessagesFailResult;
|
|
2177
|
-
}
|
|
2252
|
+
// If there are pending unacked ops, this summary attempt may fail as the uploaded
|
|
2253
|
+
// summary would be eventually inconsistent.
|
|
2254
|
+
const pendingMessagesFailResult = await this.shouldFailSummaryOnPendingOps(summaryNumberLogger, summaryRefSeqNum, minimumSequenceNumber, finalAttempt, false /* beforeSummaryGeneration */);
|
|
2255
|
+
if (pendingMessagesFailResult !== undefined) {
|
|
2256
|
+
return pendingMessagesFailResult;
|
|
2178
2257
|
}
|
|
2179
2258
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
2180
2259
|
// Now that we have generated the summary, update the message at last summary to the last message processed.
|
|
@@ -2207,7 +2286,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2207
2286
|
};
|
|
2208
2287
|
continueResult = checkContinue();
|
|
2209
2288
|
if (!continueResult.continue) {
|
|
2210
|
-
return {
|
|
2289
|
+
return {
|
|
2290
|
+
stage: "generate",
|
|
2291
|
+
...generateSummaryData,
|
|
2292
|
+
error: new internal_7.LoggingError(continueResult.error),
|
|
2293
|
+
};
|
|
2211
2294
|
}
|
|
2212
2295
|
const summaryContext = lastAck === undefined
|
|
2213
2296
|
? {
|
|
@@ -2225,7 +2308,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2225
2308
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
2226
2309
|
}
|
|
2227
2310
|
catch (error) {
|
|
2228
|
-
return {
|
|
2311
|
+
return {
|
|
2312
|
+
stage: "generate",
|
|
2313
|
+
...generateSummaryData,
|
|
2314
|
+
error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
|
|
2315
|
+
};
|
|
2229
2316
|
}
|
|
2230
2317
|
const parent = summaryContext.ackHandle;
|
|
2231
2318
|
const summaryMessage = {
|
|
@@ -2242,14 +2329,22 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2242
2329
|
};
|
|
2243
2330
|
continueResult = checkContinue();
|
|
2244
2331
|
if (!continueResult.continue) {
|
|
2245
|
-
return {
|
|
2332
|
+
return {
|
|
2333
|
+
stage: "upload",
|
|
2334
|
+
...uploadData,
|
|
2335
|
+
error: new internal_7.LoggingError(continueResult.error),
|
|
2336
|
+
};
|
|
2246
2337
|
}
|
|
2247
2338
|
let clientSequenceNumber;
|
|
2248
2339
|
try {
|
|
2249
2340
|
clientSequenceNumber = this.submitSummaryMessage(summaryMessage, summaryRefSeqNum);
|
|
2250
2341
|
}
|
|
2251
2342
|
catch (error) {
|
|
2252
|
-
return {
|
|
2343
|
+
return {
|
|
2344
|
+
stage: "upload",
|
|
2345
|
+
...uploadData,
|
|
2346
|
+
error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
|
|
2347
|
+
};
|
|
2253
2348
|
}
|
|
2254
2349
|
const submitData = {
|
|
2255
2350
|
stage: "submit",
|
|
@@ -2258,11 +2353,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2258
2353
|
submitOpDuration: trace.trace().duration,
|
|
2259
2354
|
};
|
|
2260
2355
|
try {
|
|
2261
|
-
|
|
2262
|
-
this.summarizerNode.completeSummary(handle, !this.validateSummaryBeforeUpload /* validate */);
|
|
2356
|
+
this.summarizerNode.completeSummary(handle);
|
|
2263
2357
|
}
|
|
2264
2358
|
catch (error) {
|
|
2265
|
-
return {
|
|
2359
|
+
return {
|
|
2360
|
+
stage: "upload",
|
|
2361
|
+
...uploadData,
|
|
2362
|
+
error: (0, internal_7.wrapError)(error, (msg) => new internal_7.LoggingError(msg)),
|
|
2363
|
+
};
|
|
2266
2364
|
}
|
|
2267
2365
|
return submitData;
|
|
2268
2366
|
}
|
|
@@ -2351,9 +2449,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2351
2449
|
this.verifyNotClosed();
|
|
2352
2450
|
return this.blobManager.createBlob(blob, signal);
|
|
2353
2451
|
}
|
|
2354
|
-
submitIdAllocationOpIfNeeded() {
|
|
2452
|
+
submitIdAllocationOpIfNeeded(resubmitOutstandingRanges = false) {
|
|
2355
2453
|
if (this._idCompressor) {
|
|
2356
|
-
const idRange =
|
|
2454
|
+
const idRange = resubmitOutstandingRanges
|
|
2455
|
+
? this.idCompressor?.takeUnfinalizedCreationRange()
|
|
2456
|
+
: this._idCompressor.takeNextCreationRange();
|
|
2357
2457
|
// Don't include the idRange if there weren't any Ids allocated
|
|
2358
2458
|
if (idRange?.ids !== undefined) {
|
|
2359
2459
|
const idAllocationMessage = {
|
|
@@ -2370,11 +2470,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2370
2470
|
}
|
|
2371
2471
|
submit(containerRuntimeMessage, localOpMetadata = undefined, metadata) {
|
|
2372
2472
|
this.verifyNotClosed();
|
|
2373
|
-
this.verifyCanSubmitOps();
|
|
2374
2473
|
// There should be no ops in detached container state!
|
|
2375
2474
|
(0, internal_2.assert)(this.attachState !== container_definitions_1.AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
2376
2475
|
(0, internal_2.assert)(metadata === undefined ||
|
|
2377
|
-
containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach,
|
|
2476
|
+
containerRuntimeMessage.type === messageTypes_js_1.ContainerMessageType.BlobAttach, 0x93f /* metadata */);
|
|
2378
2477
|
const serializedContent = JSON.stringify(containerRuntimeMessage);
|
|
2379
2478
|
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
2380
2479
|
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
@@ -2406,6 +2505,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2406
2505
|
// on this callback to do actual sending.
|
|
2407
2506
|
const contents = this.documentsSchemaController.maybeSendSchemaMessage();
|
|
2408
2507
|
if (contents) {
|
|
2508
|
+
this.logger.sendTelemetryEvent({
|
|
2509
|
+
eventName: "SchemaChangeProposal",
|
|
2510
|
+
refSeq: contents.refSeq,
|
|
2511
|
+
version: contents.version,
|
|
2512
|
+
newRuntimeSchema: JSON.stringify(contents.runtime),
|
|
2513
|
+
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
2514
|
+
oldRuntimeSchema: JSON.stringify(this.metadata?.documentSchema?.runtime),
|
|
2515
|
+
});
|
|
2409
2516
|
const msg = {
|
|
2410
2517
|
type: messageTypes_js_1.ContainerMessageType.DocumentSchemaChange,
|
|
2411
2518
|
contents,
|
|
@@ -2415,32 +2522,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2415
2522
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2416
2523
|
});
|
|
2417
2524
|
}
|
|
2418
|
-
|
|
2419
|
-
// Is it safe:
|
|
2420
|
-
// Yes, this should be safe reordering. Newly created data stores are not visible through API surface.
|
|
2421
|
-
// They become visible only when aliased, or handle to some sub-element of newly created datastore
|
|
2422
|
-
// is stored in some DDS, i.e. only after some other op.
|
|
2423
|
-
// Why:
|
|
2424
|
-
// Attach ops are large, and expensive to process. Plus there are scenarios where a lot of new data
|
|
2425
|
-
// stores are created, causing issues like relay service throttling (too many ops) and catastrophic
|
|
2426
|
-
// failure (batch is too large). Pushing them earlier and outside of main batch should alleviate
|
|
2427
|
-
// these issues.
|
|
2428
|
-
// Cons:
|
|
2429
|
-
// 1. With large batches, relay service may throttle clients. Clients may disconnect while throttled.
|
|
2430
|
-
// This change creates new possibility of a lot of newly created data stores never being referenced
|
|
2431
|
-
// because client died before it had a change to submit the rest of the ops. This will create more
|
|
2432
|
-
// garbage that needs to be collected leveraging GC (Garbage Collection) feature.
|
|
2433
|
-
// 2. Sending ops out of order means they are excluded from rollback functionality. This is not an issue
|
|
2434
|
-
// today as rollback can't undo creation of data store. To some extent not sending them is a bigger
|
|
2435
|
-
// issue than sending.
|
|
2436
|
-
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2437
|
-
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2438
|
-
if (this.currentlyBatching() &&
|
|
2439
|
-
type === messageTypes_js_1.ContainerMessageType.Attach &&
|
|
2440
|
-
this.disableAttachReorder !== true) {
|
|
2441
|
-
this.outbox.submitAttach(message);
|
|
2442
|
-
}
|
|
2443
|
-
else if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
|
|
2525
|
+
if (type === messageTypes_js_1.ContainerMessageType.BlobAttach) {
|
|
2444
2526
|
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2445
2527
|
this.outbox.submitBlobAttach(message);
|
|
2446
2528
|
}
|
|
@@ -2515,32 +2597,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2515
2597
|
throw new Error("Runtime is closed");
|
|
2516
2598
|
}
|
|
2517
2599
|
}
|
|
2518
|
-
verifyCanSubmitOps() {
|
|
2519
|
-
if (this.ensureNoDataModelChangesCalls > 0) {
|
|
2520
|
-
const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
|
|
2521
|
-
if (this.opReentryCallsToReport > 0) {
|
|
2522
|
-
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
2523
|
-
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
2524
|
-
(0, index_js_2.getLongStack)(() => new internal_7.UsageError(errorMessage)));
|
|
2525
|
-
this.opReentryCallsToReport--;
|
|
2526
|
-
}
|
|
2527
|
-
// Creating ops while processing ops can lead
|
|
2528
|
-
// to undefined behavior and events observed in the wrong order.
|
|
2529
|
-
// For example, we have two callbacks registered for a DDS, A and B.
|
|
2530
|
-
// Then if on change #1 callback A creates change #2, the invocation flow will be:
|
|
2531
|
-
//
|
|
2532
|
-
// A because of #1
|
|
2533
|
-
// A because of #2
|
|
2534
|
-
// B because of #2
|
|
2535
|
-
// B because of #1
|
|
2536
|
-
//
|
|
2537
|
-
// The runtime must enforce op coherence by not allowing ops to be submitted
|
|
2538
|
-
// while ops are being processed.
|
|
2539
|
-
if (this.enableOpReentryCheck) {
|
|
2540
|
-
throw new internal_7.UsageError(errorMessage);
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
2600
|
reSubmitBatch(batch) {
|
|
2545
2601
|
this.orderSequentially(() => {
|
|
2546
2602
|
for (const message of batch) {
|
|
@@ -2572,11 +2628,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2572
2628
|
this.channelCollection.reSubmit(message.type, message.contents, localOpMetadata);
|
|
2573
2629
|
break;
|
|
2574
2630
|
case messageTypes_js_1.ContainerMessageType.IdAllocation: {
|
|
2575
|
-
|
|
2631
|
+
// Allocation ops are never resubmitted/rebased. This is because they require special handling to
|
|
2632
|
+
// avoid being submitted out of order. For example, if the pending state manager contained
|
|
2633
|
+
// [idOp1, dataOp1, idOp2, dataOp2] and the resubmission of dataOp1 generated idOp3, that would be
|
|
2634
|
+
// placed into the outbox in the same batch as idOp1, but before idOp2 is resubmitted.
|
|
2635
|
+
// To avoid this, allocation ops are simply never resubmitted. Prior to invoking the pending state
|
|
2636
|
+
// manager to replay pending ops, the runtime will always submit a new allocation range that includes
|
|
2637
|
+
// all pending IDs. The resubmitted allocation ops are then ignored here.
|
|
2576
2638
|
break;
|
|
2577
2639
|
}
|
|
2578
|
-
case messageTypes_js_1.ContainerMessageType.ChunkedOp:
|
|
2579
|
-
throw new Error(`chunkedOp not expected here`);
|
|
2580
2640
|
case messageTypes_js_1.ContainerMessageType.BlobAttach:
|
|
2581
2641
|
this.blobManager.reSubmit(opMetadata);
|
|
2582
2642
|
break;
|
|
@@ -2603,7 +2663,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2603
2663
|
});
|
|
2604
2664
|
}
|
|
2605
2665
|
else {
|
|
2606
|
-
const error = internal_7.DataProcessingError.create("Resubmitting runtime message of
|
|
2666
|
+
const error = internal_7.DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
|
|
2607
2667
|
messageDetails: JSON.stringify({
|
|
2608
2668
|
type: message.type,
|
|
2609
2669
|
compatBehavior,
|
|
@@ -2670,7 +2730,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2670
2730
|
await this.closeStaleSummarizer();
|
|
2671
2731
|
return {
|
|
2672
2732
|
stage: "base",
|
|
2673
|
-
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
2733
|
+
error: new internal_7.LoggingError("summary state stale - Unsupported option 'refreshLatestAck'"),
|
|
2674
2734
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2675
2735
|
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
2676
2736
|
};
|
|
@@ -2714,16 +2774,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2714
2774
|
}
|
|
2715
2775
|
this.imminentClosure || (this.imminentClosure = props?.notifyImminentClosure ?? false);
|
|
2716
2776
|
const getSyncState = (pendingAttachmentBlobs) => {
|
|
2717
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
2718
|
-
|
|
2719
|
-
return; // no pending state to save
|
|
2720
|
-
}
|
|
2777
|
+
const pending = this.pendingStateManager.getLocalState(props?.snapshotSequenceNumber);
|
|
2778
|
+
const sessionExpiryTimerStarted = props?.sessionExpiryTimerStarted ?? this.garbageCollector.sessionExpiryTimerStarted;
|
|
2721
2779
|
const pendingIdCompressorState = this._idCompressor?.serialize(true);
|
|
2722
2780
|
return {
|
|
2723
2781
|
pending,
|
|
2724
2782
|
pendingIdCompressorState,
|
|
2725
2783
|
pendingAttachmentBlobs,
|
|
2726
|
-
sessionExpiryTimerStarted
|
|
2784
|
+
sessionExpiryTimerStarted,
|
|
2727
2785
|
};
|
|
2728
2786
|
};
|
|
2729
2787
|
const perfEvent = {
|
|
@@ -2793,7 +2851,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2793
2851
|
}
|
|
2794
2852
|
}
|
|
2795
2853
|
get groupedBatchingEnabled() {
|
|
2796
|
-
return this.
|
|
2854
|
+
return this.sessionSchema.opGroupingEnabled === true;
|
|
2797
2855
|
}
|
|
2798
2856
|
}
|
|
2799
2857
|
exports.ContainerRuntime = ContainerRuntime;
|