@fluidframework/container-runtime 0.53.0-46105 → 0.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/containerRuntime.d.ts +25 -16
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +125 -77
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +29 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +29 -4
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +7 -3
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +54 -5
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +22 -2
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +112 -34
- package/dist/garbageCollection.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 +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 +22 -0
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +135 -33
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerTypes.d.ts +1 -8
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryFormat.d.ts +1 -0
- package/dist/summaryFormat.d.ts.map +1 -1
- package/dist/summaryFormat.js +2 -1
- package/dist/summaryFormat.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/containerRuntime.d.ts +25 -16
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +131 -83
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +29 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +29 -4
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +7 -3
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +54 -5
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +22 -2
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +114 -36
- package/lib/garbageCollection.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 +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 +22 -0
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +135 -33
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerTypes.d.ts +1 -8
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryFormat.d.ts +1 -0
- package/lib/summaryFormat.d.ts.map +1 -1
- package/lib/summaryFormat.js +1 -0
- package/lib/summaryFormat.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/containerRuntime.ts +176 -93
- package/src/dataStoreContext.ts +44 -6
- package/src/dataStores.ts +84 -4
- package/src/garbageCollection.ts +137 -46
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +12 -10
- package/src/summarizer.ts +154 -38
- package/src/summarizerTypes.ts +2 -9
- package/src/summaryFormat.ts +1 -0
- 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/src/containerRuntime.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
ICriticalContainerError,
|
|
27
27
|
AttachState,
|
|
28
28
|
ILoaderOptions,
|
|
29
|
+
LoaderHeader,
|
|
29
30
|
} from "@fluidframework/container-definitions";
|
|
30
31
|
import {
|
|
31
32
|
IContainerRuntime,
|
|
@@ -44,14 +45,22 @@ import {
|
|
|
44
45
|
PerformanceEvent,
|
|
45
46
|
normalizeError,
|
|
46
47
|
TaggedLoggerAdapter,
|
|
48
|
+
MonitoringContext,
|
|
49
|
+
loggerToMonitoringContext,
|
|
47
50
|
} from "@fluidframework/telemetry-utils";
|
|
48
|
-
import { IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
|
|
51
|
+
import { DriverHeader, IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
|
|
49
52
|
import { readAndParse, BlobAggregationStorage } from "@fluidframework/driver-utils";
|
|
50
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
CreateProcessingError,
|
|
55
|
+
DataCorruptionError,
|
|
56
|
+
GenericError,
|
|
57
|
+
UsageError,
|
|
58
|
+
extractSafePropertiesFromMessage,
|
|
59
|
+
} from "@fluidframework/container-utils";
|
|
51
60
|
import {
|
|
52
61
|
IClientDetails,
|
|
53
62
|
IDocumentMessage,
|
|
54
|
-
|
|
63
|
+
IQuorumClients,
|
|
55
64
|
ISequencedDocumentMessage,
|
|
56
65
|
ISignalMessage,
|
|
57
66
|
ISummaryConfiguration,
|
|
@@ -89,6 +98,7 @@ import {
|
|
|
89
98
|
RequestParser,
|
|
90
99
|
create404Response,
|
|
91
100
|
exceptionToResponse,
|
|
101
|
+
requestFluidObject,
|
|
92
102
|
responseToException,
|
|
93
103
|
seqFromTree,
|
|
94
104
|
convertSummaryTreeToITree,
|
|
@@ -97,7 +107,7 @@ import { v4 as uuid } from "uuid";
|
|
|
97
107
|
import { ContainerFluidHandleContext } from "./containerHandleContext";
|
|
98
108
|
import { FluidDataStoreRegistry } from "./dataStoreRegistry";
|
|
99
109
|
import { Summarizer } from "./summarizer";
|
|
100
|
-
import {
|
|
110
|
+
import { SummaryManager } from "./summaryManager";
|
|
101
111
|
import { DeltaScheduler } from "./deltaScheduler";
|
|
102
112
|
import { ReportOpPerfTelemetry, latencyThreshold } from "./connectionTelemetry";
|
|
103
113
|
import { IPendingLocalState, PendingStateManager } from "./pendingStateManager";
|
|
@@ -105,6 +115,7 @@ import { pkgVersion } from "./packageVersion";
|
|
|
105
115
|
import { BlobManager, IBlobManagerLoadInfo } from "./blobManager";
|
|
106
116
|
import { DataStores, getSummaryForDatastores } from "./dataStores";
|
|
107
117
|
import {
|
|
118
|
+
aliasBlobName,
|
|
108
119
|
blobsTreeName,
|
|
109
120
|
chunksBlobName,
|
|
110
121
|
electedSummarizerBlobName,
|
|
@@ -116,7 +127,6 @@ import {
|
|
|
116
127
|
wrapSummaryInChannelsTree,
|
|
117
128
|
} from "./summaryFormat";
|
|
118
129
|
import { SummaryCollection } from "./summaryCollection";
|
|
119
|
-
import { getLocalStorageFeatureGate } from "./localStorageFeatureGates";
|
|
120
130
|
import { ISerializedElection, OrderedClientCollection, OrderedClientElection } from "./orderedClientElection";
|
|
121
131
|
import { SummarizerClientElection, summarizerClientType } from "./summarizerClientElection";
|
|
122
132
|
import {
|
|
@@ -155,6 +165,9 @@ export enum ContainerMessageType {
|
|
|
155
165
|
|
|
156
166
|
// Ties our new clientId to our old one on reconnect
|
|
157
167
|
Rejoin = "rejoin",
|
|
168
|
+
|
|
169
|
+
// Sets the alias of a root data store
|
|
170
|
+
Alias = "alias",
|
|
158
171
|
}
|
|
159
172
|
|
|
160
173
|
export interface IChunkedOp {
|
|
@@ -279,13 +292,14 @@ type IRuntimeMessageMetadata = undefined | {
|
|
|
279
292
|
};
|
|
280
293
|
|
|
281
294
|
// Local storage key to set the default flush mode to TurnBased
|
|
282
|
-
const turnBasedFlushModeKey = "
|
|
295
|
+
const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
|
|
283
296
|
|
|
284
297
|
export function isRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
285
298
|
switch (message.type) {
|
|
286
299
|
case ContainerMessageType.FluidDataStoreOp:
|
|
287
300
|
case ContainerMessageType.ChunkedOp:
|
|
288
301
|
case ContainerMessageType.Attach:
|
|
302
|
+
case ContainerMessageType.Alias:
|
|
289
303
|
case ContainerMessageType.BlobAttach:
|
|
290
304
|
case ContainerMessageType.Rejoin:
|
|
291
305
|
case MessageType.Operation:
|
|
@@ -609,13 +623,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
609
623
|
public get IContainerRuntime() { return this; }
|
|
610
624
|
public get IFluidRouter() { return this; }
|
|
611
625
|
|
|
612
|
-
// back-compat: Used by loader in <= 0.35
|
|
613
|
-
/**
|
|
614
|
-
* @internal
|
|
615
|
-
* @deprecated Back-compat only. Used by the loader in versions earlier than 0.35.
|
|
616
|
-
*/
|
|
617
|
-
public readonly runtimeVersion: string = pkgVersion;
|
|
618
|
-
|
|
619
626
|
/**
|
|
620
627
|
* Load the stores from a snapshot and returns the runtime.
|
|
621
628
|
* @param context - Context of the container.
|
|
@@ -685,9 +692,14 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
685
692
|
return readAndParse<T>(storage, blobId);
|
|
686
693
|
}
|
|
687
694
|
};
|
|
688
|
-
|
|
689
|
-
const metadata = await
|
|
690
|
-
|
|
695
|
+
|
|
696
|
+
const [chunks, metadata, electedSummarizerData, aliases] = await Promise.all([
|
|
697
|
+
tryFetchBlob<[string, string[]][]>(chunksBlobName),
|
|
698
|
+
tryFetchBlob<IContainerRuntimeMetadata>(metadataBlobName),
|
|
699
|
+
tryFetchBlob<ISerializedElection>(electedSummarizerBlobName),
|
|
700
|
+
tryFetchBlob<[string, string][]>(aliasBlobName),
|
|
701
|
+
]);
|
|
702
|
+
|
|
691
703
|
const loadExisting = existing === true || context.existing === true;
|
|
692
704
|
|
|
693
705
|
// read snapshot blobs needed for BlobManager to load
|
|
@@ -726,7 +738,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
726
738
|
registry,
|
|
727
739
|
metadata,
|
|
728
740
|
electedSummarizerData,
|
|
729
|
-
chunks,
|
|
741
|
+
chunks ?? [],
|
|
742
|
+
aliases ?? [],
|
|
730
743
|
{
|
|
731
744
|
summaryOptions,
|
|
732
745
|
gcOptions,
|
|
@@ -743,6 +756,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
743
756
|
return runtime;
|
|
744
757
|
}
|
|
745
758
|
|
|
759
|
+
/**
|
|
760
|
+
* @deprecated This will be removed in a later release. Deprecated in 0.53
|
|
761
|
+
*/
|
|
746
762
|
public get id(): string {
|
|
747
763
|
return this.context.id;
|
|
748
764
|
}
|
|
@@ -815,10 +831,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
815
831
|
return this.context.attachState;
|
|
816
832
|
}
|
|
817
833
|
|
|
818
|
-
public
|
|
834
|
+
public get IFluidHandleContext(): IFluidHandleContext {
|
|
835
|
+
return this.handleContext;
|
|
836
|
+
}
|
|
837
|
+
private readonly handleContext: ContainerFluidHandleContext;
|
|
819
838
|
|
|
820
839
|
// internal logger for ContainerRuntime. Use this.logger for stores, summaries, etc.
|
|
821
|
-
private readonly
|
|
840
|
+
private readonly mc: MonitoringContext;
|
|
822
841
|
private readonly summarizerClientElection?: SummarizerClientElection;
|
|
823
842
|
/**
|
|
824
843
|
* summaryManager will only be created if this client is permitted to spawn a summarizing client
|
|
@@ -831,7 +850,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
831
850
|
private readonly summarizerNode: IRootSummarizerNodeWithGC;
|
|
832
851
|
|
|
833
852
|
private _orderSequentiallyCalls: number = 0;
|
|
834
|
-
private _flushMode
|
|
853
|
+
private _flushMode: FlushMode;
|
|
835
854
|
private needsFlush = false;
|
|
836
855
|
private flushTrigger = false;
|
|
837
856
|
|
|
@@ -898,15 +917,16 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
898
917
|
/** The message in the metadata of the base summary this container is loaded from. */
|
|
899
918
|
private readonly baseSummaryMessage: ISummaryMetadataMessage | undefined;
|
|
900
919
|
|
|
901
|
-
private static get defaultFlushMode(): FlushMode {
|
|
902
|
-
return getLocalStorageFeatureGate(turnBasedFlushModeKey) ? FlushMode.TurnBased : FlushMode.Immediate;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
920
|
private get summarizer(): Summarizer {
|
|
906
921
|
assert(this._summarizer !== undefined, 0x257 /* "This is not summarizing container" */);
|
|
907
922
|
return this._summarizer;
|
|
908
923
|
}
|
|
909
924
|
|
|
925
|
+
private get summariesDisabled(): boolean {
|
|
926
|
+
return this.runtimeOptions.summaryOptions.disableSummaries === true ||
|
|
927
|
+
this.runtimeOptions.summaryOptions.summaryConfigOverrides?.disableSummaries === true;
|
|
928
|
+
}
|
|
929
|
+
|
|
910
930
|
private readonly createContainerMetadata: ICreateContainerMetadata;
|
|
911
931
|
private summaryCount: number | undefined;
|
|
912
932
|
|
|
@@ -916,6 +936,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
916
936
|
metadata: IContainerRuntimeMetadata | undefined,
|
|
917
937
|
electedSummarizerData: ISerializedElection | undefined,
|
|
918
938
|
chunks: [string, string[]][],
|
|
939
|
+
dataStoreAliasMap: [string, string][],
|
|
919
940
|
private readonly runtimeOptions: Readonly<Required<IContainerRuntimeOptions>>,
|
|
920
941
|
private readonly containerScope: FluidObject,
|
|
921
942
|
public readonly logger: ITelemetryLogger,
|
|
@@ -948,19 +969,26 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
948
969
|
this._connected = this.context.connected;
|
|
949
970
|
this.chunkMap = new Map<string, string[]>(chunks);
|
|
950
971
|
|
|
951
|
-
this.
|
|
972
|
+
this.handleContext = new ContainerFluidHandleContext("", this);
|
|
973
|
+
|
|
974
|
+
this.mc = loggerToMonitoringContext(
|
|
975
|
+
ChildLogger.create(this.logger, "ContainerRuntime"));
|
|
952
976
|
|
|
953
|
-
this.
|
|
977
|
+
this._flushMode =
|
|
978
|
+
this.mc.config.getBoolean(turnBasedFlushModeKey) ?? false
|
|
979
|
+
? FlushMode.TurnBased : FlushMode.Immediate;
|
|
954
980
|
|
|
955
981
|
/**
|
|
956
982
|
* Function that return the current server timestamp. This is used by the garbage collector to set the
|
|
957
983
|
* time when a node becomes unreferenced.
|
|
958
|
-
*
|
|
984
|
+
* We use the timestamp of the last op for current timestamp. However, there can be cases where
|
|
959
985
|
* we don't have an op (on demand summaries for instance). In those cases, we will use the timestamp
|
|
960
|
-
* of this client's connection
|
|
986
|
+
* of this client's connection.
|
|
961
987
|
*/
|
|
962
|
-
|
|
963
|
-
|
|
988
|
+
const getCurrentTimestamp = () => {
|
|
989
|
+
const client = this.clientId !== undefined ? this.getAudience().getMember(this.clientId) : undefined;
|
|
990
|
+
const timestamp = client?.timestamp;
|
|
991
|
+
return this.deltaManager.lastMessage?.timestamp ?? timestamp ?? Date.now();
|
|
964
992
|
};
|
|
965
993
|
this.garbageCollector = GarbageCollector.create(
|
|
966
994
|
this,
|
|
@@ -969,7 +997,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
969
997
|
getCurrentTimestamp,
|
|
970
998
|
context.baseSnapshot,
|
|
971
999
|
async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
972
|
-
this.
|
|
1000
|
+
this.mc.logger,
|
|
973
1001
|
existing,
|
|
974
1002
|
metadata,
|
|
975
1003
|
);
|
|
@@ -1016,13 +1044,14 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1016
1044
|
getInitialGCSummaryDetailsFn,
|
|
1017
1045
|
),
|
|
1018
1046
|
(id: string) => this.summarizerNode.deleteChild(id),
|
|
1019
|
-
this.
|
|
1047
|
+
this.mc.logger,
|
|
1020
1048
|
async () => this.garbageCollector.getDataStoreBaseGCDetails(),
|
|
1021
1049
|
(id: string) => this.garbageCollector.nodeChanged(id),
|
|
1050
|
+
new Map<string, string>(dataStoreAliasMap),
|
|
1022
1051
|
);
|
|
1023
1052
|
|
|
1024
1053
|
this.blobManager = new BlobManager(
|
|
1025
|
-
this.
|
|
1054
|
+
this.handleContext,
|
|
1026
1055
|
blobManagerSnapshot,
|
|
1027
1056
|
() => this.storage,
|
|
1028
1057
|
(blobId) => this.submit(ContainerMessageType.BlobAttach, undefined, undefined, { blobId }),
|
|
@@ -1049,46 +1078,32 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1049
1078
|
|
|
1050
1079
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1051
1080
|
|
|
1052
|
-
// Only create a SummaryManager if summaries are enabled and we are not the summarizer client
|
|
1053
1081
|
// Map the deprecated generateSummaries flag to disableSummaries.
|
|
1054
1082
|
if (this.runtimeOptions.summaryOptions.generateSummaries === false) {
|
|
1055
1083
|
this.runtimeOptions.summaryOptions.disableSummaries = true;
|
|
1056
1084
|
}
|
|
1057
|
-
if (this.summariesDisabled()) {
|
|
1058
|
-
this._logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
1059
|
-
} else {
|
|
1060
|
-
const maxOpsSinceLastSummary = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary ?? 7000;
|
|
1061
|
-
const defaultAction = () => {
|
|
1062
|
-
if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
1063
|
-
this.logger.sendErrorEvent({eventName: "SummaryStatus:Behind"});
|
|
1064
|
-
// unregister default to no log on every op after falling behind
|
|
1065
|
-
// and register summary ack handler to re-register this handler
|
|
1066
|
-
// after successful summary
|
|
1067
|
-
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
1068
|
-
this.logger.sendTelemetryEvent({eventName: "SummaryStatus:CaughtUp"});
|
|
1069
|
-
// we've caught up, so re-register the default action to monitor for
|
|
1070
|
-
// falling behind, and unregister ourself
|
|
1071
|
-
this.summaryCollection.on("default", defaultAction);
|
|
1072
|
-
});
|
|
1073
|
-
this.summaryCollection.off("default", defaultAction);
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1076
1085
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1086
|
+
if (this.summariesDisabled) {
|
|
1087
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
const orderedClientLogger = ChildLogger.create(this.logger, "OrderedClientElection");
|
|
1079
1091
|
const orderedClientCollection = new OrderedClientCollection(
|
|
1080
1092
|
orderedClientLogger,
|
|
1081
1093
|
this.context.deltaManager,
|
|
1082
1094
|
this.context.quorum,
|
|
1083
1095
|
);
|
|
1084
1096
|
const orderedClientElectionForSummarizer = new OrderedClientElection(
|
|
1097
|
+
|
|
1085
1098
|
orderedClientLogger,
|
|
1086
1099
|
orderedClientCollection,
|
|
1087
1100
|
electedSummarizerData ?? this.context.deltaManager.lastSequenceNumber,
|
|
1088
1101
|
SummarizerClientElection.isClientEligible,
|
|
1089
1102
|
);
|
|
1090
|
-
const summarizerClientElectionEnabled =
|
|
1103
|
+
const summarizerClientElectionEnabled =
|
|
1104
|
+
this.mc.config.getBoolean("Fluid.ContainerRuntime.summarizerClientElection") ??
|
|
1091
1105
|
this.runtimeOptions.summaryOptions?.summarizerClientElection === true;
|
|
1106
|
+
const maxOpsSinceLastSummary = this.runtimeOptions.summaryOptions.maxOpsSinceLastSummary ?? 7000;
|
|
1092
1107
|
this.summarizerClientElection = new SummarizerClientElection(
|
|
1093
1108
|
orderedClientLogger,
|
|
1094
1109
|
this.summaryCollection,
|
|
@@ -1103,27 +1118,39 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1103
1118
|
this /* ISummarizerRuntime */,
|
|
1104
1119
|
() => this.summaryConfiguration,
|
|
1105
1120
|
this /* ISummarizerInternalsProvider */,
|
|
1106
|
-
this.
|
|
1121
|
+
this.handleContext,
|
|
1107
1122
|
this.summaryCollection,
|
|
1108
1123
|
async (runtime: IConnectableRuntime) => RunWhileConnectedCoordinator.create(runtime),
|
|
1109
1124
|
);
|
|
1110
|
-
}
|
|
1125
|
+
}
|
|
1126
|
+
else if (SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)) {
|
|
1127
|
+
// Only create a SummaryManager and SummarizerClientElection
|
|
1128
|
+
// if summaries are enabled and we are not the summarizer client.
|
|
1129
|
+
const defaultAction = () => {
|
|
1130
|
+
if (this.summaryCollection.opsSinceLastAck > maxOpsSinceLastSummary) {
|
|
1131
|
+
this.logger.sendErrorEvent({eventName: "SummaryStatus:Behind"});
|
|
1132
|
+
// unregister default to no log on every op after falling behind
|
|
1133
|
+
// and register summary ack handler to re-register this handler
|
|
1134
|
+
// after successful summary
|
|
1135
|
+
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
1136
|
+
this.logger.sendTelemetryEvent({eventName: "SummaryStatus:CaughtUp"});
|
|
1137
|
+
// we've caught up, so re-register the default action to monitor for
|
|
1138
|
+
// falling behind, and unregister ourself
|
|
1139
|
+
this.summaryCollection.on("default", defaultAction);
|
|
1140
|
+
});
|
|
1141
|
+
this.summaryCollection.off("default", defaultAction);
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
this.summaryCollection.on("default", defaultAction);
|
|
1146
|
+
|
|
1111
1147
|
// Create the SummaryManager and mark the initial state
|
|
1112
|
-
const requestOptions: ISummarizerRequestOptions =
|
|
1113
|
-
{
|
|
1114
|
-
cache: false,
|
|
1115
|
-
reconnect: false,
|
|
1116
|
-
summarizingClient: true,
|
|
1117
|
-
};
|
|
1118
1148
|
this.summaryManager = new SummaryManager(
|
|
1119
1149
|
this.summarizerClientElection,
|
|
1120
1150
|
this, // IConnectedState
|
|
1121
1151
|
this.summaryCollection,
|
|
1122
1152
|
this.logger,
|
|
1123
|
-
formRequestSummarizerFn(
|
|
1124
|
-
this.context.loader,
|
|
1125
|
-
this.context.deltaManager.lastSequenceNumber,
|
|
1126
|
-
requestOptions),
|
|
1153
|
+
this.formRequestSummarizerFn(this.context.loader),
|
|
1127
1154
|
new Throttler(
|
|
1128
1155
|
60 * 1000, // 60 sec delay window
|
|
1129
1156
|
30 * 1000, // 30 sec max delay
|
|
@@ -1143,8 +1170,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1143
1170
|
this.deltaManager.on("readonly", (readonly: boolean) => {
|
|
1144
1171
|
// we accumulate ops while being in read-only state.
|
|
1145
1172
|
// once user gets write permissions and we have active connection, flush all pending ops.
|
|
1146
|
-
|
|
1147
|
-
|
|
1173
|
+
assert(readonly === this.deltaManager.readOnlyInfo.readonly,
|
|
1174
|
+
0x124 /* "inconsistent readonly property/event state" */);
|
|
1148
1175
|
|
|
1149
1176
|
// We need to be very careful with when we (re)send pending ops, to ensure that we only send ops
|
|
1150
1177
|
// when we either never send an op, or attempted to send it but we know for sure it was not
|
|
@@ -1363,6 +1390,11 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1363
1390
|
addBlobToSummary(summaryTree, chunksBlobName, content);
|
|
1364
1391
|
}
|
|
1365
1392
|
|
|
1393
|
+
const dataStoreAliases = this.dataStores.aliases();
|
|
1394
|
+
if (dataStoreAliases.size > 0) {
|
|
1395
|
+
addBlobToSummary(summaryTree, aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1366
1398
|
if (this.summarizerClientElection) {
|
|
1367
1399
|
const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
|
|
1368
1400
|
addBlobToSummary(summaryTree, electedSummarizerBlobName, electedSummarizerContent);
|
|
@@ -1442,6 +1474,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1442
1474
|
return this.dataStores.applyStashedOp(op);
|
|
1443
1475
|
case ContainerMessageType.Attach:
|
|
1444
1476
|
return this.dataStores.applyStashedAttachOp(op as unknown as IAttachMessage);
|
|
1477
|
+
case ContainerMessageType.Alias:
|
|
1445
1478
|
case ContainerMessageType.BlobAttach:
|
|
1446
1479
|
return;
|
|
1447
1480
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -1468,7 +1501,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1468
1501
|
|
|
1469
1502
|
this.dataStores.setConnectionState(connected, clientId);
|
|
1470
1503
|
|
|
1471
|
-
raiseConnectedEvent(this.
|
|
1504
|
+
raiseConnectedEvent(this.mc.logger, this, connected, clientId);
|
|
1472
1505
|
}
|
|
1473
1506
|
|
|
1474
1507
|
public process(messageArg: ISequencedDocumentMessage, local: boolean) {
|
|
@@ -1510,6 +1543,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1510
1543
|
case ContainerMessageType.Attach:
|
|
1511
1544
|
this.dataStores.processAttachMessage(message, local || localAck);
|
|
1512
1545
|
break;
|
|
1546
|
+
case ContainerMessageType.Alias:
|
|
1547
|
+
this.processAliasMessage(message, localOpMetadata, local);
|
|
1548
|
+
break;
|
|
1513
1549
|
case ContainerMessageType.FluidDataStoreOp:
|
|
1514
1550
|
// if localAck === true, treat this as a local op because it's one we sent on a previous container
|
|
1515
1551
|
this.dataStores.processFluidDataStoreOp(message, local || localAck, localOpMetadata);
|
|
@@ -1529,6 +1565,14 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1529
1565
|
}
|
|
1530
1566
|
}
|
|
1531
1567
|
|
|
1568
|
+
private processAliasMessage(
|
|
1569
|
+
message: ISequencedDocumentMessage,
|
|
1570
|
+
localOpMetadata: unknown,
|
|
1571
|
+
local: boolean,
|
|
1572
|
+
) {
|
|
1573
|
+
this.dataStores.processAliasMessage(message, localOpMetadata, local);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1532
1576
|
public processSignal(message: ISignalMessage, local: boolean) {
|
|
1533
1577
|
const envelope = message.content as ISignalEnvelope;
|
|
1534
1578
|
const transformed: IInboundSignalMessage = {
|
|
@@ -1592,6 +1636,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1592
1636
|
}
|
|
1593
1637
|
|
|
1594
1638
|
this.needsFlush = false;
|
|
1639
|
+
|
|
1640
|
+
// Did we disconnect in the middle of turn-based batch?
|
|
1641
|
+
// If so, do nothing, as pending state manager will resubmit it correctly on reconnect.
|
|
1642
|
+
if (!this.canSendOps()) {
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1595
1646
|
return this.deltaSender.flush();
|
|
1596
1647
|
}
|
|
1597
1648
|
|
|
@@ -1611,9 +1662,10 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1611
1662
|
|
|
1612
1663
|
try {
|
|
1613
1664
|
this.trackOrderSequentiallyCalls(callback);
|
|
1614
|
-
} finally {
|
|
1615
1665
|
this.flush();
|
|
1616
1666
|
this.setFlushMode(savedFlushMode);
|
|
1667
|
+
} catch(error) {
|
|
1668
|
+
this.closeFn(CreateProcessingError(error, "orderSequentially"));
|
|
1617
1669
|
}
|
|
1618
1670
|
}
|
|
1619
1671
|
|
|
@@ -1673,7 +1725,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1673
1725
|
return this.connected && !this.deltaManager.readonly;
|
|
1674
1726
|
}
|
|
1675
1727
|
|
|
1676
|
-
public getQuorum():
|
|
1728
|
+
public getQuorum(): IQuorumClients {
|
|
1677
1729
|
return this.context.quorum;
|
|
1678
1730
|
}
|
|
1679
1731
|
|
|
@@ -1845,7 +1897,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1845
1897
|
}
|
|
1846
1898
|
|
|
1847
1899
|
/**
|
|
1848
|
-
* Runs garbage collection and
|
|
1900
|
+
* Runs garbage collection and updates the reference / used state of the nodes in the container.
|
|
1849
1901
|
* @returns the statistics of the garbage collection run.
|
|
1850
1902
|
*/
|
|
1851
1903
|
public async collectGarbage(
|
|
@@ -1861,6 +1913,16 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1861
1913
|
return this.garbageCollector.collectGarbage(options);
|
|
1862
1914
|
}
|
|
1863
1915
|
|
|
1916
|
+
/**
|
|
1917
|
+
* Called when a new outbound reference is added to another node. This is used by garbage collection to identify
|
|
1918
|
+
* all references added in the system.
|
|
1919
|
+
* @param srcHandle - The handle of the node that added the reference.
|
|
1920
|
+
* @param outboundHandle - The handle of the outbound node that is referenced.
|
|
1921
|
+
*/
|
|
1922
|
+
public addedGCOutboundReference(srcHandle: IFluidHandle, outboundHandle: IFluidHandle) {
|
|
1923
|
+
this.garbageCollector.addedOutboundReference(srcHandle.absolutePath, outboundHandle.absolutePath);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1864
1926
|
/**
|
|
1865
1927
|
* Generates the summary tree, uploads it to storage, and then submits the summarize op.
|
|
1866
1928
|
* This is intended to be called by the summarizer, since it is the implementation of
|
|
@@ -2093,10 +2155,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2093
2155
|
this.dirtyContainer = dirty;
|
|
2094
2156
|
if (this.emitDirtyDocumentEvent) {
|
|
2095
2157
|
this.emit(dirty ? "dirty" : "saved");
|
|
2096
|
-
|
|
2097
|
-
if (this.context.updateDirtyContainerState !== undefined) {
|
|
2098
|
-
this.context.updateDirtyContainerState(dirty);
|
|
2099
|
-
}
|
|
2158
|
+
this.context.updateDirtyContainerState(dirty);
|
|
2100
2159
|
}
|
|
2101
2160
|
}
|
|
2102
2161
|
|
|
@@ -2215,7 +2274,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2215
2274
|
// That might be not what caller hopes to get, but we can look deeper if telemetry tells us it's a problem.
|
|
2216
2275
|
const middleOfBatch = this.flushMode === FlushMode.TurnBased && this.needsFlush;
|
|
2217
2276
|
if (middleOfBatch) {
|
|
2218
|
-
this.
|
|
2277
|
+
this.mc.logger.sendErrorEvent({ eventName: "submitSystemMessageError", type });
|
|
2219
2278
|
}
|
|
2220
2279
|
|
|
2221
2280
|
return this.context.submitFn(
|
|
@@ -2269,6 +2328,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2269
2328
|
this.dataStores.resubmitDataStoreOp(content, localOpMetadata);
|
|
2270
2329
|
break;
|
|
2271
2330
|
case ContainerMessageType.Attach:
|
|
2331
|
+
case ContainerMessageType.Alias:
|
|
2272
2332
|
this.submit(type, content, localOpMetadata);
|
|
2273
2333
|
break;
|
|
2274
2334
|
case ContainerMessageType.ChunkedOp:
|
|
@@ -2314,7 +2374,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2314
2374
|
* @returns downloaded snapshot's reference sequence number
|
|
2315
2375
|
*/
|
|
2316
2376
|
private async refreshLatestSummaryAckFromServer(summaryLogger: ITelemetryLogger): Promise<number> {
|
|
2317
|
-
const snapshot = await this.fetchSnapshotFromStorage(
|
|
2377
|
+
const snapshot = await this.fetchSnapshotFromStorage(null, summaryLogger, {
|
|
2318
2378
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
2319
2379
|
fetchLatest: true,
|
|
2320
2380
|
});
|
|
@@ -2336,7 +2396,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2336
2396
|
return snapshotRefSeq;
|
|
2337
2397
|
}
|
|
2338
2398
|
|
|
2339
|
-
private async fetchSnapshotFromStorage(
|
|
2399
|
+
private async fetchSnapshotFromStorage(
|
|
2400
|
+
versionId: string | null, logger: ITelemetryLogger, event: ITelemetryGenericEvent) {
|
|
2340
2401
|
return PerformanceEvent.timedExecAsync(logger, event, async (perfEvent) => {
|
|
2341
2402
|
const stats: { getVersionDuration?: number; getSnapshotDuration?: number } = {};
|
|
2342
2403
|
const trace = Trace.start();
|
|
@@ -2358,14 +2419,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2358
2419
|
return this.pendingStateManager.getLocalState();
|
|
2359
2420
|
}
|
|
2360
2421
|
|
|
2361
|
-
/**
|
|
2362
|
-
* @returns true if summaries are explicitly disabled for this ContainerRuntime, false otherwise
|
|
2363
|
-
*/
|
|
2364
|
-
public summariesDisabled(): boolean {
|
|
2365
|
-
return this.runtimeOptions.summaryOptions.disableSummaries === true ||
|
|
2366
|
-
this.runtimeOptions.summaryOptions.summaryConfigOverrides?.disableSummaries === true;
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
2422
|
public readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"] = (...args) => {
|
|
2370
2423
|
if (this.clientDetails.type === summarizerClientType) {
|
|
2371
2424
|
return this.summarizer.summarizeOnDemand(...args);
|
|
@@ -2375,8 +2428,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2375
2428
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2376
2429
|
// disableSummaries is turned on. We are throwing instead of returning a failure here,
|
|
2377
2430
|
// because it is a misuse of the API rather than an expected failure.
|
|
2378
|
-
throw new
|
|
2379
|
-
`Can't summarize, disableSummaries: ${this.summariesDisabled
|
|
2431
|
+
throw new UsageError(
|
|
2432
|
+
`Can't summarize, disableSummaries: ${this.summariesDisabled}`,
|
|
2380
2433
|
);
|
|
2381
2434
|
}
|
|
2382
2435
|
};
|
|
@@ -2390,11 +2443,41 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2390
2443
|
// If we're not the summarizer, and we don't have a summaryManager, we expect that
|
|
2391
2444
|
// generateSummaries is turned off. We are throwing instead of returning a failure here,
|
|
2392
2445
|
// because it is a misuse of the API rather than an expected failure.
|
|
2393
|
-
throw new
|
|
2394
|
-
`Can't summarize, disableSummaries: ${this.summariesDisabled
|
|
2446
|
+
throw new UsageError(
|
|
2447
|
+
`Can't summarize, disableSummaries: ${this.summariesDisabled}`,
|
|
2395
2448
|
);
|
|
2396
2449
|
}
|
|
2397
2450
|
};
|
|
2451
|
+
|
|
2452
|
+
/**
|
|
2453
|
+
* * Forms a function that will request a Summarizer.
|
|
2454
|
+
* @param loaderRouter - the loader acting as an IFluidRouter
|
|
2455
|
+
* */
|
|
2456
|
+
private formRequestSummarizerFn(loaderRouter: IFluidRouter) {
|
|
2457
|
+
return async () => {
|
|
2458
|
+
const request: IRequest = {
|
|
2459
|
+
headers: {
|
|
2460
|
+
[LoaderHeader.cache]: false,
|
|
2461
|
+
[LoaderHeader.clientDetails]: {
|
|
2462
|
+
capabilities: { interactive: false },
|
|
2463
|
+
type: summarizerClientType,
|
|
2464
|
+
},
|
|
2465
|
+
[DriverHeader.summarizingClient]: true,
|
|
2466
|
+
[LoaderHeader.reconnect]: false,
|
|
2467
|
+
},
|
|
2468
|
+
url: "/_summarizer",
|
|
2469
|
+
};
|
|
2470
|
+
|
|
2471
|
+
const fluidObject = await requestFluidObject<FluidObject<ISummarizer>>(loaderRouter, request);
|
|
2472
|
+
const summarizer = fluidObject.ISummarizer;
|
|
2473
|
+
|
|
2474
|
+
if (!summarizer) {
|
|
2475
|
+
throw new UsageError("Fluid object does not implement ISummarizer");
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
return summarizer;
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2398
2481
|
}
|
|
2399
2482
|
|
|
2400
2483
|
/**
|