@fluidframework/container-runtime 0.52.0 → 0.54.0-47413
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/containerHandleContext.d.ts +0 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js +0 -1
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +43 -19
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +201 -111
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +33 -4
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +45 -17
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +14 -10
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +73 -41
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +82 -15
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +359 -26
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- 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/pendingStateManager.d.ts +0 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +0 -36
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runningSummarizer.d.ts +3 -2
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +6 -6
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summarizer.d.ts +23 -3
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +135 -45
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerTypes.d.ts +3 -10
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryFormat.d.ts +10 -1
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +2 -1
- package/dist/summaryFormat.js.map +1 -1
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +1 -3
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts +0 -15
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +1 -35
- package/dist/summaryManager.js.map +1 -1
- package/lib/containerHandleContext.d.ts +0 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js +0 -1
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +43 -19
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +206 -117
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +33 -4
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +45 -17
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +14 -10
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +76 -44
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +82 -15
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +361 -28
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +2 -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/pendingStateManager.d.ts +0 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +0 -36
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runningSummarizer.d.ts +3 -2
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +6 -6
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summarizer.d.ts +23 -3
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +135 -45
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerTypes.d.ts +3 -10
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryFormat.d.ts +10 -1
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +1 -0
- package/lib/summaryFormat.js.map +1 -1
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +1 -3
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts +0 -15
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +1 -34
- package/lib/summaryManager.js.map +1 -1
- package/package.json +14 -14
- package/src/containerHandleContext.ts +0 -1
- package/src/containerRuntime.ts +280 -140
- package/src/dataStoreContext.ts +59 -20
- package/src/dataStores.ts +116 -54
- package/src/garbageCollection.ts +492 -29
- package/src/index.ts +20 -2
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +0 -43
- package/src/runningSummarizer.ts +12 -10
- package/src/summarizer.ts +154 -53
- package/src/summarizerTypes.ts +3 -11
- package/src/summaryFormat.ts +11 -1
- package/src/summaryGenerator.ts +2 -3
- package/src/summaryManager.ts +2 -49
- package/dist/localStorageFeatureGates.d.ts +0 -13
- package/dist/localStorageFeatureGates.d.ts.map +0 -1
- package/dist/localStorageFeatureGates.js +0 -31
- package/dist/localStorageFeatureGates.js.map +0 -1
- package/lib/localStorageFeatureGates.d.ts +0 -13
- package/lib/localStorageFeatureGates.d.ts.map +0 -1
- package/lib/localStorageFeatureGates.js +0 -27
- package/lib/localStorageFeatureGates.js.map +0 -1
- package/src/localStorageFeatureGates.ts +0 -27
package/lib/containerRuntime.js
CHANGED
|
@@ -2,34 +2,33 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { AttachState, } from "@fluidframework/container-definitions";
|
|
5
|
+
import { AttachState, LoaderHeader, } from "@fluidframework/container-definitions";
|
|
6
6
|
import { assert, Trace, TypedEventEmitter, unreachableCase, performance, } from "@fluidframework/common-utils";
|
|
7
|
-
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, } from "@fluidframework/telemetry-utils";
|
|
7
|
+
import { ChildLogger, raiseConnectedEvent, PerformanceEvent, normalizeError, TaggedLoggerAdapter, loggerToMonitoringContext, } from "@fluidframework/telemetry-utils";
|
|
8
|
+
import { DriverHeader } from "@fluidframework/driver-definitions";
|
|
8
9
|
import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-utils";
|
|
9
|
-
import { DataCorruptionError, GenericError, extractSafePropertiesFromMessage } from "@fluidframework/container-utils";
|
|
10
|
-
import { BlobTreeEntry, TreeTreeEntry, } from "@fluidframework/protocol-base";
|
|
10
|
+
import { CreateProcessingError, DataCorruptionError, GenericError, UsageError, extractSafePropertiesFromMessage, } from "@fluidframework/container-utils";
|
|
11
11
|
import { MessageType, SummaryType, } from "@fluidframework/protocol-definitions";
|
|
12
12
|
import { FlushMode, channelsTreeName, } from "@fluidframework/runtime-definitions";
|
|
13
|
-
import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC,
|
|
13
|
+
import { addBlobToSummary, addTreeToSummary, convertToSummaryTree, createRootSummarizerNodeWithGC, RequestParser, create404Response, exceptionToResponse, requestFluidObject, responseToException, seqFromTree, convertSummaryTreeToITree, } from "@fluidframework/runtime-utils";
|
|
14
14
|
import { v4 as uuid } from "uuid";
|
|
15
15
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
16
16
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
17
17
|
import { Summarizer } from "./summarizer";
|
|
18
|
-
import {
|
|
18
|
+
import { SummaryManager } from "./summaryManager";
|
|
19
19
|
import { DeltaScheduler } from "./deltaScheduler";
|
|
20
20
|
import { ReportOpPerfTelemetry, latencyThreshold } from "./connectionTelemetry";
|
|
21
21
|
import { PendingStateManager } from "./pendingStateManager";
|
|
22
22
|
import { pkgVersion } from "./packageVersion";
|
|
23
23
|
import { BlobManager } from "./blobManager";
|
|
24
24
|
import { DataStores, getSummaryForDatastores } from "./dataStores";
|
|
25
|
-
import { blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
|
|
25
|
+
import { aliasBlobName, blobsTreeName, chunksBlobName, electedSummarizerBlobName, extractSummaryMetadataMessage, metadataBlobName, wrapSummaryInChannelsTree, } from "./summaryFormat";
|
|
26
26
|
import { SummaryCollection } from "./summaryCollection";
|
|
27
|
-
import { getLocalStorageFeatureGate } from "./localStorageFeatureGates";
|
|
28
27
|
import { OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
|
|
29
28
|
import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
|
|
30
29
|
import { formExponentialFn, Throttler } from "./throttler";
|
|
31
30
|
import { RunWhileConnectedCoordinator } from "./runWhileConnectedCoordinator";
|
|
32
|
-
import { GarbageCollector, } from "./garbageCollection";
|
|
31
|
+
import { GarbageCollector, gcTreeKey, } from "./garbageCollection";
|
|
33
32
|
export var ContainerMessageType;
|
|
34
33
|
(function (ContainerMessageType) {
|
|
35
34
|
// An op to be delivered to store
|
|
@@ -42,6 +41,8 @@ export var ContainerMessageType;
|
|
|
42
41
|
ContainerMessageType["BlobAttach"] = "blobAttach";
|
|
43
42
|
// Ties our new clientId to our old one on reconnect
|
|
44
43
|
ContainerMessageType["Rejoin"] = "rejoin";
|
|
44
|
+
// Sets the alias of a root data store
|
|
45
|
+
ContainerMessageType["Alias"] = "alias";
|
|
45
46
|
})(ContainerMessageType || (ContainerMessageType = {}));
|
|
46
47
|
// Consider idle 5s of no activity. And snapshot if a minute has gone by with no snapshot.
|
|
47
48
|
const IdleDetectionTime = 5000;
|
|
@@ -56,12 +57,13 @@ const DefaultSummaryConfiguration = {
|
|
|
56
57
|
maxAckWaitTime: 120000,
|
|
57
58
|
};
|
|
58
59
|
// Local storage key to set the default flush mode to TurnBased
|
|
59
|
-
const turnBasedFlushModeKey = "
|
|
60
|
+
const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
|
|
60
61
|
export function isRuntimeMessage(message) {
|
|
61
62
|
switch (message.type) {
|
|
62
63
|
case ContainerMessageType.FluidDataStoreOp:
|
|
63
64
|
case ContainerMessageType.ChunkedOp:
|
|
64
65
|
case ContainerMessageType.Attach:
|
|
66
|
+
case ContainerMessageType.Alias:
|
|
65
67
|
case ContainerMessageType.BlobAttach:
|
|
66
68
|
case ContainerMessageType.Rejoin:
|
|
67
69
|
case MessageType.Operation:
|
|
@@ -306,13 +308,27 @@ export class ScheduleManager {
|
|
|
306
308
|
* ContainerRuntime's perspective.
|
|
307
309
|
*/
|
|
308
310
|
export const agentSchedulerId = "_scheduler";
|
|
311
|
+
// safely check navigator and get the hardware spec value
|
|
312
|
+
export function getDeviceSpec() {
|
|
313
|
+
try {
|
|
314
|
+
if (typeof navigator === "object" && navigator !== null) {
|
|
315
|
+
return {
|
|
316
|
+
deviceMemory: navigator.deviceMemory,
|
|
317
|
+
hardwareConcurrency: navigator.hardwareConcurrency,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (_a) {
|
|
322
|
+
}
|
|
323
|
+
return {};
|
|
324
|
+
}
|
|
309
325
|
/**
|
|
310
326
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
311
327
|
* It will define the store level mappings.
|
|
312
328
|
*/
|
|
313
329
|
export class ContainerRuntime extends TypedEventEmitter {
|
|
314
|
-
constructor(context, registry, metadata, electedSummarizerData, chunks, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
|
|
315
|
-
var _a, _b, _c, _d;
|
|
330
|
+
constructor(context, registry, metadata, electedSummarizerData, chunks, dataStoreAliasMap, runtimeOptions, containerScope, logger, existing, blobManagerSnapshot, requestHandler, _storage) {
|
|
331
|
+
var _a, _b, _c, _d, _e;
|
|
316
332
|
super();
|
|
317
333
|
this.context = context;
|
|
318
334
|
this.registry = registry;
|
|
@@ -321,14 +337,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
321
337
|
this.logger = logger;
|
|
322
338
|
this.requestHandler = requestHandler;
|
|
323
339
|
this._storage = _storage;
|
|
324
|
-
// back-compat: Used by loader in <= 0.35
|
|
325
|
-
/**
|
|
326
|
-
* @internal
|
|
327
|
-
* @deprecated Back-compat only. Used by the loader in versions earlier than 0.35.
|
|
328
|
-
*/
|
|
329
|
-
this.runtimeVersion = pkgVersion;
|
|
330
340
|
this._orderSequentiallyCalls = 0;
|
|
331
|
-
this._flushMode = ContainerRuntime.defaultFlushMode;
|
|
332
341
|
this.needsFlush = false;
|
|
333
342
|
this.flushTrigger = false;
|
|
334
343
|
this.paused = false;
|
|
@@ -371,7 +380,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
371
380
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
372
381
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
373
382
|
// because it is a misuse of the API rather than an expected failure.
|
|
374
|
-
throw new
|
|
383
|
+
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
375
384
|
}
|
|
376
385
|
};
|
|
377
386
|
this.enqueueSummarize = (...args) => {
|
|
@@ -385,18 +394,47 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
385
394
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
386
395
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
387
396
|
// because it is a misuse of the API rather than an expected failure.
|
|
388
|
-
throw new
|
|
397
|
+
throw new UsageError(`Can't summarize, disableSummaries: ${this.summariesDisabled}`);
|
|
389
398
|
}
|
|
390
399
|
};
|
|
391
400
|
this.baseSummaryMessage = metadata === null || metadata === void 0 ? void 0 : metadata.message;
|
|
401
|
+
// If this is an existing container, we get values from metadata.
|
|
402
|
+
// otherwise, we initialize them.
|
|
403
|
+
if (existing) {
|
|
404
|
+
this.createContainerMetadata = {
|
|
405
|
+
createContainerRuntimeVersion: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerRuntimeVersion,
|
|
406
|
+
createContainerTimestamp: metadata === null || metadata === void 0 ? void 0 : metadata.createContainerTimestamp,
|
|
407
|
+
};
|
|
408
|
+
this.summaryCount = metadata === null || metadata === void 0 ? void 0 : metadata.summaryCount;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
this.createContainerMetadata = {
|
|
412
|
+
createContainerRuntimeVersion: pkgVersion,
|
|
413
|
+
createContainerTimestamp: Date.now(),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
392
416
|
// Default to false (enabled).
|
|
393
417
|
this.disableIsolatedChannels = (_a = this.runtimeOptions.summaryOptions.disableIsolatedChannels) !== null && _a !== void 0 ? _a : false;
|
|
394
418
|
this._connected = this.context.connected;
|
|
395
419
|
this.chunkMap = new Map(chunks);
|
|
396
|
-
this.
|
|
397
|
-
this.
|
|
398
|
-
this.
|
|
399
|
-
|
|
420
|
+
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
421
|
+
this.mc = loggerToMonitoringContext(ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
422
|
+
this._flushMode =
|
|
423
|
+
((_b = this.mc.config.getBoolean(turnBasedFlushModeKey)) !== null && _b !== void 0 ? _b : false) ? FlushMode.TurnBased : FlushMode.Immediate;
|
|
424
|
+
/**
|
|
425
|
+
* Function that return the current server timestamp. This is used by the garbage collector to set the
|
|
426
|
+
* time when a node becomes unreferenced.
|
|
427
|
+
* We use the timestamp of the last op for current timestamp. However, there can be cases where
|
|
428
|
+
* we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
|
|
429
|
+
* of this client's connection.
|
|
430
|
+
*/
|
|
431
|
+
const getCurrentTimestamp = () => {
|
|
432
|
+
var _a, _b, _c;
|
|
433
|
+
const client = this.clientId !== undefined ? this.getAudience().getMember(this.clientId) : undefined;
|
|
434
|
+
const timestamp = client === null || client === void 0 ? void 0 : client.timestamp;
|
|
435
|
+
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();
|
|
436
|
+
};
|
|
437
|
+
this.garbageCollector = GarbageCollector.create(this, this.runtimeOptions.gcOptions, (unusedRoutes) => this.dataStores.deleteUnusedRoutes(unusedRoutes), getCurrentTimestamp, context.baseSnapshot, async (id) => readAndParse(this.storage, id), this.mc.logger, existing, metadata);
|
|
400
438
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
401
439
|
this.summarizerNode = createRootSummarizerNodeWithGC(ChildLogger.create(this.logger, "SummarizerNode"),
|
|
402
440
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
@@ -413,69 +451,58 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
413
451
|
throwOnFailure: true,
|
|
414
452
|
// If GC should not run, let the summarizer node know so that it does not track GC state.
|
|
415
453
|
gcDisabled: !this.garbageCollector.shouldRunGC,
|
|
416
|
-
// The max duration for which objects can be unreferenced before they are eligible for deletion.
|
|
417
|
-
maxUnreferencedDurationMs: this.runtimeOptions.gcOptions.maxUnreferencedDurationMs,
|
|
418
454
|
});
|
|
419
455
|
if (this.context.baseSnapshot) {
|
|
420
456
|
this.summarizerNode.loadBaseSummaryWithoutDifferential(this.context.baseSnapshot);
|
|
421
457
|
}
|
|
422
|
-
this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getInitialGCSummaryDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getInitialGCSummaryDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.
|
|
423
|
-
this.blobManager = new BlobManager(this.
|
|
458
|
+
this.dataStores = new DataStores(getSummaryForDatastores(context.baseSnapshot, metadata), this, (attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg), (id, createParam) => (summarizeInternal, getGCDataFn, getInitialGCSummaryDetailsFn) => this.summarizerNode.createChild(summarizeInternal, id, createParam, undefined, getGCDataFn, getInitialGCSummaryDetailsFn), (id) => this.summarizerNode.deleteChild(id), this.mc.logger, async () => this.garbageCollector.getDataStoreBaseGCDetails(), (id) => this.garbageCollector.nodeChanged(id), new Map(dataStoreAliasMap));
|
|
459
|
+
this.blobManager = new BlobManager(this.handleContext, blobManagerSnapshot, () => this.storage, (blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }), this, this.logger);
|
|
424
460
|
this.scheduleManager = new ScheduleManager(context.deltaManager, this, ChildLogger.create(this.logger, "ScheduleManager"));
|
|
425
461
|
this.deltaSender = this.deltaManager;
|
|
426
462
|
this.pendingStateManager = new PendingStateManager(this, async (type, content) => this.applyStashedOp(type, content), context.pendingLocalState);
|
|
427
463
|
this.context.quorum.on("removeMember", (clientId) => {
|
|
428
464
|
this.clearPartialChunks(clientId);
|
|
429
465
|
});
|
|
430
|
-
this.context.quorum.on("addProposal", (proposal) => {
|
|
431
|
-
if (proposal.key === "code" || proposal.key === "code2") {
|
|
432
|
-
this.emit("codeDetailsProposed", proposal.value, proposal);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
466
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
436
|
-
// Only create a SummaryManager if summaries are enabled and we are not the summarizer client
|
|
437
467
|
// Map the deprecated generateSummaries flag to disableSummaries.
|
|
438
468
|
if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
|
|
439
469
|
this.runtimeOptions.summaryOptions.disableSummaries = true;
|
|
440
470
|
}
|
|
441
|
-
if (this.summariesDisabled
|
|
442
|
-
this.
|
|
471
|
+
if (this.summariesDisabled) {
|
|
472
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
443
473
|
}
|
|
444
474
|
else {
|
|
445
|
-
const maxOpsSinceLastSummary = (_b = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _b !== void 0 ? _b : 7000;
|
|
446
|
-
const defaultAction = () => {
|
|
447
|
-
if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
448
|
-
this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
|
|
449
|
-
// unregister default to no log on every op after falling behind
|
|
450
|
-
// and register summary ack handler to re-register this handler
|
|
451
|
-
// after successful summary
|
|
452
|
-
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
453
|
-
this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
|
|
454
|
-
// we've caught up, so re-register the default action to monitor for
|
|
455
|
-
// falling behind, and unregister ourself
|
|
456
|
-
this.summaryCollection.on("default", defaultAction);
|
|
457
|
-
});
|
|
458
|
-
this.summaryCollection.off("default", defaultAction);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
this.summaryCollection.on("default", defaultAction);
|
|
462
475
|
const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
|
|
463
476
|
const orderedClientCollection = new OrderedClientCollection(orderedClientLogger, this.context.deltaManager, this.context.quorum);
|
|
464
477
|
const orderedClientElectionForSummarizer = new OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData !== null && electedSummarizerData !== void 0 ? electedSummarizerData : this.context.deltaManager.lastSequenceNumber, SummarizerClientElection.isClientEligible);
|
|
465
|
-
const summarizerClientElectionEnabled = (_c =
|
|
478
|
+
const summarizerClientElectionEnabled = (_c = this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection")) !== null && _c !== void 0 ? _c : ((_d = this.runtimeOptions.summaryOptions) === null || _d === void 0 ? void 0 : _d.summarizerClientElection) === true;
|
|
479
|
+
const maxOpsSinceLastSummary = (_e = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary) !== null && _e !== void 0 ? _e : 7000;
|
|
466
480
|
this.summarizerClientElection = new SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, maxOpsSinceLastSummary, summarizerClientElectionEnabled);
|
|
467
481
|
if (this.context.clientDetails.type === summarizerClientType) {
|
|
468
|
-
this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.
|
|
482
|
+
this._summarizer = new Summarizer("/_summarizer", this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => RunWhileConnectedCoordinator.create(runtime));
|
|
469
483
|
}
|
|
470
484
|
else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
485
|
+
// Only create a SummaryManager and SummarizerClientElection
|
|
486
|
+
// if summaries are enabled and we are not the summarizer client.
|
|
487
|
+
const defaultAction = () => {
|
|
488
|
+
if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
489
|
+
this.logger.sendErrorEvent({ eventName: "SummaryStatus:Behind" });
|
|
490
|
+
// unregister default to no log on every op after falling behind
|
|
491
|
+
// and register summary ack handler to re-register this handler
|
|
492
|
+
// after successful summary
|
|
493
|
+
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
494
|
+
this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:CaughtUp" });
|
|
495
|
+
// we've caught up, so re-register the default action to monitor for
|
|
496
|
+
// falling behind, and unregister ourself
|
|
497
|
+
this.summaryCollection.on("default", defaultAction);
|
|
498
|
+
});
|
|
499
|
+
this.summaryCollection.off("default", defaultAction);
|
|
500
|
+
}
|
|
476
501
|
};
|
|
502
|
+
this.summaryCollection.on("default", defaultAction);
|
|
503
|
+
// Create the SummaryManager and mark the initial state
|
|
477
504
|
this.summaryManager = new SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
478
|
-
this.summaryCollection, this.logger, formRequestSummarizerFn(this.context.loader
|
|
505
|
+
this.summaryCollection, this.logger, this.formRequestSummarizerFn(this.context.loader), new Throttler(60 * 1000, // 60 sec delay window
|
|
479
506
|
30 * 1000, // 30 sec max delay
|
|
480
507
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
481
508
|
formExponentialFn({ coefficient: 20, initialDelay: 0 })), {
|
|
@@ -488,7 +515,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
488
515
|
this.deltaManager.on("readonly", (readonly) => {
|
|
489
516
|
// we accumulate ops while being in read-only state.
|
|
490
517
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
491
|
-
assert(readonly === this.deltaManager.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
518
|
+
assert(readonly === this.deltaManager.readOnlyInfo.readonly, 0x124 /* "inconsistent readonly property/event state" */);
|
|
492
519
|
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
493
520
|
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
494
521
|
// sequenced by server and will never be sequenced (i.e. was lost)
|
|
@@ -507,6 +534,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
507
534
|
if (context.pendingLocalState !== undefined) {
|
|
508
535
|
this.deltaManager.on("op", this.onOp);
|
|
509
536
|
}
|
|
537
|
+
// logging hardware telemetry
|
|
538
|
+
logger.sendTelemetryEvent(Object.assign({ eventName: "DeviceSpec" }, getDeviceSpec()));
|
|
539
|
+
// logging container load stats
|
|
540
|
+
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 }));
|
|
510
541
|
ReportOpPerfTelemetry(this.context.clientId, this.deltaManager, this.logger);
|
|
511
542
|
}
|
|
512
543
|
get IContainerRuntime() { return this; }
|
|
@@ -520,7 +551,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
520
551
|
* @param existing - (optional) When loading from an existing snapshot. Precedes context.existing if provided
|
|
521
552
|
*/
|
|
522
553
|
static async load(context, registryEntries, requestHandler, runtimeOptions = {}, containerScope = context.scope, existing) {
|
|
523
|
-
var _a, _b, _c
|
|
554
|
+
var _a, _b, _c;
|
|
524
555
|
// If taggedLogger exists, use it. Otherwise, wrap the vanilla logger:
|
|
525
556
|
const passLogger = (_a = context.taggedLogger) !== null && _a !== void 0 ? _a : new TaggedLoggerAdapter(context.logger);
|
|
526
557
|
const logger = ChildLogger.create(passLogger, undefined, {
|
|
@@ -562,19 +593,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
562
593
|
return readAndParse(storage, blobId);
|
|
563
594
|
}
|
|
564
595
|
};
|
|
565
|
-
const chunks
|
|
566
|
-
|
|
567
|
-
|
|
596
|
+
const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
|
|
597
|
+
tryFetchBlob(chunksBlobName),
|
|
598
|
+
tryFetchBlob(metadataBlobName),
|
|
599
|
+
tryFetchBlob(electedSummarizerBlobName),
|
|
600
|
+
tryFetchBlob(aliasBlobName),
|
|
601
|
+
]);
|
|
568
602
|
const loadExisting = existing === true || context.existing === true;
|
|
569
603
|
// read snapshot blobs needed for BlobManager to load
|
|
570
|
-
const blobManagerSnapshot = await BlobManager.load((
|
|
604
|
+
const blobManagerSnapshot = await BlobManager.load((_b = context.baseSnapshot) === null || _b === void 0 ? void 0 : _b.trees[blobsTreeName], async (id) => {
|
|
571
605
|
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
572
606
|
// So once we release 0.40 container-defn package we can remove this check.
|
|
573
607
|
assert(storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
574
608
|
return readAndParse(storage, id);
|
|
575
609
|
});
|
|
576
610
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
577
|
-
const runtimeSequenceNumber = (
|
|
611
|
+
const runtimeSequenceNumber = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.message) === null || _c === void 0 ? void 0 : _c.sequenceNumber;
|
|
578
612
|
if (runtimeSequenceNumber !== undefined) {
|
|
579
613
|
const protocolSequenceNumber = context.deltaManager.initialSequenceNumber;
|
|
580
614
|
// Unless bypass is explicitly set, then take action when sequence numbers mismatch.
|
|
@@ -589,13 +623,16 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
589
623
|
}
|
|
590
624
|
}
|
|
591
625
|
}
|
|
592
|
-
const runtime = new ContainerRuntime(context, registry, metadata, electedSummarizerData, chunks, {
|
|
626
|
+
const runtime = new ContainerRuntime(context, registry, metadata, electedSummarizerData, chunks !== null && chunks !== void 0 ? chunks : [], aliases !== null && aliases !== void 0 ? aliases : [], {
|
|
593
627
|
summaryOptions,
|
|
594
628
|
gcOptions,
|
|
595
629
|
loadSequenceNumberVerification,
|
|
596
630
|
}, containerScope, logger, loadExisting, blobManagerSnapshot, requestHandler, storage);
|
|
597
631
|
return runtime;
|
|
598
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* @deprecated This will be removed in a later release. Deprecated in 0.53
|
|
635
|
+
*/
|
|
599
636
|
get id() {
|
|
600
637
|
return this.context.id;
|
|
601
638
|
}
|
|
@@ -646,6 +683,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
646
683
|
get attachState() {
|
|
647
684
|
return this.context.attachState;
|
|
648
685
|
}
|
|
686
|
+
get IFluidHandleContext() {
|
|
687
|
+
return this.handleContext;
|
|
688
|
+
}
|
|
649
689
|
get connected() {
|
|
650
690
|
return this._connected;
|
|
651
691
|
}
|
|
@@ -659,13 +699,22 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
659
699
|
return Object.assign(Object.assign(Object.assign({}, DefaultSummaryConfiguration), (_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.serviceConfiguration) === null || _b === void 0 ? void 0 : _b.summary), (_c = this.runtimeOptions.summaryOptions) === null || _c === void 0 ? void 0 : _c.summaryConfigOverrides);
|
|
660
700
|
}
|
|
661
701
|
get disposed() { return this._disposed; }
|
|
662
|
-
|
|
663
|
-
|
|
702
|
+
/**
|
|
703
|
+
* True, if GC data should be written at root of the summary tree.
|
|
704
|
+
* False, if data stores should write GC blobs in their summary tree.
|
|
705
|
+
*/
|
|
706
|
+
get writeGCDataAtRoot() {
|
|
707
|
+
return this.garbageCollector.writeDataAtRoot;
|
|
664
708
|
}
|
|
665
709
|
get summarizer() {
|
|
666
710
|
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
667
711
|
return this._summarizer;
|
|
668
712
|
}
|
|
713
|
+
get summariesDisabled() {
|
|
714
|
+
var _a;
|
|
715
|
+
return this.runtimeOptions.summaryOptions.disableSummaries === true ||
|
|
716
|
+
((_a = this.runtimeOptions.summaryOptions.summaryConfigOverrides) === null || _a === void 0 ? void 0 : _a.disableSummaries) === true;
|
|
717
|
+
}
|
|
669
718
|
dispose(error) {
|
|
670
719
|
var _a;
|
|
671
720
|
if (this._disposed) {
|
|
@@ -779,14 +828,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
779
828
|
}
|
|
780
829
|
formMetadata() {
|
|
781
830
|
var _a;
|
|
782
|
-
return {
|
|
783
|
-
summaryFormatVersion: 1,
|
|
784
|
-
disableIsolatedChannels: this.disableIsolatedChannels || undefined,
|
|
785
|
-
gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
|
|
831
|
+
return Object.assign(Object.assign({}, this.createContainerMetadata), { summaryCount: this.summaryCount, summaryFormatVersion: 1, disableIsolatedChannels: this.disableIsolatedChannels || undefined, gcFeature: this.garbageCollector.gcSummaryFeatureVersion,
|
|
786
832
|
// The last message processed at the time of summary. If there are no messages, nothing has changed from
|
|
787
833
|
// the base summary we loaded from. So, use the message from its metadata blob.
|
|
788
|
-
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage
|
|
789
|
-
};
|
|
834
|
+
message: (_a = extractSummaryMetadataMessage(this.deltaManager.lastMessage)) !== null && _a !== void 0 ? _a : this.baseSummaryMessage });
|
|
790
835
|
}
|
|
791
836
|
/**
|
|
792
837
|
* Retrieves the runtime for a data store if it's referenced as per the initially summary that it is loaded with.
|
|
@@ -813,22 +858,14 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
813
858
|
* @deprecated - Use summarize to get summary of the container runtime.
|
|
814
859
|
*/
|
|
815
860
|
async snapshot() {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
else {
|
|
825
|
-
root.entries.push(new TreeTreeEntry(channelsTreeName, { entries }));
|
|
826
|
-
}
|
|
827
|
-
root.entries.push(new BlobTreeEntry(metadataBlobName, JSON.stringify(this.formMetadata())));
|
|
828
|
-
if (this.chunkMap.size > 0) {
|
|
829
|
-
root.entries.push(new BlobTreeEntry(chunksBlobName, JSON.stringify([...this.chunkMap])));
|
|
830
|
-
}
|
|
831
|
-
return root;
|
|
861
|
+
const summaryResult = await this.summarize({
|
|
862
|
+
summaryLogger: this.logger,
|
|
863
|
+
fullTree: true,
|
|
864
|
+
trackState: false,
|
|
865
|
+
runGC: this.garbageCollector.shouldRunGC,
|
|
866
|
+
fullGC: true,
|
|
867
|
+
});
|
|
868
|
+
return convertSummaryTreeToITree(summaryResult.summary);
|
|
832
869
|
}
|
|
833
870
|
addContainerBlobsToSummary(summaryTree) {
|
|
834
871
|
var _a;
|
|
@@ -837,6 +874,10 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
837
874
|
const content = JSON.stringify([...this.chunkMap]);
|
|
838
875
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
839
876
|
}
|
|
877
|
+
const dataStoreAliases = this.dataStores.aliases();
|
|
878
|
+
if (dataStoreAliases.size > 0) {
|
|
879
|
+
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
880
|
+
}
|
|
840
881
|
if (this.summarizerClientElection) {
|
|
841
882
|
const electedSummarizerContent = JSON.stringify((_a = this.summarizerClientElection) === null || _a === void 0 ? void 0 : _a.serialize());
|
|
842
883
|
addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
|
|
@@ -848,6 +889,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
848
889
|
const blobsTree = convertToSummaryTree(snapshot, false);
|
|
849
890
|
addTreeToSummary(summaryTree, blobsTreeName, blobsTree);
|
|
850
891
|
}
|
|
892
|
+
if (this.writeGCDataAtRoot) {
|
|
893
|
+
const gcSummary = this.garbageCollector.summarize();
|
|
894
|
+
if (gcSummary !== undefined) {
|
|
895
|
+
addTreeToSummary(summaryTree, gcTreeKey, gcSummary);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
851
898
|
}
|
|
852
899
|
replayPendingStates() {
|
|
853
900
|
// We need to be able to send ops to replay states
|
|
@@ -882,6 +929,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
882
929
|
return this.dataStores.applyStashedOp(op);
|
|
883
930
|
case ContainerMessageType.Attach:
|
|
884
931
|
return this.dataStores.applyStashedAttachOp(op);
|
|
932
|
+
case ContainerMessageType.Alias:
|
|
885
933
|
case ContainerMessageType.BlobAttach:
|
|
886
934
|
return;
|
|
887
935
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -903,7 +951,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
903
951
|
this.replayPendingStates();
|
|
904
952
|
}
|
|
905
953
|
this.dataStores.setConnectionState(connected, clientId);
|
|
906
|
-
raiseConnectedEvent(this.
|
|
954
|
+
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
907
955
|
}
|
|
908
956
|
process(messageArg, local) {
|
|
909
957
|
var _a;
|
|
@@ -937,6 +985,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
937
985
|
case ContainerMessageType.Attach:
|
|
938
986
|
this.dataStores.processAttachMessage(message, local || localAck);
|
|
939
987
|
break;
|
|
988
|
+
case ContainerMessageType.Alias:
|
|
989
|
+
this.processAliasMessage(message, localOpMetadata, local);
|
|
990
|
+
break;
|
|
940
991
|
case ContainerMessageType.FluidDataStoreOp:
|
|
941
992
|
// if localAck === true, treat this as a local op because it's one we sent on a previous container
|
|
942
993
|
this.dataStores.processFluidDataStoreOp(message, local || localAck, localOpMetadata);
|
|
@@ -955,6 +1006,9 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
955
1006
|
throw e;
|
|
956
1007
|
}
|
|
957
1008
|
}
|
|
1009
|
+
processAliasMessage(message, localOpMetadata, local) {
|
|
1010
|
+
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
1011
|
+
}
|
|
958
1012
|
processSignal(message, local) {
|
|
959
1013
|
const envelope = message.content;
|
|
960
1014
|
const transformed = {
|
|
@@ -1004,6 +1058,11 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1004
1058
|
return;
|
|
1005
1059
|
}
|
|
1006
1060
|
this.needsFlush = false;
|
|
1061
|
+
// Did we disconnect in the middle of turn-based batch?
|
|
1062
|
+
// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
|
|
1063
|
+
if (!this.canSendOps()) {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1007
1066
|
return this.deltaSender.flush();
|
|
1008
1067
|
}
|
|
1009
1068
|
orderSequentially(callback) {
|
|
@@ -1020,11 +1079,12 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1020
1079
|
this.setFlushMode(FlushMode.TurnBased);
|
|
1021
1080
|
try {
|
|
1022
1081
|
this.trackOrderSequentiallyCalls(callback);
|
|
1023
|
-
}
|
|
1024
|
-
finally {
|
|
1025
1082
|
this.flush();
|
|
1026
1083
|
this.setFlushMode(savedFlushMode);
|
|
1027
1084
|
}
|
|
1085
|
+
catch (error) {
|
|
1086
|
+
this.closeFn(CreateProcessingError(error, "orderSequentially"));
|
|
1087
|
+
}
|
|
1028
1088
|
}
|
|
1029
1089
|
trackOrderSequentiallyCalls(callback) {
|
|
1030
1090
|
try {
|
|
@@ -1180,27 +1240,33 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1180
1240
|
* Implementation of IGarbageCollectionRuntime::updateUsedRoutes.
|
|
1181
1241
|
* After GC has run, called to notify this container's nodes of routes that are used in it.
|
|
1182
1242
|
* @param usedRoutes - The routes that are used in all nodes in this Container.
|
|
1243
|
+
* @param gcTimestamp - The time when GC was run that generated these used routes. If any node node becomes
|
|
1244
|
+
* unreferenced as part of this GC run, this should be used to update the time when it happens.
|
|
1183
1245
|
* @returns the statistics of the used state of the data stores.
|
|
1184
1246
|
*/
|
|
1185
|
-
updateUsedRoutes(usedRoutes) {
|
|
1186
|
-
var _a;
|
|
1247
|
+
updateUsedRoutes(usedRoutes, gcTimestamp) {
|
|
1187
1248
|
// Update our summarizer node's used routes. Updating used routes in summarizer node before
|
|
1188
1249
|
// summarizing is required and asserted by the the summarizer node. We are the root and are
|
|
1189
1250
|
// always referenced, so the used routes is only self-route (empty string).
|
|
1190
1251
|
this.summarizerNode.updateUsedRoutes([""]);
|
|
1191
|
-
return this.dataStores.updateUsedRoutes(usedRoutes,
|
|
1192
|
-
// For now, we use the timestamp of the last op for gcTimestamp. However, there can be cases where
|
|
1193
|
-
// we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
|
|
1194
|
-
// of this client's connection - https://github.com/microsoft/FluidFramework/issues/7152.
|
|
1195
|
-
this.deltaManager.lastMessage) === null || _a === void 0 ? void 0 : _a.timestamp);
|
|
1252
|
+
return this.dataStores.updateUsedRoutes(usedRoutes, gcTimestamp);
|
|
1196
1253
|
}
|
|
1197
1254
|
/**
|
|
1198
|
-
* Runs garbage collection and
|
|
1255
|
+
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
1199
1256
|
* @returns the statistics of the garbage collection run.
|
|
1200
1257
|
*/
|
|
1201
1258
|
async collectGarbage(options) {
|
|
1202
1259
|
return this.garbageCollector.collectGarbage(options);
|
|
1203
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Called when a new outbound reference is added to another node. This is used by garbage collection to identify
|
|
1263
|
+
* all references added in the system.
|
|
1264
|
+
* @param srcHandle - The handle of the node that added the reference.
|
|
1265
|
+
* @param outboundHandle - The handle of the outbound node that is referenced.
|
|
1266
|
+
*/
|
|
1267
|
+
addedGCOutboundReference(srcHandle, outboundHandle) {
|
|
1268
|
+
this.garbageCollector.addedOutboundReference(srcHandle.absolutePath, outboundHandle.absolutePath);
|
|
1269
|
+
}
|
|
1204
1270
|
/**
|
|
1205
1271
|
* Generates the summary tree, uploads it to storage, and then submits the summarize op.
|
|
1206
1272
|
* This is intended to be called by the summarizer, since it is the implementation of
|
|
@@ -1260,6 +1326,13 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1260
1326
|
if (!continueResult.continue) {
|
|
1261
1327
|
return { stage: "base", referenceSequenceNumber: summaryRefSeqNum, error: continueResult.error };
|
|
1262
1328
|
}
|
|
1329
|
+
// increment summary count
|
|
1330
|
+
if (this.summaryCount !== undefined) {
|
|
1331
|
+
this.summaryCount++;
|
|
1332
|
+
}
|
|
1333
|
+
else {
|
|
1334
|
+
this.summaryCount = 1;
|
|
1335
|
+
}
|
|
1263
1336
|
const trace = Trace.start();
|
|
1264
1337
|
let summarizeResult;
|
|
1265
1338
|
try {
|
|
@@ -1383,10 +1456,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1383
1456
|
this.dirtyContainer = dirty;
|
|
1384
1457
|
if (this.emitDirtyDocumentEvent) {
|
|
1385
1458
|
this.emit(dirty ? "dirty" : "saved");
|
|
1386
|
-
|
|
1387
|
-
if (this.context.updateDirtyContainerState !== undefined) {
|
|
1388
|
-
this.context.updateDirtyContainerState(dirty);
|
|
1389
|
-
}
|
|
1459
|
+
this.context.updateDirtyContainerState(dirty);
|
|
1390
1460
|
}
|
|
1391
1461
|
}
|
|
1392
1462
|
submitDataStoreOp(id, contents, localOpMetadata = undefined) {
|
|
@@ -1467,7 +1537,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1467
1537
|
// That might be not what caller hopes to get, but we can look deeper if telemetry tells us it's a problem.
|
|
1468
1538
|
const middleOfBatch = this.flushMode === FlushMode.TurnBased && this.needsFlush;
|
|
1469
1539
|
if (middleOfBatch) {
|
|
1470
|
-
this.
|
|
1540
|
+
this.mc.logger.sendErrorEvent({ eventName: "submitSystemMessageError", type });
|
|
1471
1541
|
}
|
|
1472
1542
|
return this.context.submitFn(type, contents, middleOfBatch);
|
|
1473
1543
|
}
|
|
@@ -1500,6 +1570,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1500
1570
|
this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
|
|
1501
1571
|
break;
|
|
1502
1572
|
case ContainerMessageType.Attach:
|
|
1573
|
+
case ContainerMessageType.Alias:
|
|
1503
1574
|
this.submit(type, content, localOpMetadata);
|
|
1504
1575
|
break;
|
|
1505
1576
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -1531,7 +1602,7 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1531
1602
|
* @returns downloaded snapshot's reference sequence number
|
|
1532
1603
|
*/
|
|
1533
1604
|
async refreshLatestSummaryAckFromServer(summaryLogger) {
|
|
1534
|
-
const snapshot = await this.fetchSnapshotFromStorage(
|
|
1605
|
+
const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
|
|
1535
1606
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
1536
1607
|
fetchLatest: true,
|
|
1537
1608
|
});
|
|
@@ -1560,12 +1631,30 @@ export class ContainerRuntime extends TypedEventEmitter {
|
|
|
1560
1631
|
return this.pendingStateManager.getLocalState();
|
|
1561
1632
|
}
|
|
1562
1633
|
/**
|
|
1563
|
-
*
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
return
|
|
1568
|
-
|
|
1634
|
+
* * Forms a function that will request a Summarizer.
|
|
1635
|
+
* @param loaderRouter - the loader acting as an IFluidRouter
|
|
1636
|
+
* */
|
|
1637
|
+
formRequestSummarizerFn(loaderRouter) {
|
|
1638
|
+
return async () => {
|
|
1639
|
+
const request = {
|
|
1640
|
+
headers: {
|
|
1641
|
+
[LoaderHeader.cache]: false,
|
|
1642
|
+
[LoaderHeader.clientDetails]: {
|
|
1643
|
+
capabilities: { interactive: false },
|
|
1644
|
+
type: summarizerClientType,
|
|
1645
|
+
},
|
|
1646
|
+
[DriverHeader.summarizingClient]: true,
|
|
1647
|
+
[LoaderHeader.reconnect]: false,
|
|
1648
|
+
},
|
|
1649
|
+
url: "/_summarizer",
|
|
1650
|
+
};
|
|
1651
|
+
const fluidObject = await requestFluidObject(loaderRouter, request);
|
|
1652
|
+
const summarizer = fluidObject.ISummarizer;
|
|
1653
|
+
if (!summarizer) {
|
|
1654
|
+
throw new UsageError("Fluid object does not implement ISummarizer");
|
|
1655
|
+
}
|
|
1656
|
+
return summarizer;
|
|
1657
|
+
};
|
|
1569
1658
|
}
|
|
1570
1659
|
}
|
|
1571
1660
|
/**
|