@fluidframework/container-runtime 2.0.0-internal.2.4.0 → 2.0.0-internal.3.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/dist/containerRuntime.d.ts +45 -42
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +87 -38
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -0
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +7 -2
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +0 -1
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +4 -13
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +130 -160
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/summarizerClientElection.d.ts +1 -2
- package/dist/summarizerClientElection.d.ts.map +1 -1
- package/dist/summarizerClientElection.js +3 -30
- package/dist/summarizerClientElection.js.map +1 -1
- package/dist/summarizerTypes.d.ts +0 -4
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/lib/containerRuntime.d.ts +45 -42
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +87 -38
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -0
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +7 -2
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +0 -1
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +4 -13
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +130 -160
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/summarizerClientElection.d.ts +1 -2
- package/lib/summarizerClientElection.d.ts.map +1 -1
- package/lib/summarizerClientElection.js +3 -30
- package/lib/summarizerClientElection.js.map +1 -1
- package/lib/summarizerTypes.d.ts +0 -4
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/package.json +34 -16
- package/src/containerRuntime.ts +116 -84
- package/src/dataStoreContext.ts +12 -6
- package/src/opLifecycle/outbox.ts +0 -2
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +146 -187
- package/src/summarizerClientElection.ts +1 -30
- package/src/summarizerTypes.ts +0 -4
package/lib/containerRuntime.js
CHANGED
|
@@ -55,7 +55,6 @@ export const DefaultSummaryConfiguration = {
|
|
|
55
55
|
maxAckWaitTime: 10 * 60 * 1000,
|
|
56
56
|
maxOpsSinceLastSummary: 7000,
|
|
57
57
|
initialSummarizerDelayMs: 5 * 1000,
|
|
58
|
-
summarizerClientElection: false,
|
|
59
58
|
nonRuntimeOpWeight: 0.1,
|
|
60
59
|
runtimeOpWeight: 1.0,
|
|
61
60
|
nonRuntimeHeuristicThreshold: 20,
|
|
@@ -164,6 +163,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
164
163
|
this.flushMicroTaskExists = false;
|
|
165
164
|
this.savedOps = [];
|
|
166
165
|
this.consecutiveReconnects = 0;
|
|
166
|
+
this.ensureNoDataModelChangesCalls = 0;
|
|
167
|
+
/**
|
|
168
|
+
* Tracks the number of detected reentrant ops to report,
|
|
169
|
+
* in order to self-throttle the telemetry events.
|
|
170
|
+
*
|
|
171
|
+
* This should be removed as part of ADO:2322
|
|
172
|
+
*/
|
|
173
|
+
this.opReentryCallsToReport = 5;
|
|
167
174
|
this._disposed = false;
|
|
168
175
|
this.emitDirtyDocumentEvent = true;
|
|
169
176
|
this.defaultTelemetrySignalSampleCount = 100;
|
|
@@ -236,7 +243,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
236
243
|
&& this.mc.config.getBoolean("Fluid.ContainerRuntime.DisableOpReentryCheck") !== true;
|
|
237
244
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
238
245
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
239
|
-
this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
|
|
240
246
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
241
247
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
242
248
|
this.maxConsecutiveReconnects =
|
|
@@ -302,7 +308,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
302
308
|
clientId: () => this.clientId,
|
|
303
309
|
close: this.closeFn,
|
|
304
310
|
connected: () => this.connected,
|
|
305
|
-
flush: this.flush.bind(this),
|
|
306
311
|
reSubmit: this.reSubmit.bind(this),
|
|
307
312
|
rollback: this.rollback.bind(this),
|
|
308
313
|
orderSequentially: this.orderSequentially.bind(this),
|
|
@@ -339,7 +344,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
339
344
|
const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
|
|
340
345
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
|
|
341
346
|
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
342
|
-
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary
|
|
347
|
+
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
343
348
|
if (this.context.clientDetails.type === summarizerClientType) {
|
|
344
349
|
this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
|
|
345
350
|
}
|
|
@@ -401,6 +406,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
401
406
|
get IContainerRuntime() { return this; }
|
|
402
407
|
get IFluidRouter() { return this; }
|
|
403
408
|
/**
|
|
409
|
+
* @deprecated - use loadRuntime instead.
|
|
404
410
|
* Load the stores from a snapshot and returns the runtime.
|
|
405
411
|
* @param context - Context of the container.
|
|
406
412
|
* @param registryEntries - Mapping to the stores.
|
|
@@ -411,7 +417,35 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
411
417
|
* allows mixin classes to leverage this method to define their own async initializer.
|
|
412
418
|
*/
|
|
413
419
|
static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing, containerRuntimeCtor = ContainerRuntime) {
|
|
420
|
+
let existingFlag = true;
|
|
421
|
+
if (!existing) {
|
|
422
|
+
existingFlag = false;
|
|
423
|
+
}
|
|
424
|
+
return this.loadRuntime({
|
|
425
|
+
context,
|
|
426
|
+
registryEntries,
|
|
427
|
+
existing: existingFlag,
|
|
428
|
+
requestHandler,
|
|
429
|
+
runtimeOptions,
|
|
430
|
+
containerScope,
|
|
431
|
+
containerRuntimeCtor,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Load the stores from a snapshot and returns the runtime.
|
|
436
|
+
* @param params - An object housing the runtime properties:
|
|
437
|
+
* - context - Context of the container.
|
|
438
|
+
* - registryEntries - Mapping to the stores.
|
|
439
|
+
* - existing - When loading from an existing snapshot
|
|
440
|
+
* - requestHandler - Request handlers for the container runtime
|
|
441
|
+
* - runtimeOptions - Additional options to be passed to the runtime
|
|
442
|
+
* - containerScope - runtime services provided with context
|
|
443
|
+
* - containerRuntimeCtor - Constructor to use to create the ContainerRuntime instance.
|
|
444
|
+
* This allows mixin classes to leverage this method to define their own async initializer.
|
|
445
|
+
*/
|
|
446
|
+
static async loadRuntime(params) {
|
|
414
447
|
var _a, _b, _c, _d;
|
|
448
|
+
const { context, registryEntries, existing, requestHandler, runtimeOptions = {}, containerScope = {}, containerRuntimeCtor = ContainerRuntime } = params;
|
|
415
449
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
416
450
|
// back-compat: Remove the TaggedLoggerAdapter fallback once all the host are using loader > 0.45
|
|
417
451
|
const backCompatContext = context;
|
|
@@ -542,6 +576,23 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
542
576
|
get IFluidHandleContext() {
|
|
543
577
|
return this.handleContext;
|
|
544
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* Invokes the given callback and expects that no ops are submitted
|
|
581
|
+
* until execution finishes. If an op is submitted, an error will be raised.
|
|
582
|
+
*
|
|
583
|
+
* Can be disabled by feature gate `Fluid.ContainerRuntime.DisableOpReentryCheck`
|
|
584
|
+
*
|
|
585
|
+
* @param callback - the callback to be invoked
|
|
586
|
+
*/
|
|
587
|
+
ensureNoDataModelChanges(callback) {
|
|
588
|
+
this.ensureNoDataModelChangesCalls++;
|
|
589
|
+
try {
|
|
590
|
+
return callback();
|
|
591
|
+
}
|
|
592
|
+
finally {
|
|
593
|
+
this.ensureNoDataModelChangesCalls--;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
545
596
|
get connected() {
|
|
546
597
|
return this._connected;
|
|
547
598
|
}
|
|
@@ -556,42 +607,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
556
607
|
return this._summarizer;
|
|
557
608
|
}
|
|
558
609
|
isSummariesDisabled() {
|
|
559
|
-
// back-compat: disableSummaries was moved from ISummaryRuntimeOptions
|
|
560
|
-
// to ISummaryConfiguration in 0.60.
|
|
561
|
-
if (this.runtimeOptions.summaryOptions.disableSummaries === true) {
|
|
562
|
-
return true;
|
|
563
|
-
}
|
|
564
610
|
return this.summaryConfiguration.state === "disabled";
|
|
565
611
|
}
|
|
566
612
|
isHeuristicsDisabled() {
|
|
567
|
-
var _a;
|
|
568
|
-
// back-compat: disableHeuristics was moved from ISummarizerOptions
|
|
569
|
-
// to ISummaryConfiguration in 0.60.
|
|
570
|
-
if (((_a = this.runtimeOptions.summaryOptions.summarizerOptions) === null || _a === void 0 ? void 0 : _a.disableHeuristics) === true) {
|
|
571
|
-
return true;
|
|
572
|
-
}
|
|
573
613
|
return this.summaryConfiguration.state === "disableHeuristics";
|
|
574
614
|
}
|
|
575
|
-
isSummarizerClientElectionEnabled() {
|
|
576
|
-
var _a;
|
|
577
|
-
if (this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) {
|
|
578
|
-
return (_a = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _a !== void 0 ? _a : true;
|
|
579
|
-
}
|
|
580
|
-
// back-compat: summarizerClientElection was moved from ISummaryRuntimeOptions
|
|
581
|
-
// to ISummaryConfiguration in 0.60.
|
|
582
|
-
if (this.runtimeOptions.summaryOptions.summarizerClientElection === true) {
|
|
583
|
-
return true;
|
|
584
|
-
}
|
|
585
|
-
return this.summaryConfiguration.state !== "disabled"
|
|
586
|
-
? this.summaryConfiguration.summarizerClientElection === true
|
|
587
|
-
: false;
|
|
588
|
-
}
|
|
589
615
|
getMaxOpsSinceLastSummary() {
|
|
590
|
-
// back-compat: maxOpsSinceLastSummary was moved from ISummaryRuntimeOptions
|
|
591
|
-
// to ISummaryConfiguration in 0.60.
|
|
592
|
-
if (this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary !== undefined) {
|
|
593
|
-
return this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary;
|
|
594
|
-
}
|
|
595
616
|
return this.summaryConfiguration.state !== "disabled"
|
|
596
617
|
? this.summaryConfiguration.maxOpsSinceLastSummary
|
|
597
618
|
: 0;
|
|
@@ -1092,7 +1113,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1092
1113
|
finally {
|
|
1093
1114
|
this._orderSequentiallyCalls--;
|
|
1094
1115
|
}
|
|
1095
|
-
|
|
1116
|
+
// We don't flush on TurnBased since we expect all messages in the same JS turn to be part of the same batch
|
|
1117
|
+
if (this.flushMode !== FlushMode.TurnBased && this._orderSequentiallyCalls === 0) {
|
|
1096
1118
|
this.flush();
|
|
1097
1119
|
}
|
|
1098
1120
|
return result;
|
|
@@ -1616,6 +1638,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1616
1638
|
}
|
|
1617
1639
|
submit(type, contents, localOpMetadata = undefined, metadata = undefined) {
|
|
1618
1640
|
this.verifyNotClosed();
|
|
1641
|
+
this.verifyCanSubmitOps();
|
|
1619
1642
|
// There should be no ops in detached container state!
|
|
1620
1643
|
assert(this.attachState !== AttachState.Detached, 0x132 /* "sending ops in detached container" */);
|
|
1621
1644
|
const deserializedContent = { type, contents };
|
|
@@ -1697,6 +1720,32 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1697
1720
|
throw new Error("Runtime is closed");
|
|
1698
1721
|
}
|
|
1699
1722
|
}
|
|
1723
|
+
verifyCanSubmitOps() {
|
|
1724
|
+
if (this.ensureNoDataModelChangesCalls > 0) {
|
|
1725
|
+
const errorMessage = "Op was submitted from within a `ensureNoDataModelChanges` callback";
|
|
1726
|
+
if (this.opReentryCallsToReport > 0) {
|
|
1727
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "OpReentry" },
|
|
1728
|
+
// We need to capture the call stack in order to inspect the source of this usage pattern
|
|
1729
|
+
new UsageError(errorMessage));
|
|
1730
|
+
this.opReentryCallsToReport--;
|
|
1731
|
+
}
|
|
1732
|
+
// Creating ops while processing ops can lead
|
|
1733
|
+
// to undefined behavior and events observed in the wrong order.
|
|
1734
|
+
// For example, we have two callbacks registered for a DDS, A and B.
|
|
1735
|
+
// Then if on change #1 callback A creates change #2, the invocation flow will be:
|
|
1736
|
+
//
|
|
1737
|
+
// A because of #1
|
|
1738
|
+
// A because of #2
|
|
1739
|
+
// B because of #2
|
|
1740
|
+
// B because of #1
|
|
1741
|
+
//
|
|
1742
|
+
// The runtime must enforce op coherence by not allowing ops to be submitted
|
|
1743
|
+
// while ops are being processed.
|
|
1744
|
+
if (this.enableOpReentryCheck) {
|
|
1745
|
+
throw new UsageError(errorMessage);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1700
1749
|
/**
|
|
1701
1750
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
1702
1751
|
* reconnect and there are pending messages.
|
|
@@ -1849,13 +1898,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1849
1898
|
if (!((_a = this.mc.config.getBoolean("enableOfflineLoad")) !== null && _a !== void 0 ? _a : this.runtimeOptions.enableOfflineLoad)) {
|
|
1850
1899
|
throw new UsageError("can't get state when offline load disabled");
|
|
1851
1900
|
}
|
|
1901
|
+
if (this._orderSequentiallyCalls !== 0) {
|
|
1902
|
+
throw new UsageError("can't get state during orderSequentially");
|
|
1903
|
+
}
|
|
1852
1904
|
// Flush pending batch.
|
|
1853
1905
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
1854
1906
|
// to close current batch.
|
|
1855
1907
|
this.flush();
|
|
1856
|
-
if (this._orderSequentiallyCalls !== 0) {
|
|
1857
|
-
throw new UsageError("can't get state during orderSequentially");
|
|
1858
|
-
}
|
|
1859
1908
|
const previousPendingState = this.context.pendingLocalState;
|
|
1860
1909
|
if (previousPendingState) {
|
|
1861
1910
|
return {
|