@fluidframework/container-runtime 2.33.0-333010 → 2.33.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 +4 -0
- package/api-report/container-runtime.legacy.alpha.api.md +71 -67
- package/container-runtime.test-files.tar +0 -0
- package/dist/blobManager/blobManager.d.ts +7 -4
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +38 -12
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/channelCollection.d.ts +4 -0
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +24 -0
- package/dist/channelCollection.js.map +1 -1
- package/dist/compatUtils.d.ts +74 -0
- package/dist/compatUtils.d.ts.map +1 -0
- package/dist/compatUtils.js +151 -0
- package/dist/compatUtils.js.map +1 -0
- package/dist/compressionDefinitions.d.ts +39 -0
- package/dist/compressionDefinitions.d.ts.map +1 -0
- package/dist/compressionDefinitions.js +30 -0
- package/dist/compressionDefinitions.js.map +1 -0
- package/dist/containerRuntime.d.ts +78 -52
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +141 -54
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +3 -0
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +122 -66
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/deltaManagerProxies.d.ts +55 -12
- package/dist/deltaManagerProxies.d.ts.map +1 -1
- package/dist/deltaManagerProxies.js +63 -55
- package/dist/deltaManagerProxies.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +2 -0
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +1 -0
- package/dist/opLifecycle/batchManager.d.ts +1 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +4 -1
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +35 -4
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.js +2 -2
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +3 -3
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts +2 -2
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +1 -2
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSerialization.d.ts +3 -1
- package/dist/opLifecycle/opSerialization.d.ts.map +1 -1
- package/dist/opLifecycle/opSerialization.js +4 -2
- package/dist/opLifecycle/opSerialization.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +6 -3
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +46 -20
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +36 -7
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +83 -16
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runtimeLayerCompatState.d.ts.map +1 -1
- package/dist/runtimeLayerCompatState.js +1 -1
- package/dist/runtimeLayerCompatState.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +1 -0
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +2 -0
- package/dist/summary/documentSchema.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts +7 -4
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +38 -12
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/channelCollection.d.ts +4 -0
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +24 -0
- package/lib/channelCollection.js.map +1 -1
- package/lib/compatUtils.d.ts +74 -0
- package/lib/compatUtils.d.ts.map +1 -0
- package/lib/compatUtils.js +142 -0
- package/lib/compatUtils.js.map +1 -0
- package/lib/compressionDefinitions.d.ts +39 -0
- package/lib/compressionDefinitions.d.ts.map +1 -0
- package/lib/compressionDefinitions.js +27 -0
- package/lib/compressionDefinitions.js.map +1 -0
- package/lib/containerRuntime.d.ts +78 -52
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +143 -56
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +3 -0
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +57 -1
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/deltaManagerProxies.d.ts +55 -12
- package/lib/deltaManagerProxies.d.ts.map +1 -1
- package/lib/deltaManagerProxies.js +63 -55
- package/lib/deltaManagerProxies.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +2 -0
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +1 -0
- package/lib/opLifecycle/batchManager.d.ts +1 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +4 -1
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +35 -4
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.js +1 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +1 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts +2 -2
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +1 -2
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSerialization.d.ts +3 -1
- package/lib/opLifecycle/opSerialization.d.ts.map +1 -1
- package/lib/opLifecycle/opSerialization.js +4 -2
- package/lib/opLifecycle/opSerialization.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +6 -3
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +46 -20
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +36 -7
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +84 -17
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runtimeLayerCompatState.d.ts.map +1 -1
- package/lib/runtimeLayerCompatState.js +2 -2
- package/lib/runtimeLayerCompatState.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +1 -0
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +2 -0
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +21 -20
- package/src/blobManager/blobManager.ts +48 -15
- package/src/channelCollection.ts +27 -0
- package/src/compatUtils.ts +211 -0
- package/src/compressionDefinitions.ts +47 -0
- package/src/containerRuntime.ts +259 -108
- package/src/dataStoreContext.ts +82 -2
- package/src/deltaManagerProxies.ts +132 -70
- package/src/gc/gcDefinitions.ts +2 -0
- package/src/index.ts +5 -3
- package/src/opLifecycle/batchManager.ts +5 -4
- package/src/opLifecycle/definitions.ts +34 -4
- package/src/opLifecycle/index.ts +1 -0
- package/src/opLifecycle/opCompressor.ts +1 -1
- package/src/opLifecycle/opDecompressor.ts +1 -1
- package/src/opLifecycle/opGroupingManager.ts +7 -5
- package/src/opLifecycle/opSerialization.ts +6 -2
- package/src/opLifecycle/outbox.ts +65 -30
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +135 -21
- package/src/runtimeLayerCompatState.ts +5 -2
- package/src/summary/documentSchema.ts +3 -0
package/src/containerRuntime.ts
CHANGED
|
@@ -90,6 +90,11 @@ import type {
|
|
|
90
90
|
IInboundSignalMessage,
|
|
91
91
|
IRuntimeMessagesContent,
|
|
92
92
|
ISummarizerNodeWithGC,
|
|
93
|
+
// eslint-disable-next-line import/no-deprecated
|
|
94
|
+
StageControlsExperimental,
|
|
95
|
+
// eslint-disable-next-line import/no-deprecated
|
|
96
|
+
IContainerRuntimeBaseExperimental,
|
|
97
|
+
IFluidParentContext,
|
|
93
98
|
} from "@fluidframework/runtime-definitions/internal";
|
|
94
99
|
import {
|
|
95
100
|
FlushMode,
|
|
@@ -100,6 +105,7 @@ import {
|
|
|
100
105
|
import {
|
|
101
106
|
GCDataBuilder,
|
|
102
107
|
RequestParser,
|
|
108
|
+
RuntimeHeaders,
|
|
103
109
|
TelemetryContext,
|
|
104
110
|
addBlobToSummary,
|
|
105
111
|
addSummarizeResultToSummary,
|
|
@@ -151,11 +157,20 @@ import {
|
|
|
151
157
|
getSummaryForDatastores,
|
|
152
158
|
wrapContext,
|
|
153
159
|
} from "./channelCollection.js";
|
|
160
|
+
import {
|
|
161
|
+
defaultCompatibilityVersion,
|
|
162
|
+
getCompatibilityVersionDefaults,
|
|
163
|
+
isValidCompatVersion,
|
|
164
|
+
type RuntimeOptionsAffectingDocSchema,
|
|
165
|
+
} from "./compatUtils.js";
|
|
166
|
+
import type { ICompressionRuntimeOptions } from "./compressionDefinitions.js";
|
|
167
|
+
import { CompressionAlgorithms, disabledCompressionConfig } from "./compressionDefinitions.js";
|
|
154
168
|
import { ReportOpPerfTelemetry } from "./connectionTelemetry.js";
|
|
155
169
|
import { ContainerFluidHandleContext } from "./containerHandleContext.js";
|
|
156
170
|
import { channelToDataStore } from "./dataStore.js";
|
|
157
171
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry.js";
|
|
158
172
|
import {
|
|
173
|
+
BaseDeltaManagerProxy,
|
|
159
174
|
DeltaManagerPendingOpsProxy,
|
|
160
175
|
DeltaManagerSummarizerProxy,
|
|
161
176
|
} from "./deltaManagerProxies.js";
|
|
@@ -168,6 +183,7 @@ import {
|
|
|
168
183
|
IGarbageCollector,
|
|
169
184
|
gcGenerationOptionName,
|
|
170
185
|
type GarbageCollectionMessage,
|
|
186
|
+
type IGarbageCollectionRuntime,
|
|
171
187
|
} from "./gc/index.js";
|
|
172
188
|
import { InboundBatchAggregator } from "./inboundBatchAggregator.js";
|
|
173
189
|
import {
|
|
@@ -193,7 +209,6 @@ import {
|
|
|
193
209
|
OpSplitter,
|
|
194
210
|
Outbox,
|
|
195
211
|
RemoteMessageProcessor,
|
|
196
|
-
serializeOp,
|
|
197
212
|
type OutboundBatch,
|
|
198
213
|
} from "./opLifecycle/index.js";
|
|
199
214
|
import { pkgVersion } from "./packageVersion.js";
|
|
@@ -247,7 +262,6 @@ import {
|
|
|
247
262
|
idCompressorBlobName,
|
|
248
263
|
metadataBlobName,
|
|
249
264
|
rootHasIsolatedChannels,
|
|
250
|
-
summarizerClientType,
|
|
251
265
|
wrapSummaryInChannelsTree,
|
|
252
266
|
formCreateSummarizerFn,
|
|
253
267
|
summarizerRequestUrl,
|
|
@@ -259,6 +273,7 @@ import {
|
|
|
259
273
|
ISummaryConfiguration,
|
|
260
274
|
DefaultSummaryConfiguration,
|
|
261
275
|
isSummariesDisabled,
|
|
276
|
+
summarizerClientType,
|
|
262
277
|
} from "./summary/index.js";
|
|
263
278
|
import { Throttler, formExponentialFn } from "./throttler.js";
|
|
264
279
|
|
|
@@ -311,32 +326,27 @@ export interface ISummaryRuntimeOptions {
|
|
|
311
326
|
}
|
|
312
327
|
|
|
313
328
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* @
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
readonly compressionAlgorithm: CompressionAlgorithms;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Options for container runtime.
|
|
329
|
+
* Full set of options for container runtime as "required".
|
|
330
|
+
*
|
|
331
|
+
* @remarks
|
|
332
|
+
* {@link IContainerRuntimeOptions} is expected to be used by consumers.
|
|
333
|
+
*
|
|
334
|
+
* @privateRemarks If any new properties are added to this interface (or
|
|
335
|
+
* {@link IContainerRuntimeOptionsInternal}), then we will also need to make
|
|
336
|
+
* changes in {@link file://./compatUtils.ts}.
|
|
337
|
+
* If the new property does not change the DocumentSchema, then it must be
|
|
338
|
+
* explicity omitted from {@link RuntimeOptionsAffectingDocSchema}.
|
|
339
|
+
* If it does change the DocumentSchema, then a corresponding entry must be
|
|
340
|
+
* added to `runtimeOptionsAffectingDocSchemaConfigMap` with the appropriate
|
|
341
|
+
* compat configuration info.
|
|
342
|
+
* If neither of the above is done, then the build will fail to compile.
|
|
343
|
+
*
|
|
334
344
|
* @legacy
|
|
335
345
|
* @alpha
|
|
336
346
|
*/
|
|
337
|
-
export interface
|
|
338
|
-
readonly summaryOptions
|
|
339
|
-
readonly gcOptions
|
|
347
|
+
export interface ContainerRuntimeOptions {
|
|
348
|
+
readonly summaryOptions: ISummaryRuntimeOptions;
|
|
349
|
+
readonly gcOptions: IGCRuntimeOptions;
|
|
340
350
|
/**
|
|
341
351
|
* Affects the behavior while loading the runtime when the data verification check which
|
|
342
352
|
* compares the DeltaManager sequence number (obtained from protocol in summary) to the
|
|
@@ -345,12 +355,12 @@ export interface IContainerRuntimeOptions {
|
|
|
345
355
|
* 2. "log" will log an error event to telemetry, but still continue to load.
|
|
346
356
|
* 3. "bypass" will skip the check entirely. This is not recommended.
|
|
347
357
|
*/
|
|
348
|
-
readonly loadSequenceNumberVerification
|
|
358
|
+
readonly loadSequenceNumberVerification: "close" | "log" | "bypass";
|
|
349
359
|
|
|
350
360
|
/**
|
|
351
361
|
* Enables the runtime to compress ops. See {@link ICompressionRuntimeOptions}.
|
|
352
362
|
*/
|
|
353
|
-
readonly compressionOptions
|
|
363
|
+
readonly compressionOptions: ICompressionRuntimeOptions;
|
|
354
364
|
/**
|
|
355
365
|
* If specified, when in FlushMode.TurnBased, if the size of the ops between JS turns exceeds this value,
|
|
356
366
|
* an error will be thrown and the container will close.
|
|
@@ -361,27 +371,27 @@ export interface IContainerRuntimeOptions {
|
|
|
361
371
|
*
|
|
362
372
|
* @experimental This config should be driven by the connection with the service and will be moved in the future.
|
|
363
373
|
*/
|
|
364
|
-
readonly maxBatchSizeInBytes
|
|
374
|
+
readonly maxBatchSizeInBytes: number;
|
|
365
375
|
/**
|
|
366
376
|
* If the op payload needs to be chunked in order to work around the maximum size of the batch, this value represents
|
|
367
377
|
* how large the individual chunks will be. This is only supported when compression is enabled. If after compression, the
|
|
368
378
|
* batch content size exceeds this value, it will be chunked into smaller ops of this exact size.
|
|
369
379
|
*
|
|
370
380
|
* This value is a trade-off between having many small chunks vs fewer larger chunks and by default, the runtime is configured to use
|
|
371
|
-
* 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link
|
|
381
|
+
* 200 * 1024 = 204800 bytes. This default value ensures that no compressed payload's content is able to exceed {@link ContainerRuntimeOptions.maxBatchSizeInBytes}
|
|
372
382
|
* regardless of the overhead of an individual op.
|
|
373
383
|
*
|
|
374
|
-
* Any value of `chunkSizeInBytes` exceeding {@link
|
|
375
|
-
* size exceeds {@link
|
|
384
|
+
* Any value of `chunkSizeInBytes` exceeding {@link ContainerRuntimeOptions.maxBatchSizeInBytes} will disable this feature, therefore if a compressed batch's content
|
|
385
|
+
* size exceeds {@link ContainerRuntimeOptions.maxBatchSizeInBytes} after compression, the container will close with an instance of `DataProcessingError` with
|
|
376
386
|
* the `BatchTooLarge` message.
|
|
377
387
|
*/
|
|
378
|
-
readonly chunkSizeInBytes
|
|
388
|
+
readonly chunkSizeInBytes: number;
|
|
379
389
|
|
|
380
390
|
/**
|
|
381
391
|
* Enable the IdCompressor in the runtime.
|
|
382
392
|
* @experimental Not ready for use.
|
|
383
393
|
*/
|
|
384
|
-
readonly enableRuntimeIdCompressor
|
|
394
|
+
readonly enableRuntimeIdCompressor: IdCompressorMode;
|
|
385
395
|
|
|
386
396
|
/**
|
|
387
397
|
* If enabled, the runtime will group messages within a batch into a single
|
|
@@ -391,7 +401,7 @@ export interface IContainerRuntimeOptions {
|
|
|
391
401
|
* By default, the feature is enabled. This feature can only be disabled when compression is also disabled.
|
|
392
402
|
* @deprecated The ability to disable Grouped Batching is deprecated and will be removed in a future release. This feature is required for the proper functioning of the Fluid Framework.
|
|
393
403
|
*/
|
|
394
|
-
readonly enableGroupedBatching
|
|
404
|
+
readonly enableGroupedBatching: boolean;
|
|
395
405
|
|
|
396
406
|
/**
|
|
397
407
|
* When this property is set to true, it requires runtime to control is document schema properly through ops
|
|
@@ -400,34 +410,60 @@ export interface IContainerRuntimeOptions {
|
|
|
400
410
|
* When this property is not set (or set to false), runtime operates in legacy mode, where new features (modifying document schema)
|
|
401
411
|
* are engaged as they become available, without giving legacy clients any chance to fail predictably.
|
|
402
412
|
*/
|
|
403
|
-
readonly explicitSchemaControl
|
|
413
|
+
readonly explicitSchemaControl: boolean;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Create blob handles with pending payloads when calling createBlob (default is `undefined` (disabled)).
|
|
417
|
+
* When enabled (`true`), createBlob will return a handle before the blob upload completes.
|
|
418
|
+
*/
|
|
419
|
+
readonly createBlobPayloadPending: true | undefined;
|
|
404
420
|
}
|
|
405
421
|
|
|
406
422
|
/**
|
|
407
|
-
*
|
|
423
|
+
* Options for container runtime.
|
|
424
|
+
*
|
|
425
|
+
* @legacy
|
|
426
|
+
* @alpha
|
|
427
|
+
*/
|
|
428
|
+
export type IContainerRuntimeOptions = Partial<ContainerRuntimeOptions>;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Internal extension of {@link ContainerRuntimeOptions}
|
|
408
432
|
*
|
|
433
|
+
* @privateRemarks
|
|
409
434
|
* These options are not available to consumers when creating a new container runtime,
|
|
410
435
|
* but we do need to expose them for internal use, e.g. when configuring the container runtime
|
|
411
436
|
* to ensure compatibility with older versions.
|
|
412
437
|
*
|
|
438
|
+
* This is defined as a fully required set of options as this package does not yet
|
|
439
|
+
* use `exactOptionalPropertyTypes` and `Required<>` applied to optional type allowing
|
|
440
|
+
* `undefined` like {@link IdCompressorMode} will exclude `undefined`.
|
|
441
|
+
*
|
|
413
442
|
* @internal
|
|
414
443
|
*/
|
|
415
|
-
export interface
|
|
444
|
+
export interface ContainerRuntimeOptionsInternal extends ContainerRuntimeOptions {
|
|
416
445
|
/**
|
|
417
446
|
* Sets the flush mode for the runtime. In Immediate flush mode the runtime will immediately
|
|
418
447
|
* send all operations to the driver layer, while in TurnBased the operations will be buffered
|
|
419
448
|
* and then sent them as a single batch at the end of the turn.
|
|
420
449
|
* By default, flush mode is TurnBased.
|
|
421
450
|
*/
|
|
422
|
-
readonly flushMode
|
|
451
|
+
readonly flushMode: FlushMode;
|
|
423
452
|
|
|
424
453
|
/**
|
|
425
454
|
* Allows Grouped Batching to be disabled by setting to false (default is true).
|
|
426
455
|
* In that case, batched messages will be sent individually (but still all at the same time).
|
|
427
456
|
*/
|
|
428
|
-
readonly enableGroupedBatching
|
|
457
|
+
readonly enableGroupedBatching: boolean;
|
|
429
458
|
}
|
|
430
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Internal extension of {@link IContainerRuntimeOptions}
|
|
462
|
+
*
|
|
463
|
+
* @internal
|
|
464
|
+
*/
|
|
465
|
+
export type IContainerRuntimeOptionsInternal = Partial<ContainerRuntimeOptionsInternal>;
|
|
466
|
+
|
|
431
467
|
/**
|
|
432
468
|
* Error responses when requesting a deleted object will have this header set to true
|
|
433
469
|
* @internal
|
|
@@ -468,24 +504,6 @@ export const defaultRuntimeHeaderData: Required<RuntimeHeaderData> = {
|
|
|
468
504
|
allowTombstone: false,
|
|
469
505
|
};
|
|
470
506
|
|
|
471
|
-
/**
|
|
472
|
-
* Available compression algorithms for op compression.
|
|
473
|
-
* @legacy
|
|
474
|
-
* @alpha
|
|
475
|
-
*/
|
|
476
|
-
export enum CompressionAlgorithms {
|
|
477
|
-
lz4 = "lz4",
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* @legacy
|
|
482
|
-
* @alpha
|
|
483
|
-
*/
|
|
484
|
-
export const disabledCompressionConfig: ICompressionRuntimeOptions = {
|
|
485
|
-
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
|
|
486
|
-
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
487
|
-
};
|
|
488
|
-
|
|
489
507
|
/**
|
|
490
508
|
* @deprecated
|
|
491
509
|
* Untagged logger is unsupported going forward. There are old loaders with old ContainerContexts that only
|
|
@@ -524,20 +542,12 @@ export interface IPendingRuntimeState {
|
|
|
524
542
|
|
|
525
543
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
526
544
|
|
|
527
|
-
const defaultFlushMode = FlushMode.TurnBased;
|
|
528
|
-
|
|
529
545
|
// The actual limit is 1Mb (socket.io and Kafka limits)
|
|
530
546
|
// We can't estimate it fully, as we
|
|
531
547
|
// - do not know what properties relay service will add
|
|
532
548
|
// - we do not stringify final op, thus we do not know how much escaping will be added.
|
|
533
549
|
const defaultMaxBatchSizeInBytes = 700 * 1024;
|
|
534
550
|
|
|
535
|
-
const defaultCompressionConfig = {
|
|
536
|
-
// Batches with content size exceeding this value will be compressed
|
|
537
|
-
minimumBatchSizeInBytes: 614400,
|
|
538
|
-
compressionAlgorithm: CompressionAlgorithms.lz4,
|
|
539
|
-
};
|
|
540
|
-
|
|
541
551
|
const defaultChunkSizeInBytes = 204800;
|
|
542
552
|
|
|
543
553
|
/**
|
|
@@ -718,9 +728,13 @@ export class ContainerRuntime
|
|
|
718
728
|
extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
719
729
|
implements
|
|
720
730
|
IContainerRuntime,
|
|
731
|
+
// eslint-disable-next-line import/no-deprecated
|
|
732
|
+
IContainerRuntimeBaseExperimental,
|
|
721
733
|
IRuntime,
|
|
734
|
+
IGarbageCollectionRuntime,
|
|
722
735
|
ISummarizerRuntime,
|
|
723
736
|
ISummarizerInternalsProvider,
|
|
737
|
+
IFluidParentContext,
|
|
724
738
|
IProvideFluidHandleContext,
|
|
725
739
|
IProvideLayerCompatDetails
|
|
726
740
|
{
|
|
@@ -781,21 +795,63 @@ export class ContainerRuntime
|
|
|
781
795
|
|
|
782
796
|
const mc = loggerToMonitoringContext(logger);
|
|
783
797
|
|
|
798
|
+
// Some options require a minimum version of the FF runtime to operate, so the default configs will be generated
|
|
799
|
+
// based on the compatibility mode.
|
|
800
|
+
// For example, if compatibility mode is set to "1.0.0", the default configs will ensure compatibility with FF runtime
|
|
801
|
+
// 1.0.0 or later. If the compatibility mode is set to "2.10.0", the default values will be generated to ensure compatibility
|
|
802
|
+
// with FF runtime 2.10.0 or later.
|
|
803
|
+
// TODO: We will add in a way for users to pass in compatibilityVersion in a follow up PR.
|
|
804
|
+
const compatibilityVersion = defaultCompatibilityVersion;
|
|
805
|
+
if (!isValidCompatVersion(compatibilityVersion)) {
|
|
806
|
+
throw new UsageError(
|
|
807
|
+
`Invalid compatibility version: ${compatibilityVersion}. It must be an existing FF version (i.e. 2.22.1).`,
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
const defaultVersionDependentConfigs =
|
|
811
|
+
getCompatibilityVersionDefaults(compatibilityVersion);
|
|
812
|
+
|
|
813
|
+
// The following are the default values for the options that do not affect the DocumentSchema.
|
|
814
|
+
const defaultConfigsNonVersionDependent: Required<
|
|
815
|
+
Omit<IContainerRuntimeOptionsInternal, keyof RuntimeOptionsAffectingDocSchema>
|
|
816
|
+
> = {
|
|
817
|
+
summaryOptions: {},
|
|
818
|
+
loadSequenceNumberVerification: "close",
|
|
819
|
+
maxBatchSizeInBytes: defaultMaxBatchSizeInBytes,
|
|
820
|
+
chunkSizeInBytes: defaultChunkSizeInBytes,
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const defaultConfigs = {
|
|
824
|
+
...defaultVersionDependentConfigs,
|
|
825
|
+
...defaultConfigsNonVersionDependent,
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
// Here we set each option to its corresponding default config value if it's not provided in runtimeOptions.
|
|
829
|
+
// Note: We cannot do a simple object merge of defaultConfigs/runtimeOptions because in most cases we don't want
|
|
830
|
+
// a option that is undefined in runtimeOptions to override the default value (except for idCompressor, see below).
|
|
784
831
|
const {
|
|
785
|
-
summaryOptions =
|
|
786
|
-
gcOptions =
|
|
787
|
-
loadSequenceNumberVerification =
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
832
|
+
summaryOptions = defaultConfigs.summaryOptions,
|
|
833
|
+
gcOptions = defaultConfigs.gcOptions,
|
|
834
|
+
loadSequenceNumberVerification = defaultConfigs.loadSequenceNumberVerification,
|
|
835
|
+
maxBatchSizeInBytes = defaultConfigs.maxBatchSizeInBytes,
|
|
836
|
+
chunkSizeInBytes = defaultConfigs.chunkSizeInBytes,
|
|
837
|
+
explicitSchemaControl = defaultConfigs.explicitSchemaControl,
|
|
838
|
+
enableGroupedBatching = defaultConfigs.enableGroupedBatching,
|
|
839
|
+
flushMode = defaultConfigs.flushMode,
|
|
840
|
+
// If batching is disabled then we should disable compression as well. If batching is disabled and compression
|
|
841
|
+
// is enabled via runtimeOptions, we will throw an error later.
|
|
842
|
+
compressionOptions = enableGroupedBatching === false
|
|
843
|
+
? disabledCompressionConfig
|
|
844
|
+
: defaultConfigs.compressionOptions,
|
|
845
|
+
createBlobPayloadPending = defaultConfigs.createBlobPayloadPending,
|
|
797
846
|
}: IContainerRuntimeOptionsInternal = runtimeOptions;
|
|
798
847
|
|
|
848
|
+
// The logic for enableRuntimeIdCompressor is a bit different. Since `undefined` represents a logical state (off)
|
|
849
|
+
// we need to check it's explicitly set in runtimeOptions. If so, we should use that value even if it's undefined.
|
|
850
|
+
const enableRuntimeIdCompressor =
|
|
851
|
+
"enableRuntimeIdCompressor" in runtimeOptions
|
|
852
|
+
? runtimeOptions.enableRuntimeIdCompressor
|
|
853
|
+
: defaultConfigs.enableRuntimeIdCompressor;
|
|
854
|
+
|
|
799
855
|
const registry = new FluidDataStoreRegistry(registryEntries);
|
|
800
856
|
|
|
801
857
|
const tryFetchBlob = async <T>(blobName: string): Promise<T | undefined> => {
|
|
@@ -970,6 +1026,7 @@ export class ContainerRuntime
|
|
|
970
1026
|
compressionLz4,
|
|
971
1027
|
idCompressorMode,
|
|
972
1028
|
opGroupingEnabled: enableGroupedBatching,
|
|
1029
|
+
createBlobPayloadPending,
|
|
973
1030
|
disallowedVersions: [],
|
|
974
1031
|
},
|
|
975
1032
|
(schema) => {
|
|
@@ -984,7 +1041,7 @@ export class ContainerRuntime
|
|
|
984
1041
|
const featureGatesForTelemetry: Record<string, boolean | number | undefined> = {};
|
|
985
1042
|
|
|
986
1043
|
// Make sure we've got all the options including internal ones
|
|
987
|
-
const internalRuntimeOptions: Readonly<
|
|
1044
|
+
const internalRuntimeOptions: Readonly<ContainerRuntimeOptionsInternal> = {
|
|
988
1045
|
summaryOptions,
|
|
989
1046
|
gcOptions,
|
|
990
1047
|
loadSequenceNumberVerification,
|
|
@@ -992,10 +1049,10 @@ export class ContainerRuntime
|
|
|
992
1049
|
compressionOptions,
|
|
993
1050
|
maxBatchSizeInBytes,
|
|
994
1051
|
chunkSizeInBytes,
|
|
995
|
-
|
|
996
|
-
enableRuntimeIdCompressor: enableRuntimeIdCompressor as "on" | "delayed",
|
|
1052
|
+
enableRuntimeIdCompressor,
|
|
997
1053
|
enableGroupedBatching,
|
|
998
1054
|
explicitSchemaControl,
|
|
1055
|
+
createBlobPayloadPending,
|
|
999
1056
|
};
|
|
1000
1057
|
|
|
1001
1058
|
const runtime = new containerRuntimeCtor(
|
|
@@ -1087,6 +1144,8 @@ export class ContainerRuntime
|
|
|
1087
1144
|
return this._getAttachState();
|
|
1088
1145
|
}
|
|
1089
1146
|
|
|
1147
|
+
public readonly isReadOnly = (): boolean => this.deltaManager.readOnlyInfo.readonly === true;
|
|
1148
|
+
|
|
1090
1149
|
/**
|
|
1091
1150
|
* Current session schema - defines what options are on & off.
|
|
1092
1151
|
* It's overlap of document schema (controlled by summary & ops) and options controlling this session.
|
|
@@ -1158,7 +1217,7 @@ export class ContainerRuntime
|
|
|
1158
1217
|
return this._deltaManager;
|
|
1159
1218
|
}
|
|
1160
1219
|
|
|
1161
|
-
private readonly _deltaManager:
|
|
1220
|
+
private readonly _deltaManager: BaseDeltaManagerProxy;
|
|
1162
1221
|
|
|
1163
1222
|
/**
|
|
1164
1223
|
* The delta manager provided by the container context. By default, using the default delta manager (proxy)
|
|
@@ -1334,7 +1393,7 @@ export class ContainerRuntime
|
|
|
1334
1393
|
private readonly electedSummarizerData: ISerializedElection | undefined,
|
|
1335
1394
|
chunks: [string, string[]][],
|
|
1336
1395
|
dataStoreAliasMap: [string, string][],
|
|
1337
|
-
private readonly runtimeOptions: Readonly<
|
|
1396
|
+
private readonly runtimeOptions: Readonly<ContainerRuntimeOptionsInternal>,
|
|
1338
1397
|
private readonly containerScope: FluidObject,
|
|
1339
1398
|
// Create a custom ITelemetryBaseLogger to output telemetry events.
|
|
1340
1399
|
public readonly baseLogger: ITelemetryBaseLogger,
|
|
@@ -1537,26 +1596,27 @@ export class ContainerRuntime
|
|
|
1537
1596
|
this.baseLogger,
|
|
1538
1597
|
);
|
|
1539
1598
|
|
|
1540
|
-
let outerDeltaManager: IDeltaManagerFull;
|
|
1599
|
+
let outerDeltaManager: IDeltaManagerFull = this.innerDeltaManager;
|
|
1541
1600
|
this.useDeltaManagerOpsProxy =
|
|
1542
1601
|
this.mc.config.getBoolean("Fluid.ContainerRuntime.DeltaManagerOpsProxy") === true;
|
|
1543
1602
|
// The summarizerDeltaManager Proxy is used to lie to the summarizer to convince it is in the right state as a summarizer client.
|
|
1544
|
-
|
|
1545
|
-
this.innerDeltaManager,
|
|
1546
|
-
);
|
|
1547
|
-
outerDeltaManager = summarizerDeltaManagerProxy;
|
|
1603
|
+
outerDeltaManager = DeltaManagerSummarizerProxy.wrapIfSummarizer(outerDeltaManager);
|
|
1548
1604
|
|
|
1549
1605
|
// The DeltaManagerPendingOpsProxy is used to control the minimum sequence number
|
|
1550
1606
|
// It allows us to lie to the layers below so that they can maintain enough local state for rebasing ops.
|
|
1551
1607
|
if (this.useDeltaManagerOpsProxy) {
|
|
1552
1608
|
const pendingOpsDeltaManagerProxy = new DeltaManagerPendingOpsProxy(
|
|
1553
|
-
|
|
1609
|
+
outerDeltaManager,
|
|
1554
1610
|
this.pendingStateManager,
|
|
1555
1611
|
);
|
|
1556
1612
|
outerDeltaManager = pendingOpsDeltaManagerProxy;
|
|
1557
1613
|
}
|
|
1558
1614
|
|
|
1559
|
-
|
|
1615
|
+
// always wrap the exposed delta manager in at least on layer of proxying
|
|
1616
|
+
this._deltaManager =
|
|
1617
|
+
outerDeltaManager instanceof BaseDeltaManagerProxy
|
|
1618
|
+
? outerDeltaManager
|
|
1619
|
+
: new BaseDeltaManagerProxy(outerDeltaManager);
|
|
1560
1620
|
|
|
1561
1621
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
1562
1622
|
|
|
@@ -1704,6 +1764,7 @@ export class ContainerRuntime
|
|
|
1704
1764
|
new Map<string, string>(dataStoreAliasMap),
|
|
1705
1765
|
async (runtime: ChannelCollection) => provideEntryPoint,
|
|
1706
1766
|
);
|
|
1767
|
+
this._deltaManager.on("readonly", this.notifyReadOnlyState);
|
|
1707
1768
|
|
|
1708
1769
|
this.blobManager = new BlobManager({
|
|
1709
1770
|
routeContext: this.handleContext,
|
|
@@ -1730,6 +1791,7 @@ export class ContainerRuntime
|
|
|
1730
1791
|
isBlobDeleted: (blobPath: string) => this.garbageCollector.isNodeDeleted(blobPath),
|
|
1731
1792
|
runtime: this,
|
|
1732
1793
|
stashedBlobs: pendingRuntimeState?.pendingAttachmentBlobs,
|
|
1794
|
+
createBlobPayloadPending: this.sessionSchema.createBlobPayloadPending === true,
|
|
1733
1795
|
});
|
|
1734
1796
|
|
|
1735
1797
|
this.deltaScheduler = new DeltaScheduler(
|
|
@@ -2093,6 +2155,7 @@ export class ContainerRuntime
|
|
|
2093
2155
|
this.pendingStateManager.dispose();
|
|
2094
2156
|
this.inboundBatchAggregator.dispose();
|
|
2095
2157
|
this.deltaScheduler.dispose();
|
|
2158
|
+
this._deltaManager.dispose();
|
|
2096
2159
|
this.emit("dispose");
|
|
2097
2160
|
this.removeAllListeners();
|
|
2098
2161
|
}
|
|
@@ -2275,7 +2338,16 @@ export class ContainerRuntime
|
|
|
2275
2338
|
}
|
|
2276
2339
|
|
|
2277
2340
|
if (id === blobManagerBasePath && requestParser.isLeaf(2)) {
|
|
2278
|
-
const
|
|
2341
|
+
const localId = requestParser.pathParts[1];
|
|
2342
|
+
const payloadPending = requestParser.headers?.[RuntimeHeaders.payloadPending] === true;
|
|
2343
|
+
if (
|
|
2344
|
+
!this.blobManager.hasBlob(localId) &&
|
|
2345
|
+
requestParser.headers?.[RuntimeHeaders.wait] === false
|
|
2346
|
+
) {
|
|
2347
|
+
return create404Response(request);
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
const blob = await this.blobManager.getBlob(localId, payloadPending);
|
|
2279
2351
|
return {
|
|
2280
2352
|
status: 200,
|
|
2281
2353
|
mimeType: "fluid/object",
|
|
@@ -2545,6 +2617,9 @@ export class ContainerRuntime
|
|
|
2545
2617
|
return this._loadIdCompressor;
|
|
2546
2618
|
}
|
|
2547
2619
|
|
|
2620
|
+
private readonly notifyReadOnlyState = (readonly: boolean): void =>
|
|
2621
|
+
this.channelCollection.notifyReadOnlyState(readonly);
|
|
2622
|
+
|
|
2548
2623
|
public setConnectionState(connected: boolean, clientId?: string): void {
|
|
2549
2624
|
// Validate we have consistent state
|
|
2550
2625
|
const currentClientId = this._audience.getSelf()?.clientId;
|
|
@@ -3121,15 +3196,17 @@ export class ContainerRuntime
|
|
|
3121
3196
|
*
|
|
3122
3197
|
* @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch
|
|
3123
3198
|
* with the given Batch ID, which must be preserved
|
|
3199
|
+
* @param resubmittingStagedBatch - If defined, indicates this is a resubmission of a batch that is staged,
|
|
3200
|
+
* meaning it should not be sent to the ordering service yet.
|
|
3124
3201
|
*/
|
|
3125
|
-
private flush(resubmittingBatchId?: BatchId): void {
|
|
3202
|
+
private flush(resubmittingBatchId?: BatchId, resubmittingStagedBatch?: boolean): void {
|
|
3126
3203
|
try {
|
|
3127
3204
|
assert(
|
|
3128
3205
|
!this.batchRunner.running,
|
|
3129
3206
|
0x24c /* "Cannot call `flush()` while manually accumulating a batch (e.g. under orderSequentially) */,
|
|
3130
3207
|
);
|
|
3131
3208
|
|
|
3132
|
-
this.outbox.flush(resubmittingBatchId);
|
|
3209
|
+
this.outbox.flush(resubmittingBatchId, resubmittingStagedBatch);
|
|
3133
3210
|
assert(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
3134
3211
|
} catch (error) {
|
|
3135
3212
|
const error2 = normalizeError(error, {
|
|
@@ -3148,7 +3225,12 @@ export class ContainerRuntime
|
|
|
3148
3225
|
public orderSequentially<T>(callback: () => T): T {
|
|
3149
3226
|
let checkpoint: IBatchCheckpoint | undefined;
|
|
3150
3227
|
const checkpointDirtyState = this.dirtyContainer;
|
|
3228
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3229
|
+
let stageControls: StageControlsExperimental | undefined;
|
|
3151
3230
|
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.EnableRollback")) {
|
|
3231
|
+
if (!this.batchRunner.running && !this.inStagingMode) {
|
|
3232
|
+
stageControls = this.enterStagingMode();
|
|
3233
|
+
}
|
|
3152
3234
|
// Note: we are not touching any batches other than mainBatch here, for two reasons:
|
|
3153
3235
|
// 1. It would not help, as other batches are flushed independently from main batch.
|
|
3154
3236
|
// 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
|
|
@@ -3162,12 +3244,14 @@ export class ContainerRuntime
|
|
|
3162
3244
|
// This will throw and close the container if rollback fails
|
|
3163
3245
|
try {
|
|
3164
3246
|
checkpoint.rollback((message: LocalBatchMessage) =>
|
|
3165
|
-
this.rollback(message.
|
|
3247
|
+
this.rollback(message.runtimeOp, message.localOpMetadata),
|
|
3166
3248
|
);
|
|
3167
3249
|
// reset the dirty state after rollback to what it was before to keep it consistent
|
|
3168
3250
|
if (this.dirtyContainer !== checkpointDirtyState) {
|
|
3169
3251
|
this.updateDocumentDirtyState(checkpointDirtyState);
|
|
3170
3252
|
}
|
|
3253
|
+
stageControls?.discardChanges();
|
|
3254
|
+
stageControls = undefined;
|
|
3171
3255
|
} catch (error_) {
|
|
3172
3256
|
const error2 = wrapError(error_, (message) => {
|
|
3173
3257
|
return DataProcessingError.create(
|
|
@@ -3198,6 +3282,7 @@ export class ContainerRuntime
|
|
|
3198
3282
|
throw error; // throw the original error for the consumer of the runtime
|
|
3199
3283
|
}
|
|
3200
3284
|
});
|
|
3285
|
+
stageControls?.commitChanges();
|
|
3201
3286
|
|
|
3202
3287
|
// We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
|
|
3203
3288
|
if (this.flushMode !== FlushMode.TurnBased && !this.batchRunner.running) {
|
|
@@ -3206,6 +3291,70 @@ export class ContainerRuntime
|
|
|
3206
3291
|
return result;
|
|
3207
3292
|
}
|
|
3208
3293
|
|
|
3294
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3295
|
+
private stageControls: StageControlsExperimental | undefined;
|
|
3296
|
+
|
|
3297
|
+
/**
|
|
3298
|
+
* If true, the ContainerRuntime is not submitting any new ops to the ordering service.
|
|
3299
|
+
* Ops submitted to the ContainerRuntime while in Staging Mode will be queued in the PendingStateManager,
|
|
3300
|
+
* either to be discarded or committed later (via the Stage Controls returned from enterStagingMode).
|
|
3301
|
+
*/
|
|
3302
|
+
public get inStagingMode(): boolean {
|
|
3303
|
+
return this.stageControls !== undefined;
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
/**
|
|
3307
|
+
* Enter Staging Mode, such that ops submitted to the ContainerRuntime will not be sent to the ordering service.
|
|
3308
|
+
* To exit Staging Mode, call either discardChanges or commitChanges on the Stage Controls returned from this method.
|
|
3309
|
+
*
|
|
3310
|
+
* @returns StageControlsExperimental - Controls for exiting Staging Mode.
|
|
3311
|
+
*/
|
|
3312
|
+
// eslint-disable-next-line import/no-deprecated
|
|
3313
|
+
public enterStagingMode = (): StageControlsExperimental => {
|
|
3314
|
+
if (this.stageControls !== undefined) {
|
|
3315
|
+
throw new Error("already in staging mode");
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
// Make sure all BatchManagers are empty before entering staging mode,
|
|
3319
|
+
// since we mark whole batches as "staged" or not to indicate whether to submit them.
|
|
3320
|
+
this.outbox.flush();
|
|
3321
|
+
const exitStagingMode = (discardOrCommit: () => void) => (): void => {
|
|
3322
|
+
// Final flush of any last staged changes
|
|
3323
|
+
this.outbox.flush(undefined, true /* staged */);
|
|
3324
|
+
|
|
3325
|
+
this.stageControls = undefined;
|
|
3326
|
+
|
|
3327
|
+
discardOrCommit();
|
|
3328
|
+
};
|
|
3329
|
+
|
|
3330
|
+
const stageControls = {
|
|
3331
|
+
discardChanges: exitStagingMode(() => {
|
|
3332
|
+
// Pop all staged batches from the PSM and roll them back in LIFO order
|
|
3333
|
+
this.pendingStateManager.popStagedBatches(({ runtimeOp, localOpMetadata }) => {
|
|
3334
|
+
assert(
|
|
3335
|
+
runtimeOp !== undefined,
|
|
3336
|
+
0xb82 /* Staged batches expected to have runtimeOp defined */,
|
|
3337
|
+
);
|
|
3338
|
+
this.rollback(runtimeOp, localOpMetadata);
|
|
3339
|
+
});
|
|
3340
|
+
if (this.attachState === AttachState.Attached) {
|
|
3341
|
+
this.updateDocumentDirtyState(this.pendingMessagesCount !== 0);
|
|
3342
|
+
}
|
|
3343
|
+
}),
|
|
3344
|
+
commitChanges: exitStagingMode(() => {
|
|
3345
|
+
// All staged changes are in the PSM, so just replay them (ignore pre-staging batches)
|
|
3346
|
+
// FUTURE: Have this do squash-rebase instead of resubmitting all intermediate changes
|
|
3347
|
+
if (this.connected) {
|
|
3348
|
+
this.pendingStateManager.replayPendingStates(true /* onlyStagedBatched */);
|
|
3349
|
+
} else {
|
|
3350
|
+
this.pendingStateManager.clearStagingFlags();
|
|
3351
|
+
}
|
|
3352
|
+
}),
|
|
3353
|
+
};
|
|
3354
|
+
|
|
3355
|
+
return (this.stageControls = stageControls);
|
|
3356
|
+
};
|
|
3357
|
+
|
|
3209
3358
|
/**
|
|
3210
3359
|
* Returns the aliased data store's entryPoint, given the alias.
|
|
3211
3360
|
* @param alias - The alias for the data store.
|
|
@@ -4214,8 +4363,11 @@ export class ContainerRuntime
|
|
|
4214
4363
|
contents: idRange,
|
|
4215
4364
|
};
|
|
4216
4365
|
const idAllocationBatchMessage: LocalBatchMessage = {
|
|
4217
|
-
|
|
4366
|
+
runtimeOp: idAllocationMessage,
|
|
4218
4367
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
4368
|
+
// Note: For now, we will never stage ID Allocation messages.
|
|
4369
|
+
// They won't contain personal info and no harm in extra allocations in case of discarding the staged changes
|
|
4370
|
+
staged: false,
|
|
4219
4371
|
};
|
|
4220
4372
|
this.outbox.submitIdAllocation(idAllocationBatchMessage);
|
|
4221
4373
|
}
|
|
@@ -4277,18 +4429,20 @@ export class ContainerRuntime
|
|
|
4277
4429
|
contents: schemaChangeMessage,
|
|
4278
4430
|
};
|
|
4279
4431
|
this.outbox.submit({
|
|
4280
|
-
|
|
4432
|
+
runtimeOp: msg,
|
|
4281
4433
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
4434
|
+
staged: this.inStagingMode,
|
|
4282
4435
|
});
|
|
4283
4436
|
}
|
|
4284
4437
|
|
|
4285
4438
|
const message: LocalBatchMessage = {
|
|
4286
4439
|
// This will encode any handles present in this op before serializing to string
|
|
4287
4440
|
// Note: handles may already have been encoded by the DDS layer, but encoding handles is idempotent so there's no problem.
|
|
4288
|
-
|
|
4441
|
+
runtimeOp: containerRuntimeMessage,
|
|
4289
4442
|
metadata,
|
|
4290
4443
|
localOpMetadata,
|
|
4291
4444
|
referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
4445
|
+
staged: this.inStagingMode,
|
|
4292
4446
|
};
|
|
4293
4447
|
if (type === ContainerMessageType.BlobAttach) {
|
|
4294
4448
|
// BlobAttach ops must have their metadata visible and cannot be grouped (see opGroupingManager.ts)
|
|
@@ -4391,7 +4545,11 @@ export class ContainerRuntime
|
|
|
4391
4545
|
* @remarks - If the "Offline Load" feature is enabled, the batchId is included in the resubmitted messages,
|
|
4392
4546
|
* for correlation to detect container forking.
|
|
4393
4547
|
*/
|
|
4394
|
-
private reSubmitBatch(
|
|
4548
|
+
private reSubmitBatch(
|
|
4549
|
+
batch: PendingMessageResubmitData[],
|
|
4550
|
+
batchId: BatchId,
|
|
4551
|
+
staged: boolean,
|
|
4552
|
+
): void {
|
|
4395
4553
|
this.batchRunner.run(() => {
|
|
4396
4554
|
for (const message of batch) {
|
|
4397
4555
|
this.reSubmit(message);
|
|
@@ -4400,15 +4558,11 @@ export class ContainerRuntime
|
|
|
4400
4558
|
|
|
4401
4559
|
// Only include Batch ID if "Offline Load" feature is enabled
|
|
4402
4560
|
// It's only needed to identify batches across container forks arising from misuse of offline load.
|
|
4403
|
-
this.flush(this.offlineEnabled ? batchId : undefined);
|
|
4561
|
+
this.flush(this.offlineEnabled ? batchId : undefined, staged);
|
|
4404
4562
|
}
|
|
4405
4563
|
|
|
4406
4564
|
private reSubmit(message: PendingMessageResubmitData): void {
|
|
4407
|
-
|
|
4408
|
-
// Note that roundtripping handles through string like this means this parsed contents
|
|
4409
|
-
// contains RemoteFluidObjectHandles, not the original handle.
|
|
4410
|
-
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
4411
|
-
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
4565
|
+
this.reSubmitCore(message.runtimeOp, message.localOpMetadata, message.opMetadata);
|
|
4412
4566
|
}
|
|
4413
4567
|
|
|
4414
4568
|
/**
|
|
@@ -4472,11 +4626,8 @@ export class ContainerRuntime
|
|
|
4472
4626
|
}
|
|
4473
4627
|
}
|
|
4474
4628
|
|
|
4475
|
-
private rollback(
|
|
4476
|
-
|
|
4477
|
-
// Note that roundtripping handles through string like this means this parsed contents
|
|
4478
|
-
// contains RemoteFluidObjectHandles, not the original handle.
|
|
4479
|
-
const { type, contents } = this.parseLocalOpContent(content);
|
|
4629
|
+
private rollback(runtimeOp: LocalContainerRuntimeMessage, localOpMetadata: unknown): void {
|
|
4630
|
+
const { type, contents } = runtimeOp;
|
|
4480
4631
|
switch (type) {
|
|
4481
4632
|
case ContainerMessageType.FluidDataStoreOp: {
|
|
4482
4633
|
// For operations, call rollbackDataStoreOp which will find the right store
|