@fluidframework/container-runtime 1.2.1 → 2.0.0-internal.1.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/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +81 -25
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +301 -100
- package/dist/blobManager.js.map +1 -1
- package/dist/containerRuntime.d.ts +66 -49
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +129 -164
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +29 -24
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +3 -4
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +16 -23
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +6 -3
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +13 -5
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +17 -12
- package/dist/garbageCollection.js.map +1 -1
- package/dist/opProperties.d.ts +7 -0
- package/dist/opProperties.d.ts.map +1 -0
- package/dist/opProperties.js +20 -0
- package/dist/opProperties.js.map +1 -0
- 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/runningSummarizer.d.ts +28 -4
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +93 -26
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summarizer.d.ts +0 -2
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +34 -15
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerHeuristics.d.ts +26 -4
- package/dist/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summarizerHeuristics.js +95 -18
- package/dist/summarizerHeuristics.js.map +1 -1
- package/dist/summarizerTypes.d.ts +30 -10
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryCollection.js +1 -1
- package/dist/summaryCollection.js.map +1 -1
- package/dist/summaryFormat.d.ts +0 -5
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts +1 -0
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +11 -9
- package/dist/summaryGenerator.js.map +1 -1
- package/lib/batchTracker.js +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +81 -25
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +302 -101
- package/lib/blobManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +66 -49
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +131 -166
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +29 -24
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +3 -4
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +17 -24
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +6 -3
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +13 -5
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +17 -12
- package/lib/garbageCollection.js.map +1 -1
- package/lib/opProperties.d.ts +7 -0
- package/lib/opProperties.d.ts.map +1 -0
- package/lib/opProperties.js +16 -0
- package/lib/opProperties.js.map +1 -0
- 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/runningSummarizer.d.ts +28 -4
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +93 -26
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summarizer.d.ts +0 -2
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +36 -17
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerHeuristics.d.ts +26 -4
- package/lib/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summarizerHeuristics.js +95 -18
- package/lib/summarizerHeuristics.js.map +1 -1
- package/lib/summarizerTypes.d.ts +30 -10
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryCollection.js +1 -1
- package/lib/summaryCollection.js.map +1 -1
- package/lib/summaryFormat.d.ts +0 -5
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts +1 -0
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +11 -9
- package/lib/summaryGenerator.js.map +1 -1
- package/package.json +55 -21
- package/src/batchTracker.ts +1 -1
- package/src/blobManager.ts +364 -119
- package/src/containerRuntime.ts +232 -216
- package/src/dataStore.ts +49 -37
- package/src/dataStoreContext.ts +16 -23
- package/src/dataStores.ts +27 -16
- package/src/garbageCollection.ts +13 -7
- package/src/opProperties.ts +19 -0
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +108 -23
- package/src/summarizer.ts +47 -28
- package/src/summarizerHeuristics.ts +133 -19
- package/src/summarizerTypes.ts +37 -10
- package/src/summaryCollection.ts +1 -1
- package/src/summaryFormat.ts +0 -6
- package/src/summaryGenerator.ts +40 -22
- package/dist/opTelemetry.d.ts +0 -22
- package/dist/opTelemetry.d.ts.map +0 -1
- package/dist/opTelemetry.js +0 -59
- package/dist/opTelemetry.js.map +0 -1
- package/lib/opTelemetry.d.ts +0 -22
- package/lib/opTelemetry.d.ts.map +0 -1
- package/lib/opTelemetry.js +0 -55
- package/lib/opTelemetry.js.map +0 -1
- package/src/opTelemetry.ts +0 -71
package/lib/containerRuntime.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
2
2
|
import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
|
|
3
|
-
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext,
|
|
4
|
-
import { DriverHeader } from "@fluidframework/driver-definitions";
|
|
3
|
+
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, TaggedLoggerAdapter, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
|
|
4
|
+
import { DriverHeader, FetchSource, } from "@fluidframework/driver-definitions";
|
|
5
5
|
import { readAndParse, isUnpackedRuntimeMessage } from "@fluidframework/driver-utils";
|
|
6
6
|
import { DataCorruptionError, DataProcessingError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
|
|
7
7
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
@@ -29,7 +29,6 @@ import { GarbageCollector, GCNodeType, gcTreeKey, } from "./garbageCollection";
|
|
|
29
29
|
import { channelToDataStore, isDataStoreAliasMessage, } from "./dataStore";
|
|
30
30
|
import { BindBatchTracker } from "./batchTracker";
|
|
31
31
|
import { SerializedSnapshotStorage } from "./serializedSnapshotStorage";
|
|
32
|
-
import { OpTracker } from "./opTelemetry";
|
|
33
32
|
export var ContainerMessageType;
|
|
34
33
|
(function (ContainerMessageType) {
|
|
35
34
|
// An op to be delivered to store
|
|
@@ -47,14 +46,18 @@ export var ContainerMessageType;
|
|
|
47
46
|
})(ContainerMessageType || (ContainerMessageType = {}));
|
|
48
47
|
export const DefaultSummaryConfiguration = {
|
|
49
48
|
state: "enabled",
|
|
50
|
-
idleTime:
|
|
51
|
-
|
|
49
|
+
idleTime: 15 * 1000,
|
|
50
|
+
minIdleTime: 0,
|
|
51
|
+
maxIdleTime: 30 * 1000,
|
|
52
|
+
maxTime: 60 * 1000,
|
|
52
53
|
maxOps: 100,
|
|
53
54
|
minOpsForLastSummaryAttempt: 10,
|
|
54
|
-
maxAckWaitTime:
|
|
55
|
+
maxAckWaitTime: 10 * 60 * 1000,
|
|
55
56
|
maxOpsSinceLastSummary: 7000,
|
|
56
|
-
initialSummarizerDelayMs:
|
|
57
|
+
initialSummarizerDelayMs: 5 * 1000,
|
|
57
58
|
summarizerClientElection: false,
|
|
59
|
+
nonRuntimeOpWeight: 0.1,
|
|
60
|
+
runtimeOpWeight: 1.0,
|
|
58
61
|
};
|
|
59
62
|
/**
|
|
60
63
|
* Accepted header keys for requests coming to the runtime.
|
|
@@ -71,7 +74,6 @@ export var RuntimeHeaders;
|
|
|
71
74
|
/** True if the request is coming from an IFluidHandle. */
|
|
72
75
|
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
73
76
|
})(RuntimeHeaders || (RuntimeHeaders = {}));
|
|
74
|
-
const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
|
|
75
77
|
const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
|
|
76
78
|
// Feature gate for the max op size. If the value is negative, chunking is enabled
|
|
77
79
|
// and all ops over 16k would be chunked. If the value is positive, all ops with
|
|
@@ -81,10 +83,6 @@ const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
|
|
|
81
83
|
// in order to account for some extra overhead from serialization
|
|
82
84
|
// to not reach the 1MB limits in socket.io and Kafka.
|
|
83
85
|
const defaultMaxOpSizeInBytes = 768000;
|
|
84
|
-
// By default, the size of the contents for the incoming ops is tracked.
|
|
85
|
-
// However, in certain situations, this may incur a performance hit.
|
|
86
|
-
// The feature-gate below can be used to disable this feature.
|
|
87
|
-
const disableOpTrackingKey = "Fluid.ContainerRuntime.DisableOpTracking";
|
|
88
86
|
const defaultFlushMode = FlushMode.TurnBased;
|
|
89
87
|
export var RuntimeMessage;
|
|
90
88
|
(function (RuntimeMessage) {
|
|
@@ -373,7 +371,7 @@ export function getDeviceSpec() {
|
|
|
373
371
|
*/
|
|
374
372
|
export class ContainerRuntime extends TypedEventEmitter {
|
|
375
373
|
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, _storage, requestHandler, summaryConfiguration) {
|
|
376
|
-
var _a, _b, _c, _d, _e, _f
|
|
374
|
+
var _a, _b, _c, _d, _e, _f;
|
|
377
375
|
if (summaryConfiguration === void 0) { summaryConfiguration = Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_a = runtimeOptions.summaryOptions) === null || _a === void 0 ? void 0 : _a.summaryConfigOverrides); }
|
|
378
376
|
super();
|
|
379
377
|
this.context = context;
|
|
@@ -434,20 +432,20 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
434
432
|
this.chunkMap = new Map(chunks);
|
|
435
433
|
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
436
434
|
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
435
|
+
if (this.summaryConfiguration.state === "enabled") {
|
|
436
|
+
this.validateSummaryHeuristicConfiguration(this.summaryConfiguration);
|
|
437
|
+
}
|
|
437
438
|
this.summariesDisabled = this.isSummariesDisabled();
|
|
438
439
|
this.heuristicsDisabled = this.isHeuristicsDisabled();
|
|
439
440
|
this.summarizerClientElectionEnabled = this.isSummarizerClientElectionEnabled();
|
|
440
441
|
this.maxOpsSinceLastSummary = this.getMaxOpsSinceLastSummary();
|
|
441
442
|
this.initialSummarizerDelayMs = this.getInitialSummarizerDelayMs();
|
|
442
|
-
this.
|
|
443
|
-
((_c = this.mc.config.getBoolean(useDataStoreAliasingKey)) !== null && _c !== void 0 ? _c : false) ||
|
|
444
|
-
((_d = runtimeOptions.useDataStoreAliasing) !== null && _d !== void 0 ? _d : false);
|
|
445
|
-
this._maxOpSizeInBytes = ((_e = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _e !== void 0 ? _e : defaultMaxOpSizeInBytes);
|
|
443
|
+
this._maxOpSizeInBytes = ((_c = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _c !== void 0 ? _c : defaultMaxOpSizeInBytes);
|
|
446
444
|
this.maxConsecutiveReconnects =
|
|
447
|
-
(
|
|
445
|
+
(_d = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _d !== void 0 ? _d : this.defaultMaxConsecutiveReconnects;
|
|
448
446
|
this._flushMode = runtimeOptions.flushMode;
|
|
449
447
|
const pendingRuntimeState = context.pendingLocalState;
|
|
450
|
-
const baseSnapshot = (
|
|
448
|
+
const baseSnapshot = (_e = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _e !== void 0 ? _e : context.baseSnapshot;
|
|
451
449
|
this.garbageCollector = GarbageCollector.create({
|
|
452
450
|
runtime: this,
|
|
453
451
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
@@ -481,7 +479,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
481
479
|
this.summarizerNode.loadBaseSummaryWithoutDifferential(baseSnapshot);
|
|
482
480
|
}
|
|
483
481
|
this.dataStores = new DataStores(getSummaryForDatastores(baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getBaseGCDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getBaseGCDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
|
|
484
|
-
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this
|
|
482
|
+
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId, localId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId, localId }), (blobPath) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"), this);
|
|
485
483
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
|
|
486
484
|
this.deltaSender = this.deltaManager;
|
|
487
485
|
this.pendingStateManager = new PendingStateManager({
|
|
@@ -572,9 +570,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
572
570
|
createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
|
|
573
571
|
createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
|
|
574
572
|
};
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
loadSummaryNumber = (
|
|
573
|
+
// summaryNumber was renamed from summaryCount. For older docs that haven't been opened for a long time,
|
|
574
|
+
// the count is reset to 0.
|
|
575
|
+
loadSummaryNumber = (_f = metadata === null || metadata === void 0 ? void 0 : metadata.summaryNumber) !== null && _f !== void 0 ? _f : 0;
|
|
578
576
|
}
|
|
579
577
|
else {
|
|
580
578
|
this.createContainerMetadata = {
|
|
@@ -587,7 +585,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
587
585
|
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryNumber: loadSummaryNumber, summaryFormatVersion: metadata === null || metadata === void 0 ? void 0 : metadata.summaryFormatVersion, disableIsolatedChannels: metadata === null || metadata === void 0 ? void 0 : metadata.disableIsolatedChannels, gcVersion: metadata === null || metadata === void 0 ? void 0 : metadata.gcFeature }));
|
|
588
586
|
ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
589
587
|
BindBatchTracker(this, this.logger);
|
|
590
|
-
this.opTracker = new OpTracker(this.deltaManager, this.mc.config.getBoolean(disableOpTrackingKey) === true);
|
|
591
588
|
}
|
|
592
589
|
get IContainerRuntime() { return this; }
|
|
593
590
|
get IFluidRouter() { return this; }
|
|
@@ -610,7 +607,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
610
607
|
runtimeVersion: pkgVersion,
|
|
611
608
|
},
|
|
612
609
|
});
|
|
613
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close",
|
|
610
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", flushMode = defaultFlushMode, enableOfflineLoad = false, } = runtimeOptions;
|
|
614
611
|
const pendingRuntimeState = context.pendingLocalState;
|
|
615
612
|
const baseSnapshot = (_b = pendingRuntimeState === null || pendingRuntimeState === void 0 ? void 0 : pendingRuntimeState.baseSnapshot) !== null && _b !== void 0 ? _b : context.baseSnapshot;
|
|
616
613
|
const storage = !pendingRuntimeState ?
|
|
@@ -663,7 +660,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
663
660
|
summaryOptions,
|
|
664
661
|
gcOptions,
|
|
665
662
|
loadSequenceNumberVerification,
|
|
666
|
-
useDataStoreAliasing,
|
|
667
663
|
flushMode,
|
|
668
664
|
enableOfflineLoad,
|
|
669
665
|
}, containerScope, logger, loadExisting, blobManagerSnapshot, storage, requestHandler);
|
|
@@ -856,12 +852,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
856
852
|
return this.resolveHandle(requestParser.createSubRequest(1));
|
|
857
853
|
}
|
|
858
854
|
if (id === BlobManager.basePath && requestParser.isLeaf(2)) {
|
|
859
|
-
const
|
|
860
|
-
if (
|
|
855
|
+
const blob = await this.blobManager.getBlob(requestParser.pathParts[1]);
|
|
856
|
+
if (blob) {
|
|
861
857
|
return {
|
|
862
858
|
status: 200,
|
|
863
859
|
mimeType: "fluid/object",
|
|
864
|
-
value:
|
|
860
|
+
value: blob,
|
|
865
861
|
};
|
|
866
862
|
}
|
|
867
863
|
else {
|
|
@@ -884,13 +880,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
884
880
|
}
|
|
885
881
|
internalId(maybeAlias) {
|
|
886
882
|
var _a;
|
|
887
|
-
return (_a = this.dataStores.aliases
|
|
883
|
+
return (_a = this.dataStores.aliases.get(maybeAlias)) !== null && _a !== void 0 ? _a : maybeAlias;
|
|
888
884
|
}
|
|
889
885
|
async getDataStoreFromRequest(id, request) {
|
|
890
886
|
var _a, _b, _c;
|
|
891
887
|
const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
|
|
892
888
|
? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait]
|
|
893
889
|
: true;
|
|
890
|
+
await this.dataStores.waitIfPendingAlias(id);
|
|
894
891
|
const internalId = this.internalId(id);
|
|
895
892
|
const dataStoreContext = await this.dataStores.getDataStore(internalId, wait);
|
|
896
893
|
/**
|
|
@@ -920,8 +917,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
920
917
|
addMetadataToSummary(summaryTree) {
|
|
921
918
|
var _a;
|
|
922
919
|
const metadata = Object.assign(Object.assign(Object.assign(Object.assign({}, this.createContainerMetadata), {
|
|
923
|
-
// back-compat 0.59.3000: This is renamed to summaryNumber. Can be removed when 0.59.3000 saturates.
|
|
924
|
-
summaryCount: this.nextSummaryNumber,
|
|
925
920
|
// Increment the summary number for the next summary that will be generated.
|
|
926
921
|
summaryNumber: this.nextSummaryNumber++, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined }), this.garbageCollector.getMetadata()), {
|
|
927
922
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
@@ -936,7 +931,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
936
931
|
const content = JSON.stringify([...this.chunkMap]);
|
|
937
932
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
938
933
|
}
|
|
939
|
-
const dataStoreAliases = this.dataStores.aliases
|
|
934
|
+
const dataStoreAliases = this.dataStores.aliases;
|
|
940
935
|
if (dataStoreAliases.size > 0) {
|
|
941
936
|
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
942
937
|
}
|
|
@@ -1033,6 +1028,35 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1033
1028
|
}
|
|
1034
1029
|
}
|
|
1035
1030
|
setConnectionState(connected, clientId) {
|
|
1031
|
+
if (connected === false && this.delayConnectClientId !== undefined) {
|
|
1032
|
+
this.delayConnectClientId = undefined;
|
|
1033
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1034
|
+
eventName: "UnsuccessfulConnectedTransition",
|
|
1035
|
+
});
|
|
1036
|
+
// Don't propagate "disconnected" event because we didn't propagate the previous "connected" event
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
// If attachment blobs were added while disconnected, we need to delay
|
|
1040
|
+
// propagation of the "connected" event until we have uploaded them to
|
|
1041
|
+
// ensure we don't submit ops referencing a blob that has not been uploaded
|
|
1042
|
+
const connecting = connected && !this._connected && !this.deltaManager.readOnlyInfo.readonly;
|
|
1043
|
+
if (connecting && this.blobManager.hasPendingOfflineUploads) {
|
|
1044
|
+
assert(!this.delayConnectClientId, 0x392 /* Connect event delay must be canceled before subsequent connect event */);
|
|
1045
|
+
assert(!!clientId, 0x393 /* Must have clientId when connecting */);
|
|
1046
|
+
this.delayConnectClientId = clientId;
|
|
1047
|
+
this.blobManager.onConnected().then(() => {
|
|
1048
|
+
// make sure we didn't reconnect before the promise resolved
|
|
1049
|
+
if (this.delayConnectClientId === clientId && !this.disposed) {
|
|
1050
|
+
this.delayConnectClientId = undefined;
|
|
1051
|
+
this.setConnectionStateCore(connected, clientId);
|
|
1052
|
+
}
|
|
1053
|
+
}, (error) => this.closeFn(error));
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
this.setConnectionStateCore(connected, clientId);
|
|
1057
|
+
}
|
|
1058
|
+
setConnectionStateCore(connected, clientId) {
|
|
1059
|
+
assert(!this.delayConnectClientId, 0x394 /* connect event delay must be cleared before propagating connect event */);
|
|
1036
1060
|
this.verifyNotClosed();
|
|
1037
1061
|
// There might be no change of state due to Container calling this API after loading runtime.
|
|
1038
1062
|
const changeOfState = this._connected !== connected;
|
|
@@ -1063,7 +1087,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1063
1087
|
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
1064
1088
|
}
|
|
1065
1089
|
process(messageArg, local) {
|
|
1066
|
-
var _a
|
|
1090
|
+
var _a;
|
|
1067
1091
|
this.verifyNotClosed();
|
|
1068
1092
|
// If it's not message for runtime, bail out right away.
|
|
1069
1093
|
if (!isUnpackedRuntimeMessage(messageArg)) {
|
|
@@ -1110,8 +1134,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1110
1134
|
this.dataStores.processFluidDataStoreOp(message, local, localOpMetadata);
|
|
1111
1135
|
break;
|
|
1112
1136
|
case ContainerMessageType.BlobAttach:
|
|
1113
|
-
|
|
1114
|
-
this.blobManager.processBlobAttachOp(message.metadata.blobId, local);
|
|
1137
|
+
this.blobManager.processBlobAttachOp(message, local);
|
|
1115
1138
|
break;
|
|
1116
1139
|
default:
|
|
1117
1140
|
}
|
|
@@ -1181,6 +1204,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1181
1204
|
this.dataStores.processSignal(envelope.address, transformed, local);
|
|
1182
1205
|
}
|
|
1183
1206
|
async getRootDataStore(id, wait = true) {
|
|
1207
|
+
return this.getRootDataStoreChannel(id, wait);
|
|
1208
|
+
}
|
|
1209
|
+
async getRootDataStoreChannel(id, wait = true) {
|
|
1210
|
+
await this.dataStores.waitIfPendingAlias(id);
|
|
1184
1211
|
const internalId = this.internalId(id);
|
|
1185
1212
|
const context = await this.dataStores.getDataStore(internalId, wait);
|
|
1186
1213
|
assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
|
|
@@ -1271,67 +1298,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1271
1298
|
}
|
|
1272
1299
|
async createDataStore(pkg) {
|
|
1273
1300
|
const internalId = uuid();
|
|
1274
|
-
return channelToDataStore(await this._createDataStore(pkg,
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
* Creates a root datastore directly with a user generated id and attaches it to storage.
|
|
1278
|
-
* It is vulnerable to name collisions and should not be used.
|
|
1279
|
-
*
|
|
1280
|
-
* This method will be removed. See #6465.
|
|
1281
|
-
*/
|
|
1282
|
-
async createRootDataStoreLegacy(pkg, rootDataStoreId) {
|
|
1283
|
-
const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
|
|
1284
|
-
// back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel. For
|
|
1285
|
-
// older versions, we still have to call bindToContext.
|
|
1286
|
-
if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
|
|
1287
|
-
fluidDataStore.makeVisibleAndAttachGraph();
|
|
1288
|
-
}
|
|
1289
|
-
else {
|
|
1290
|
-
fluidDataStore.bindToContext();
|
|
1291
|
-
}
|
|
1292
|
-
return fluidDataStore;
|
|
1293
|
-
}
|
|
1294
|
-
/**
|
|
1295
|
-
* @deprecated - will be removed in an upcoming release. See #9660.
|
|
1296
|
-
*/
|
|
1297
|
-
async createRootDataStore(pkg, rootDataStoreId) {
|
|
1298
|
-
if (rootDataStoreId.includes("/")) {
|
|
1299
|
-
throw new UsageError(`Id cannot contain slashes: '${rootDataStoreId}'`);
|
|
1300
|
-
}
|
|
1301
|
-
return this._aliasingEnabled === true ?
|
|
1302
|
-
this.createAndAliasDataStore(pkg, rootDataStoreId) :
|
|
1303
|
-
this.createRootDataStoreLegacy(pkg, rootDataStoreId);
|
|
1304
|
-
}
|
|
1305
|
-
/**
|
|
1306
|
-
* Creates a data store then attempts to alias it.
|
|
1307
|
-
* If aliasing fails, it will raise an exception.
|
|
1308
|
-
*
|
|
1309
|
-
* This method will be removed. See #6465.
|
|
1310
|
-
*
|
|
1311
|
-
* @param pkg - Package name of the data store
|
|
1312
|
-
* @param alias - Alias to be assigned to the data store
|
|
1313
|
-
* @param props - Properties for the data store
|
|
1314
|
-
* @returns - An aliased data store which can can be found / loaded by alias.
|
|
1315
|
-
*/
|
|
1316
|
-
async createAndAliasDataStore(pkg, alias, props) {
|
|
1317
|
-
const internalId = uuid();
|
|
1318
|
-
const dataStore = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
|
|
1319
|
-
const aliasedDataStore = channelToDataStore(dataStore, internalId, this, this.dataStores, this.mc.logger);
|
|
1320
|
-
const result = await aliasedDataStore.trySetAlias(alias);
|
|
1321
|
-
if (result !== "Success") {
|
|
1322
|
-
throw new GenericError("dataStoreAliasFailure", undefined /* error */, {
|
|
1323
|
-
alias: {
|
|
1324
|
-
value: alias,
|
|
1325
|
-
tag: TelemetryDataTag.UserData,
|
|
1326
|
-
},
|
|
1327
|
-
internalId: {
|
|
1328
|
-
value: internalId,
|
|
1329
|
-
tag: TelemetryDataTag.PackageData,
|
|
1330
|
-
},
|
|
1331
|
-
aliasResult: result,
|
|
1332
|
-
});
|
|
1333
|
-
}
|
|
1334
|
-
return aliasedDataStore;
|
|
1301
|
+
return channelToDataStore(await this._createDataStore(pkg, internalId), internalId, this, this.dataStores, this.mc.logger);
|
|
1335
1302
|
}
|
|
1336
1303
|
createDetachedRootDataStore(pkg, rootDataStoreId) {
|
|
1337
1304
|
if (rootDataStoreId.includes("/")) {
|
|
@@ -1342,38 +1309,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1342
1309
|
createDetachedDataStore(pkg) {
|
|
1343
1310
|
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
1344
1311
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
* It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
|
|
1348
|
-
*
|
|
1349
|
-
* This method will be removed. See #6465.
|
|
1350
|
-
*/
|
|
1351
|
-
async _createDataStoreWithPropsLegacy(pkg, props, id = uuid(), isRoot = false) {
|
|
1352
|
-
const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
|
|
1353
|
-
if (isRoot) {
|
|
1354
|
-
// back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel.
|
|
1355
|
-
// For older versions, we still have to call bindToContext.
|
|
1356
|
-
if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
|
|
1357
|
-
fluidDataStore.makeVisibleAndAttachGraph();
|
|
1358
|
-
}
|
|
1359
|
-
else {
|
|
1360
|
-
fluidDataStore.bindToContext();
|
|
1361
|
-
}
|
|
1362
|
-
this.logger.sendTelemetryEvent({
|
|
1363
|
-
eventName: "Root datastore with props",
|
|
1364
|
-
hasProps: props !== undefined,
|
|
1365
|
-
});
|
|
1366
|
-
}
|
|
1312
|
+
async _createDataStoreWithProps(pkg, props, id = uuid()) {
|
|
1313
|
+
const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props).realize();
|
|
1367
1314
|
return channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
|
|
1368
1315
|
}
|
|
1369
|
-
async
|
|
1370
|
-
return this._aliasingEnabled === true && isRoot ?
|
|
1371
|
-
this.createAndAliasDataStore(pkg, id, props) :
|
|
1372
|
-
this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
|
|
1373
|
-
}
|
|
1374
|
-
async _createDataStore(pkg, isRoot, id = uuid(), props) {
|
|
1316
|
+
async _createDataStore(pkg, id = uuid(), props) {
|
|
1375
1317
|
return this.dataStores
|
|
1376
|
-
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id,
|
|
1318
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
|
|
1377
1319
|
.realize();
|
|
1378
1320
|
}
|
|
1379
1321
|
canSendOps() {
|
|
@@ -1639,7 +1581,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1639
1581
|
* @param options - options controlling how the summary is generated or submitted
|
|
1640
1582
|
*/
|
|
1641
1583
|
async submitSummary(options) {
|
|
1642
|
-
var _a, _b
|
|
1584
|
+
var _a, _b;
|
|
1643
1585
|
const { fullTree, refreshLatestAck, summaryLogger } = options;
|
|
1644
1586
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
1645
1587
|
// use it for all events logged during this summary.
|
|
@@ -1647,16 +1589,19 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1647
1589
|
const summaryNumberLogger = ChildLogger.create(summaryLogger, undefined, {
|
|
1648
1590
|
all: { summaryNumber },
|
|
1649
1591
|
});
|
|
1592
|
+
let latestSnapshotVersionId;
|
|
1650
1593
|
if (refreshLatestAck) {
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1594
|
+
const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(ChildLogger.create(summaryNumberLogger, undefined, { all: { safeSummary: true } }));
|
|
1595
|
+
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
1596
|
+
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
1597
|
+
if (latestSnapshotRefSeq > this.deltaManager.lastSequenceNumber) {
|
|
1653
1598
|
// We need to catch up to the latest summary's reference sequence number before pausing.
|
|
1654
1599
|
await PerformanceEvent.timedExecAsync(summaryNumberLogger, {
|
|
1655
1600
|
eventName: "WaitingForSeq",
|
|
1656
1601
|
lastSequenceNumber: this.deltaManager.lastSequenceNumber,
|
|
1657
|
-
targetSequenceNumber:
|
|
1602
|
+
targetSequenceNumber: latestSnapshotRefSeq,
|
|
1658
1603
|
lastKnownSeqNumber: this.deltaManager.lastKnownSeqNumber,
|
|
1659
|
-
}, async () => waitForSeq(this.deltaManager,
|
|
1604
|
+
}, async () => waitForSeq(this.deltaManager, latestSnapshotRefSeq), { start: true, end: true, cancel: "error" });
|
|
1660
1605
|
}
|
|
1661
1606
|
}
|
|
1662
1607
|
try {
|
|
@@ -1664,17 +1609,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1664
1609
|
const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
1665
1610
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1666
1611
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
1667
|
-
|
|
1668
|
-
// doesn't match the last processed sequence number, log an error.
|
|
1669
|
-
if (summaryRefSeqNum !== ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber)) {
|
|
1670
|
-
summaryNumberLogger.sendErrorEvent({
|
|
1671
|
-
eventName: "LastSequenceMismatch",
|
|
1672
|
-
error: message,
|
|
1673
|
-
});
|
|
1674
|
-
}
|
|
1612
|
+
const lastAck = this.summaryCollection.latestAck;
|
|
1675
1613
|
this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger);
|
|
1676
1614
|
// Helper function to check whether we should still continue between each async step.
|
|
1677
1615
|
const checkContinue = () => {
|
|
1616
|
+
var _a;
|
|
1678
1617
|
// Do not check for loss of connectivity directly! Instead leave it up to
|
|
1679
1618
|
// RunWhileConnectedCoordinator to control policy in a single place.
|
|
1680
1619
|
// This will allow easier change of design if we chose to. For example, we may chose to allow
|
|
@@ -1698,6 +1637,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1698
1637
|
error: `lastSequenceNumber changed before uploading to storage. ${this.deltaManager.lastSequenceNumber} !== ${summaryRefSeqNum}`,
|
|
1699
1638
|
};
|
|
1700
1639
|
}
|
|
1640
|
+
assert(summaryRefSeqNum === ((_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.sequenceNumber), 0x395 /* it's one and the same thing */);
|
|
1641
|
+
if (lastAck !== this.summaryCollection.latestAck) {
|
|
1642
|
+
return {
|
|
1643
|
+
continue: false,
|
|
1644
|
+
// eslint-disable-next-line max-len
|
|
1645
|
+
error: `Last summary changed while summarizing. ${this.summaryCollection.latestAck} !== ${lastAck}`,
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1701
1648
|
return { continue: true };
|
|
1702
1649
|
};
|
|
1703
1650
|
let continueResult = checkContinue();
|
|
@@ -1742,7 +1689,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1742
1689
|
const gcSummaryTreeStats = summaryTree.tree[gcTreeKey]
|
|
1743
1690
|
? calculateStats(summaryTree.tree[gcTreeKey])
|
|
1744
1691
|
: undefined;
|
|
1745
|
-
const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (
|
|
1692
|
+
const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_a = summarizeResult.gcStats) === null || _a === void 0 ? void 0 : _a.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, summaryNumber }, partialStats);
|
|
1746
1693
|
const generateSummaryData = {
|
|
1747
1694
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1748
1695
|
minimumSequenceNumber,
|
|
@@ -1755,18 +1702,34 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1755
1702
|
if (!continueResult.continue) {
|
|
1756
1703
|
return Object.assign(Object.assign({ stage: "generate" }, generateSummaryData), { error: continueResult.error });
|
|
1757
1704
|
}
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1705
|
+
// It may happen that the lastAck it not correct due to missing summaryAck in case of single commit
|
|
1706
|
+
// summary. So if the previous summarizer closes just after submitting the summary and before
|
|
1707
|
+
// submitting the summaryOp then we can't rely on summaryAck. So in case we have
|
|
1708
|
+
// latestSnapshotVersionId from storage and it does not match with the lastAck ackHandle, then use
|
|
1709
|
+
// the one fetched from storage as parent as that is the latest.
|
|
1710
|
+
let summaryContext;
|
|
1711
|
+
if ((lastAck === null || lastAck === void 0 ? void 0 : lastAck.summaryAck.contents.handle) !== latestSnapshotVersionId
|
|
1712
|
+
&& latestSnapshotVersionId !== undefined) {
|
|
1713
|
+
summaryContext = {
|
|
1761
1714
|
proposalHandle: undefined,
|
|
1762
|
-
ackHandle:
|
|
1715
|
+
ackHandle: latestSnapshotVersionId,
|
|
1763
1716
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
else if (lastAck === undefined) {
|
|
1720
|
+
summaryContext = {
|
|
1721
|
+
proposalHandle: undefined,
|
|
1722
|
+
ackHandle: (_b = this.context.getLoadedFromVersion()) === null || _b === void 0 ? void 0 : _b.id,
|
|
1723
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
else {
|
|
1727
|
+
summaryContext = {
|
|
1766
1728
|
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
1767
1729
|
ackHandle: lastAck.summaryAck.contents.handle,
|
|
1768
1730
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1769
1731
|
};
|
|
1732
|
+
}
|
|
1770
1733
|
let handle;
|
|
1771
1734
|
try {
|
|
1772
1735
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
@@ -1796,7 +1759,6 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1796
1759
|
}
|
|
1797
1760
|
const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
|
|
1798
1761
|
this.summarizerNode.completeSummary(handle);
|
|
1799
|
-
this.opTracker.reset();
|
|
1800
1762
|
return submitData;
|
|
1801
1763
|
}
|
|
1802
1764
|
finally {
|
|
@@ -1907,14 +1869,8 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1907
1869
|
// instead of splitting the content, we will fail by explicitly close the container
|
|
1908
1870
|
this.closeFn(new GenericError("OpTooLarge",
|
|
1909
1871
|
/* error */ undefined, {
|
|
1910
|
-
length:
|
|
1911
|
-
|
|
1912
|
-
tag: TelemetryDataTag.PackageData,
|
|
1913
|
-
},
|
|
1914
|
-
limit: {
|
|
1915
|
-
value: this._maxOpSizeInBytes,
|
|
1916
|
-
tag: TelemetryDataTag.PackageData,
|
|
1917
|
-
},
|
|
1872
|
+
length: serializedContent.length,
|
|
1873
|
+
limit: this._maxOpSizeInBytes,
|
|
1918
1874
|
}));
|
|
1919
1875
|
return -1;
|
|
1920
1876
|
}
|
|
@@ -1989,7 +1945,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1989
1945
|
case ContainerMessageType.ChunkedOp:
|
|
1990
1946
|
throw new Error(`chunkedOp not expected here`);
|
|
1991
1947
|
case ContainerMessageType.BlobAttach:
|
|
1992
|
-
this.
|
|
1948
|
+
this.blobManager.reSubmit(opMetadata);
|
|
1993
1949
|
break;
|
|
1994
1950
|
case ContainerMessageType.Rejoin:
|
|
1995
1951
|
this.submit(type, content);
|
|
@@ -2012,12 +1968,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2012
1968
|
/** Implementation of ISummarizerInternalsProvider.refreshLatestSummaryAck */
|
|
2013
1969
|
async refreshLatestSummaryAck(proposalHandle, ackHandle, summaryRefSeq, summaryLogger) {
|
|
2014
1970
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
2015
|
-
const
|
|
1971
|
+
const { snapshotTree } = await this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
|
|
2016
1972
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
2017
1973
|
ackHandle,
|
|
2018
1974
|
summaryRefSeq,
|
|
2019
1975
|
fetchLatest: false,
|
|
2020
|
-
})
|
|
1976
|
+
});
|
|
1977
|
+
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
|
|
2021
1978
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2022
1979
|
await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
|
|
2023
1980
|
}
|
|
@@ -2028,29 +1985,29 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2028
1985
|
* @returns downloaded snapshot's reference sequence number
|
|
2029
1986
|
*/
|
|
2030
1987
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
2031
|
-
const
|
|
1988
|
+
const { snapshotTree, versionId } = await this.fetchSnapshotFromStorage(null, summaryLogger, {
|
|
2032
1989
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
2033
1990
|
fetchLatest: true,
|
|
2034
|
-
});
|
|
1991
|
+
}, FetchSource.noCache);
|
|
2035
1992
|
const readAndParseBlob = async (id) => readAndParse(this.storage, id);
|
|
2036
|
-
const
|
|
2037
|
-
const result = await this.summarizerNode.refreshLatestSummary(undefined,
|
|
1993
|
+
const latestSnapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
1994
|
+
const result = await this.summarizerNode.refreshLatestSummary(undefined, latestSnapshotRefSeq, async () => snapshotTree, readAndParseBlob, summaryLogger);
|
|
2038
1995
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2039
1996
|
await this.garbageCollector.latestSummaryStateRefreshed(result, readAndParseBlob);
|
|
2040
|
-
return
|
|
1997
|
+
return { latestSnapshotRefSeq, latestSnapshotVersionId: versionId };
|
|
2041
1998
|
}
|
|
2042
|
-
async fetchSnapshotFromStorage(versionId, logger, event) {
|
|
1999
|
+
async fetchSnapshotFromStorage(versionId, logger, event, fetchSource) {
|
|
2043
2000
|
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2044
2001
|
const stats = {};
|
|
2045
2002
|
const trace = Trace.start();
|
|
2046
|
-
const versions = await this.storage.getVersions(versionId, 1);
|
|
2003
|
+
const versions = await this.storage.getVersions(versionId, 1, "refreshLatestSummaryAckFromServer", fetchSource);
|
|
2047
2004
|
assert(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
2048
2005
|
stats.getVersionDuration = trace.trace().duration;
|
|
2049
2006
|
const maybeSnapshot = await this.storage.getSnapshotTree(versions[0]);
|
|
2050
2007
|
assert(!!maybeSnapshot, 0x138 /* "Failed to get snapshot from storage" */);
|
|
2051
2008
|
stats.getSnapshotDuration = trace.trace().duration;
|
|
2052
2009
|
perfEvent.end(stats);
|
|
2053
|
-
return maybeSnapshot;
|
|
2010
|
+
return { snapshotTree: maybeSnapshot, versionId: versions[0].id };
|
|
2054
2011
|
});
|
|
2055
2012
|
}
|
|
2056
2013
|
notifyAttaching(snapshot) {
|
|
@@ -2126,6 +2083,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
2126
2083
|
// don't have any more saved ops
|
|
2127
2084
|
await this.pendingStateManager.applyStashedOpsAt();
|
|
2128
2085
|
}
|
|
2086
|
+
validateSummaryHeuristicConfiguration(configuration) {
|
|
2087
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
2088
|
+
for (const prop in configuration) {
|
|
2089
|
+
if (typeof configuration[prop] === "number" && configuration[prop] < 0) {
|
|
2090
|
+
throw new UsageError(`Summary heuristic configuration property "${prop}" cannot be less than 0`);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2129
2094
|
}
|
|
2130
2095
|
/**
|
|
2131
2096
|
* Wait for a specific sequence number. Promise should resolve when we reach that number,
|