@fluidframework/container-runtime 2.0.0-internal.6.3.3 → 2.0.0-internal.7.0.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 +111 -0
- package/dist/blobManager.d.ts +4 -3
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +35 -31
- package/dist/blobManager.js.map +1 -1
- package/dist/containerHandleContext.js +3 -3
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +21 -78
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +378 -412
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +9 -9
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +54 -56
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreRegistry.js +3 -3
- package/dist/dataStoreRegistry.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/deltaManagerProxyBase.js +4 -4
- package/dist/deltaManagerProxyBase.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +6 -6
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +6 -3
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +19 -16
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +17 -17
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js +14 -15
- 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 +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/gcUnreferencedStateTracker.js +3 -3
- package/dist/gc/gcUnreferencedStateTracker.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 +3 -4
- package/dist/gc/index.js.map +1 -1
- package/dist/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/id-compressor/identifiers.d.ts +3 -3
- package/dist/id-compressor/identifiers.d.ts.map +1 -1
- package/dist/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/batchManager.js +6 -6
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +4 -3
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +0 -4
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +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 +4 -20
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +33 -45
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +3 -3
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +54 -54
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runWhileConnectedCoordinator.js +6 -6
- package/dist/summary/runWhileConnectedCoordinator.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 +41 -39
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.d.ts +2 -2
- package/dist/summary/summarizer.d.ts.map +1 -1
- package/dist/summary/summarizer.js +10 -8
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.js +6 -6
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +9 -9
- package/dist/summary/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +8 -8
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +14 -13
- 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 +21 -21
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +8 -5
- 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/dist/summary/summaryGenerator.d.ts +3 -3
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +7 -7
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.js +16 -16
- package/dist/throttler.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/blobManager.d.ts +4 -3
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +36 -32
- package/lib/blobManager.js.map +1 -1
- package/lib/containerHandleContext.js +3 -3
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +21 -78
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +339 -375
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +9 -9
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +54 -56
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreRegistry.js +3 -3
- package/lib/dataStoreRegistry.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/deltaManagerProxyBase.js +4 -4
- package/lib/deltaManagerProxyBase.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js +6 -6
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +6 -3
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +19 -16
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +17 -17
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js +13 -14
- 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 +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/gcUnreferencedStateTracker.js +3 -3
- package/lib/gc/gcUnreferencedStateTracker.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/id-compressor/appendOnlySortedMap.js.map +1 -1
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/id-compressor/identifiers.d.ts +3 -3
- package/lib/id-compressor/identifiers.d.ts.map +1 -1
- package/lib/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/batchManager.js +6 -6
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +4 -3
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +0 -4
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +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 +4 -20
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +32 -44
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +3 -3
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +54 -54
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runWhileConnectedCoordinator.js +6 -6
- package/lib/summary/runWhileConnectedCoordinator.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 +41 -39
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.d.ts +2 -2
- package/lib/summary/summarizer.d.ts.map +1 -1
- package/lib/summary/summarizer.js +10 -8
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.js +6 -6
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +9 -9
- package/lib/summary/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +8 -8
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +3 -3
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -2
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +14 -13
- 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 +21 -21
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +8 -5
- 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/lib/summary/summaryGenerator.d.ts +3 -3
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +6 -6
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.js +16 -16
- package/lib/throttler.js.map +1 -1
- package/package.json +57 -22
- package/src/blobManager.ts +38 -28
- package/src/containerRuntime.ts +210 -278
- package/src/dataStore.ts +1 -1
- package/src/dataStoreContext.ts +4 -7
- package/src/dataStores.ts +4 -4
- package/src/gc/garbageCollection.md +53 -5
- package/src/gc/garbageCollection.ts +6 -3
- package/src/gc/gcDefinitions.ts +14 -27
- 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 +2 -3
- 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 +30 -52
- package/src/summary/runningSummarizer.ts +4 -2
- package/src/summary/summarizer.ts +5 -3
- package/src/summary/summarizerNode/summarizerNode.ts +1 -1
- package/src/summary/summarizerTypes.ts +2 -1
- package/src/summary/summaryFormat.ts +3 -0
package/src/containerRuntime.ts
CHANGED
|
@@ -8,9 +8,11 @@ import {
|
|
|
8
8
|
FluidObject,
|
|
9
9
|
IFluidHandle,
|
|
10
10
|
IFluidHandleContext,
|
|
11
|
+
// eslint-disable-next-line import/no-deprecated
|
|
11
12
|
IFluidRouter,
|
|
12
13
|
IRequest,
|
|
13
14
|
IResponse,
|
|
15
|
+
IProvideFluidHandleContext,
|
|
14
16
|
} from "@fluidframework/core-interfaces";
|
|
15
17
|
import {
|
|
16
18
|
IAudience,
|
|
@@ -88,7 +90,6 @@ import {
|
|
|
88
90
|
IIdCompressorCore,
|
|
89
91
|
IdCreationRange,
|
|
90
92
|
IdCreationRangeWithStashedState,
|
|
91
|
-
IAttachMessage,
|
|
92
93
|
} from "@fluidframework/runtime-definitions";
|
|
93
94
|
import {
|
|
94
95
|
addBlobToSummary,
|
|
@@ -98,6 +99,7 @@ import {
|
|
|
98
99
|
create404Response,
|
|
99
100
|
exceptionToResponse,
|
|
100
101
|
GCDataBuilder,
|
|
102
|
+
// eslint-disable-next-line import/no-deprecated
|
|
101
103
|
requestFluidObject,
|
|
102
104
|
seqFromTree,
|
|
103
105
|
calculateStats,
|
|
@@ -184,92 +186,42 @@ import {
|
|
|
184
186
|
} from "./opLifecycle";
|
|
185
187
|
import { DeltaManagerSummarizerProxy } from "./deltaManagerSummarizerProxy";
|
|
186
188
|
import { IBatchMetadata } from "./metadata";
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Signifies that a blob has been attached and should not be garbage collected by storage
|
|
199
|
-
BlobAttach = "blobAttach",
|
|
200
|
-
|
|
201
|
-
// Ties our new clientId to our old one on reconnect
|
|
202
|
-
Rejoin = "rejoin",
|
|
203
|
-
|
|
204
|
-
// Sets the alias of a root data store
|
|
205
|
-
Alias = "alias",
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* An op containing an IdRange of Ids allocated using the runtime's IdCompressor since
|
|
209
|
-
* the last allocation op was sent.
|
|
210
|
-
* See the [IdCompressor README](./id-compressor/README.md) for more details.
|
|
211
|
-
*/
|
|
212
|
-
IdAllocation = "idAllocation",
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* How should an older client handle an unrecognized remote op type?
|
|
217
|
-
*
|
|
218
|
-
* @internal
|
|
219
|
-
*/
|
|
220
|
-
export type CompatModeBehavior =
|
|
221
|
-
/** Ignore the op. It won't be persisted if this client summarizes */
|
|
222
|
-
| "Ignore"
|
|
223
|
-
/** Fail processing immediately. (The container will close) */
|
|
224
|
-
| "FailToProcess";
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* All the info an older client would need to know how to handle an unrecognized remote op type
|
|
228
|
-
*
|
|
229
|
-
* @internal
|
|
230
|
-
*/
|
|
231
|
-
export interface IContainerRuntimeMessageCompatDetails {
|
|
232
|
-
/** How should an older client handle an unrecognized remote op type? */
|
|
233
|
-
behavior: CompatModeBehavior;
|
|
234
|
-
}
|
|
189
|
+
import {
|
|
190
|
+
ContainerMessageType,
|
|
191
|
+
type InboundSequencedContainerRuntimeMessage,
|
|
192
|
+
type InboundSequencedContainerRuntimeMessageOrSystemMessage,
|
|
193
|
+
type ContainerRuntimeIdAllocationMessage,
|
|
194
|
+
type LocalContainerRuntimeIdAllocationMessage,
|
|
195
|
+
type LocalContainerRuntimeMessage,
|
|
196
|
+
type OutboundContainerRuntimeMessage,
|
|
197
|
+
type UnknownContainerRuntimeMessage,
|
|
198
|
+
} from "./messageTypes";
|
|
235
199
|
|
|
236
200
|
/**
|
|
237
201
|
* Utility to implement compat behaviors given an unknown message type
|
|
238
202
|
* The parameters are typed to support compile-time enforcement of handling all known types/behaviors
|
|
239
203
|
*
|
|
240
|
-
* @param _unknownContainerRuntimeMessageType - Typed as
|
|
204
|
+
* @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
|
|
241
205
|
* handled before calling this function (e.g. in a switch statement).
|
|
242
206
|
* @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
|
|
243
207
|
*/
|
|
244
208
|
function compatBehaviorAllowsMessageType(
|
|
245
|
-
_unknownContainerRuntimeMessageType:
|
|
209
|
+
_unknownContainerRuntimeMessageType: UnknownContainerRuntimeMessage["type"],
|
|
246
210
|
compatBehavior: "Ignore" | "FailToProcess" | undefined,
|
|
247
211
|
): boolean {
|
|
248
212
|
// undefined defaults to same behavior as "FailToProcess"
|
|
249
213
|
return compatBehavior === "Ignore";
|
|
250
214
|
}
|
|
251
215
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
/** Type of the op, within the ContainerRuntime's domain */
|
|
260
|
-
type: ContainerMessageType;
|
|
261
|
-
/** Domain-specific contents, interpreted according to the type */
|
|
262
|
-
contents: any;
|
|
263
|
-
/** Info describing how to handle this op in case the type is unrecognized (default: fail to process) */
|
|
264
|
-
compatDetails?: IContainerRuntimeMessageCompatDetails;
|
|
216
|
+
function prepareLocalContainerRuntimeIdAllocationMessageForTransit(
|
|
217
|
+
message: LocalContainerRuntimeIdAllocationMessage | ContainerRuntimeIdAllocationMessage,
|
|
218
|
+
): asserts message is ContainerRuntimeIdAllocationMessage {
|
|
219
|
+
// Remove the stashedState from the op if it's a stashed op
|
|
220
|
+
if ("stashedState" in message.contents) {
|
|
221
|
+
delete message.contents.stashedState;
|
|
222
|
+
}
|
|
265
223
|
}
|
|
266
224
|
|
|
267
|
-
/**
|
|
268
|
-
* An unpacked ISequencedDocumentMessage with the inner ContainerRuntimeMessage type/contents/etc
|
|
269
|
-
* promoted up to the outer object
|
|
270
|
-
*/
|
|
271
|
-
export type SequencedContainerRuntimeMessage = ISequencedDocumentMessage & ContainerRuntimeMessage;
|
|
272
|
-
|
|
273
225
|
export interface ISummaryBaseConfiguration {
|
|
274
226
|
/**
|
|
275
227
|
* Delay before first attempt to spawn summarizing container.
|
|
@@ -597,7 +549,7 @@ export const defaultPendingOpsRetryDelayMs = 1000;
|
|
|
597
549
|
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
598
550
|
|
|
599
551
|
/**
|
|
600
|
-
* @deprecated - use
|
|
552
|
+
* @deprecated - use ContainerRuntimeMessageType instead
|
|
601
553
|
*/
|
|
602
554
|
export enum RuntimeMessage {
|
|
603
555
|
FluidDataStoreOp = "component",
|
|
@@ -660,13 +612,35 @@ export const makeLegacySendBatchFn =
|
|
|
660
612
|
deltaManager.flush();
|
|
661
613
|
};
|
|
662
614
|
|
|
615
|
+
/** Helper type for type constraints passed through several functions.
|
|
616
|
+
* message - The unpacked message. Likely a TypedContainerRuntimeMessage, but could also be a system op
|
|
617
|
+
* modernRuntimeMessage - Does this appear like a current TypedContainerRuntimeMessage?
|
|
618
|
+
* local - Did this client send the op?
|
|
619
|
+
*/
|
|
620
|
+
type MessageWithContext =
|
|
621
|
+
| {
|
|
622
|
+
message: InboundSequencedContainerRuntimeMessage;
|
|
623
|
+
modernRuntimeMessage: true;
|
|
624
|
+
local: boolean;
|
|
625
|
+
}
|
|
626
|
+
| {
|
|
627
|
+
message: InboundSequencedContainerRuntimeMessageOrSystemMessage;
|
|
628
|
+
modernRuntimeMessage: false;
|
|
629
|
+
local: boolean;
|
|
630
|
+
};
|
|
631
|
+
|
|
663
632
|
/**
|
|
664
633
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
665
634
|
* It will define the store level mappings.
|
|
666
635
|
*/
|
|
667
636
|
export class ContainerRuntime
|
|
668
637
|
extends TypedEventEmitter<IContainerRuntimeEvents & ISummarizerEvents>
|
|
669
|
-
implements
|
|
638
|
+
implements
|
|
639
|
+
IContainerRuntime,
|
|
640
|
+
IRuntime,
|
|
641
|
+
ISummarizerRuntime,
|
|
642
|
+
ISummarizerInternalsProvider,
|
|
643
|
+
IProvideFluidHandleContext
|
|
670
644
|
{
|
|
671
645
|
/**
|
|
672
646
|
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
@@ -703,10 +677,15 @@ export class ContainerRuntime
|
|
|
703
677
|
context,
|
|
704
678
|
registryEntries,
|
|
705
679
|
existing: existingFlag,
|
|
706
|
-
requestHandler,
|
|
707
680
|
runtimeOptions,
|
|
708
681
|
containerScope,
|
|
709
682
|
containerRuntimeCtor,
|
|
683
|
+
requestHandler,
|
|
684
|
+
provideEntryPoint: () => {
|
|
685
|
+
throw new UsageError(
|
|
686
|
+
"ContainerRuntime.load is deprecated and should no longer be used",
|
|
687
|
+
);
|
|
688
|
+
},
|
|
710
689
|
});
|
|
711
690
|
}
|
|
712
691
|
|
|
@@ -722,7 +701,7 @@ export class ContainerRuntime
|
|
|
722
701
|
* - containerScope - runtime services provided with context
|
|
723
702
|
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
724
703
|
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
725
|
-
* -
|
|
704
|
+
* - provideEntryPoint - Promise that resolves to an object which will act as entryPoint for the Container.
|
|
726
705
|
* This object should provide all the functionality that the Container is expected to provide to the loader layer.
|
|
727
706
|
*/
|
|
728
707
|
public static async loadRuntime(params: {
|
|
@@ -732,30 +711,21 @@ export class ContainerRuntime
|
|
|
732
711
|
runtimeOptions?: IContainerRuntimeOptions;
|
|
733
712
|
containerScope?: FluidObject;
|
|
734
713
|
containerRuntimeCtor?: typeof ContainerRuntime;
|
|
714
|
+
/** @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md */
|
|
735
715
|
requestHandler?: (request: IRequest, runtime: IContainerRuntime) => Promise<IResponse>;
|
|
736
|
-
|
|
716
|
+
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>;
|
|
737
717
|
}): Promise<ContainerRuntime> {
|
|
738
718
|
const {
|
|
739
719
|
context,
|
|
740
720
|
registryEntries,
|
|
741
721
|
existing,
|
|
742
722
|
requestHandler,
|
|
723
|
+
provideEntryPoint,
|
|
743
724
|
runtimeOptions = {},
|
|
744
725
|
containerScope = {},
|
|
745
726
|
containerRuntimeCtor = ContainerRuntime,
|
|
746
727
|
} = params;
|
|
747
728
|
|
|
748
|
-
const initializeEntryPoint =
|
|
749
|
-
params.initializeEntryPoint ??
|
|
750
|
-
(async (containerRuntime: IContainerRuntime) => ({
|
|
751
|
-
get IFluidRouter() {
|
|
752
|
-
return this;
|
|
753
|
-
},
|
|
754
|
-
async request(req) {
|
|
755
|
-
return containerRuntime.request(req);
|
|
756
|
-
},
|
|
757
|
-
}));
|
|
758
|
-
|
|
759
729
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
760
730
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
761
731
|
const backCompatContext: IContainerContext | OldContainerContextWithLogger = context;
|
|
@@ -884,15 +854,14 @@ export class ContainerRuntime
|
|
|
884
854
|
blobManagerSnapshot,
|
|
885
855
|
context.storage,
|
|
886
856
|
idCompressor,
|
|
857
|
+
provideEntryPoint,
|
|
887
858
|
requestHandler,
|
|
888
859
|
undefined, // summaryConfiguration
|
|
889
|
-
initializeEntryPoint,
|
|
890
860
|
);
|
|
891
861
|
|
|
892
|
-
|
|
893
|
-
//
|
|
894
|
-
|
|
895
|
-
await runtime.pendingStateManager.applyStashedOpsAt(0);
|
|
862
|
+
// Apply stashed ops with a reference sequence number equal to the sequence number of the snapshot,
|
|
863
|
+
// or zero. This must be done before Container replays saved ops.
|
|
864
|
+
await runtime.pendingStateManager.applyStashedOpsAt(runtimeSequenceNumber ?? 0);
|
|
896
865
|
|
|
897
866
|
// Initialize the base state of the runtime before it's returned.
|
|
898
867
|
await runtime.initializeBaseState();
|
|
@@ -913,17 +882,6 @@ export class ContainerRuntime
|
|
|
913
882
|
return this._storage;
|
|
914
883
|
}
|
|
915
884
|
|
|
916
|
-
/** @deprecated - The functionality is no longer exposed publicly */
|
|
917
|
-
public get reSubmitFn() {
|
|
918
|
-
return (
|
|
919
|
-
type: ContainerMessageType,
|
|
920
|
-
contents: any,
|
|
921
|
-
localOpMetadata: unknown,
|
|
922
|
-
opMetadata: Record<string, unknown> | undefined,
|
|
923
|
-
) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
924
|
-
// Note: compatDetails is not included in this deprecated API
|
|
925
|
-
}
|
|
926
|
-
|
|
927
885
|
private readonly submitFn: (
|
|
928
886
|
type: MessageType,
|
|
929
887
|
contents: any,
|
|
@@ -1175,6 +1133,7 @@ export class ContainerRuntime
|
|
|
1175
1133
|
blobManagerSnapshot: IBlobManagerLoadInfo,
|
|
1176
1134
|
private readonly _storage: IDocumentStorageService,
|
|
1177
1135
|
idCompressor: (IIdCompressor & IIdCompressorCore) | undefined,
|
|
1136
|
+
provideEntryPoint: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1178
1137
|
private readonly requestHandler?: (
|
|
1179
1138
|
request: IRequest,
|
|
1180
1139
|
runtime: IContainerRuntime,
|
|
@@ -1185,7 +1144,6 @@ export class ContainerRuntime
|
|
|
1185
1144
|
// the runtime configuration overrides
|
|
1186
1145
|
...runtimeOptions.summaryOptions?.summaryConfigOverrides,
|
|
1187
1146
|
},
|
|
1188
|
-
initializeEntryPoint?: (containerRuntime: IContainerRuntime) => Promise<FluidObject>,
|
|
1189
1147
|
) {
|
|
1190
1148
|
super();
|
|
1191
1149
|
|
|
@@ -1638,35 +1596,6 @@ export class ContainerRuntime
|
|
|
1638
1596
|
}
|
|
1639
1597
|
}
|
|
1640
1598
|
|
|
1641
|
-
this.deltaManager.on("readonly", (readonly: boolean) => {
|
|
1642
|
-
// we accumulate ops while being in read-only state.
|
|
1643
|
-
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
1644
|
-
// Note that the inner (non-proxy) delta manager is needed here to get the readonly information.
|
|
1645
|
-
assert(
|
|
1646
|
-
readonly === this.innerDeltaManager.readOnlyInfo.readonly,
|
|
1647
|
-
0x124 /* "inconsistent readonly property/event state" */,
|
|
1648
|
-
);
|
|
1649
|
-
|
|
1650
|
-
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
1651
|
-
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
1652
|
-
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
1653
|
-
// For loss of connection, we wait for our own "join" op and use it a a barrier to know all the
|
|
1654
|
-
// ops that made it from previous connection, before switching clientId and raising "connected" event
|
|
1655
|
-
// But with read-only permissions, if we transition between read-only and r/w states while on same
|
|
1656
|
-
// connection, then we have no good signal to tell us when it's safe to send ops we accumulated while
|
|
1657
|
-
// being in read-only state.
|
|
1658
|
-
// For that reason, we support getting to read-only state only when disconnected. This ensures that we
|
|
1659
|
-
// can rely on same safety mechanism and resend ops only when we establish new connection.
|
|
1660
|
-
// This is applicable for read-only permissions (event is raised before connection is properly registered),
|
|
1661
|
-
// but it's an extra requirement for Container.forceReadonly() API
|
|
1662
|
-
assert(
|
|
1663
|
-
!readonly || !this.connected,
|
|
1664
|
-
0x125 /* "Unsafe to transition to read-only state!" */,
|
|
1665
|
-
);
|
|
1666
|
-
|
|
1667
|
-
this.replayPendingStates();
|
|
1668
|
-
});
|
|
1669
|
-
|
|
1670
1599
|
// logging hardware telemetry
|
|
1671
1600
|
logger.sendTelemetryEvent({
|
|
1672
1601
|
eventName: "DeviceSpec",
|
|
@@ -1706,7 +1635,7 @@ export class ContainerRuntime
|
|
|
1706
1635
|
);
|
|
1707
1636
|
return this._summarizer;
|
|
1708
1637
|
}
|
|
1709
|
-
return
|
|
1638
|
+
return provideEntryPoint(this);
|
|
1710
1639
|
});
|
|
1711
1640
|
}
|
|
1712
1641
|
|
|
@@ -1817,16 +1746,19 @@ export class ContainerRuntime
|
|
|
1817
1746
|
/**
|
|
1818
1747
|
* {@inheritDoc @fluidframework/container-definitions#IRuntime.getEntryPoint}
|
|
1819
1748
|
*/
|
|
1820
|
-
public async getEntryPoint
|
|
1749
|
+
public async getEntryPoint(): Promise<FluidObject> {
|
|
1821
1750
|
return this.entryPoint;
|
|
1822
1751
|
}
|
|
1823
|
-
private readonly entryPoint: LazyPromise<FluidObject
|
|
1752
|
+
private readonly entryPoint: LazyPromise<FluidObject>;
|
|
1824
1753
|
|
|
1825
1754
|
private internalId(maybeAlias: string): string {
|
|
1826
1755
|
return this.dataStores.aliases.get(maybeAlias) ?? maybeAlias;
|
|
1827
1756
|
}
|
|
1828
1757
|
|
|
1829
|
-
private async getDataStoreFromRequest(
|
|
1758
|
+
private async getDataStoreFromRequest(
|
|
1759
|
+
id: string,
|
|
1760
|
+
request: IRequest,
|
|
1761
|
+
): Promise<IFluidDataStoreChannel> {
|
|
1830
1762
|
const headerData: RuntimeHeaderData = {};
|
|
1831
1763
|
if (typeof request.headers?.[RuntimeHeaders.wait] === "boolean") {
|
|
1832
1764
|
headerData.wait = request.headers[RuntimeHeaders.wait];
|
|
@@ -2015,28 +1947,28 @@ export class ContainerRuntime
|
|
|
2015
1947
|
* Parse an op's type and actual content from given serialized content
|
|
2016
1948
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
2017
1949
|
*/
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
2023
|
-
return
|
|
1950
|
+
// TODO: markfields: confirm Local- versus Outbound- ContainerRuntimeMessage typing
|
|
1951
|
+
private parseLocalOpContent(serializedContents?: string): LocalContainerRuntimeMessage {
|
|
1952
|
+
assert(serializedContents !== undefined, 0x6d5 /* content must be defined */);
|
|
1953
|
+
const message: LocalContainerRuntimeMessage = JSON.parse(serializedContents);
|
|
1954
|
+
assert(message.type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1955
|
+
return message;
|
|
2024
1956
|
}
|
|
2025
1957
|
|
|
2026
|
-
private async applyStashedOp(
|
|
1958
|
+
private async applyStashedOp(serializedOpContent: string): Promise<unknown> {
|
|
2027
1959
|
// Need to parse from string for back-compat
|
|
2028
|
-
const
|
|
2029
|
-
switch (type) {
|
|
1960
|
+
const opContents = this.parseLocalOpContent(serializedOpContent);
|
|
1961
|
+
switch (opContents.type) {
|
|
2030
1962
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2031
|
-
return this.dataStores.applyStashedOp(contents
|
|
1963
|
+
return this.dataStores.applyStashedOp(opContents.contents);
|
|
2032
1964
|
case ContainerMessageType.Attach:
|
|
2033
|
-
return this.dataStores.applyStashedAttachOp(contents
|
|
1965
|
+
return this.dataStores.applyStashedAttachOp(opContents.contents);
|
|
2034
1966
|
case ContainerMessageType.IdAllocation:
|
|
2035
1967
|
assert(
|
|
2036
1968
|
this.idCompressor !== undefined,
|
|
2037
1969
|
0x67b /* IdCompressor should be defined if enabled */,
|
|
2038
1970
|
);
|
|
2039
|
-
return this.applyStashedIdAllocationOp(contents
|
|
1971
|
+
return this.applyStashedIdAllocationOp(opContents.contents);
|
|
2040
1972
|
case ContainerMessageType.Alias:
|
|
2041
1973
|
case ContainerMessageType.BlobAttach:
|
|
2042
1974
|
return;
|
|
@@ -2048,15 +1980,15 @@ export class ContainerRuntime
|
|
|
2048
1980
|
// This should be extremely rare for stashed ops.
|
|
2049
1981
|
// It would require a newer runtime stashing ops and then an older one applying them,
|
|
2050
1982
|
// e.g. if an app rolled back its container version
|
|
2051
|
-
const compatBehavior = compatDetails?.behavior;
|
|
2052
|
-
if (!compatBehaviorAllowsMessageType(type, compatBehavior)) {
|
|
1983
|
+
const compatBehavior = opContents.compatDetails?.behavior;
|
|
1984
|
+
if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
|
|
2053
1985
|
const error = DataProcessingError.create(
|
|
2054
1986
|
"Stashed runtime message of unknown type",
|
|
2055
1987
|
"applyStashedOp",
|
|
2056
1988
|
undefined /* sequencedMessage */,
|
|
2057
1989
|
{
|
|
2058
1990
|
messageDetails: JSON.stringify({
|
|
2059
|
-
type,
|
|
1991
|
+
type: opContents.type,
|
|
2060
1992
|
compatBehavior,
|
|
2061
1993
|
}),
|
|
2062
1994
|
},
|
|
@@ -2078,6 +2010,30 @@ export class ContainerRuntime
|
|
|
2078
2010
|
return;
|
|
2079
2011
|
}
|
|
2080
2012
|
|
|
2013
|
+
// If there are stashed blobs in the pending state, we need to delay
|
|
2014
|
+
// propagation of the "connected" event until we have uploaded them to
|
|
2015
|
+
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
2016
|
+
const connecting = connected && !this._connected;
|
|
2017
|
+
if (connecting && this.blobManager.hasPendingStashedBlobs()) {
|
|
2018
|
+
assert(
|
|
2019
|
+
!this.delayConnectClientId,
|
|
2020
|
+
0x791 /* Connect event delay must be canceled before subsequent connect event */,
|
|
2021
|
+
);
|
|
2022
|
+
assert(!!clientId, 0x792 /* Must have clientId when connecting */);
|
|
2023
|
+
this.delayConnectClientId = clientId;
|
|
2024
|
+
this.blobManager.processStashedChanges().then(
|
|
2025
|
+
() => {
|
|
2026
|
+
// make sure we didn't reconnect before the promise resolved
|
|
2027
|
+
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
2028
|
+
this.delayConnectClientId = undefined;
|
|
2029
|
+
this.setConnectionStateCore(connected, clientId);
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
(error) => this.closeFn(error),
|
|
2033
|
+
);
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2081
2037
|
this.setConnectionStateCore(connected, clientId);
|
|
2082
2038
|
}
|
|
2083
2039
|
|
|
@@ -2156,9 +2112,25 @@ export class ContainerRuntime
|
|
|
2156
2112
|
const modernRuntimeMessage = messageArg.type === MessageType.Operation;
|
|
2157
2113
|
|
|
2158
2114
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
2115
|
+
// There might be multiple container instances receiving the same message.
|
|
2116
|
+
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
2117
|
+
// but will not modify the contents object (likely it will replace it on the message).
|
|
2159
2118
|
const messageCopy = { ...messageArg };
|
|
2160
2119
|
for (const message of this.remoteMessageProcessor.process(messageCopy)) {
|
|
2161
|
-
|
|
2120
|
+
if (modernRuntimeMessage) {
|
|
2121
|
+
this.processCore({
|
|
2122
|
+
// Cast it since we expect it to be this based on modernRuntimeMessage computation above.
|
|
2123
|
+
// There is nothing really ensuring that anytime original message.type is Operation that
|
|
2124
|
+
// the result messages will be so. In the end modern bool being true only directs to
|
|
2125
|
+
// throw error if ultimately unrecognized without compat details saying otherwise.
|
|
2126
|
+
message: message as InboundSequencedContainerRuntimeMessage,
|
|
2127
|
+
local,
|
|
2128
|
+
modernRuntimeMessage,
|
|
2129
|
+
});
|
|
2130
|
+
} else {
|
|
2131
|
+
// Unrecognized message will be ignored.
|
|
2132
|
+
this.processCore({ message, local, modernRuntimeMessage });
|
|
2133
|
+
}
|
|
2162
2134
|
}
|
|
2163
2135
|
}
|
|
2164
2136
|
|
|
@@ -2166,15 +2138,9 @@ export class ContainerRuntime
|
|
|
2166
2138
|
|
|
2167
2139
|
/**
|
|
2168
2140
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
*/
|
|
2173
|
-
private processCore(
|
|
2174
|
-
message: ISequencedDocumentMessage | SequencedContainerRuntimeMessage,
|
|
2175
|
-
local: boolean,
|
|
2176
|
-
modernRuntimeMessage: boolean,
|
|
2177
|
-
) {
|
|
2141
|
+
*/
|
|
2142
|
+
private processCore(messageWithContext: MessageWithContext) {
|
|
2143
|
+
const { message, local } = messageWithContext;
|
|
2178
2144
|
// Surround the actual processing of the operation with messages to the schedule manager indicating
|
|
2179
2145
|
// the beginning and end. This allows it to emit appropriate events and/or pause the processing of new
|
|
2180
2146
|
// messages once a batch has been fully processed.
|
|
@@ -2184,9 +2150,13 @@ export class ContainerRuntime
|
|
|
2184
2150
|
|
|
2185
2151
|
try {
|
|
2186
2152
|
let localOpMetadata: unknown;
|
|
2187
|
-
if (
|
|
2153
|
+
if (
|
|
2154
|
+
local &&
|
|
2155
|
+
messageWithContext.modernRuntimeMessage &&
|
|
2156
|
+
message.type !== ContainerMessageType.ChunkedOp
|
|
2157
|
+
) {
|
|
2188
2158
|
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2189
|
-
message
|
|
2159
|
+
messageWithContext.message,
|
|
2190
2160
|
);
|
|
2191
2161
|
}
|
|
2192
2162
|
|
|
@@ -2196,14 +2166,9 @@ export class ContainerRuntime
|
|
|
2196
2166
|
this.updateDocumentDirtyState(false);
|
|
2197
2167
|
}
|
|
2198
2168
|
|
|
2199
|
-
this.validateAndProcessRuntimeMessage(
|
|
2200
|
-
message,
|
|
2201
|
-
localOpMetadata,
|
|
2202
|
-
local,
|
|
2203
|
-
modernRuntimeMessage,
|
|
2204
|
-
);
|
|
2169
|
+
this.validateAndProcessRuntimeMessage(messageWithContext, localOpMetadata);
|
|
2205
2170
|
|
|
2206
|
-
this.emit("op", message, modernRuntimeMessage);
|
|
2171
|
+
this.emit("op", message, messageWithContext.modernRuntimeMessage);
|
|
2207
2172
|
|
|
2208
2173
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
2209
2174
|
|
|
@@ -2219,39 +2184,43 @@ export class ContainerRuntime
|
|
|
2219
2184
|
}
|
|
2220
2185
|
}
|
|
2221
2186
|
/**
|
|
2222
|
-
* Assuming the given message is also a
|
|
2187
|
+
* Assuming the given message is also a TypedContainerRuntimeMessage,
|
|
2223
2188
|
* checks its type and dispatches the message to the appropriate handler in the runtime.
|
|
2224
|
-
* Throws a DataProcessingError if the message doesn't conform to
|
|
2189
|
+
* Throws a DataProcessingError if the message looks like but doesn't conform to a known TypedContainerRuntimeMessage type.
|
|
2225
2190
|
*/
|
|
2226
2191
|
private validateAndProcessRuntimeMessage(
|
|
2227
|
-
|
|
2192
|
+
messageWithContext: MessageWithContext,
|
|
2228
2193
|
localOpMetadata: unknown,
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const { type: maybeContainerMessageType, compatDetails } =
|
|
2234
|
-
message as ContainerRuntimeMessage;
|
|
2235
|
-
|
|
2236
|
-
switch (maybeContainerMessageType) {
|
|
2194
|
+
): void {
|
|
2195
|
+
// TODO: destructure message and modernRuntimeMessage once using typescript 5.2.2+
|
|
2196
|
+
const { local } = messageWithContext;
|
|
2197
|
+
switch (messageWithContext.message.type) {
|
|
2237
2198
|
case ContainerMessageType.Attach:
|
|
2238
|
-
this.dataStores.processAttachMessage(message, local);
|
|
2199
|
+
this.dataStores.processAttachMessage(messageWithContext.message, local);
|
|
2239
2200
|
break;
|
|
2240
2201
|
case ContainerMessageType.Alias:
|
|
2241
|
-
this.dataStores.processAliasMessage(
|
|
2202
|
+
this.dataStores.processAliasMessage(
|
|
2203
|
+
messageWithContext.message,
|
|
2204
|
+
localOpMetadata,
|
|
2205
|
+
local,
|
|
2206
|
+
);
|
|
2242
2207
|
break;
|
|
2243
2208
|
case ContainerMessageType.FluidDataStoreOp:
|
|
2244
|
-
this.dataStores.processFluidDataStoreOp(
|
|
2209
|
+
this.dataStores.processFluidDataStoreOp(
|
|
2210
|
+
messageWithContext.message,
|
|
2211
|
+
local,
|
|
2212
|
+
localOpMetadata,
|
|
2213
|
+
);
|
|
2245
2214
|
break;
|
|
2246
2215
|
case ContainerMessageType.BlobAttach:
|
|
2247
|
-
this.blobManager.processBlobAttachOp(message, local);
|
|
2216
|
+
this.blobManager.processBlobAttachOp(messageWithContext.message, local);
|
|
2248
2217
|
break;
|
|
2249
2218
|
case ContainerMessageType.IdAllocation:
|
|
2250
2219
|
assert(
|
|
2251
2220
|
this.idCompressor !== undefined,
|
|
2252
2221
|
0x67c /* IdCompressor should be defined if enabled */,
|
|
2253
2222
|
);
|
|
2254
|
-
this.idCompressor.finalizeCreationRange(message.contents
|
|
2223
|
+
this.idCompressor.finalizeCreationRange(messageWithContext.message.contents);
|
|
2255
2224
|
break;
|
|
2256
2225
|
case ContainerMessageType.ChunkedOp:
|
|
2257
2226
|
case ContainerMessageType.Rejoin:
|
|
@@ -2259,12 +2228,18 @@ export class ContainerRuntime
|
|
|
2259
2228
|
default: {
|
|
2260
2229
|
// If we didn't necessarily expect a runtime message type, then no worries - just return
|
|
2261
2230
|
// e.g. this case applies to system ops, or legacy ops that would have fallen into the above cases anyway.
|
|
2262
|
-
if (!
|
|
2231
|
+
if (!messageWithContext.modernRuntimeMessage) {
|
|
2263
2232
|
return;
|
|
2264
2233
|
}
|
|
2265
2234
|
|
|
2266
|
-
const compatBehavior = compatDetails?.behavior;
|
|
2267
|
-
if (
|
|
2235
|
+
const compatBehavior = messageWithContext.message.compatDetails?.behavior;
|
|
2236
|
+
if (
|
|
2237
|
+
!compatBehaviorAllowsMessageType(
|
|
2238
|
+
messageWithContext.message.type,
|
|
2239
|
+
compatBehavior,
|
|
2240
|
+
)
|
|
2241
|
+
) {
|
|
2242
|
+
const { message } = messageWithContext;
|
|
2268
2243
|
const error = DataProcessingError.create(
|
|
2269
2244
|
// Former assert 0x3ce
|
|
2270
2245
|
"Runtime message of unknown type",
|
|
@@ -2356,6 +2331,7 @@ export class ContainerRuntime
|
|
|
2356
2331
|
* @param wait - True if you want to wait for it.
|
|
2357
2332
|
* @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
2358
2333
|
*/
|
|
2334
|
+
// eslint-disable-next-line import/no-deprecated
|
|
2359
2335
|
public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
|
|
2360
2336
|
return this.getRootDataStoreChannel(id, wait);
|
|
2361
2337
|
}
|
|
@@ -2434,8 +2410,8 @@ export class ContainerRuntime
|
|
|
2434
2410
|
/**
|
|
2435
2411
|
* Returns the aliased data store's entryPoint, given the alias.
|
|
2436
2412
|
* @param alias - The alias for the data store.
|
|
2437
|
-
* @returns
|
|
2438
|
-
* data store has been assigned the given alias.
|
|
2413
|
+
* @returns The data store's entry point ({@link @fluidframework/core-interfaces#IFluidHandle}) if it exists and is aliased.
|
|
2414
|
+
* Returns undefined if no data store has been assigned the given alias.
|
|
2439
2415
|
*/
|
|
2440
2416
|
public async getAliasedDataStoreEntryPoint(
|
|
2441
2417
|
alias: string,
|
|
@@ -2535,7 +2511,7 @@ export class ContainerRuntime
|
|
|
2535
2511
|
return this.dirtyContainer;
|
|
2536
2512
|
}
|
|
2537
2513
|
|
|
2538
|
-
private isContainerMessageDirtyable({ type, contents }:
|
|
2514
|
+
private isContainerMessageDirtyable({ type, contents }: OutboundContainerRuntimeMessage) {
|
|
2539
2515
|
// For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
|
|
2540
2516
|
// Ultimately we should have no special-cases from the ContainerRuntime's perspective.
|
|
2541
2517
|
if (type === ContainerMessageType.Attach) {
|
|
@@ -2544,7 +2520,7 @@ export class ContainerRuntime
|
|
|
2544
2520
|
return false;
|
|
2545
2521
|
}
|
|
2546
2522
|
} else if (type === ContainerMessageType.FluidDataStoreOp) {
|
|
2547
|
-
const envelope = contents
|
|
2523
|
+
const envelope = contents;
|
|
2548
2524
|
if (envelope.address === agentSchedulerId) {
|
|
2549
2525
|
return false;
|
|
2550
2526
|
}
|
|
@@ -2797,7 +2773,7 @@ export class ContainerRuntime
|
|
|
2797
2773
|
/**
|
|
2798
2774
|
* After GC has run and identified nodes that are sweep ready, this is called to delete the sweep ready nodes.
|
|
2799
2775
|
* @param sweepReadyRoutes - The routes of nodes that are sweep ready and should be deleted.
|
|
2800
|
-
* @returns
|
|
2776
|
+
* @returns The routes of nodes that were deleted.
|
|
2801
2777
|
*/
|
|
2802
2778
|
public deleteSweepReadyNodes(sweepReadyRoutes: string[]): string[] {
|
|
2803
2779
|
const { dataStoreRoutes, blobManagerRoutes } =
|
|
@@ -2868,7 +2844,7 @@ export class ContainerRuntime
|
|
|
2868
2844
|
/**
|
|
2869
2845
|
* From a given list of routes, separate and return routes that belong to blob manager and data stores.
|
|
2870
2846
|
* @param routes - A list of routes that can belong to data stores or blob manager.
|
|
2871
|
-
* @returns
|
|
2847
|
+
* @returns Two route lists - One that contains routes for blob manager and another one that contains routes
|
|
2872
2848
|
* for data stores.
|
|
2873
2849
|
*/
|
|
2874
2850
|
private getDataStoreAndBlobManagerRoutes(routes: string[]) {
|
|
@@ -2937,19 +2913,15 @@ export class ContainerRuntime
|
|
|
2937
2913
|
|
|
2938
2914
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
2939
2915
|
|
|
2916
|
+
// We close the summarizer and download a new snapshot and reload the container
|
|
2940
2917
|
let latestSnapshotVersionId: string | undefined;
|
|
2941
|
-
if (refreshLatestAck) {
|
|
2942
|
-
|
|
2918
|
+
if (refreshLatestAck === true) {
|
|
2919
|
+
return this.prefetchLatestSummaryThenClose(
|
|
2943
2920
|
createChildLogger({
|
|
2944
2921
|
logger: summaryNumberLogger,
|
|
2945
2922
|
properties: { all: { safeSummary: true } },
|
|
2946
2923
|
}),
|
|
2947
2924
|
);
|
|
2948
|
-
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
2949
|
-
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
2950
|
-
|
|
2951
|
-
// We might need to catch up to the latest summary's reference sequence number before pausing.
|
|
2952
|
-
await this.waitForDeltaManagerToCatchup(latestSnapshotRefSeq, summaryNumberLogger);
|
|
2953
2925
|
}
|
|
2954
2926
|
|
|
2955
2927
|
// If there are pending (unacked ops), the summary will not be eventual consistent and it may even be
|
|
@@ -3397,7 +3369,7 @@ export class ContainerRuntime
|
|
|
3397
3369
|
}
|
|
3398
3370
|
|
|
3399
3371
|
if (idRange !== undefined) {
|
|
3400
|
-
const idAllocationMessage:
|
|
3372
|
+
const idAllocationMessage: ContainerRuntimeIdAllocationMessage = {
|
|
3401
3373
|
type: ContainerMessageType.IdAllocation,
|
|
3402
3374
|
contents: idRange,
|
|
3403
3375
|
};
|
|
@@ -3417,7 +3389,7 @@ export class ContainerRuntime
|
|
|
3417
3389
|
}
|
|
3418
3390
|
|
|
3419
3391
|
private submit(
|
|
3420
|
-
containerRuntimeMessage:
|
|
3392
|
+
containerRuntimeMessage: OutboundContainerRuntimeMessage,
|
|
3421
3393
|
localOpMetadata: unknown = undefined,
|
|
3422
3394
|
metadata: Record<string, unknown> | undefined = undefined,
|
|
3423
3395
|
): void {
|
|
@@ -3613,39 +3585,36 @@ export class ContainerRuntime
|
|
|
3613
3585
|
|
|
3614
3586
|
private reSubmit(message: IPendingBatchMessage) {
|
|
3615
3587
|
// Need to parse from string for back-compat
|
|
3616
|
-
const containerRuntimeMessage = this.
|
|
3588
|
+
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
3617
3589
|
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
3618
3590
|
}
|
|
3619
3591
|
|
|
3620
3592
|
/**
|
|
3621
3593
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
3622
3594
|
* reconnect and there are pending messages.
|
|
3623
|
-
* @param message - The original
|
|
3595
|
+
* @param message - The original LocalContainerRuntimeMessage.
|
|
3624
3596
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
3625
3597
|
*/
|
|
3626
3598
|
private reSubmitCore(
|
|
3627
|
-
message:
|
|
3599
|
+
message: LocalContainerRuntimeMessage,
|
|
3628
3600
|
localOpMetadata: unknown,
|
|
3629
3601
|
opMetadata: Record<string, unknown> | undefined,
|
|
3630
3602
|
) {
|
|
3631
|
-
const contents = message.contents;
|
|
3632
3603
|
switch (message.type) {
|
|
3633
3604
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3634
3605
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3635
3606
|
// and trigger resubmission on it.
|
|
3636
|
-
this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
|
|
3607
|
+
this.dataStores.resubmitDataStoreOp(message.contents, localOpMetadata);
|
|
3637
3608
|
break;
|
|
3638
3609
|
case ContainerMessageType.Attach:
|
|
3639
3610
|
case ContainerMessageType.Alias:
|
|
3640
3611
|
this.submit(message, localOpMetadata);
|
|
3641
3612
|
break;
|
|
3642
|
-
case ContainerMessageType.IdAllocation:
|
|
3643
|
-
|
|
3644
|
-
if (contents.stashedState !== undefined) {
|
|
3645
|
-
delete contents.stashedState;
|
|
3646
|
-
}
|
|
3613
|
+
case ContainerMessageType.IdAllocation: {
|
|
3614
|
+
prepareLocalContainerRuntimeIdAllocationMessageForTransit(message);
|
|
3647
3615
|
this.submit(message, localOpMetadata);
|
|
3648
3616
|
break;
|
|
3617
|
+
}
|
|
3649
3618
|
case ContainerMessageType.ChunkedOp:
|
|
3650
3619
|
throw new Error(`chunkedOp not expected here`);
|
|
3651
3620
|
case ContainerMessageType.BlobAttach:
|
|
@@ -3684,12 +3653,12 @@ export class ContainerRuntime
|
|
|
3684
3653
|
|
|
3685
3654
|
private rollback(content: string | undefined, localOpMetadata: unknown) {
|
|
3686
3655
|
// Need to parse from string for back-compat
|
|
3687
|
-
const { type, contents } = this.
|
|
3656
|
+
const { type, contents } = this.parseLocalOpContent(content);
|
|
3688
3657
|
switch (type) {
|
|
3689
3658
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3690
3659
|
// For operations, call rollbackDataStoreOp which will find the right store
|
|
3691
3660
|
// and trigger rollback on it.
|
|
3692
|
-
this.dataStores.rollbackDataStoreOp(contents
|
|
3661
|
+
this.dataStores.rollbackDataStoreOp(contents, localOpMetadata);
|
|
3693
3662
|
break;
|
|
3694
3663
|
default:
|
|
3695
3664
|
// Don't check message.compatDetails because this is for rolling back a local op so the type will be known
|
|
@@ -3697,26 +3666,6 @@ export class ContainerRuntime
|
|
|
3697
3666
|
}
|
|
3698
3667
|
}
|
|
3699
3668
|
|
|
3700
|
-
private async waitForDeltaManagerToCatchup(
|
|
3701
|
-
latestSnapshotRefSeq: number,
|
|
3702
|
-
summaryLogger: ITelemetryLoggerExt,
|
|
3703
|
-
): Promise<void> {
|
|
3704
|
-
if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
|
|
3705
|
-
// We need to catch up to the latest summary's reference sequence number before proceeding.
|
|
3706
|
-
await PerformanceEvent.timedExecAsync(
|
|
3707
|
-
summaryLogger,
|
|
3708
|
-
{
|
|
3709
|
-
eventName: "WaitingForSeq",
|
|
3710
|
-
lastSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3711
|
-
targetSequenceNumber: latestSnapshotRefSeq,
|
|
3712
|
-
lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
|
|
3713
|
-
},
|
|
3714
|
-
async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq),
|
|
3715
|
-
{ start: true, end: true, cancel: "error" }, // definitely want start event
|
|
3716
|
-
);
|
|
3717
|
-
}
|
|
3718
|
-
}
|
|
3719
|
-
|
|
3720
3669
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
3721
3670
|
public async refreshLatestSummaryAck(options: IRefreshSummaryAckOptions) {
|
|
3722
3671
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
@@ -3780,16 +3729,19 @@ export class ContainerRuntime
|
|
|
3780
3729
|
}
|
|
3781
3730
|
|
|
3782
3731
|
/**
|
|
3783
|
-
* Fetches the latest snapshot from storage
|
|
3784
|
-
*
|
|
3732
|
+
* Fetches the latest snapshot from storage to refresh the cache as a performance optimization and closes the
|
|
3733
|
+
* summarizer to reload from new state.
|
|
3785
3734
|
* @param summaryLogger - logger to use when fetching snapshot from storage
|
|
3786
|
-
* @returns
|
|
3735
|
+
* @returns a generic summarization error
|
|
3787
3736
|
*/
|
|
3788
|
-
private async
|
|
3737
|
+
private async prefetchLatestSummaryThenClose(
|
|
3789
3738
|
summaryLogger: ITelemetryLoggerExt,
|
|
3790
|
-
): Promise<
|
|
3739
|
+
): Promise<IBaseSummarizeResult> {
|
|
3791
3740
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
3792
|
-
|
|
3741
|
+
|
|
3742
|
+
// This is a performance optimization as the same parent is likely to be elected again, and would use its
|
|
3743
|
+
// cache to fetch the snapshot instead of the network.
|
|
3744
|
+
await this.fetchSnapshotFromStorage(
|
|
3793
3745
|
summaryLogger,
|
|
3794
3746
|
{
|
|
3795
3747
|
eventName: "RefreshLatestSummaryFromServerFetch",
|
|
@@ -3800,7 +3752,12 @@ export class ContainerRuntime
|
|
|
3800
3752
|
|
|
3801
3753
|
await this.closeStaleSummarizer("RefreshLatestSummaryFromServerFetch");
|
|
3802
3754
|
|
|
3803
|
-
return {
|
|
3755
|
+
return {
|
|
3756
|
+
stage: "base",
|
|
3757
|
+
error: "summary state stale - Unsupported option 'refreshLatestAck'",
|
|
3758
|
+
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
3759
|
+
minimumSequenceNumber: this.deltaManager.minimumSequenceNumber,
|
|
3760
|
+
};
|
|
3804
3761
|
}
|
|
3805
3762
|
|
|
3806
3763
|
private async closeStaleSummarizer(codePath: string): Promise<void> {
|
|
@@ -3853,7 +3810,7 @@ export class ContainerRuntime
|
|
|
3853
3810
|
const versions = await this.storage.getVersions(
|
|
3854
3811
|
versionId,
|
|
3855
3812
|
1,
|
|
3856
|
-
"
|
|
3813
|
+
"prefetchLatestSummaryBeforeClose",
|
|
3857
3814
|
versionId === null ? FetchSource.noCache : undefined,
|
|
3858
3815
|
);
|
|
3859
3816
|
assert(
|
|
@@ -3896,17 +3853,17 @@ export class ContainerRuntime
|
|
|
3896
3853
|
if (this._orderSequentiallyCalls !== 0) {
|
|
3897
3854
|
throw new UsageError("can't get state during orderSequentially");
|
|
3898
3855
|
}
|
|
3899
|
-
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(
|
|
3900
|
-
waitBlobsToAttach,
|
|
3901
|
-
);
|
|
3902
|
-
const pending = this.pendingStateManager.getLocalState();
|
|
3903
|
-
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3904
|
-
return; // no pending state to save
|
|
3905
|
-
}
|
|
3906
3856
|
// Flush pending batch.
|
|
3907
3857
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3908
3858
|
// to close current batch.
|
|
3909
3859
|
this.flush();
|
|
3860
|
+
const pendingAttachmentBlobs = waitBlobsToAttach
|
|
3861
|
+
? await this.blobManager.attachAndGetPendingBlobs()
|
|
3862
|
+
: undefined;
|
|
3863
|
+
const pending = this.pendingStateManager.getLocalState();
|
|
3864
|
+
if (!pendingAttachmentBlobs && !this.hasPendingMessages()) {
|
|
3865
|
+
return; // no pending state to save
|
|
3866
|
+
}
|
|
3910
3867
|
|
|
3911
3868
|
const pendingState: IPendingRuntimeState = {
|
|
3912
3869
|
pending,
|
|
@@ -3951,6 +3908,7 @@ export class ContainerRuntime
|
|
|
3951
3908
|
* * Forms a function that will request a Summarizer.
|
|
3952
3909
|
* @param loaderRouter - the loader acting as an IFluidRouter
|
|
3953
3910
|
* */
|
|
3911
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3954
3912
|
private formRequestSummarizerFn(loaderRouter: IFluidRouter) {
|
|
3955
3913
|
return async () => {
|
|
3956
3914
|
const request: IRequest = {
|
|
@@ -3966,6 +3924,7 @@ export class ContainerRuntime
|
|
|
3966
3924
|
url: "/_summarizer",
|
|
3967
3925
|
};
|
|
3968
3926
|
|
|
3927
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3969
3928
|
const fluidObject = await requestFluidObject<FluidObject<ISummarizer>>(
|
|
3970
3929
|
loaderRouter,
|
|
3971
3930
|
request,
|
|
@@ -4003,30 +3962,3 @@ export class ContainerRuntime
|
|
|
4003
3962
|
return killSwitch !== true && this.runtimeOptions.enableGroupedBatching;
|
|
4004
3963
|
}
|
|
4005
3964
|
}
|
|
4006
|
-
|
|
4007
|
-
/**
|
|
4008
|
-
* Wait for a specific sequence number. Promise should resolve when we reach that number,
|
|
4009
|
-
* or reject if closed.
|
|
4010
|
-
*/
|
|
4011
|
-
const waitForSeq = async (
|
|
4012
|
-
deltaManager: IDeltaManager<Pick<ISequencedDocumentMessage, "sequenceNumber">, unknown>,
|
|
4013
|
-
targetSeq: number,
|
|
4014
|
-
): Promise<void> =>
|
|
4015
|
-
new Promise<void>((resolve, reject) => {
|
|
4016
|
-
// TODO: remove cast to any when actual event is determined
|
|
4017
|
-
deltaManager.on("closed" as any, reject);
|
|
4018
|
-
deltaManager.on("disposed" as any, reject);
|
|
4019
|
-
|
|
4020
|
-
// If we already reached target sequence number, simply resolve the promise.
|
|
4021
|
-
if (deltaManager.lastSequenceNumber >= targetSeq) {
|
|
4022
|
-
resolve();
|
|
4023
|
-
} else {
|
|
4024
|
-
const handleOp = (message: Pick<ISequencedDocumentMessage, "sequenceNumber">) => {
|
|
4025
|
-
if (message.sequenceNumber >= targetSeq) {
|
|
4026
|
-
resolve();
|
|
4027
|
-
deltaManager.off("op", handleOp);
|
|
4028
|
-
}
|
|
4029
|
-
};
|
|
4030
|
-
deltaManager.on("op", handleOp);
|
|
4031
|
-
}
|
|
4032
|
-
});
|