@fluidframework/container-runtime 0.58.2001 → 0.59.2000-61729
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 +15 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +65 -9
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +63 -23
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +39 -7
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +161 -29
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +8 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +9 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +22 -6
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +13 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +39 -18
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaScheduler.d.ts +4 -5
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +54 -35
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/garbageCollection.d.ts +31 -27
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +76 -75
- package/dist/garbageCollection.js.map +1 -1
- package/dist/opTelemetry.d.ts +22 -0
- package/dist/opTelemetry.d.ts.map +1 -0
- package/dist/opTelemetry.js +59 -0
- package/dist/opTelemetry.js.map +1 -0
- package/dist/orderedClientElection.d.ts +57 -6
- package/dist/orderedClientElection.d.ts.map +1 -1
- package/dist/orderedClientElection.js +141 -26
- package/dist/orderedClientElection.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/summarizerClientElection.d.ts +2 -0
- package/dist/summarizerClientElection.d.ts.map +1 -1
- package/dist/summarizerClientElection.js +15 -2
- package/dist/summarizerClientElection.js.map +1 -1
- package/dist/summarizerTypes.d.ts +9 -0
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +3 -4
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +14 -3
- package/dist/summaryManager.js.map +1 -1
- package/lib/blobManager.d.ts +15 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +66 -10
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +63 -23
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +39 -7
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +163 -31
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +8 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +9 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +22 -6
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +13 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +39 -18
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaScheduler.d.ts +4 -5
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +54 -35
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/garbageCollection.d.ts +31 -27
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +75 -74
- package/lib/garbageCollection.js.map +1 -1
- package/lib/opTelemetry.d.ts +22 -0
- package/lib/opTelemetry.d.ts.map +1 -0
- package/lib/opTelemetry.js +55 -0
- package/lib/opTelemetry.js.map +1 -0
- package/lib/orderedClientElection.d.ts +57 -6
- package/lib/orderedClientElection.d.ts.map +1 -1
- package/lib/orderedClientElection.js +141 -26
- package/lib/orderedClientElection.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/summarizerClientElection.d.ts +2 -0
- package/lib/summarizerClientElection.d.ts.map +1 -1
- package/lib/summarizerClientElection.js +15 -2
- package/lib/summarizerClientElection.js.map +1 -1
- package/lib/summarizerTypes.d.ts +9 -0
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +3 -4
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +14 -3
- package/lib/summaryManager.js.map +1 -1
- package/package.json +63 -19
- package/src/blobManager.ts +78 -11
- package/src/connectionTelemetry.ts +110 -19
- package/src/containerRuntime.ts +191 -36
- package/src/dataStore.ts +7 -1
- package/src/dataStoreContext.ts +22 -7
- package/src/dataStores.ts +40 -19
- package/src/deltaScheduler.ts +65 -39
- package/src/garbageCollection.ts +92 -78
- package/src/opTelemetry.ts +71 -0
- package/src/orderedClientElection.ts +155 -25
- package/src/packageVersion.ts +1 -1
- package/src/summarizerClientElection.ts +15 -2
- package/src/summarizerTypes.ts +9 -0
- package/src/summaryGenerator.ts +10 -8
- package/src/summaryManager.ts +15 -4
package/dist/containerRuntime.js
CHANGED
|
@@ -10,6 +10,7 @@ const container_utils_1 = require("@fluidframework/container-utils");
|
|
|
10
10
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
11
11
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
12
12
|
const runtime_utils_1 = require("@fluidframework/runtime-utils");
|
|
13
|
+
const garbage_collector_1 = require("@fluidframework/garbage-collector");
|
|
13
14
|
const uuid_1 = require("uuid");
|
|
14
15
|
const containerHandleContext_1 = require("./containerHandleContext");
|
|
15
16
|
const dataStoreRegistry_1 = require("./dataStoreRegistry");
|
|
@@ -30,6 +31,7 @@ const runWhileConnectedCoordinator_1 = require("./runWhileConnectedCoordinator")
|
|
|
30
31
|
const garbageCollection_1 = require("./garbageCollection");
|
|
31
32
|
const dataStore_1 = require("./dataStore");
|
|
32
33
|
const batchTracker_1 = require("./batchTracker");
|
|
34
|
+
const opTelemetry_1 = require("./opTelemetry");
|
|
33
35
|
var ContainerMessageType;
|
|
34
36
|
(function (ContainerMessageType) {
|
|
35
37
|
// An op to be delivered to store
|
|
@@ -82,6 +84,11 @@ const maxOpSizeInBytesKey = "Fluid.ContainerRuntime.MaxOpSizeInBytes";
|
|
|
82
84
|
// in order to account for some extra overhead from serialization
|
|
83
85
|
// to not reach the 1MB limits in socket.io and Kafka.
|
|
84
86
|
const defaultMaxOpSizeInBytes = 768000;
|
|
87
|
+
// By default, the size of the contents for the incoming ops is tracked.
|
|
88
|
+
// However, in certain situations, this may incur a performance hit.
|
|
89
|
+
// The feature-gate below can be used to disable this feature.
|
|
90
|
+
const disableOpTrackingKey = "Fluid.ContainerRuntime.DisableOpTracking";
|
|
91
|
+
const defaultFlushMode = runtime_definitions_1.FlushMode.TurnBased;
|
|
85
92
|
var RuntimeMessage;
|
|
86
93
|
(function (RuntimeMessage) {
|
|
87
94
|
RuntimeMessage["FluidDataStoreOp"] = "component";
|
|
@@ -132,6 +139,7 @@ class ScheduleManagerCore {
|
|
|
132
139
|
this.logger = logger;
|
|
133
140
|
this.localPaused = false;
|
|
134
141
|
this.timePaused = 0;
|
|
142
|
+
this.batchCount = 0;
|
|
135
143
|
// Listen for delta manager sends and add batch metadata to messages
|
|
136
144
|
this.deltaManager.on("prepareSend", (messages) => {
|
|
137
145
|
if (messages.length === 0) {
|
|
@@ -198,13 +206,26 @@ class ScheduleManagerCore {
|
|
|
198
206
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
199
207
|
this.deltaManager.inbound.pause();
|
|
200
208
|
}
|
|
201
|
-
resumeQueue(startBatch,
|
|
209
|
+
resumeQueue(startBatch, messageEndBatch) {
|
|
210
|
+
const endBatch = messageEndBatch.sequenceNumber;
|
|
211
|
+
const duration = common_utils_1.performance.now() - this.timePaused;
|
|
212
|
+
this.batchCount++;
|
|
213
|
+
if (this.batchCount % 1000 === 1) {
|
|
214
|
+
this.logger.sendTelemetryEvent({
|
|
215
|
+
eventName: "BatchStats",
|
|
216
|
+
sequenceNumber: endBatch,
|
|
217
|
+
length: endBatch - startBatch + 1,
|
|
218
|
+
msnDistance: endBatch - messageEndBatch.minimumSequenceNumber,
|
|
219
|
+
duration,
|
|
220
|
+
batchCount: this.batchCount,
|
|
221
|
+
interrupted: this.localPaused,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
202
224
|
// Return early if no change in value
|
|
203
225
|
if (!this.localPaused) {
|
|
204
226
|
return;
|
|
205
227
|
}
|
|
206
228
|
this.localPaused = false;
|
|
207
|
-
const duration = common_utils_1.performance.now() - this.timePaused;
|
|
208
229
|
// Random round number - we want to know when batch waiting paused op processing.
|
|
209
230
|
if (duration > connectionTelemetry_1.latencyThreshold) {
|
|
210
231
|
this.logger.sendErrorEvent({
|
|
@@ -265,7 +286,7 @@ class ScheduleManagerCore {
|
|
|
265
286
|
else if (batchMetadata === false) {
|
|
266
287
|
common_utils_1.assert(this.pauseSequenceNumber !== undefined, 0x2a0 /* "batch presence was validated above" */);
|
|
267
288
|
// Batch is complete, we can process it!
|
|
268
|
-
this.resumeQueue(this.pauseSequenceNumber, message
|
|
289
|
+
this.resumeQueue(this.pauseSequenceNumber, message);
|
|
269
290
|
this.pauseSequenceNumber = undefined;
|
|
270
291
|
this.currentBatchClientId = undefined;
|
|
271
292
|
}
|
|
@@ -297,7 +318,7 @@ class ScheduleManager {
|
|
|
297
318
|
common_utils_1.assert(this.batchClientId === undefined, 0x2a2 /* "Batch is interrupted by other client op. Should be caught by trackPending()" */);
|
|
298
319
|
// This could be the beginning of a new batch or an individual message.
|
|
299
320
|
this.emitter.emit("batchBegin", message);
|
|
300
|
-
this.deltaScheduler.batchBegin();
|
|
321
|
+
this.deltaScheduler.batchBegin(message);
|
|
301
322
|
const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
|
|
302
323
|
if (batch) {
|
|
303
324
|
this.batchClientId = message.clientId;
|
|
@@ -317,7 +338,7 @@ class ScheduleManager {
|
|
|
317
338
|
this.hitError = true;
|
|
318
339
|
this.batchClientId = undefined;
|
|
319
340
|
this.emitter.emit("batchEnd", error, message);
|
|
320
|
-
this.deltaScheduler.batchEnd();
|
|
341
|
+
this.deltaScheduler.batchEnd(message);
|
|
321
342
|
return;
|
|
322
343
|
}
|
|
323
344
|
const batch = (_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.batch;
|
|
@@ -326,7 +347,7 @@ class ScheduleManager {
|
|
|
326
347
|
if (this.batchClientId === undefined || batch === false) {
|
|
327
348
|
this.batchClientId = undefined;
|
|
328
349
|
this.emitter.emit("batchEnd", undefined, message);
|
|
329
|
-
this.deltaScheduler.batchEnd();
|
|
350
|
+
this.deltaScheduler.batchEnd(message);
|
|
330
351
|
return;
|
|
331
352
|
}
|
|
332
353
|
}
|
|
@@ -370,7 +391,6 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
370
391
|
this._storage = _storage;
|
|
371
392
|
this.defaultMaxConsecutiveReconnects = 15;
|
|
372
393
|
this._orderSequentiallyCalls = 0;
|
|
373
|
-
this._flushMode = runtime_definitions_1.FlushMode.TurnBased;
|
|
374
394
|
this.needsFlush = false;
|
|
375
395
|
this.flushTrigger = false;
|
|
376
396
|
this.paused = false;
|
|
@@ -453,12 +473,8 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
453
473
|
((_c = runtimeOptions.useDataStoreAliasing) !== null && _c !== void 0 ? _c : false);
|
|
454
474
|
this._maxOpSizeInBytes = ((_d = this.mc.config.getNumber(maxOpSizeInBytesKey)) !== null && _d !== void 0 ? _d : defaultMaxOpSizeInBytes);
|
|
455
475
|
this.maxConsecutiveReconnects = (_e = this.mc.config.getNumber(maxConsecutiveReconnectsKey)) !== null && _e !== void 0 ? _e : this.defaultMaxConsecutiveReconnects;
|
|
456
|
-
this.
|
|
457
|
-
|
|
458
|
-
* Returns the timestamp of the last message seen by this client. This is used by garbage collector as
|
|
459
|
-
* the current reference timestamp for tracking unreferenced objects.
|
|
460
|
-
*/
|
|
461
|
-
() => { var _a, _b, _c; return (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = this.messageAtLastSummary) === null || _c === void 0 ? void 0 : _c.timestamp; }, () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; }, context.baseSnapshot, async (id) => driver_utils_1.readAndParse(this.storage, id), this.mc.logger, existing, metadata);
|
|
476
|
+
this._flushMode = runtimeOptions.flushMode;
|
|
477
|
+
this.garbageCollector = garbageCollection_1.GarbageCollector.create(this, this.runtimeOptions.gcOptions, (nodePath) => this.getGCNodePackagePath(nodePath), () => { var _a; return (_a = this.messageAtLastSummary) === null || _a === void 0 ? void 0 : _a.timestamp; }, context.baseSnapshot, async (id) => driver_utils_1.readAndParse(this.storage, id), this.mc.logger, existing, metadata);
|
|
462
478
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
463
479
|
this.summarizerNode = runtime_utils_1.createRootSummarizerNodeWithGC(telemetry_utils_1.ChildLogger.create(this.logger, "SummarizerNode"),
|
|
464
480
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
@@ -479,7 +495,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
479
495
|
if (this.context.baseSnapshot) {
|
|
480
496
|
this.summarizerNode.loadBaseSummaryWithoutDifferential(this.context.baseSnapshot);
|
|
481
497
|
}
|
|
482
|
-
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.
|
|
498
|
+
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.getBaseGCDetails(), (path, timestampMs, packagePath) => this.garbageCollector.nodeUpdated(path, "Changed", timestampMs, packagePath), new Map(dataStoreAliasMap), this.garbageCollector.writeDataAtRoot);
|
|
483
499
|
this.blobManager = new blobManager_1.BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
|
|
484
500
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, telemetry_utils_1.ChildLogger.create(this.logger, "ScheduleManager"));
|
|
485
501
|
this.deltaSender = this.deltaManager;
|
|
@@ -567,6 +583,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
567
583
|
this.logger.sendTelemetryEvent(Object.assign(Object.assign(Object.assign({ eventName: "ContainerLoadStats" }, this.createContainerMetadata), this.dataStores.containerLoadStats), { summaryCount: this.summaryCount, 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 }));
|
|
568
584
|
connectionTelemetry_1.ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
569
585
|
batchTracker_1.BindBatchTracker(this, this.logger);
|
|
586
|
+
this.opTracker = new opTelemetry_1.OpTracker(this.deltaManager, this.mc.config.getBoolean(disableOpTrackingKey) === true);
|
|
570
587
|
}
|
|
571
588
|
get IContainerRuntime() { return this; }
|
|
572
589
|
get IFluidRouter() { return this; }
|
|
@@ -589,7 +606,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
589
606
|
runtimeVersion: packageVersion_1.pkgVersion,
|
|
590
607
|
},
|
|
591
608
|
});
|
|
592
|
-
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, } = runtimeOptions;
|
|
609
|
+
const { summaryOptions = {}, gcOptions = {}, loadSequenceNumberVerification = "close", useDataStoreAliasing = false, flushMode = defaultFlushMode, } = runtimeOptions;
|
|
593
610
|
// We pack at data store level only. If isolated channels are disabled,
|
|
594
611
|
// then there are no .channel layers, we pack at level 1, otherwise we pack at level 2
|
|
595
612
|
const packingLevel = summaryOptions.disableIsolatedChannels ? 1 : 2;
|
|
@@ -660,6 +677,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
660
677
|
gcOptions,
|
|
661
678
|
loadSequenceNumberVerification,
|
|
662
679
|
useDataStoreAliasing,
|
|
680
|
+
flushMode,
|
|
663
681
|
}, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
|
|
664
682
|
return runtime;
|
|
665
683
|
}
|
|
@@ -878,12 +896,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
878
896
|
const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
|
|
879
897
|
runtime_utils_1.addBlobToSummary(summaryTree, summaryFormat_1.electedSummarizerBlobName, electedSummarizerContent);
|
|
880
898
|
}
|
|
881
|
-
const
|
|
899
|
+
const summary = this.blobManager.summarize();
|
|
882
900
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
883
901
|
// and the blob manager can handle the tree not existing when loading
|
|
884
|
-
if (
|
|
885
|
-
|
|
886
|
-
runtime_utils_1.addTreeToSummary(summaryTree, summaryFormat_1.blobsTreeName, blobsTree);
|
|
902
|
+
if (Object.keys(summary.summary.tree).length > 0) {
|
|
903
|
+
runtime_utils_1.addTreeToSummary(summaryTree, summaryFormat_1.blobsTreeName, summary);
|
|
887
904
|
}
|
|
888
905
|
if (this.garbageCollector.writeDataAtRoot) {
|
|
889
906
|
const gcSummary = this.garbageCollector.summarize();
|
|
@@ -1072,6 +1089,11 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1072
1089
|
if (mode === this._flushMode) {
|
|
1073
1090
|
return;
|
|
1074
1091
|
}
|
|
1092
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1093
|
+
eventName: "FlushMode Updated",
|
|
1094
|
+
old: this._flushMode,
|
|
1095
|
+
new: mode,
|
|
1096
|
+
});
|
|
1075
1097
|
// Flush any pending batches if switching to immediate
|
|
1076
1098
|
if (mode === runtime_definitions_1.FlushMode.Immediate) {
|
|
1077
1099
|
this.flush();
|
|
@@ -1144,7 +1166,14 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1144
1166
|
*/
|
|
1145
1167
|
async createRootDataStoreLegacy(pkg, rootDataStoreId) {
|
|
1146
1168
|
const fluidDataStore = await this._createDataStore(pkg, true /* isRoot */, rootDataStoreId);
|
|
1147
|
-
|
|
1169
|
+
// back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel. For
|
|
1170
|
+
// older versions, we still have to call bindToContext.
|
|
1171
|
+
if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
|
|
1172
|
+
fluidDataStore.makeVisibleAndAttachGraph();
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
fluidDataStore.bindToContext();
|
|
1176
|
+
}
|
|
1148
1177
|
return fluidDataStore;
|
|
1149
1178
|
}
|
|
1150
1179
|
async createRootDataStore(pkg, rootDataStoreId) {
|
|
@@ -1198,7 +1227,18 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1198
1227
|
async _createDataStoreWithPropsLegacy(pkg, props, id = uuid_1.v4(), isRoot = false) {
|
|
1199
1228
|
const fluidDataStore = await this.dataStores._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, isRoot, props).realize();
|
|
1200
1229
|
if (isRoot) {
|
|
1201
|
-
|
|
1230
|
+
// back-compat 0.59.1000 - makeVisibleAndAttachGraph was added in this version to IFluidDataStoreChannel.
|
|
1231
|
+
// For older versions, we still have to call bindToContext.
|
|
1232
|
+
if (fluidDataStore.makeVisibleAndAttachGraph !== undefined) {
|
|
1233
|
+
fluidDataStore.makeVisibleAndAttachGraph();
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
fluidDataStore.bindToContext();
|
|
1237
|
+
}
|
|
1238
|
+
this.logger.sendTelemetryEvent({
|
|
1239
|
+
eventName: "Root datastore with props",
|
|
1240
|
+
hasProps: props !== undefined,
|
|
1241
|
+
});
|
|
1202
1242
|
}
|
|
1203
1243
|
return dataStore_1.channelToDataStore(fluidDataStore, id, this, this.dataStores, this.mc.logger);
|
|
1204
1244
|
}
|
|
@@ -1322,9 +1362,9 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1322
1362
|
if (runGC) {
|
|
1323
1363
|
gcStats = await this.collectGarbage({ logger: summaryLogger, runSweep, fullGC });
|
|
1324
1364
|
}
|
|
1325
|
-
const
|
|
1326
|
-
common_utils_1.assert(
|
|
1327
|
-
return
|
|
1365
|
+
const { stats, summary } = await this.summarizerNode.summarize(fullTree, trackState);
|
|
1366
|
+
common_utils_1.assert(summary.type === protocol_definitions_1.SummaryType.Tree, 0x12f /* "Container Runtime's summarize should always return a tree" */);
|
|
1367
|
+
return { stats, summary, gcStats };
|
|
1328
1368
|
}
|
|
1329
1369
|
/**
|
|
1330
1370
|
* Implementation of IGarbageCollectionRuntime::updateStateBeforeGC.
|
|
@@ -1341,7 +1381,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1341
1381
|
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
1342
1382
|
*/
|
|
1343
1383
|
async getGCData(fullGC) {
|
|
1344
|
-
|
|
1384
|
+
const builder = new garbage_collector_1.GCDataBuilder();
|
|
1385
|
+
const dsGCData = await this.dataStores.getGCData(fullGC);
|
|
1386
|
+
builder.addNodes(dsGCData.gcNodes);
|
|
1387
|
+
const blobsGCData = this.blobManager.getGCData(fullGC);
|
|
1388
|
+
builder.addNodes(blobsGCData.gcNodes);
|
|
1389
|
+
return builder.getGCData();
|
|
1345
1390
|
}
|
|
1346
1391
|
/**
|
|
1347
1392
|
* Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
|
|
@@ -1355,7 +1400,78 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1355
1400
|
// summarizing is required and asserted by the the summarizer node. We are the root and are
|
|
1356
1401
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1357
1402
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1358
|
-
|
|
1403
|
+
const dataStoreUsedRoutes = [];
|
|
1404
|
+
for (const route of usedRoutes) {
|
|
1405
|
+
if (route.split("/")[1] !== blobManager_1.BlobManager.basePath) {
|
|
1406
|
+
dataStoreUsedRoutes.push(route);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
return this.dataStores.updateUsedRoutes(dataStoreUsedRoutes, gcTimestamp);
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* When running GC in test mode, this is called to delete objects whose routes are unused. This enables testing
|
|
1413
|
+
* scenarios with accessing deleted content.
|
|
1414
|
+
* @param unusedRoutes - The routes that are unused in all data stores in this Container.
|
|
1415
|
+
*/
|
|
1416
|
+
deleteUnusedRoutes(unusedRoutes) {
|
|
1417
|
+
const blobManagerUnusedRoutes = [];
|
|
1418
|
+
const dataStoreUnusedRoutes = [];
|
|
1419
|
+
for (const route of unusedRoutes) {
|
|
1420
|
+
if (this.isBlobPath(route)) {
|
|
1421
|
+
blobManagerUnusedRoutes.push(route);
|
|
1422
|
+
}
|
|
1423
|
+
else {
|
|
1424
|
+
dataStoreUnusedRoutes.push(route);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
this.blobManager.deleteUnusedRoutes(blobManagerUnusedRoutes);
|
|
1428
|
+
this.dataStores.deleteUnusedRoutes(dataStoreUnusedRoutes);
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Returns a server generated referenced timestamp to be used to track unreferenced nodes by GC.
|
|
1432
|
+
*/
|
|
1433
|
+
getCurrentReferenceTimestampMs() {
|
|
1434
|
+
var _a, _b, _c;
|
|
1435
|
+
// Use the timestamp of the last message seen by this client as that is server generated. If no messages have
|
|
1436
|
+
// been processed, use the timestamp of the message from the last summary.
|
|
1437
|
+
return (_b = (_a = this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = this.messageAtLastSummary) === null || _c === void 0 ? void 0 : _c.timestamp;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Returns the type of the GC node. Currently, there are nodes that belong to data store and nodes that belong
|
|
1441
|
+
* to the blob manager.
|
|
1442
|
+
*/
|
|
1443
|
+
getNodeType(nodePath) {
|
|
1444
|
+
if (this.isBlobPath(nodePath)) {
|
|
1445
|
+
return garbageCollection_1.GCNodeType.Blob;
|
|
1446
|
+
}
|
|
1447
|
+
if (this.dataStores.isDataStoreNode(nodePath)) {
|
|
1448
|
+
return garbageCollection_1.GCNodeType.DataStore;
|
|
1449
|
+
}
|
|
1450
|
+
// Root node ("/") and DDS nodes belong to "Other" node types.
|
|
1451
|
+
return garbageCollection_1.GCNodeType.Other;
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
1455
|
+
* data store or an attachment blob.
|
|
1456
|
+
*/
|
|
1457
|
+
getGCNodePackagePath(nodePath) {
|
|
1458
|
+
// If the node is a blob, return "_blobs" as the package path.
|
|
1459
|
+
if (this.isBlobPath(nodePath)) {
|
|
1460
|
+
return ["_blobs"];
|
|
1461
|
+
}
|
|
1462
|
+
const dataStorePkgPath = this.dataStores.getDataStorePackagePath(nodePath);
|
|
1463
|
+
common_utils_1.assert(dataStorePkgPath !== undefined, 0x2d6 /* "Package path requested for unknown node type." */);
|
|
1464
|
+
return dataStorePkgPath;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Returns whether a given path is for attachment blobs that are in the format - "/BlobManager.basePath/...".
|
|
1468
|
+
*/
|
|
1469
|
+
isBlobPath(path) {
|
|
1470
|
+
const pathParts = path.split("/");
|
|
1471
|
+
if (pathParts.length < 2 || pathParts[1] !== blobManager_1.BlobManager.basePath) {
|
|
1472
|
+
return false;
|
|
1473
|
+
}
|
|
1474
|
+
return true;
|
|
1359
1475
|
}
|
|
1360
1476
|
/**
|
|
1361
1477
|
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
@@ -1399,6 +1515,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1399
1515
|
try {
|
|
1400
1516
|
await this.deltaManager.inbound.pause();
|
|
1401
1517
|
const summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
1518
|
+
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
1402
1519
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
1403
1520
|
// We should be here is we haven't processed be here. If we are of if the last message's sequence number
|
|
1404
1521
|
// doesn't match the last processed sequence number, log an error.
|
|
@@ -1438,7 +1555,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1438
1555
|
};
|
|
1439
1556
|
let continueResult = checkContinue();
|
|
1440
1557
|
if (!continueResult.continue) {
|
|
1441
|
-
return {
|
|
1558
|
+
return {
|
|
1559
|
+
stage: "base",
|
|
1560
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1561
|
+
minimumSequenceNumber,
|
|
1562
|
+
error: continueResult.error,
|
|
1563
|
+
};
|
|
1442
1564
|
}
|
|
1443
1565
|
// increment summary count
|
|
1444
1566
|
if (this.summaryCount !== undefined) {
|
|
@@ -1461,7 +1583,12 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1461
1583
|
});
|
|
1462
1584
|
}
|
|
1463
1585
|
catch (error) {
|
|
1464
|
-
return {
|
|
1586
|
+
return {
|
|
1587
|
+
stage: "base",
|
|
1588
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
1589
|
+
minimumSequenceNumber,
|
|
1590
|
+
error,
|
|
1591
|
+
};
|
|
1465
1592
|
}
|
|
1466
1593
|
const { summary: summaryTree, stats: partialStats } = summarizeResult;
|
|
1467
1594
|
// Now that we have generated the summary, update the message at last summary to the last message processed.
|
|
@@ -1472,9 +1599,13 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1472
1599
|
const dataStoreTree = this.disableIsolatedChannels ? summaryTree : summaryTree.tree[runtime_definitions_1.channelsTreeName];
|
|
1473
1600
|
common_utils_1.assert(dataStoreTree.type === protocol_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
1474
1601
|
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === protocol_definitions_1.SummaryType.Handle).length;
|
|
1475
|
-
const
|
|
1602
|
+
const gcSummaryTreeStats = summaryTree.tree[garbageCollection_1.gcTreeKey]
|
|
1603
|
+
? runtime_utils_1.calculateStats(summaryTree.tree[garbageCollection_1.gcTreeKey])
|
|
1604
|
+
: undefined;
|
|
1605
|
+
const summaryStats = Object.assign({ dataStoreCount: this.dataStores.size, summarizedDataStoreCount: this.dataStores.size - handleCount, gcStateUpdatedDataStoreCount: (_b = summarizeResult.gcStats) === null || _b === void 0 ? void 0 : _b.updatedDataStoreCount, gcBlobNodeCount: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.blobNodeCount, gcTotalBlobsSize: gcSummaryTreeStats === null || gcSummaryTreeStats === void 0 ? void 0 : gcSummaryTreeStats.totalBlobSize, opsSizesSinceLastSummary: this.opTracker.opsSizeAccumulator, nonSystemOpsSinceLastSummary: this.opTracker.nonSystemOpCount }, partialStats);
|
|
1476
1606
|
const generateSummaryData = {
|
|
1477
1607
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
1608
|
+
minimumSequenceNumber,
|
|
1478
1609
|
summaryTree,
|
|
1479
1610
|
summaryStats,
|
|
1480
1611
|
generateDuration: trace.trace().duration,
|
|
@@ -1525,6 +1656,7 @@ class ContainerRuntime extends common_utils_1.TypedEventEmitter {
|
|
|
1525
1656
|
}
|
|
1526
1657
|
const submitData = Object.assign(Object.assign({ stage: "submit" }, uploadData), { clientSequenceNumber, submitOpDuration: trace.trace().duration });
|
|
1527
1658
|
this.summarizerNode.completeSummary(handle);
|
|
1659
|
+
this.opTracker.reset();
|
|
1528
1660
|
return submitData;
|
|
1529
1661
|
}
|
|
1530
1662
|
finally {
|