@fluidframework/container-runtime 2.0.0-internal.6.3.2 → 2.0.0-internal.6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/blobManager.d.ts +3 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +29 -25
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +14 -69
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +155 -184
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +3 -1
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +1 -1
- package/dist/dataStores.js +3 -3
- package/dist/dataStores.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +6 -3
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +13 -12
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +1 -1
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +17 -6
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +19 -20
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +0 -9
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +1 -13
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +1 -4
- 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 +5 -6
- package/dist/gc/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/messageTypes.d.ts +134 -0
- package/dist/messageTypes.d.ts.map +1 -0
- package/dist/messageTypes.js +29 -0
- package/dist/messageTypes.js.map +1 -0
- package/dist/opLifecycle/definitions.d.ts +2 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +0 -4
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +4 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.js +3 -3
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +17 -3
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +38 -25
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +2 -2
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +13 -6
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +1 -1
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +4 -2
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +2 -2
- package/dist/summary/summarizer.js +2 -2
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +2 -1
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +3 -0
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +3 -0
- package/dist/summary/summaryFormat.js.map +1 -1
- package/lib/blobManager.d.ts +3 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +30 -26
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +14 -69
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +121 -150
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +3 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +1 -1
- package/lib/dataStores.js +4 -4
- package/lib/dataStores.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +6 -3
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +13 -12
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.js +2 -2
- package/lib/gc/gcConfigs.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +17 -6
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +18 -19
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +0 -9
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +0 -11
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +1 -4
- 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 +2 -2
- package/lib/gc/index.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/messageTypes.d.ts +134 -0
- package/lib/messageTypes.d.ts.map +1 -0
- package/lib/messageTypes.js +26 -0
- package/lib/messageTypes.js.map +1 -0
- package/lib/opLifecycle/definitions.d.ts +2 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +0 -4
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +4 -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/remoteMessageProcessor.d.ts +17 -3
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +37 -24
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +2 -2
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +12 -5
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +1 -1
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +4 -2
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +2 -2
- package/lib/summary/summarizer.js +2 -2
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +2 -1
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +3 -0
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +3 -0
- package/lib/summary/summaryFormat.js.map +1 -1
- package/package.json +16 -16
- package/src/blobManager.ts +38 -28
- package/src/containerRuntime.ts +181 -245
- package/src/dataStoreContext.ts +3 -1
- package/src/dataStores.ts +4 -4
- package/src/gc/garbageCollection.md +53 -5
- package/src/gc/garbageCollection.ts +13 -12
- package/src/gc/gcConfigs.ts +3 -3
- package/src/gc/gcDefinitions.ts +18 -19
- package/src/gc/gcEarlyAdoption.md +145 -0
- package/src/gc/gcHelpers.ts +0 -12
- package/src/gc/gcTelemetry.ts +1 -4
- package/src/gc/index.ts +4 -5
- package/src/index.ts +7 -4
- package/src/messageTypes.ts +225 -0
- package/src/opLifecycle/README.md +40 -40
- package/src/opLifecycle/definitions.ts +2 -1
- package/src/opLifecycle/opDecompressor.ts +0 -8
- package/src/opLifecycle/opGroupingManager.ts +7 -6
- package/src/opLifecycle/opSplitter.ts +2 -2
- package/src/opLifecycle/remoteMessageProcessor.ts +54 -33
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +23 -6
- package/src/summary/runningSummarizer.ts +4 -2
- package/src/summary/summarizer.ts +2 -2
- package/src/summary/summarizerNode/summarizerNode.ts +1 -1
- package/src/summary/summarizerTypes.ts +2 -1
- package/src/summary/summaryFormat.ts +3 -0
package/dist/containerRuntime.js
CHANGED
|
@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration =
|
|
22
|
+
exports.ContainerRuntime = exports.makeLegacySendBatchFn = exports.getDeviceSpec = exports.agentSchedulerId = exports.isRuntimeMessage = exports.RuntimeMessage = exports.defaultPendingOpsRetryDelayMs = exports.defaultPendingOpsWaitTimeoutMs = exports.CompressionAlgorithms = exports.defaultRuntimeHeaderData = exports.InactiveResponseHeaderKey = exports.TombstoneResponseHeaderKey = exports.AllowInactiveRequestHeaderKey = exports.AllowTombstoneRequestHeaderKey = exports.RuntimeHeaders = exports.DefaultSummaryConfiguration = void 0;
|
|
23
23
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
24
24
|
const core_utils_1 = require("@fluidframework/core-utils");
|
|
25
25
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
@@ -45,32 +45,12 @@ const batchTracker_1 = require("./batchTracker");
|
|
|
45
45
|
const scheduleManager_1 = require("./scheduleManager");
|
|
46
46
|
const opLifecycle_1 = require("./opLifecycle");
|
|
47
47
|
const deltaManagerSummarizerProxy_1 = require("./deltaManagerSummarizerProxy");
|
|
48
|
-
|
|
49
|
-
(function (ContainerMessageType) {
|
|
50
|
-
// An op to be delivered to store
|
|
51
|
-
ContainerMessageType["FluidDataStoreOp"] = "component";
|
|
52
|
-
// Creates a new store
|
|
53
|
-
ContainerMessageType["Attach"] = "attach";
|
|
54
|
-
// Chunked operation.
|
|
55
|
-
ContainerMessageType["ChunkedOp"] = "chunkedOp";
|
|
56
|
-
// Signifies that a blob has been attached and should not be garbage collected by storage
|
|
57
|
-
ContainerMessageType["BlobAttach"] = "blobAttach";
|
|
58
|
-
// Ties our new clientId to our old one on reconnect
|
|
59
|
-
ContainerMessageType["Rejoin"] = "rejoin";
|
|
60
|
-
// Sets the alias of a root data store
|
|
61
|
-
ContainerMessageType["Alias"] = "alias";
|
|
62
|
-
/**
|
|
63
|
-
* An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
|
|
64
|
-
* the last allocation op was sent.
|
|
65
|
-
* See the [IdCompressor README](./id-compressor/README.md) for more details.
|
|
66
|
-
*/
|
|
67
|
-
ContainerMessageType["IdAllocation"] = "idAllocation";
|
|
68
|
-
})(ContainerMessageType = exports.ContainerMessageType || (exports.ContainerMessageType = {}));
|
|
48
|
+
const messageTypes_1 = require("./messageTypes");
|
|
69
49
|
/**
|
|
70
50
|
* Utility to implement compat behaviors given an unknown message type
|
|
71
51
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
72
52
|
*
|
|
73
|
-
* @param _unknownContainerRuntimeMessageType - Typed as
|
|
53
|
+
* @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
|
|
74
54
|
* handled before calling this function (e.g. in a switch statement).
|
|
75
55
|
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
76
56
|
*/
|
|
@@ -78,6 +58,12 @@ function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, co
|
|
|
78
58
|
// undefined defaults to same behavior as "FailToProcess"
|
|
79
59
|
return compatBehavior === "Ignore";
|
|
80
60
|
}
|
|
61
|
+
function prepareLocalContainerRuntimeIdAllocationMessageForTransit(message) {
|
|
62
|
+
// Remove the stashedState from the op if it's a stashed op
|
|
63
|
+
if ("stashedState" in message.contents) {
|
|
64
|
+
delete message.contents.stashedState;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
81
67
|
exports.DefaultSummaryConfiguration = {
|
|
82
68
|
state: "enabled",
|
|
83
69
|
minIdleTime: 0,
|
|
@@ -147,7 +133,7 @@ exports.defaultPendingOpsRetryDelayMs = 1000;
|
|
|
147
133
|
*/
|
|
148
134
|
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
149
135
|
/**
|
|
150
|
-
* @deprecated - use
|
|
136
|
+
* @deprecated - use ContainerRuntimeMessageType instead
|
|
151
137
|
*/
|
|
152
138
|
var RuntimeMessage;
|
|
153
139
|
(function (RuntimeMessage) {
|
|
@@ -401,10 +387,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
401
387
|
if (baseSnapshot) {
|
|
402
388
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
403
389
|
}
|
|
404
|
-
this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
|
|
390
|
+
this.dataStores = new dataStores_1.DataStores((0, dataStores_1.getSummaryForDatastores)(baseSnapshot, metadata), this, (attachMsg) => this.submit({ type: messageTypes_1.ContainerMessageType.Attach, contents: attachMsg }), (id, createParam) => (summarizeInternal, getGCDataFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap));
|
|
405
391
|
this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (localId, blobId) => {
|
|
406
392
|
if (!this.disposed) {
|
|
407
|
-
this.submit({ type: ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
|
|
393
|
+
this.submit({ type: messageTypes_1.ContainerMessageType.BlobAttach, contents: undefined }, undefined, {
|
|
408
394
|
localId,
|
|
409
395
|
blobId,
|
|
410
396
|
});
|
|
@@ -518,26 +504,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
518
504
|
this.summaryManager.start();
|
|
519
505
|
}
|
|
520
506
|
}
|
|
521
|
-
this.deltaManager.on("readonly", (readonly) => {
|
|
522
|
-
// we accumulate ops while being in read-only state.
|
|
523
|
-
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
524
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
525
|
-
(0, core_utils_1.assert)(readonly === this.innerDeltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
526
|
-
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
527
|
-
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
528
|
-
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
529
|
-
// For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
|
|
530
|
-
// ops that made it from previous connection, before switching clientId and raising "connected" event
|
|
531
|
-
// But with read-only permissions, if we transition between read-only and r/w states while on same
|
|
532
|
-
// connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
|
|
533
|
-
// being in read-only state.
|
|
534
|
-
// For that reason, we support getting to read-only state only when disconnected. This ensures that we
|
|
535
|
-
// can rely on same safety mechanism and resend ops only when we establish new connection.
|
|
536
|
-
// This is applicable for read-only permissions (event is raised before connection is properly registered),
|
|
537
|
-
// but it's an extra requirement for Container.forceReadonly() API
|
|
538
|
-
(0, core_utils_1.assert)(!readonly || !this.connected, 0x125 /* "Unsafe to transition to read-only state!" */);
|
|
539
|
-
this.replayPendingStates();
|
|
540
|
-
});
|
|
541
507
|
// logging hardware telemetry
|
|
542
508
|
logger.sendTelemetryEvent({
|
|
543
509
|
eventName: "DeviceSpec",
|
|
@@ -713,10 +679,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
713
679
|
enableGroupedBatching,
|
|
714
680
|
}, containerScope, logger, existing, blobManagerSnapshot, context.storage, idCompressor, requestHandler, undefined, // summaryConfiguration
|
|
715
681
|
initializeEntryPoint);
|
|
716
|
-
|
|
717
|
-
//
|
|
718
|
-
|
|
719
|
-
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
682
|
+
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
683
|
+
// or zero. This must be done before Container replays saved ops.
|
|
684
|
+
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
720
685
|
// Initialize the base state of the runtime before it's returned.
|
|
721
686
|
await runtime.initializeBaseState();
|
|
722
687
|
return runtime;
|
|
@@ -999,7 +964,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
999
964
|
// in their own batches before the originating batch is sent.
|
|
1000
965
|
// Therefore, receiving them while attempting to send the originating batch
|
|
1001
966
|
// does not mean that the container is making any progress.
|
|
1002
|
-
if (message?.type !== ContainerMessageType.ChunkedOp) {
|
|
967
|
+
if (message?.type !== messageTypes_1.ContainerMessageType.ChunkedOp) {
|
|
1003
968
|
this.consecutiveReconnects = 0;
|
|
1004
969
|
}
|
|
1005
970
|
}
|
|
@@ -1047,39 +1012,40 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1047
1012
|
* Parse an op's type and actual content from given serialized content
|
|
1048
1013
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
1049
1014
|
*/
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1015
|
+
// TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
|
|
1016
|
+
parseLocalOpContent(serializedContents) {
|
|
1017
|
+
(0, core_utils_1.assert)(serializedContents !== undefined, 0x6d5 /* content must be defined */);
|
|
1018
|
+
const message = JSON.parse(serializedContents);
|
|
1019
|
+
(0, core_utils_1.assert)(message.type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1020
|
+
return message;
|
|
1021
|
+
}
|
|
1022
|
+
async applyStashedOp(serializedOpContent) {
|
|
1057
1023
|
// Need to parse from string for back-compat
|
|
1058
|
-
const
|
|
1059
|
-
switch (type) {
|
|
1060
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
1061
|
-
return this.dataStores.applyStashedOp(contents);
|
|
1062
|
-
case ContainerMessageType.Attach:
|
|
1063
|
-
return this.dataStores.applyStashedAttachOp(contents);
|
|
1064
|
-
case ContainerMessageType.IdAllocation:
|
|
1024
|
+
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
1025
|
+
switch (opContents.type) {
|
|
1026
|
+
case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
|
|
1027
|
+
return this.dataStores.applyStashedOp(opContents.contents);
|
|
1028
|
+
case messageTypes_1.ContainerMessageType.Attach:
|
|
1029
|
+
return this.dataStores.applyStashedAttachOp(opContents.contents);
|
|
1030
|
+
case messageTypes_1.ContainerMessageType.IdAllocation:
|
|
1065
1031
|
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67b /* IdCompressor should be defined if enabled */);
|
|
1066
|
-
return this.applyStashedIdAllocationOp(contents);
|
|
1067
|
-
case ContainerMessageType.Alias:
|
|
1068
|
-
case ContainerMessageType.BlobAttach:
|
|
1032
|
+
return this.applyStashedIdAllocationOp(opContents.contents);
|
|
1033
|
+
case messageTypes_1.ContainerMessageType.Alias:
|
|
1034
|
+
case messageTypes_1.ContainerMessageType.BlobAttach:
|
|
1069
1035
|
return;
|
|
1070
|
-
case ContainerMessageType.ChunkedOp:
|
|
1036
|
+
case messageTypes_1.ContainerMessageType.ChunkedOp:
|
|
1071
1037
|
throw new Error("chunkedOp not expected here");
|
|
1072
|
-
case ContainerMessageType.Rejoin:
|
|
1038
|
+
case messageTypes_1.ContainerMessageType.Rejoin:
|
|
1073
1039
|
throw new Error("rejoin not expected here");
|
|
1074
1040
|
default: {
|
|
1075
1041
|
// This should be extremely rare for stashed ops.
|
|
1076
1042
|
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
1077
1043
|
// e.g. if an app rolled back its container version
|
|
1078
|
-
const compatBehavior = compatDetails?.behavior;
|
|
1079
|
-
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
1044
|
+
const compatBehavior = opContents.compatDetails?.behavior;
|
|
1045
|
+
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
1080
1046
|
const error = telemetry_utils_1.DataProcessingError.create("Stashed runtime message of unknown type", "applyStashedOp", undefined /* sequencedMessage */, {
|
|
1081
1047
|
messageDetails: JSON.stringify({
|
|
1082
|
-
type,
|
|
1048
|
+
type: opContents.type,
|
|
1083
1049
|
compatBehavior,
|
|
1084
1050
|
}),
|
|
1085
1051
|
});
|
|
@@ -1098,6 +1064,23 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1098
1064
|
// Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
|
|
1099
1065
|
return;
|
|
1100
1066
|
}
|
|
1067
|
+
// If there are stashed blobs in the pending state, we need to delay
|
|
1068
|
+
// propagation of the "connected" event until we have uploaded them to
|
|
1069
|
+
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1070
|
+
const connecting = connected && !this._connected;
|
|
1071
|
+
if (connecting && this.blobManager.hasPendingStashedBlobs()) {
|
|
1072
|
+
(0, core_utils_1.assert)(!this.delayConnectClientId, 0x791 /* Connect event delay must be canceled before subsequent connect event */);
|
|
1073
|
+
(0, core_utils_1.assert)(!!clientId, 0x792 /* Must have clientId when connecting */);
|
|
1074
|
+
this.delayConnectClientId = clientId;
|
|
1075
|
+
this.blobManager.processStashedChanges().then(() => {
|
|
1076
|
+
// make sure we didn't reconnect before the promise resolved
|
|
1077
|
+
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
1078
|
+
this.delayConnectClientId = undefined;
|
|
1079
|
+
this.setConnectionStateCore(connected, clientId);
|
|
1080
|
+
}
|
|
1081
|
+
}, (error) => this.closeFn(error));
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1101
1084
|
this.setConnectionStateCore(connected, clientId);
|
|
1102
1085
|
}
|
|
1103
1086
|
setConnectionStateCore(connected, clientId) {
|
|
@@ -1150,18 +1133,33 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1150
1133
|
// or something different, like a system message.
|
|
1151
1134
|
const modernRuntimeMessage = messageArg.type === protocol_definitions_1.MessageType.Operation;
|
|
1152
1135
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
1136
|
+
// There might be multiple container instances receiving the same message.
|
|
1137
|
+
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
1138
|
+
// but will not modify the contents object (likely it will replace it on the message).
|
|
1153
1139
|
const messageCopy = { ...messageArg };
|
|
1154
1140
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
1155
|
-
|
|
1141
|
+
if (modernRuntimeMessage) {
|
|
1142
|
+
this.processCore({
|
|
1143
|
+
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
1144
|
+
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
1145
|
+
// the result messages will be so. In the end modern bool being true only directs to
|
|
1146
|
+
// throw error if ultimately unrecognized without compat details saying otherwise.
|
|
1147
|
+
message: message,
|
|
1148
|
+
local,
|
|
1149
|
+
modernRuntimeMessage,
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
else {
|
|
1153
|
+
// Unrecognized message will be ignored.
|
|
1154
|
+
this.processCore({ message, local, modernRuntimeMessage });
|
|
1155
|
+
}
|
|
1156
1156
|
}
|
|
1157
1157
|
}
|
|
1158
1158
|
/**
|
|
1159
1159
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
1160
|
-
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
1161
|
-
* @param local - Did this client send the op?
|
|
1162
|
-
* @param modernRuntimeMessage - Does this appear like a current ContainerRuntimeMessage?
|
|
1163
1160
|
*/
|
|
1164
|
-
processCore(
|
|
1161
|
+
processCore(messageWithContext) {
|
|
1162
|
+
const { message, local } = messageWithContext;
|
|
1165
1163
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
1166
1164
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
1167
1165
|
// messages once a batch has been fully processed.
|
|
@@ -1169,16 +1167,18 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1169
1167
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1170
1168
|
try {
|
|
1171
1169
|
let localOpMetadata;
|
|
1172
|
-
if (local &&
|
|
1173
|
-
|
|
1170
|
+
if (local &&
|
|
1171
|
+
messageWithContext.modernRuntimeMessage &&
|
|
1172
|
+
message.type !== messageTypes_1.ContainerMessageType.ChunkedOp) {
|
|
1173
|
+
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
|
|
1174
1174
|
}
|
|
1175
1175
|
// If there are no more pending messages after processing a local message,
|
|
1176
1176
|
// the document is no longer dirty.
|
|
1177
1177
|
if (!this.hasPendingMessages()) {
|
|
1178
1178
|
this.updateDocumentDirtyState(false);
|
|
1179
1179
|
}
|
|
1180
|
-
this.validateAndProcessRuntimeMessage(
|
|
1181
|
-
this.emit("op", message, modernRuntimeMessage);
|
|
1180
|
+
this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
|
|
1181
|
+
this.emit("op", message, messageWithContext.modernRuntimeMessage);
|
|
1182
1182
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
1183
1183
|
if (local) {
|
|
1184
1184
|
// If we have processed a local op, this means that the container is
|
|
@@ -1193,41 +1193,42 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1193
1193
|
}
|
|
1194
1194
|
}
|
|
1195
1195
|
/**
|
|
1196
|
-
* Assuming the given message is also a
|
|
1196
|
+
* Assuming the given message is also a TypedContainerRuntimeMessage,
|
|
1197
1197
|
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
1198
|
-
* Throws a DataProcessingError if the message doesn't conform to
|
|
1198
|
+
* Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
|
|
1199
1199
|
*/
|
|
1200
|
-
validateAndProcessRuntimeMessage(
|
|
1201
|
-
//
|
|
1202
|
-
const {
|
|
1203
|
-
switch (
|
|
1204
|
-
case ContainerMessageType.Attach:
|
|
1205
|
-
this.dataStores.processAttachMessage(message, local);
|
|
1200
|
+
validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata) {
|
|
1201
|
+
// TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
|
|
1202
|
+
const { local } = messageWithContext;
|
|
1203
|
+
switch (messageWithContext.message.type) {
|
|
1204
|
+
case messageTypes_1.ContainerMessageType.Attach:
|
|
1205
|
+
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
1206
1206
|
break;
|
|
1207
|
-
case ContainerMessageType.Alias:
|
|
1208
|
-
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
1207
|
+
case messageTypes_1.ContainerMessageType.Alias:
|
|
1208
|
+
this.dataStores.processAliasMessage(messageWithContext.message, localOpMetadata, local);
|
|
1209
1209
|
break;
|
|
1210
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
1211
|
-
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1210
|
+
case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
|
|
1211
|
+
this.dataStores.processFluidDataStoreOp(messageWithContext.message, local, localOpMetadata);
|
|
1212
1212
|
break;
|
|
1213
|
-
case ContainerMessageType.BlobAttach:
|
|
1214
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
1213
|
+
case messageTypes_1.ContainerMessageType.BlobAttach:
|
|
1214
|
+
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
1215
1215
|
break;
|
|
1216
|
-
case ContainerMessageType.IdAllocation:
|
|
1216
|
+
case messageTypes_1.ContainerMessageType.IdAllocation:
|
|
1217
1217
|
(0, core_utils_1.assert)(this.idCompressor !== undefined, 0x67c /* IdCompressor should be defined if enabled */);
|
|
1218
|
-
this.idCompressor.finalizeCreationRange(message.contents);
|
|
1218
|
+
this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
|
|
1219
1219
|
break;
|
|
1220
|
-
case ContainerMessageType.ChunkedOp:
|
|
1221
|
-
case ContainerMessageType.Rejoin:
|
|
1220
|
+
case messageTypes_1.ContainerMessageType.ChunkedOp:
|
|
1221
|
+
case messageTypes_1.ContainerMessageType.Rejoin:
|
|
1222
1222
|
break;
|
|
1223
1223
|
default: {
|
|
1224
1224
|
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
1225
1225
|
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
1226
|
-
if (!
|
|
1226
|
+
if (!messageWithContext.modernRuntimeMessage) {
|
|
1227
1227
|
return;
|
|
1228
1228
|
}
|
|
1229
|
-
const compatBehavior = compatDetails?.behavior;
|
|
1230
|
-
if (!compatBehaviorAllowsMessageType(
|
|
1229
|
+
const compatBehavior = messageWithContext.message.compatDetails?.behavior;
|
|
1230
|
+
if (!compatBehaviorAllowsMessageType(messageWithContext.message.type, compatBehavior)) {
|
|
1231
|
+
const { message } = messageWithContext;
|
|
1231
1232
|
const error = telemetry_utils_1.DataProcessingError.create(
|
|
1232
1233
|
// Former assert 0x3ce
|
|
1233
1234
|
"Runtime message of unknown type", "OpProcessing", message, {
|
|
@@ -1369,8 +1370,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1369
1370
|
/**
|
|
1370
1371
|
* Returns the aliased data store's entryPoint, given the alias.
|
|
1371
1372
|
* @param alias - The alias for the data store.
|
|
1372
|
-
* @returns
|
|
1373
|
-
* data store has been assigned the given alias.
|
|
1373
|
+
* @returns The data store's entry point ({@link @fluidframework/core-interfaces#IFluidHandle}) if it exists and is aliased.
|
|
1374
|
+
* Returns undefined if no data store has been assigned the given alias.
|
|
1374
1375
|
*/
|
|
1375
1376
|
async getAliasedDataStoreEntryPoint(alias) {
|
|
1376
1377
|
await this.dataStores.waitIfPendingAlias(alias);
|
|
@@ -1437,13 +1438,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1437
1438
|
isContainerMessageDirtyable({ type, contents }) {
|
|
1438
1439
|
// For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
|
|
1439
1440
|
// Ultimately we should have no special-cases from the ContainerRuntime's perspective.
|
|
1440
|
-
if (type === ContainerMessageType.Attach) {
|
|
1441
|
+
if (type === messageTypes_1.ContainerMessageType.Attach) {
|
|
1441
1442
|
const attachMessage = contents;
|
|
1442
1443
|
if (attachMessage.id === exports.agentSchedulerId) {
|
|
1443
1444
|
return false;
|
|
1444
1445
|
}
|
|
1445
1446
|
}
|
|
1446
|
-
else if (type === ContainerMessageType.FluidDataStoreOp) {
|
|
1447
|
+
else if (type === messageTypes_1.ContainerMessageType.FluidDataStoreOp) {
|
|
1447
1448
|
const envelope = contents;
|
|
1448
1449
|
if (envelope.address === exports.agentSchedulerId) {
|
|
1449
1450
|
return false;
|
|
@@ -1609,7 +1610,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1609
1610
|
/**
|
|
1610
1611
|
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
1611
1612
|
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
1612
|
-
* @returns
|
|
1613
|
+
* @returns The routes of nodes that were deleted.
|
|
1613
1614
|
*/
|
|
1614
1615
|
deleteSweepReadyNodes(sweepReadyRoutes) {
|
|
1615
1616
|
const { dataStoreRoutes, blobManagerRoutes } = this.getDataStoreAndBlobManagerRoutes(sweepReadyRoutes);
|
|
@@ -1671,7 +1672,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1671
1672
|
/**
|
|
1672
1673
|
* From a given list of routes, separate and return routes that belong to blob manager and data stores.
|
|
1673
1674
|
* @param routes - A list of routes that can belong to data stores or blob manager.
|
|
1674
|
-
* @returns
|
|
1675
|
+
* @returns Two route lists - One that contains routes for blob manager and another one that contains routes
|
|
1675
1676
|
* for data stores.
|
|
1676
1677
|
*/
|
|
1677
1678
|
getDataStoreAndBlobManagerRoutes(routes) {
|
|
@@ -1723,16 +1724,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1723
1724
|
},
|
|
1724
1725
|
});
|
|
1725
1726
|
(0, core_utils_1.assert)(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
1727
|
+
// We close the summarizer and download a new snapshot and reload the container
|
|
1726
1728
|
let latestSnapshotVersionId;
|
|
1727
|
-
if (refreshLatestAck) {
|
|
1728
|
-
|
|
1729
|
+
if (refreshLatestAck === true) {
|
|
1730
|
+
return this.prefetchLatestSummaryThenClose((0, telemetry_utils_1.createChildLogger)({
|
|
1729
1731
|
logger: summaryNumberLogger,
|
|
1730
1732
|
properties: { all: { safeSummary: true } },
|
|
1731
1733
|
}));
|
|
1732
|
-
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
1733
|
-
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
1734
|
-
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
1735
|
-
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
1736
1734
|
}
|
|
1737
1735
|
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
1738
1736
|
// incorrect. So, wait for the container to be saved with a timeout. If the container is not saved
|
|
@@ -2052,21 +2050,21 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2052
2050
|
address: id,
|
|
2053
2051
|
contents,
|
|
2054
2052
|
};
|
|
2055
|
-
this.submit({ type: ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
|
|
2053
|
+
this.submit({ type: messageTypes_1.ContainerMessageType.FluidDataStoreOp, contents: envelope }, localOpMetadata);
|
|
2056
2054
|
}
|
|
2057
2055
|
submitDataStoreAliasOp(contents, localOpMetadata) {
|
|
2058
2056
|
const aliasMessage = contents;
|
|
2059
2057
|
if (!(0, dataStore_1.isDataStoreAliasMessage)(aliasMessage)) {
|
|
2060
2058
|
throw new telemetry_utils_1.UsageError("malformedDataStoreAliasMessage");
|
|
2061
2059
|
}
|
|
2062
|
-
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
2060
|
+
this.submit({ type: messageTypes_1.ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
2063
2061
|
}
|
|
2064
2062
|
async uploadBlob(blob, signal) {
|
|
2065
2063
|
this.verifyNotClosed();
|
|
2066
2064
|
return this.blobManager.createBlob(blob, signal);
|
|
2067
2065
|
}
|
|
2068
2066
|
maybeSubmitIdAllocationOp(type) {
|
|
2069
|
-
if (type !== ContainerMessageType.IdAllocation) {
|
|
2067
|
+
if (type !== messageTypes_1.ContainerMessageType.IdAllocation) {
|
|
2070
2068
|
let idAllocationBatchMessage;
|
|
2071
2069
|
let idRange;
|
|
2072
2070
|
if (this.idCompressorEnabled) {
|
|
@@ -2077,7 +2075,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2077
2075
|
}
|
|
2078
2076
|
if (idRange !== undefined) {
|
|
2079
2077
|
const idAllocationMessage = {
|
|
2080
|
-
type: ContainerMessageType.IdAllocation,
|
|
2078
|
+
type: messageTypes_1.ContainerMessageType.IdAllocation,
|
|
2081
2079
|
contents: idRange,
|
|
2082
2080
|
};
|
|
2083
2081
|
idAllocationBatchMessage = {
|
|
@@ -2085,7 +2083,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2085
2083
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2086
2084
|
metadata: undefined,
|
|
2087
2085
|
localOpMetadata: this.idCompressor?.serialize(true),
|
|
2088
|
-
type: ContainerMessageType.IdAllocation,
|
|
2086
|
+
type: messageTypes_1.ContainerMessageType.IdAllocation,
|
|
2089
2087
|
};
|
|
2090
2088
|
}
|
|
2091
2089
|
if (idAllocationBatchMessage !== undefined) {
|
|
@@ -2142,11 +2140,11 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2142
2140
|
// Please note that this does not change file format, so it can be disabled in the future if this
|
|
2143
2141
|
// optimization no longer makes sense (for example, batch compression may make it less appealing).
|
|
2144
2142
|
if (this.currentlyBatching() &&
|
|
2145
|
-
type === ContainerMessageType.Attach &&
|
|
2143
|
+
type === messageTypes_1.ContainerMessageType.Attach &&
|
|
2146
2144
|
this.disableAttachReorder !== true) {
|
|
2147
2145
|
this.outbox.submitAttach(message);
|
|
2148
2146
|
}
|
|
2149
|
-
else if (type === ContainerMessageType.BlobAttach) {
|
|
2147
|
+
else if (type === messageTypes_1.ContainerMessageType.BlobAttach) {
|
|
2150
2148
|
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
2151
2149
|
this.outbox.submitBlobAttach(message);
|
|
2152
2150
|
}
|
|
@@ -2256,40 +2254,37 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2256
2254
|
}
|
|
2257
2255
|
reSubmit(message) {
|
|
2258
2256
|
// Need to parse from string for back-compat
|
|
2259
|
-
const containerRuntimeMessage = this.
|
|
2257
|
+
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
2260
2258
|
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
2261
2259
|
}
|
|
2262
2260
|
/**
|
|
2263
2261
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
2264
2262
|
* reconnect and there are pending messages.
|
|
2265
|
-
* @param message - The original
|
|
2263
|
+
* @param message - The original LocalContainerRuntimeMessage.
|
|
2266
2264
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
2267
2265
|
*/
|
|
2268
2266
|
reSubmitCore(message, localOpMetadata, opMetadata) {
|
|
2269
|
-
const contents = message.contents;
|
|
2270
2267
|
switch (message.type) {
|
|
2271
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
2268
|
+
case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
|
|
2272
2269
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
2273
2270
|
// and trigger resubmission on it.
|
|
2274
|
-
this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
|
|
2271
|
+
this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
|
|
2275
2272
|
break;
|
|
2276
|
-
case ContainerMessageType.Attach:
|
|
2277
|
-
case ContainerMessageType.Alias:
|
|
2273
|
+
case messageTypes_1.ContainerMessageType.Attach:
|
|
2274
|
+
case messageTypes_1.ContainerMessageType.Alias:
|
|
2278
2275
|
this.submit(message, localOpMetadata);
|
|
2279
2276
|
break;
|
|
2280
|
-
case ContainerMessageType.IdAllocation:
|
|
2281
|
-
|
|
2282
|
-
if (contents.stashedState !== undefined) {
|
|
2283
|
-
delete contents.stashedState;
|
|
2284
|
-
}
|
|
2277
|
+
case messageTypes_1.ContainerMessageType.IdAllocation: {
|
|
2278
|
+
prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
|
|
2285
2279
|
this.submit(message, localOpMetadata);
|
|
2286
2280
|
break;
|
|
2287
|
-
|
|
2281
|
+
}
|
|
2282
|
+
case messageTypes_1.ContainerMessageType.ChunkedOp:
|
|
2288
2283
|
throw new Error(`chunkedOp not expected here`);
|
|
2289
|
-
case ContainerMessageType.BlobAttach:
|
|
2284
|
+
case messageTypes_1.ContainerMessageType.BlobAttach:
|
|
2290
2285
|
this.blobManager.reSubmit(opMetadata);
|
|
2291
2286
|
break;
|
|
2292
|
-
case ContainerMessageType.Rejoin:
|
|
2287
|
+
case messageTypes_1.ContainerMessageType.Rejoin:
|
|
2293
2288
|
this.submit(message);
|
|
2294
2289
|
break;
|
|
2295
2290
|
default: {
|
|
@@ -2317,9 +2312,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2317
2312
|
}
|
|
2318
2313
|
rollback(content, localOpMetadata) {
|
|
2319
2314
|
// Need to parse from string for back-compat
|
|
2320
|
-
const { type, contents } = this.
|
|
2315
|
+
const { type, contents } = this.parseLocalOpContent(content);
|
|
2321
2316
|
switch (type) {
|
|
2322
|
-
case ContainerMessageType.FluidDataStoreOp:
|
|
2317
|
+
case messageTypes_1.ContainerMessageType.FluidDataStoreOp:
|
|
2323
2318
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
2324
2319
|
// and trigger rollback on it.
|
|
2325
2320
|
this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
|
|
@@ -2329,17 +2324,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2329
2324
|
throw new Error(`Can't rollback ${type}`);
|
|
2330
2325
|
}
|
|
2331
2326
|
}
|
|
2332
|
-
async waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryLogger) {
|
|
2333
|
-
if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
|
|
2334
|
-
// We need to catch up to the latest summary's reference sequence number before proceeding.
|
|
2335
|
-
await telemetry_utils_1.PerformanceEvent.timedExecAsync(summaryLogger, {
|
|
2336
|
-
eventName: "WaitingForSeq",
|
|
2337
|
-
lastSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2338
|
-
targetSequenceNumber: latestSnapshotRefSeq,
|
|
2339
|
-
lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
|
|
2340
|
-
}, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
2327
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
2344
2328
|
async refreshLatestSummaryAck(options) {
|
|
2345
2329
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
@@ -2385,18 +2369,25 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2385
2369
|
await this.garbageCollector.refreshLatestSummary(result);
|
|
2386
2370
|
}
|
|
2387
2371
|
/**
|
|
2388
|
-
* Fetches the latest snapshot from storage
|
|
2389
|
-
*
|
|
2372
|
+
* Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
|
|
2373
|
+
* summarizer to reload from new state.
|
|
2390
2374
|
* @param summaryLogger - logger to use when fetching snapshot from storage
|
|
2391
|
-
* @returns
|
|
2375
|
+
* @returns a generic summarization error
|
|
2392
2376
|
*/
|
|
2393
|
-
async
|
|
2377
|
+
async prefetchLatestSummaryThenClose(summaryLogger) {
|
|
2394
2378
|
const readAndParseBlob = async (id) => (0, driver_utils_1.readAndParse)(this.storage, id);
|
|
2395
|
-
|
|
2379
|
+
// This is a performance optimization as the same parent is likely to be elected again, and would use its
|
|
2380
|
+
// cache to fetch the snapshot instead of the network.
|
|
2381
|
+
await this.fetchSnapshotFromStorage(summaryLogger, {
|
|
2396
2382
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
2397
2383
|
}, readAndParseBlob, null);
|
|
2398
2384
|
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
2399
|
-
return {
|
|
2385
|
+
return {
|
|
2386
|
+
stage: "base",
|
|
2387
|
+
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
2388
|
+
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
2389
|
+
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
2390
|
+
};
|
|
2400
2391
|
}
|
|
2401
2392
|
async closeStaleSummarizer(codePath) {
|
|
2402
2393
|
this.mc.logger.sendTelemetryEvent({
|
|
@@ -2419,7 +2410,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2419
2410
|
return telemetry_utils_1.PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2420
2411
|
const stats = {};
|
|
2421
2412
|
const trace = client_utils_1.Trace.start();
|
|
2422
|
-
const versions = await this.storage.getVersions(versionId, 1, "
|
|
2413
|
+
const versions = await this.storage.getVersions(versionId, 1, "prefetchLatestSummaryBeforeClose", versionId === null ? driver_definitions_1.FetchSource.noCache : undefined);
|
|
2423
2414
|
(0, core_utils_1.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
2424
2415
|
stats.getVersionDuration = trace.trace().duration;
|
|
2425
2416
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
@@ -2447,15 +2438,17 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2447
2438
|
if (this._orderSequentiallyCalls !== 0) {
|
|
2448
2439
|
throw new telemetry_utils_1.UsageError("can't get state during orderSequentially");
|
|
2449
2440
|
}
|
|
2450
|
-
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
|
|
2451
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
2452
|
-
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
2453
|
-
return; // no pending state to save
|
|
2454
|
-
}
|
|
2455
2441
|
// Flush pending batch.
|
|
2456
2442
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
2457
2443
|
// to close current batch.
|
|
2458
2444
|
this.flush();
|
|
2445
|
+
const pendingAttachmentBlobs = waitBlobsToAttach
|
|
2446
|
+
? await this.blobManager.attachAndGetPendingBlobs()
|
|
2447
|
+
: undefined;
|
|
2448
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
2449
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
2450
|
+
return; // no pending state to save
|
|
2451
|
+
}
|
|
2459
2452
|
const pendingState = {
|
|
2460
2453
|
pending,
|
|
2461
2454
|
pendingAttachmentBlobs,
|
|
@@ -2538,26 +2531,4 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2538
2531
|
}
|
|
2539
2532
|
}
|
|
2540
2533
|
exports.ContainerRuntime = ContainerRuntime;
|
|
2541
|
-
/**
|
|
2542
|
-
* Wait for a specific sequence number. Promise should resolve when we reach that number,
|
|
2543
|
-
* or reject if closed.
|
|
2544
|
-
*/
|
|
2545
|
-
const waitForSeq = async (deltaManager, targetSeq) => new Promise((resolve, reject) => {
|
|
2546
|
-
// TODO: remove cast to any when actual event is determined
|
|
2547
|
-
deltaManager.on("closed", reject);
|
|
2548
|
-
deltaManager.on("disposed", reject);
|
|
2549
|
-
// If we already reached target sequence number, simply resolve the promise.
|
|
2550
|
-
if (deltaManager.lastSequenceNumber >= targetSeq) {
|
|
2551
|
-
resolve();
|
|
2552
|
-
}
|
|
2553
|
-
else {
|
|
2554
|
-
const handleOp = (message) => {
|
|
2555
|
-
if (message.sequenceNumber >= targetSeq) {
|
|
2556
|
-
resolve();
|
|
2557
|
-
deltaManager.off("op", handleOp);
|
|
2558
|
-
}
|
|
2559
|
-
};
|
|
2560
|
-
deltaManager.on("op", handleOp);
|
|
2561
|
-
}
|
|
2562
|
-
});
|
|
2563
2534
|
//# sourceMappingURL=containerRuntime.js.map
|