@fluidframework/container-runtime 0.56.3 → 0.57.0-51086
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/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +9 -1
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +6 -6
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +65 -24
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +139 -72
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +62 -0
- package/dist/dataStore.d.ts.map +1 -0
- package/dist/dataStore.js +135 -0
- package/dist/dataStore.js.map +1 -0
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +9 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +14 -19
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +47 -21
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +195 -61
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.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/runningSummarizer.d.ts +1 -0
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +23 -15
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summarizerTypes.d.ts +4 -6
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryGenerator.d.ts +2 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +46 -29
- package/dist/summaryGenerator.js.map +1 -1
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +9 -1
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +6 -6
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +65 -24
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +140 -73
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +62 -0
- package/lib/dataStore.d.ts.map +1 -0
- package/lib/dataStore.js +130 -0
- package/lib/dataStore.js.map +1 -0
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +9 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +13 -18
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +47 -21
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +197 -63
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.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/runningSummarizer.d.ts +1 -0
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +23 -15
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summarizerTypes.d.ts +4 -6
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryGenerator.d.ts +2 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +46 -29
- package/lib/summaryGenerator.js.map +1 -1
- package/package.json +13 -13
- package/src/blobManager.ts +12 -1
- package/src/connectionTelemetry.ts +7 -6
- package/src/containerRuntime.ts +220 -93
- package/src/dataStore.ts +187 -0
- package/src/dataStoreContext.ts +1 -1
- package/src/dataStores.ts +18 -38
- package/src/garbageCollection.ts +283 -105
- package/src/index.ts +3 -1
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +25 -16
- package/src/summarizerTypes.ts +4 -8
- package/src/summaryGenerator.ts +71 -23
package/dist/containerRuntime.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.ScheduleManager = exports.unpackRuntimeMessage = exports.isRuntimeMessage = exports.RuntimeMessage = exports.ContainerMessageType = void 0;
|
|
7
|
+
exports.ContainerRuntime = exports.getDeviceSpec = exports.agentSchedulerId = exports.ScheduleManager = exports.unpackRuntimeMessage = exports.isRuntimeMessage = exports.RuntimeMessage = exports.RuntimeHeaders = exports.ContainerMessageType = void 0;
|
|
8
8
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
9
9
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
10
10
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
@@ -32,6 +32,7 @@ const summarizerClientElection_1 = require("./summarizerClientElection");
|
|
|
32
32
|
const throttler_1 = require("./throttler");
|
|
33
33
|
const runWhileConnectedCoordinator_1 = require("./runWhileConnectedCoordinator");
|
|
34
34
|
const garbageCollection_1 = require("./garbageCollection");
|
|
35
|
+
const dataStore_1 = require("./dataStore");
|
|
35
36
|
var ContainerMessageType;
|
|
36
37
|
(function (ContainerMessageType) {
|
|
37
38
|
// An op to be delivered to store
|
|
@@ -59,9 +60,24 @@ const DefaultSummaryConfiguration = {
|
|
|
59
60
|
// the min of the two will be chosen
|
|
60
61
|
maxAckWaitTime: 120000,
|
|
61
62
|
};
|
|
62
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Accepted header keys for requests coming to the runtime.
|
|
65
|
+
*/
|
|
66
|
+
var RuntimeHeaders;
|
|
67
|
+
(function (RuntimeHeaders) {
|
|
68
|
+
/** True to wait for a data store to be created and loaded before returning it. */
|
|
69
|
+
RuntimeHeaders["wait"] = "wait";
|
|
70
|
+
/**
|
|
71
|
+
* True if the request is from an external app. Used for GC to handle scenarios where a data store
|
|
72
|
+
* is deleted and requested via an external app.
|
|
73
|
+
*/
|
|
74
|
+
RuntimeHeaders["externalRequest"] = "externalRequest";
|
|
75
|
+
/** True if the request is coming from an IFluidHandle. */
|
|
76
|
+
RuntimeHeaders["viaHandle"] = "viaHandle";
|
|
77
|
+
})(RuntimeHeaders = exports.RuntimeHeaders || (exports.RuntimeHeaders = {}));
|
|
63
78
|
// Local storage key to set the default flush mode to TurnBased
|
|
64
79
|
const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
|
|
80
|
+
const useDataStoreAliasingKey = "Fluid.ContainerRuntime.UseDataStoreAliasing";
|
|
65
81
|
var RuntimeMessage;
|
|
66
82
|
(function (RuntimeMessage) {
|
|
67
83
|
RuntimeMessage["FluidDataStoreOp"] = "component";
|
|
@@ -339,7 +355,7 @@ exports.getDeviceSpec = getDeviceSpec;
|
|
|
339
355
|
*/
|
|
340
356
|
class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
341
357
|
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
|
|
342
|
-
var _a, _b, _c, _d, _e;
|
|
358
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
343
359
|
super();
|
|
344
360
|
this.context = context;
|
|
345
361
|
this.registry = registry;
|
|
@@ -353,7 +369,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
353
369
|
this.flushTrigger = false;
|
|
354
370
|
this.paused = false;
|
|
355
371
|
this._disposed = false;
|
|
356
|
-
this.dirtyContainer = false;
|
|
357
372
|
this.emitDirtyDocumentEvent = true;
|
|
358
373
|
this.summarizerWarning = (warning) => this.mc.logger.sendTelemetryEvent({ eventName: "summarizerWarning" }, warning);
|
|
359
374
|
/**
|
|
@@ -429,6 +444,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
429
444
|
this.mc = telemetry_utils_1.loggerToMonitoringContext(telemetry_utils_1.ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
430
445
|
this._flushMode =
|
|
431
446
|
((_b = this.mc.config.getBoolean(turnBasedFlushModeKey)) !== null && _b !== void 0 ? _b : false) ? runtime_definitions_1.FlushMode.TurnBased : runtime_definitions_1.FlushMode.Immediate;
|
|
447
|
+
this._aliasingEnabled =
|
|
448
|
+
((_c = this.mc.config.getBoolean(useDataStoreAliasingKey)) !== null && _c !== void 0 ? _c : false) ||
|
|
449
|
+
((_d = runtimeOptions.useDataStoreAliasing) !== null && _d !== void 0 ? _d : false);
|
|
432
450
|
/**
|
|
433
451
|
* Function that return the current server timestamp. This is used by the garbage collector to set the
|
|
434
452
|
* time when a node becomes unreferenced.
|
|
@@ -442,7 +460,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
442
460
|
const timestamp = client === null || client === void 0 ? void 0 : client.timestamp;
|
|
443
461
|
return (_c = (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : timestamp) !== null && _c !== void 0 ? _c : Date.now();
|
|
444
462
|
};
|
|
445
|
-
this.garbageCollector = garbageCollection_1.GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), getCurrentTimestamp, this.closeFn, context.baseSnapshot, async (id) => driver_utils_1.readAndParse(this.storage, id), this.mc.logger, existing, metadata);
|
|
463
|
+
this.garbageCollector = garbageCollection_1.GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), (nodePath) => this.dataStores.getNodePackagePath(nodePath), getCurrentTimestamp, this.closeFn, context.baseSnapshot, async (id) => driver_utils_1.readAndParse(this.storage, id), this.mc.logger, existing, metadata);
|
|
446
464
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
447
465
|
this.summarizerNode = runtime_utils_1.createRootSummarizerNodeWithGC(telemetry_utils_1.ChildLogger.create(this.logger, "SummarizerNode"),
|
|
448
466
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
@@ -463,7 +481,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
463
481
|
if (this.context.baseSnapshot) {
|
|
464
482
|
this.summarizerNode.loadBaseSummaryWithoutDifferential(this.context.baseSnapshot);
|
|
465
483
|
}
|
|
466
|
-
this.dataStores = new dataStores_1.DataStores(dataStores_1.getSummaryForDatastores(context.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.getDataStoreBaseGCDetails(), (
|
|
484
|
+
this.dataStores = new dataStores_1.DataStores(dataStores_1.getSummaryForDatastores(context.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.getDataStoreBaseGCDetails(), (dataStorePath, packagePath) => this.garbageCollector.nodeUpdated(dataStorePath, "Changed", packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
|
|
467
485
|
this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
|
|
468
486
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
|
|
469
487
|
this.deltaSender = this.deltaManager;
|
|
@@ -472,6 +490,10 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
472
490
|
this.clearPartialChunks(clientId);
|
|
473
491
|
});
|
|
474
492
|
this.summaryCollection = new summaryCollection_1.SummaryCollection(this.deltaManager, this.logger);
|
|
493
|
+
const { attachState, pendingLocalState } = this.context;
|
|
494
|
+
this.dirtyContainer = attachState !== container_definitions_1.AttachState.Attached
|
|
495
|
+
|| ((_e = pendingLocalState) === null || _e === void 0 ? void 0 : _e.pendingStates.length) > 0;
|
|
496
|
+
this.context.updateDirtyContainerState(this.dirtyContainer);
|
|
475
497
|
// Map the deprecated generateSummaries flag to disableSummaries.
|
|
476
498
|
if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
|
|
477
499
|
this.runtimeOptions.summaryOptions.disableSummaries = true;
|
|
@@ -483,8 +505,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
483
505
|
const orderedClientLogger = telemetry_utils_1.ChildLogger.create(this.logger, "OrderedClientElection");
|
|
484
506
|
const orderedClientCollection = new orderedClientElection_1.OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
|
|
485
507
|
const orderedClientElectionForSummarizer = new orderedClientElection_1.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, summarizerClientElection_1.SummarizerClientElection.isClientEligible);
|
|
486
|
-
const summarizerClientElectionEnabled = (
|
|
487
|
-
const maxOpsSinceLastSummary = (
|
|
508
|
+
const summarizerClientElectionEnabled = (_f = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _f !== void 0 ? _f : ((_g = this.runtimeOptions.summaryOptions) === null || _g === void 0 ? void 0 : _g.summarizerClientElection) === true;
|
|
509
|
+
const maxOpsSinceLastSummary = (_h = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _h !== void 0 ? _h : 7000;
|
|
488
510
|
this.summarizerClientElection = new summarizerClientElection_1.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
|
|
489
511
|
if (this.context.clientDetails.type === summarizerClientElection_1.summarizerClientType) {
|
|
490
512
|
this._summarizer = new summarizer_1.Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => runWhileConnectedCoordinator_1.RunWhileConnectedCoordinator.create(runtime));
|
|
@@ -568,7 +590,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
568
590
|
runtimeVersion: packageVersion_1.pkgVersion,
|
|
569
591
|
},
|
|
570
592
|
});
|
|
571
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", } = runtimeOptions;
|
|
593
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, } = runtimeOptions;
|
|
572
594
|
// We pack at data store level only. If isolated channels are disabled,
|
|
573
595
|
// then there are no .channel layers, we pack at level 1, otherwise we pack at level 2
|
|
574
596
|
const packingLevel = summaryOptions.disableIsolatedChannels ? 1 : 2;
|
|
@@ -636,6 +658,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
636
658
|
summaryOptions,
|
|
637
659
|
gcOptions,
|
|
638
660
|
loadSequenceNumberVerification,
|
|
661
|
+
useDataStoreAliasing,
|
|
639
662
|
}, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
|
|
640
663
|
return runtime;
|
|
641
664
|
}
|
|
@@ -775,7 +798,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
775
798
|
* @param request - Request made to the handler.
|
|
776
799
|
*/
|
|
777
800
|
async resolveHandle(request) {
|
|
778
|
-
var _a, _b;
|
|
779
801
|
try {
|
|
780
802
|
const requestParser = runtime_utils_1.RequestParser.create(request);
|
|
781
803
|
const id = requestParser.pathParts[0];
|
|
@@ -796,18 +818,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
796
818
|
}
|
|
797
819
|
}
|
|
798
820
|
else if (requestParser.pathParts.length > 0) {
|
|
799
|
-
|
|
800
|
-
* If GC should run and this an external app request with "externalRequest" header, we need to return
|
|
801
|
-
* an error if the data store being requested is marked as unreferenced as per the data store's initial
|
|
802
|
-
* summary.
|
|
803
|
-
*
|
|
804
|
-
* This is a workaround to handle scenarios where a data store shared with an external app is deleted
|
|
805
|
-
* and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
|
|
806
|
-
*/
|
|
807
|
-
const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a.wait) === "boolean" ? request.headers.wait : undefined;
|
|
808
|
-
const dataStore = ((_b = request.headers) === null || _b === void 0 ? void 0 : _b.externalRequest) && this.garbageCollector.shouldRunGC
|
|
809
|
-
? await this.getDataStoreIfInitiallyReferenced(id, wait)
|
|
810
|
-
: await this.getDataStore(id, wait);
|
|
821
|
+
const dataStore = await this.getDataStoreFromRequest(id, request);
|
|
811
822
|
const subRequest = requestParser.createSubRequest(1);
|
|
812
823
|
// We always expect createSubRequest to include a leading slash, but asserting here to protect against
|
|
813
824
|
// unintentionally modifying the url if that changes.
|
|
@@ -820,6 +831,33 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
820
831
|
return runtime_utils_1.exceptionToResponse(error);
|
|
821
832
|
}
|
|
822
833
|
}
|
|
834
|
+
async getDataStoreFromRequest(id, request) {
|
|
835
|
+
var _a, _b, _c;
|
|
836
|
+
const wait = typeof ((_a = request.headers) === null || _a === void 0 ? void 0 : _a[RuntimeHeaders.wait]) === "boolean"
|
|
837
|
+
? (_b = request.headers) === null || _b === void 0 ? void 0 : _b[RuntimeHeaders.wait] : true;
|
|
838
|
+
const dataStoreContext = await this.dataStores.getDataStore(id, wait);
|
|
839
|
+
/**
|
|
840
|
+
* If GC should run and this an external app request with "externalRequest" header, we need to return
|
|
841
|
+
* an error if the data store being requested is marked as unreferenced as per the data store's base
|
|
842
|
+
* GC data.
|
|
843
|
+
*
|
|
844
|
+
* This is a workaround to handle scenarios where a data store shared with an external app is deleted
|
|
845
|
+
* and marked as unreferenced by GC. Returning an error will fail to load the data store for the app.
|
|
846
|
+
*/
|
|
847
|
+
if (((_c = request.headers) === null || _c === void 0 ? void 0 : _c[RuntimeHeaders.externalRequest]) && this.garbageCollector.shouldRunGC) {
|
|
848
|
+
// The data store is referenced if used routes in the base summary has a route to self.
|
|
849
|
+
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
850
|
+
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
851
|
+
if (!(usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/"))) {
|
|
852
|
+
throw runtime_utils_1.responseToException(runtime_utils_1.create404Response(request), request);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const dataStoreChannel = await dataStoreContext.realize();
|
|
856
|
+
// Let the garbage collector know that a data store was requested / loaded. Realize the data store first so
|
|
857
|
+
// that the package path is available.
|
|
858
|
+
this.garbageCollector.nodeUpdated(`/${id}`, "Loaded", dataStoreContext.packagePath, request === null || request === void 0 ? void 0 : request.headers);
|
|
859
|
+
return dataStoreChannel;
|
|
860
|
+
}
|
|
823
861
|
formMetadata() {
|
|
824
862
|
var _a;
|
|
825
863
|
return Object.assign(Object.assign({}, this.createContainerMetadata), { summaryCount: this.summaryCount, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined, gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
|
|
@@ -827,40 +865,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
827
865
|
// the base summary we loaded from. So, use the message from its metadata blob.
|
|
828
866
|
message: (_a = summaryFormat_1.extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage, sessionExpiryTimeoutMs: this.garbageCollector.sessionExpiryTimeoutMs });
|
|
829
867
|
}
|
|
830
|
-
/**
|
|
831
|
-
* Retrieves the runtime for a data store if it's referenced as per the initially summary that it is loaded with.
|
|
832
|
-
* This is a workaround to handle scenarios where a data store shared with an external app is deleted and marked
|
|
833
|
-
* as unreferenced by GC.
|
|
834
|
-
* @param id - Id supplied during creating the data store.
|
|
835
|
-
* @param wait - True if you want to wait for it.
|
|
836
|
-
* @returns the data store runtime if the data store exists and is initially referenced; undefined otherwise.
|
|
837
|
-
*/
|
|
838
|
-
async getDataStoreIfInitiallyReferenced(id, wait = true) {
|
|
839
|
-
const dataStoreContext = await this.dataStores.getDataStore(id, wait);
|
|
840
|
-
// The data store is referenced if used routes in the initial summary has a route to self.
|
|
841
|
-
// Older documents may not have used routes in the summary. They are considered referenced.
|
|
842
|
-
const usedRoutes = (await dataStoreContext.getBaseGCDetails()).usedRoutes;
|
|
843
|
-
if (usedRoutes === undefined || usedRoutes.includes("") || usedRoutes.includes("/")) {
|
|
844
|
-
return dataStoreContext.realize();
|
|
845
|
-
}
|
|
846
|
-
// The data store is unreferenced. Throw a 404 response exception.
|
|
847
|
-
const request = { url: id };
|
|
848
|
-
throw runtime_utils_1.responseToException(runtime_utils_1.create404Response(request), request);
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* Notifies this object to take the snapshot of the container.
|
|
852
|
-
* @deprecated - Use summarize to get summary of the container runtime.
|
|
853
|
-
*/
|
|
854
|
-
async snapshot() {
|
|
855
|
-
const summaryResult = await this.summarize({
|
|
856
|
-
summaryLogger: this.logger,
|
|
857
|
-
fullTree: true,
|
|
858
|
-
trackState: false,
|
|
859
|
-
runGC: this.garbageCollector.shouldRunGC,
|
|
860
|
-
fullGC: true,
|
|
861
|
-
});
|
|
862
|
-
return runtime_utils_1.convertSummaryTreeToITree(summaryResult.summary);
|
|
863
|
-
}
|
|
864
868
|
addContainerStateToSummary(summaryTree) {
|
|
865
869
|
var _a;
|
|
866
870
|
runtime_utils_1.addBlobToSummary(summaryTree, summaryFormat_1.metadataBlobName, JSON.stringify(this.formMetadata()));
|
|
@@ -1022,9 +1026,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1022
1026
|
common_utils_1.assert(await context.isRoot(), 0x12b /* "did not get root data store" */);
|
|
1023
1027
|
return context.realize();
|
|
1024
1028
|
}
|
|
1025
|
-
async getDataStore(id, wait = true) {
|
|
1026
|
-
return (await this.dataStores.getDataStore(id, wait)).realize();
|
|
1027
|
-
}
|
|
1028
1029
|
setFlushMode(mode) {
|
|
1029
1030
|
if (mode === this._flushMode) {
|
|
1030
1031
|
return;
|
|
@@ -1089,28 +1090,84 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1089
1090
|
}
|
|
1090
1091
|
}
|
|
1091
1092
|
async createDataStore(pkg) {
|
|
1092
|
-
|
|
1093
|
+
const internalId = uuid_1.v4();
|
|
1094
|
+
return dataStore_1.channelToDataStore(await this._createDataStore(pkg, false /* isRoot */, internalId), internalId, this, this.dataStores, this.mc.logger);
|
|
1093
1095
|
}
|
|
1094
|
-
|
|
1096
|
+
/**
|
|
1097
|
+
* Creates a root datastore directly with a user generated id and attaches it to storage.
|
|
1098
|
+
* It is vulnerable to name collisions and should not be used.
|
|
1099
|
+
*
|
|
1100
|
+
* This method will be removed. See #6465.
|
|
1101
|
+
*/
|
|
1102
|
+
async createRootDataStoreLegacy(pkg, rootDataStoreId) {
|
|
1095
1103
|
const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
|
|
1096
1104
|
fluidDataStore.bindToContext();
|
|
1097
1105
|
return fluidDataStore;
|
|
1098
1106
|
}
|
|
1107
|
+
async createRootDataStore(pkg, rootDataStoreId) {
|
|
1108
|
+
return this._aliasingEnabled === true ?
|
|
1109
|
+
this.createAndAliasDataStore(pkg, rootDataStoreId) :
|
|
1110
|
+
this.createRootDataStoreLegacy(pkg, rootDataStoreId);
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Creates a data store then attempts to alias it.
|
|
1114
|
+
* If aliasing fails, it will raise an exception.
|
|
1115
|
+
*
|
|
1116
|
+
* This method will be removed. See #6465.
|
|
1117
|
+
*
|
|
1118
|
+
* @param pkg - Package name of the data store
|
|
1119
|
+
* @param alias - Alias to be assigned to the data store
|
|
1120
|
+
* @param props - Properties for the data store
|
|
1121
|
+
* @returns - An aliased data store which can can be found / loaded by alias.
|
|
1122
|
+
*/
|
|
1123
|
+
async createAndAliasDataStore(pkg, alias, props) {
|
|
1124
|
+
const internalId = uuid_1.v4();
|
|
1125
|
+
const dataStore = await this._createDataStore(pkg, false /* isRoot */, internalId, props);
|
|
1126
|
+
const aliasedDataStore = dataStore_1.channelToDataStore(dataStore, internalId, this, this.dataStores, this.mc.logger);
|
|
1127
|
+
const result = await aliasedDataStore.trySetAlias(alias);
|
|
1128
|
+
if (result !== dataStore_1.AliasResult.Success) {
|
|
1129
|
+
throw new container_utils_1.GenericError("dataStoreAliasFailure", undefined /* error */, {
|
|
1130
|
+
alias: {
|
|
1131
|
+
value: alias,
|
|
1132
|
+
tag: telemetry_utils_1.TelemetryDataTag.UserData,
|
|
1133
|
+
},
|
|
1134
|
+
internalId: {
|
|
1135
|
+
value: internalId,
|
|
1136
|
+
tag: telemetry_utils_1.TelemetryDataTag.PackageData,
|
|
1137
|
+
},
|
|
1138
|
+
aliasResult: result,
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
return aliasedDataStore;
|
|
1142
|
+
}
|
|
1099
1143
|
createDetachedRootDataStore(pkg, rootDataStoreId) {
|
|
1100
1144
|
return this.dataStores.createDetachedDataStoreCore(pkg, true, rootDataStoreId);
|
|
1101
1145
|
}
|
|
1102
1146
|
createDetachedDataStore(pkg) {
|
|
1103
1147
|
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
1104
1148
|
}
|
|
1105
|
-
|
|
1149
|
+
/**
|
|
1150
|
+
* Creates a possibly root datastore directly with a possibly user generated id and attaches it to storage.
|
|
1151
|
+
* It is vulnerable to name collisions if both aforementioned conditions are true, and should not be used.
|
|
1152
|
+
*
|
|
1153
|
+
* This method will be removed. See #6465.
|
|
1154
|
+
*/
|
|
1155
|
+
async _createDataStoreWithPropsLegacy(pkg, props, id = uuid_1.v4(), isRoot = false) {
|
|
1106
1156
|
const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
|
|
1107
1157
|
if (isRoot) {
|
|
1108
1158
|
fluidDataStore.bindToContext();
|
|
1109
1159
|
}
|
|
1110
1160
|
return fluidDataStore;
|
|
1111
1161
|
}
|
|
1112
|
-
async
|
|
1113
|
-
return this.
|
|
1162
|
+
async _createDataStoreWithProps(pkg, props, id = uuid_1.v4(), isRoot = false) {
|
|
1163
|
+
return this._aliasingEnabled === true && isRoot ?
|
|
1164
|
+
this.createAndAliasDataStore(pkg, id, props) :
|
|
1165
|
+
this._createDataStoreWithPropsLegacy(pkg, props, id, isRoot);
|
|
1166
|
+
}
|
|
1167
|
+
async _createDataStore(pkg, isRoot, id = uuid_1.v4(), props) {
|
|
1168
|
+
return this.dataStores
|
|
1169
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props)
|
|
1170
|
+
.realize();
|
|
1114
1171
|
}
|
|
1115
1172
|
canSendOps() {
|
|
1116
1173
|
return this.connected && !this.deltaManager.readOnlyInfo.readonly;
|
|
@@ -1168,6 +1225,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1168
1225
|
common_utils_1.assert(this.attachState === container_definitions_1.AttachState.Attached, 0x12e /* "Container Context should already be in attached state" */);
|
|
1169
1226
|
this.emit("attached");
|
|
1170
1227
|
}
|
|
1228
|
+
if (attachState === container_definitions_1.AttachState.Attached && !this.pendingStateManager.hasPendingMessages()) {
|
|
1229
|
+
this.updateDocumentDirtyState(false);
|
|
1230
|
+
}
|
|
1171
1231
|
this.dataStores.setAttachState(attachState);
|
|
1172
1232
|
}
|
|
1173
1233
|
/**
|
|
@@ -1214,13 +1274,14 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1214
1274
|
*/
|
|
1215
1275
|
async summarize(options) {
|
|
1216
1276
|
this.verifyNotClosed();
|
|
1217
|
-
const {
|
|
1277
|
+
const { fullTree = false, trackState = true, summaryLogger = this.logger, runGC = this.garbageCollector.shouldRunGC, runSweep, fullGC, } = options;
|
|
1278
|
+
let gcStats;
|
|
1218
1279
|
if (runGC) {
|
|
1219
|
-
await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1280
|
+
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1220
1281
|
}
|
|
1221
1282
|
const summarizeResult = await this.summarizerNode.summarize(fullTree, trackState);
|
|
1222
1283
|
common_utils_1.assert(summarizeResult.summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1223
|
-
return summarizeResult;
|
|
1284
|
+
return Object.assign(Object.assign({}, summarizeResult), { gcStats });
|
|
1224
1285
|
}
|
|
1225
1286
|
/**
|
|
1226
1287
|
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
@@ -1245,7 +1306,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1245
1306
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
1246
1307
|
* @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
|
|
1247
1308
|
* unreferenced as part of this GC run, this should be used to update the time when it happens.
|
|
1248
|
-
* @returns the statistics of the used state of the data stores.
|
|
1249
1309
|
*/
|
|
1250
1310
|
updateUsedRoutes(usedRoutes, gcTimestamp) {
|
|
1251
1311
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
@@ -1279,7 +1339,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1279
1339
|
* @param options - options controlling how the summary is generated or submitted
|
|
1280
1340
|
*/
|
|
1281
1341
|
async submitSummary(options) {
|
|
1282
|
-
var _a;
|
|
1342
|
+
var _a, _b;
|
|
1283
1343
|
const { fullTree, refreshLatestAck, summaryLogger } = options;
|
|
1284
1344
|
if (refreshLatestAck) {
|
|
1285
1345
|
const latestSummaryRefSeq = await this.refreshLatestSummaryAckFromServer(telemetry_utils_1.ChildLogger.create(summaryLogger, undefined, { all: { safeSummary: true } }));
|
|
@@ -1343,9 +1403,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1343
1403
|
const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
|
|
1344
1404
|
try {
|
|
1345
1405
|
summarizeResult = await this.summarize({
|
|
1346
|
-
summaryLogger,
|
|
1347
1406
|
fullTree: fullTree || forcedFullTree,
|
|
1348
1407
|
trackState: true,
|
|
1408
|
+
summaryLogger,
|
|
1349
1409
|
runGC: this.garbageCollector.shouldRunGC,
|
|
1350
1410
|
});
|
|
1351
1411
|
}
|
|
@@ -1359,7 +1419,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1359
1419
|
const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[runtime_definitions_1.channelsTreeName];
|
|
1360
1420
|
common_utils_1.assert(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
1361
1421
|
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
|
|
1362
|
-
const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount }, partialStats);
|
|
1422
|
+
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 }, partialStats);
|
|
1363
1423
|
const generateSummaryData = {
|
|
1364
1424
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1365
1425
|
summaryTree,
|
|
@@ -1375,7 +1435,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1375
1435
|
const summaryContext = lastAck === undefined
|
|
1376
1436
|
? {
|
|
1377
1437
|
proposalHandle: undefined,
|
|
1378
|
-
ackHandle: (
|
|
1438
|
+
ackHandle: (_b = this.context.getLoadedFromVersion()) === null || _b === void 0 ? void 0 : _b.id,
|
|
1379
1439
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1380
1440
|
}
|
|
1381
1441
|
: {
|
|
@@ -1470,6 +1530,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1470
1530
|
};
|
|
1471
1531
|
this.submit(ContainerMessageType.FluidDataStoreOp, envelope, localOpMetadata);
|
|
1472
1532
|
}
|
|
1533
|
+
submitDataStoreAliasOp(contents, localOpMetadata) {
|
|
1534
|
+
const aliasMessage = contents;
|
|
1535
|
+
if (!dataStore_1.isDataStoreAliasMessage(aliasMessage)) {
|
|
1536
|
+
throw new container_utils_1.UsageError("malformedDataStoreAliasMessage");
|
|
1537
|
+
}
|
|
1538
|
+
this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
|
|
1539
|
+
}
|
|
1473
1540
|
async uploadBlob(blob) {
|
|
1474
1541
|
this.verifyNotClosed();
|
|
1475
1542
|
return this.blobManager.createBlob(blob);
|