@fluidframework/container-runtime 2.0.0-internal.5.3.4 → 2.0.0-internal.5.4.2
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/CHANGELOG.md +9 -0
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager.d.ts +9 -1
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +55 -12
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +2 -2
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +43 -11
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +189 -137
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +3 -0
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +24 -27
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.js +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStores.d.ts +1 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +14 -24
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/dist/deltaManagerSummarizerProxy.js +2 -0
- package/dist/deltaManagerSummarizerProxy.js.map +1 -1
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +5 -5
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +12 -5
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts +1 -0
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +1 -0
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +15 -22
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/id-compressor/idCompressor.d.ts +3 -3
- package/dist/id-compressor/idCompressor.d.ts.map +1 -1
- package/dist/id-compressor/idCompressor.js +3 -1
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts +2 -2
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +1 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts +2 -2
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +1 -1
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +2 -2
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +6 -5
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +5 -12
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +6 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +7 -1
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +4 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +21 -12
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +1 -1
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/runningSummarizer.d.ts +3 -5
- package/dist/summary/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/runningSummarizer.js +10 -28
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.js +1 -1
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +5 -5
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +7 -10
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -3
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +4 -8
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +5 -1
- package/dist/summary/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts +2 -3
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js +6 -2
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +2 -2
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager.d.ts +9 -1
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +55 -12
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +3 -3
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +43 -11
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +188 -137
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +3 -0
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +26 -29
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.js +2 -2
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStores.d.ts +1 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +15 -25
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
- package/lib/deltaManagerSummarizerProxy.js +2 -0
- package/lib/deltaManagerSummarizerProxy.js.map +1 -1
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +6 -6
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +13 -6
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts +1 -0
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +1 -0
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +16 -23
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/id-compressor/idCompressor.d.ts +3 -3
- package/lib/id-compressor/idCompressor.d.ts.map +1 -1
- package/lib/id-compressor/idCompressor.js +3 -1
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts +2 -2
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +2 -2
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts +2 -2
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +2 -2
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +2 -2
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +2 -2
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +6 -5
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +6 -13
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +6 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +7 -1
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +4 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +21 -12
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +2 -2
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +2 -2
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/runningSummarizer.d.ts +3 -5
- package/lib/summary/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/runningSummarizer.js +11 -29
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.js +2 -2
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +5 -5
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +8 -11
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +4 -3
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +5 -9
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +6 -2
- package/lib/summary/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts +2 -3
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +7 -3
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +16 -16
- package/src/batchTracker.ts +2 -2
- package/src/blobManager.ts +70 -13
- package/src/connectionTelemetry.ts +7 -3
- package/src/containerRuntime.ts +287 -150
- package/src/dataStore.ts +3 -0
- package/src/dataStoreContext.ts +31 -33
- package/src/dataStoreContexts.ts +2 -2
- package/src/dataStores.ts +15 -18
- package/src/deltaManagerSummarizerProxy.ts +2 -0
- package/src/deltaScheduler.ts +6 -10
- package/src/gc/garbageCollection.ts +13 -8
- package/src/gc/gcHelpers.ts +1 -0
- package/src/gc/gcTelemetry.ts +12 -8
- package/src/id-compressor/idCompressor.ts +6 -5
- package/src/opLifecycle/opCompressor.ts +4 -3
- package/src/opLifecycle/opDecompressor.ts +4 -3
- package/src/opLifecycle/opSplitter.ts +4 -3
- package/src/opLifecycle/outbox.ts +13 -25
- package/src/opLifecycle/remoteMessageProcessor.ts +8 -2
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +22 -10
- package/src/scheduleManager.ts +2 -2
- package/src/summary/orderedClientElection.ts +2 -2
- package/src/summary/runningSummarizer.ts +18 -44
- package/src/summary/summarizer.ts +2 -2
- package/src/summary/summarizerNode/summarizerNode.ts +13 -15
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +8 -7
- package/src/summary/summaryGenerator.ts +6 -2
- package/src/summary/summaryManager.ts +9 -5
package/src/containerRuntime.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "@fluidframework/core-interfaces";
|
|
15
15
|
import {
|
|
16
16
|
IAudience,
|
|
17
|
+
IBatchMessage,
|
|
17
18
|
IContainerContext,
|
|
18
19
|
IDeltaManager,
|
|
19
20
|
IRuntime,
|
|
@@ -35,14 +36,14 @@ import {
|
|
|
35
36
|
} from "@fluidframework/common-utils";
|
|
36
37
|
import { LazyPromise } from "@fluidframework/core-utils";
|
|
37
38
|
import {
|
|
38
|
-
|
|
39
|
+
createChildLogger,
|
|
39
40
|
raiseConnectedEvent,
|
|
40
41
|
PerformanceEvent,
|
|
41
42
|
TaggedLoggerAdapter,
|
|
42
43
|
MonitoringContext,
|
|
43
|
-
loggerToMonitoringContext,
|
|
44
44
|
wrapError,
|
|
45
45
|
ITelemetryLoggerExt,
|
|
46
|
+
createChildMonitoringContext,
|
|
46
47
|
} from "@fluidframework/telemetry-utils";
|
|
47
48
|
import {
|
|
48
49
|
DriverHeader,
|
|
@@ -173,6 +174,7 @@ import { BindBatchTracker } from "./batchTracker";
|
|
|
173
174
|
import { ScheduleManager } from "./scheduleManager";
|
|
174
175
|
import {
|
|
175
176
|
BatchMessage,
|
|
177
|
+
IBatch,
|
|
176
178
|
IBatchCheckpoint,
|
|
177
179
|
OpCompressor,
|
|
178
180
|
OpDecompressor,
|
|
@@ -540,7 +542,7 @@ const defaultChunkSizeInBytes = 204800;
|
|
|
540
542
|
* of the current system, we should close the summarizer and let it recover.
|
|
541
543
|
* This delay's goal is to prevent tight restart loops
|
|
542
544
|
*/
|
|
543
|
-
const defaultCloseSummarizerDelayMs =
|
|
545
|
+
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
544
546
|
|
|
545
547
|
/**
|
|
546
548
|
* @deprecated - use ContainerRuntimeMessage instead
|
|
@@ -582,6 +584,30 @@ export function getDeviceSpec() {
|
|
|
582
584
|
return {};
|
|
583
585
|
}
|
|
584
586
|
|
|
587
|
+
/**
|
|
588
|
+
* Older loader doesn't have a submitBatchFn member, this is the older way of submitting a batch.
|
|
589
|
+
* Rather than exposing the submitFn (now deprecated) and IDeltaManager (dangerous to hand out) to the Outbox,
|
|
590
|
+
* we can provide a partially-applied function to keep those items private to the ContainerRuntime.
|
|
591
|
+
*/
|
|
592
|
+
export const makeLegacySendBatchFn =
|
|
593
|
+
(
|
|
594
|
+
submitFn: (type: MessageType, contents: any, batch: boolean, appData?: any) => number,
|
|
595
|
+
deltaManager: Pick<IDeltaManager<unknown, unknown>, "flush">,
|
|
596
|
+
) =>
|
|
597
|
+
(batch: IBatch) => {
|
|
598
|
+
for (const message of batch.content) {
|
|
599
|
+
submitFn(
|
|
600
|
+
MessageType.Operation,
|
|
601
|
+
// For back-compat (submitFn only works on deserialized content)
|
|
602
|
+
message.contents === undefined ? undefined : JSON.parse(message.contents),
|
|
603
|
+
true, // batch
|
|
604
|
+
message.metadata,
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
deltaManager.flush();
|
|
609
|
+
};
|
|
610
|
+
|
|
585
611
|
/**
|
|
586
612
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
587
613
|
* It will define the store level mappings.
|
|
@@ -671,9 +697,12 @@ export class ContainerRuntime
|
|
|
671
697
|
const passLogger =
|
|
672
698
|
backCompatContext.taggedLogger ??
|
|
673
699
|
new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
|
|
674
|
-
const logger =
|
|
675
|
-
|
|
676
|
-
|
|
700
|
+
const logger = createChildLogger({
|
|
701
|
+
logger: passLogger,
|
|
702
|
+
properties: {
|
|
703
|
+
all: {
|
|
704
|
+
runtimeVersion: pkgVersion,
|
|
705
|
+
},
|
|
677
706
|
},
|
|
678
707
|
});
|
|
679
708
|
|
|
@@ -808,49 +837,48 @@ export class ContainerRuntime
|
|
|
808
837
|
return runtime;
|
|
809
838
|
}
|
|
810
839
|
|
|
811
|
-
public
|
|
812
|
-
return this.context.options;
|
|
813
|
-
}
|
|
840
|
+
public readonly options: ILoaderOptions;
|
|
814
841
|
|
|
842
|
+
private readonly _getClientId: () => string | undefined;
|
|
815
843
|
public get clientId(): string | undefined {
|
|
816
|
-
return this.
|
|
844
|
+
return this._getClientId();
|
|
817
845
|
}
|
|
818
846
|
|
|
819
|
-
public
|
|
820
|
-
return this.context.clientDetails;
|
|
821
|
-
}
|
|
847
|
+
public readonly clientDetails: IClientDetails;
|
|
822
848
|
|
|
823
849
|
public get storage(): IDocumentStorageService {
|
|
824
850
|
return this._storage;
|
|
825
851
|
}
|
|
826
852
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
853
|
+
/** @deprecated - The functionality is no longer exposed publicly */
|
|
854
|
+
public get reSubmitFn() {
|
|
855
|
+
return (
|
|
856
|
+
type: ContainerMessageType,
|
|
857
|
+
contents: any,
|
|
858
|
+
localOpMetadata: unknown,
|
|
859
|
+
opMetadata: Record<string, unknown> | undefined,
|
|
860
|
+
) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
835
861
|
}
|
|
836
862
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
863
|
+
private readonly submitFn: (
|
|
864
|
+
type: MessageType,
|
|
865
|
+
contents: any,
|
|
866
|
+
batch: boolean,
|
|
867
|
+
appData?: any,
|
|
868
|
+
) => number;
|
|
869
|
+
/**
|
|
870
|
+
* Although current IContainerContext guarantees submitBatchFn, it is not available on older loaders.
|
|
871
|
+
*/
|
|
872
|
+
private readonly submitBatchFn:
|
|
873
|
+
| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)
|
|
874
|
+
| undefined;
|
|
875
|
+
private readonly submitSummaryFn: (
|
|
876
|
+
summaryOp: ISummaryContent,
|
|
877
|
+
referenceSequenceNumber?: number,
|
|
878
|
+
) => number;
|
|
879
|
+
private readonly submitSignalFn: (contents: any) => void;
|
|
880
|
+
public readonly disposeFn: (error?: ICriticalContainerError) => void;
|
|
881
|
+
public readonly closeFn: (error?: ICriticalContainerError) => void;
|
|
854
882
|
|
|
855
883
|
public get flushMode(): FlushMode {
|
|
856
884
|
return this._flushMode;
|
|
@@ -864,8 +892,9 @@ export class ContainerRuntime
|
|
|
864
892
|
return this.registry;
|
|
865
893
|
}
|
|
866
894
|
|
|
895
|
+
private readonly _getAttachState: () => AttachState;
|
|
867
896
|
public get attachState(): AttachState {
|
|
868
|
-
return this.
|
|
897
|
+
return this._getAttachState();
|
|
869
898
|
}
|
|
870
899
|
|
|
871
900
|
public idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
|
|
@@ -1056,11 +1085,21 @@ export class ContainerRuntime
|
|
|
1056
1085
|
*/
|
|
1057
1086
|
private readonly idCompressorEnabled: boolean;
|
|
1058
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1090
|
+
*/
|
|
1091
|
+
private readonly isSummarizerClient: boolean;
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* The id of the version used to initially load this runtime, or undefined if it's newly created.
|
|
1095
|
+
*/
|
|
1096
|
+
private readonly loadedFromVersionId: string | undefined;
|
|
1097
|
+
|
|
1059
1098
|
/**
|
|
1060
1099
|
* @internal
|
|
1061
1100
|
*/
|
|
1062
1101
|
protected constructor(
|
|
1063
|
-
|
|
1102
|
+
context: IContainerContext,
|
|
1064
1103
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1065
1104
|
metadata: IContainerRuntimeMetadata | undefined,
|
|
1066
1105
|
electedSummarizerData: ISerializedElection | undefined,
|
|
@@ -1087,10 +1126,70 @@ export class ContainerRuntime
|
|
|
1087
1126
|
) {
|
|
1088
1127
|
super();
|
|
1089
1128
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1129
|
+
const {
|
|
1130
|
+
options,
|
|
1131
|
+
clientDetails,
|
|
1132
|
+
connected,
|
|
1133
|
+
baseSnapshot,
|
|
1134
|
+
submitFn,
|
|
1135
|
+
submitBatchFn,
|
|
1136
|
+
submitSummaryFn,
|
|
1137
|
+
submitSignalFn,
|
|
1138
|
+
disposeFn,
|
|
1139
|
+
closeFn,
|
|
1140
|
+
deltaManager,
|
|
1141
|
+
quorum,
|
|
1142
|
+
audience,
|
|
1143
|
+
loader,
|
|
1144
|
+
pendingLocalState,
|
|
1145
|
+
supportedFeatures,
|
|
1146
|
+
} = context;
|
|
1147
|
+
|
|
1148
|
+
this.innerDeltaManager = deltaManager;
|
|
1149
|
+
this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
1150
|
+
|
|
1151
|
+
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
1152
|
+
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
1153
|
+
this.submitFn = submitFn;
|
|
1154
|
+
this.submitBatchFn = submitBatchFn;
|
|
1155
|
+
this.submitSummaryFn = submitSummaryFn;
|
|
1156
|
+
this.submitSignalFn = submitSignalFn;
|
|
1157
|
+
|
|
1158
|
+
this.options = options;
|
|
1159
|
+
this.clientDetails = clientDetails;
|
|
1160
|
+
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1161
|
+
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
1162
|
+
this._getClientId = () => context.clientId;
|
|
1163
|
+
this._getAttachState = () => context.attachState;
|
|
1164
|
+
this.getAbsoluteUrl = async (relativeUrl: string) => {
|
|
1165
|
+
if (context.getAbsoluteUrl === undefined) {
|
|
1166
|
+
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
1167
|
+
}
|
|
1168
|
+
if (this.attachState !== AttachState.Attached) {
|
|
1169
|
+
return undefined;
|
|
1170
|
+
}
|
|
1171
|
+
return context.getAbsoluteUrl(relativeUrl);
|
|
1172
|
+
};
|
|
1173
|
+
// TODO: Consider that the Container could just listen to these events itself, or even more appropriately maybe the
|
|
1174
|
+
// customer should observe dirty state on the runtime (the owner of dirty state) directly, rather than on the IContainer.
|
|
1175
|
+
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
1176
|
+
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
1092
1177
|
|
|
1093
|
-
|
|
1178
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1179
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
1180
|
+
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
1181
|
+
this.closeFn = this.isSummarizerClient
|
|
1182
|
+
? this.disposeFn
|
|
1183
|
+
: (error?: ICriticalContainerError) => {
|
|
1184
|
+
closeFn(error);
|
|
1185
|
+
// Also call disposeFn to retain functionality of runtime being disposed on close
|
|
1186
|
+
disposeFn?.(error);
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
this.mc = createChildMonitoringContext({
|
|
1190
|
+
logger: this.logger,
|
|
1191
|
+
namespace: "ContainerRuntime",
|
|
1192
|
+
});
|
|
1094
1193
|
|
|
1095
1194
|
let loadSummaryNumber: number;
|
|
1096
1195
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
@@ -1122,7 +1221,9 @@ export class ContainerRuntime
|
|
|
1122
1221
|
|
|
1123
1222
|
this.messageAtLastSummary = metadata?.message;
|
|
1124
1223
|
|
|
1125
|
-
|
|
1224
|
+
// Note that we only need to pull the *initial* connected state from the context.
|
|
1225
|
+
// Later updates come through calls to setConnectionState.
|
|
1226
|
+
this._connected = connected;
|
|
1126
1227
|
|
|
1127
1228
|
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
|
|
1128
1229
|
metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
|
|
@@ -1151,7 +1252,7 @@ export class ContainerRuntime
|
|
|
1151
1252
|
|
|
1152
1253
|
const opSplitter = new OpSplitter(
|
|
1153
1254
|
chunks,
|
|
1154
|
-
this.
|
|
1255
|
+
this.submitBatchFn,
|
|
1155
1256
|
disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes,
|
|
1156
1257
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1157
1258
|
this.mc.logger,
|
|
@@ -1192,7 +1293,7 @@ export class ContainerRuntime
|
|
|
1192
1293
|
|
|
1193
1294
|
if (
|
|
1194
1295
|
runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
|
|
1195
|
-
|
|
1296
|
+
supportedFeatures?.get("referenceSequenceNumbers") !== true
|
|
1196
1297
|
) {
|
|
1197
1298
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
1198
1299
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
@@ -1201,7 +1302,7 @@ export class ContainerRuntime
|
|
|
1201
1302
|
this._flushMode = runtimeOptions.flushMode;
|
|
1202
1303
|
}
|
|
1203
1304
|
|
|
1204
|
-
const pendingRuntimeState =
|
|
1305
|
+
const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
|
|
1205
1306
|
|
|
1206
1307
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1207
1308
|
if (
|
|
@@ -1217,12 +1318,12 @@ export class ContainerRuntime
|
|
|
1217
1318
|
this.garbageCollector = GarbageCollector.create({
|
|
1218
1319
|
runtime: this,
|
|
1219
1320
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
1220
|
-
baseSnapshot
|
|
1321
|
+
baseSnapshot,
|
|
1221
1322
|
baseLogger: this.mc.logger,
|
|
1222
1323
|
existing,
|
|
1223
1324
|
metadata,
|
|
1224
1325
|
createContainerMetadata: this.createContainerMetadata,
|
|
1225
|
-
isSummarizerClient: this.
|
|
1326
|
+
isSummarizerClient: this.isSummarizerClient,
|
|
1226
1327
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1227
1328
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1228
1329
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
@@ -1233,14 +1334,14 @@ export class ContainerRuntime
|
|
|
1233
1334
|
|
|
1234
1335
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
1235
1336
|
this.summarizerNode = createRootSummarizerNodeWithGC(
|
|
1236
|
-
|
|
1337
|
+
createChildLogger({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
1237
1338
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
1238
1339
|
async (fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext) =>
|
|
1239
1340
|
this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
1240
1341
|
// Latest change sequence number, no changes since summary applied yet
|
|
1241
1342
|
loadedFromSequenceNumber,
|
|
1242
1343
|
// Summary reference sequence number, undefined if no summary yet
|
|
1243
|
-
|
|
1344
|
+
baseSnapshot !== undefined ? loadedFromSequenceNumber : undefined,
|
|
1244
1345
|
{
|
|
1245
1346
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1246
1347
|
// a summary with an older protocol state.
|
|
@@ -1257,14 +1358,14 @@ export class ContainerRuntime
|
|
|
1257
1358
|
async () => this.garbageCollector.getBaseGCDetails(),
|
|
1258
1359
|
);
|
|
1259
1360
|
|
|
1260
|
-
if (
|
|
1261
|
-
this.summarizerNode.updateBaseSummaryState(
|
|
1361
|
+
if (baseSnapshot) {
|
|
1362
|
+
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1262
1363
|
}
|
|
1263
1364
|
|
|
1264
1365
|
this.dataStores = new DataStores(
|
|
1265
|
-
getSummaryForDatastores(
|
|
1366
|
+
getSummaryForDatastores(baseSnapshot, metadata),
|
|
1266
1367
|
this,
|
|
1267
|
-
(attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg),
|
|
1368
|
+
(attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }),
|
|
1268
1369
|
(id: string, createParam: CreateChildSummarizerNodeParam) =>
|
|
1269
1370
|
(
|
|
1270
1371
|
summarizeInternal: SummarizeInternalFn,
|
|
@@ -1291,10 +1392,14 @@ export class ContainerRuntime
|
|
|
1291
1392
|
() => this.storage,
|
|
1292
1393
|
(localId: string, blobId?: string) => {
|
|
1293
1394
|
if (!this.disposed) {
|
|
1294
|
-
this.submit(
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1395
|
+
this.submit(
|
|
1396
|
+
{ type: ContainerMessageType.BlobAttach, contents: undefined },
|
|
1397
|
+
undefined,
|
|
1398
|
+
{
|
|
1399
|
+
localId,
|
|
1400
|
+
blobId,
|
|
1401
|
+
},
|
|
1402
|
+
);
|
|
1298
1403
|
}
|
|
1299
1404
|
},
|
|
1300
1405
|
(blobPath: string) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
|
|
@@ -1305,10 +1410,10 @@ export class ContainerRuntime
|
|
|
1305
1410
|
);
|
|
1306
1411
|
|
|
1307
1412
|
this.scheduleManager = new ScheduleManager(
|
|
1308
|
-
|
|
1413
|
+
this.innerDeltaManager,
|
|
1309
1414
|
this,
|
|
1310
1415
|
() => this.clientId,
|
|
1311
|
-
|
|
1416
|
+
createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }),
|
|
1312
1417
|
);
|
|
1313
1418
|
|
|
1314
1419
|
this.pendingStateManager = new PendingStateManager(
|
|
@@ -1319,8 +1424,10 @@ export class ContainerRuntime
|
|
|
1319
1424
|
connected: () => this.connected,
|
|
1320
1425
|
reSubmit: this.reSubmit.bind(this),
|
|
1321
1426
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1427
|
+
isActiveConnection: () => this.innerDeltaManager.active,
|
|
1322
1428
|
},
|
|
1323
1429
|
pendingRuntimeState?.pending,
|
|
1430
|
+
this.logger,
|
|
1324
1431
|
);
|
|
1325
1432
|
|
|
1326
1433
|
const disableCompression = this.mc.config.getBoolean(
|
|
@@ -1337,10 +1444,14 @@ export class ContainerRuntime
|
|
|
1337
1444
|
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1338
1445
|
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1339
1446
|
);
|
|
1447
|
+
|
|
1448
|
+
const legacySendBatchFn = makeLegacySendBatchFn(this.submitFn, this.innerDeltaManager);
|
|
1449
|
+
|
|
1340
1450
|
this.outbox = new Outbox({
|
|
1341
1451
|
shouldSend: () => this.canSendOps(),
|
|
1342
1452
|
pendingStateManager: this.pendingStateManager,
|
|
1343
|
-
|
|
1453
|
+
submitBatchFn: this.submitBatchFn,
|
|
1454
|
+
legacySendBatchFn,
|
|
1344
1455
|
compressor: new OpCompressor(this.mc.logger),
|
|
1345
1456
|
splitter: opSplitter,
|
|
1346
1457
|
config: {
|
|
@@ -1360,10 +1471,14 @@ export class ContainerRuntime
|
|
|
1360
1471
|
closeContainer: this.closeFn,
|
|
1361
1472
|
});
|
|
1362
1473
|
|
|
1363
|
-
this.
|
|
1474
|
+
this._quorum = quorum;
|
|
1475
|
+
this._quorum.on("removeMember", (clientId: string) => {
|
|
1364
1476
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
1365
1477
|
});
|
|
1366
1478
|
|
|
1479
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1480
|
+
this._audience = audience!;
|
|
1481
|
+
|
|
1367
1482
|
this.summaryStateUpdateMethod = this.mc.config.getString(
|
|
1368
1483
|
"Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2",
|
|
1369
1484
|
);
|
|
@@ -1378,23 +1493,26 @@ export class ContainerRuntime
|
|
|
1378
1493
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1379
1494
|
|
|
1380
1495
|
this.dirtyContainer =
|
|
1381
|
-
this.
|
|
1496
|
+
this.attachState !== AttachState.Attached ||
|
|
1382
1497
|
this.pendingStateManager.hasPendingMessages();
|
|
1383
|
-
|
|
1498
|
+
context.updateDirtyContainerState(this.dirtyContainer);
|
|
1384
1499
|
|
|
1385
1500
|
if (this.summariesDisabled) {
|
|
1386
1501
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
1387
1502
|
} else {
|
|
1388
|
-
const orderedClientLogger =
|
|
1503
|
+
const orderedClientLogger = createChildLogger({
|
|
1504
|
+
logger: this.logger,
|
|
1505
|
+
namespace: "OrderedClientElection",
|
|
1506
|
+
});
|
|
1389
1507
|
const orderedClientCollection = new OrderedClientCollection(
|
|
1390
1508
|
orderedClientLogger,
|
|
1391
|
-
this.
|
|
1392
|
-
this.
|
|
1509
|
+
this.innerDeltaManager,
|
|
1510
|
+
this._quorum,
|
|
1393
1511
|
);
|
|
1394
1512
|
const orderedClientElectionForSummarizer = new OrderedClientElection(
|
|
1395
1513
|
orderedClientLogger,
|
|
1396
1514
|
orderedClientCollection,
|
|
1397
|
-
electedSummarizerData ?? this.
|
|
1515
|
+
electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber,
|
|
1398
1516
|
SummarizerClientElection.isClientEligible,
|
|
1399
1517
|
);
|
|
1400
1518
|
|
|
@@ -1405,7 +1523,7 @@ export class ContainerRuntime
|
|
|
1405
1523
|
this.maxOpsSinceLastSummary,
|
|
1406
1524
|
);
|
|
1407
1525
|
|
|
1408
|
-
if (this.
|
|
1526
|
+
if (this.isSummarizerClient) {
|
|
1409
1527
|
this._summarizer = new Summarizer(
|
|
1410
1528
|
this /* ISummarizerRuntime */,
|
|
1411
1529
|
() => this.summaryConfiguration,
|
|
@@ -1420,19 +1538,19 @@ export class ContainerRuntime
|
|
|
1420
1538
|
() => this.innerDeltaManager.active,
|
|
1421
1539
|
),
|
|
1422
1540
|
);
|
|
1423
|
-
} else if (
|
|
1424
|
-
SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)
|
|
1425
|
-
) {
|
|
1541
|
+
} else if (SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
1426
1542
|
// Only create a SummaryManager and SummarizerClientElection
|
|
1427
1543
|
// if summaries are enabled and we are not the summarizer client.
|
|
1428
1544
|
const defaultAction = () => {
|
|
1429
1545
|
if (this.summaryCollection.opsSinceLastAck > this.maxOpsSinceLastSummary) {
|
|
1430
|
-
this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
1546
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
1431
1547
|
// unregister default to no log on every op after falling behind
|
|
1432
1548
|
// and register summary ack handler to re-register this handler
|
|
1433
1549
|
// after successful summary
|
|
1434
1550
|
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
1435
|
-
this.logger.sendTelemetryEvent({
|
|
1551
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1552
|
+
eventName: "SummaryStatus:CaughtUp",
|
|
1553
|
+
});
|
|
1436
1554
|
// we've caught up, so re-register the default action to monitor for
|
|
1437
1555
|
// falling behind, and unregister ourself
|
|
1438
1556
|
this.summaryCollection.on("default", defaultAction);
|
|
@@ -1449,7 +1567,7 @@ export class ContainerRuntime
|
|
|
1449
1567
|
this, // IConnectedState
|
|
1450
1568
|
this.summaryCollection,
|
|
1451
1569
|
this.logger,
|
|
1452
|
-
this.formRequestSummarizerFn(
|
|
1570
|
+
this.formRequestSummarizerFn(loader),
|
|
1453
1571
|
new Throttler(
|
|
1454
1572
|
60 * 1000, // 60 sec delay window
|
|
1455
1573
|
30 * 1000, // 30 sec max delay
|
|
@@ -1500,7 +1618,7 @@ export class ContainerRuntime
|
|
|
1500
1618
|
...getDeviceSpec(),
|
|
1501
1619
|
});
|
|
1502
1620
|
|
|
1503
|
-
this.logger.sendTelemetryEvent({
|
|
1621
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1504
1622
|
eventName: "ContainerLoadStats",
|
|
1505
1623
|
...this.createContainerMetadata,
|
|
1506
1624
|
...this.dataStores.containerLoadStats,
|
|
@@ -1523,11 +1641,11 @@ export class ContainerRuntime
|
|
|
1523
1641
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1524
1642
|
});
|
|
1525
1643
|
|
|
1526
|
-
ReportOpPerfTelemetry(this.
|
|
1644
|
+
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
1527
1645
|
BindBatchTracker(this, this.logger);
|
|
1528
1646
|
|
|
1529
1647
|
this.entryPoint = new LazyPromise(async () => {
|
|
1530
|
-
if (this.
|
|
1648
|
+
if (this.isSummarizerClient) {
|
|
1531
1649
|
assert(
|
|
1532
1650
|
this._summarizer !== undefined,
|
|
1533
1651
|
0x5bf /* Summarizer object is undefined in a summarizer client */,
|
|
@@ -1551,7 +1669,7 @@ export class ContainerRuntime
|
|
|
1551
1669
|
}
|
|
1552
1670
|
this._disposed = true;
|
|
1553
1671
|
|
|
1554
|
-
this.logger.sendTelemetryEvent(
|
|
1672
|
+
this.mc.logger.sendTelemetryEvent(
|
|
1555
1673
|
{
|
|
1556
1674
|
eventName: "ContainerRuntimeDisposed",
|
|
1557
1675
|
isDirty: this.isDirty,
|
|
@@ -1841,14 +1959,11 @@ export class ContainerRuntime
|
|
|
1841
1959
|
* Parse an op's type and actual content from given serialized content
|
|
1842
1960
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
1843
1961
|
*/
|
|
1844
|
-
private parseOpContent(serializedContent?: string): {
|
|
1845
|
-
type: ContainerMessageType;
|
|
1846
|
-
contents: unknown;
|
|
1847
|
-
} {
|
|
1962
|
+
private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
|
|
1848
1963
|
assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
|
|
1849
|
-
const
|
|
1850
|
-
assert(
|
|
1851
|
-
return { type
|
|
1964
|
+
const { type, contents } = JSON.parse(serializedContent);
|
|
1965
|
+
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1966
|
+
return { type, contents };
|
|
1852
1967
|
}
|
|
1853
1968
|
|
|
1854
1969
|
private async applyStashedOp(op: string): Promise<unknown> {
|
|
@@ -1926,6 +2041,14 @@ export class ContainerRuntime
|
|
|
1926
2041
|
// There might be no change of state due to Container calling this API after loading runtime.
|
|
1927
2042
|
const changeOfState = this._connected !== connected;
|
|
1928
2043
|
const reconnection = changeOfState && !connected;
|
|
2044
|
+
|
|
2045
|
+
// We need to flush the ops currently collected by Outbox to preserve original order.
|
|
2046
|
+
// This flush NEEDS to happen before we set the ContainerRuntime to "connected".
|
|
2047
|
+
// We want these ops to get to the PendingStateManager without sending to service and have them return to the Outbox upon calling "replayPendingStates".
|
|
2048
|
+
if (changeOfState && connected) {
|
|
2049
|
+
this.flush();
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1929
2052
|
this._connected = connected;
|
|
1930
2053
|
|
|
1931
2054
|
if (!connected) {
|
|
@@ -1991,6 +2114,12 @@ export class ContainerRuntime
|
|
|
1991
2114
|
|
|
1992
2115
|
private _processedClientSequenceNumber: number | undefined;
|
|
1993
2116
|
|
|
2117
|
+
/**
|
|
2118
|
+
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2119
|
+
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
2120
|
+
* @param local - Did this client send the op?
|
|
2121
|
+
* @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
|
|
2122
|
+
*/
|
|
1994
2123
|
private processCore(
|
|
1995
2124
|
message: ISequencedDocumentMessage,
|
|
1996
2125
|
local: boolean,
|
|
@@ -2059,9 +2188,7 @@ export class ContainerRuntime
|
|
|
2059
2188
|
}
|
|
2060
2189
|
}
|
|
2061
2190
|
|
|
2062
|
-
|
|
2063
|
-
this.emit("op", message, runtimeMessage);
|
|
2064
|
-
}
|
|
2191
|
+
this.emit("op", message, runtimeMessage);
|
|
2065
2192
|
|
|
2066
2193
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
2067
2194
|
|
|
@@ -2091,7 +2218,7 @@ export class ContainerRuntime
|
|
|
2091
2218
|
*/
|
|
2092
2219
|
private sendSignalTelemetryEvent(clientSignalSequenceNumber: number) {
|
|
2093
2220
|
const duration = Date.now() - this._perfSignalData.signalTimestamp;
|
|
2094
|
-
this.logger.sendPerformanceEvent({
|
|
2221
|
+
this.mc.logger.sendPerformanceEvent({
|
|
2095
2222
|
eventName: "SignalLatency",
|
|
2096
2223
|
duration,
|
|
2097
2224
|
signalsLost: this._perfSignalData.signalsLost,
|
|
@@ -2119,7 +2246,7 @@ export class ContainerRuntime
|
|
|
2119
2246
|
) {
|
|
2120
2247
|
this._perfSignalData.signalsLost++;
|
|
2121
2248
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
2122
|
-
this.logger.sendErrorEvent({
|
|
2249
|
+
this.mc.logger.sendErrorEvent({
|
|
2123
2250
|
eventName: "SignalLost",
|
|
2124
2251
|
type: envelope.contents.type,
|
|
2125
2252
|
signalsLost: this._perfSignalData.signalsLost,
|
|
@@ -2281,13 +2408,14 @@ export class ContainerRuntime
|
|
|
2281
2408
|
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
2282
2409
|
}
|
|
2283
2410
|
|
|
2411
|
+
private readonly _quorum: IQuorumClients;
|
|
2284
2412
|
public getQuorum(): IQuorumClients {
|
|
2285
|
-
return this.
|
|
2413
|
+
return this._quorum;
|
|
2286
2414
|
}
|
|
2287
2415
|
|
|
2416
|
+
private readonly _audience: IAudience;
|
|
2288
2417
|
public getAudience(): IAudience {
|
|
2289
|
-
|
|
2290
|
-
return this.context.audience!;
|
|
2418
|
+
return this._audience;
|
|
2291
2419
|
}
|
|
2292
2420
|
|
|
2293
2421
|
/**
|
|
@@ -2298,7 +2426,7 @@ export class ContainerRuntime
|
|
|
2298
2426
|
return this.dirtyContainer;
|
|
2299
2427
|
}
|
|
2300
2428
|
|
|
2301
|
-
private isContainerMessageDirtyable(type
|
|
2429
|
+
private isContainerMessageDirtyable({ type, contents }: ContainerRuntimeMessage) {
|
|
2302
2430
|
// For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
|
|
2303
2431
|
// Ultimately we should have no special-cases from the ContainerRuntime's perspective.
|
|
2304
2432
|
if (type === ContainerMessageType.Attach) {
|
|
@@ -2347,12 +2475,12 @@ export class ContainerRuntime
|
|
|
2347
2475
|
public submitSignal(type: string, content: any) {
|
|
2348
2476
|
this.verifyNotClosed();
|
|
2349
2477
|
const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
|
|
2350
|
-
return this.
|
|
2478
|
+
return this.submitSignalFn(envelope);
|
|
2351
2479
|
}
|
|
2352
2480
|
|
|
2353
2481
|
public submitDataStoreSignal(address: string, type: string, content: any) {
|
|
2354
2482
|
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
2355
|
-
return this.
|
|
2483
|
+
return this.submitSignalFn(envelope);
|
|
2356
2484
|
}
|
|
2357
2485
|
|
|
2358
2486
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
@@ -2404,15 +2532,7 @@ export class ContainerRuntime
|
|
|
2404
2532
|
return summarizeResult.summary;
|
|
2405
2533
|
}
|
|
2406
2534
|
|
|
2407
|
-
public
|
|
2408
|
-
if (this.context.getAbsoluteUrl === undefined) {
|
|
2409
|
-
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
2410
|
-
}
|
|
2411
|
-
if (this.attachState !== AttachState.Attached) {
|
|
2412
|
-
return undefined;
|
|
2413
|
-
}
|
|
2414
|
-
return this.context.getAbsoluteUrl(relativeUrl);
|
|
2415
|
-
}
|
|
2535
|
+
public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>;
|
|
2416
2536
|
|
|
2417
2537
|
private async summarizeInternal(
|
|
2418
2538
|
fullTree: boolean,
|
|
@@ -2497,7 +2617,7 @@ export class ContainerRuntime
|
|
|
2497
2617
|
|
|
2498
2618
|
return { stats, summary, gcStats };
|
|
2499
2619
|
} finally {
|
|
2500
|
-
this.logger.sendTelemetryEvent({
|
|
2620
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2501
2621
|
eventName: "SummarizeTelemetry",
|
|
2502
2622
|
details: telemetryContext.serialize(),
|
|
2503
2623
|
});
|
|
@@ -2700,8 +2820,11 @@ export class ContainerRuntime
|
|
|
2700
2820
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2701
2821
|
// use it for all events logged during this summary.
|
|
2702
2822
|
const summaryNumber = this.nextSummaryNumber;
|
|
2703
|
-
const summaryNumberLogger =
|
|
2704
|
-
|
|
2823
|
+
const summaryNumberLogger = createChildLogger({
|
|
2824
|
+
logger: summaryLogger,
|
|
2825
|
+
properties: {
|
|
2826
|
+
all: { summaryNumber },
|
|
2827
|
+
},
|
|
2705
2828
|
});
|
|
2706
2829
|
|
|
2707
2830
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
@@ -2709,7 +2832,11 @@ export class ContainerRuntime
|
|
|
2709
2832
|
let latestSnapshotVersionId: string | undefined;
|
|
2710
2833
|
if (refreshLatestAck) {
|
|
2711
2834
|
const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(
|
|
2712
|
-
|
|
2835
|
+
createChildLogger({
|
|
2836
|
+
logger: summaryNumberLogger,
|
|
2837
|
+
namespace: undefined,
|
|
2838
|
+
properties: { all: { safeSummary: true } },
|
|
2839
|
+
}),
|
|
2713
2840
|
);
|
|
2714
2841
|
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
2715
2842
|
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
@@ -2881,7 +3008,7 @@ export class ContainerRuntime
|
|
|
2881
3008
|
} else if (lastAck === undefined) {
|
|
2882
3009
|
summaryContext = {
|
|
2883
3010
|
proposalHandle: undefined,
|
|
2884
|
-
ackHandle: this.
|
|
3011
|
+
ackHandle: this.loadedFromVersionId,
|
|
2885
3012
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2886
3013
|
};
|
|
2887
3014
|
} else {
|
|
@@ -2982,7 +3109,6 @@ export class ContainerRuntime
|
|
|
2982
3109
|
this.dirtyContainer = dirty;
|
|
2983
3110
|
if (this.emitDirtyDocumentEvent) {
|
|
2984
3111
|
this.emit(dirty ? "dirty" : "saved");
|
|
2985
|
-
this.context.updateDirtyContainerState(dirty);
|
|
2986
3112
|
}
|
|
2987
3113
|
}
|
|
2988
3114
|
|
|
@@ -2995,7 +3121,10 @@ export class ContainerRuntime
|
|
|
2995
3121
|
address: id,
|
|
2996
3122
|
contents,
|
|
2997
3123
|
};
|
|
2998
|
-
this.submit(
|
|
3124
|
+
this.submit(
|
|
3125
|
+
{ type: ContainerMessageType.FluidDataStoreOp, contents: envelope },
|
|
3126
|
+
localOpMetadata,
|
|
3127
|
+
);
|
|
2999
3128
|
}
|
|
3000
3129
|
|
|
3001
3130
|
public submitDataStoreAliasOp(contents: any, localOpMetadata: unknown): void {
|
|
@@ -3004,12 +3133,15 @@ export class ContainerRuntime
|
|
|
3004
3133
|
throw new UsageError("malformedDataStoreAliasMessage");
|
|
3005
3134
|
}
|
|
3006
3135
|
|
|
3007
|
-
this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
|
|
3136
|
+
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
3008
3137
|
}
|
|
3009
3138
|
|
|
3010
|
-
public async uploadBlob(
|
|
3139
|
+
public async uploadBlob(
|
|
3140
|
+
blob: ArrayBufferLike,
|
|
3141
|
+
signal?: AbortSignal,
|
|
3142
|
+
): Promise<IFluidHandle<ArrayBufferLike>> {
|
|
3011
3143
|
this.verifyNotClosed();
|
|
3012
|
-
return this.blobManager.createBlob(blob);
|
|
3144
|
+
return this.blobManager.createBlob(blob, signal);
|
|
3013
3145
|
}
|
|
3014
3146
|
|
|
3015
3147
|
private maybeSubmitIdAllocationOp(type: ContainerMessageType) {
|
|
@@ -3047,8 +3179,7 @@ export class ContainerRuntime
|
|
|
3047
3179
|
}
|
|
3048
3180
|
|
|
3049
3181
|
private submit(
|
|
3050
|
-
|
|
3051
|
-
contents: any,
|
|
3182
|
+
containerRuntimeMessage: ContainerRuntimeMessage,
|
|
3052
3183
|
localOpMetadata: unknown = undefined,
|
|
3053
3184
|
metadata: Record<string, unknown> | undefined = undefined,
|
|
3054
3185
|
): void {
|
|
@@ -3061,17 +3192,18 @@ export class ContainerRuntime
|
|
|
3061
3192
|
0x132 /* "sending ops in detached container" */,
|
|
3062
3193
|
);
|
|
3063
3194
|
|
|
3064
|
-
const serializedContent = JSON.stringify(
|
|
3195
|
+
const serializedContent = JSON.stringify(containerRuntimeMessage);
|
|
3065
3196
|
|
|
3066
3197
|
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
3067
3198
|
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
3068
3199
|
if (this.innerDeltaManager.readOnlyInfo.readonly) {
|
|
3069
|
-
this.logger.sendTelemetryEvent({
|
|
3200
|
+
this.mc.logger.sendTelemetryEvent({
|
|
3070
3201
|
eventName: "SubmitOpInReadonly",
|
|
3071
3202
|
connected: this.connected,
|
|
3072
3203
|
});
|
|
3073
3204
|
}
|
|
3074
3205
|
|
|
3206
|
+
const type = containerRuntimeMessage.type;
|
|
3075
3207
|
const message: BatchMessage = {
|
|
3076
3208
|
contents: serializedContent,
|
|
3077
3209
|
type,
|
|
@@ -3130,7 +3262,7 @@ export class ContainerRuntime
|
|
|
3130
3262
|
throw error;
|
|
3131
3263
|
}
|
|
3132
3264
|
|
|
3133
|
-
if (this.isContainerMessageDirtyable(
|
|
3265
|
+
if (this.isContainerMessageDirtyable(containerRuntimeMessage)) {
|
|
3134
3266
|
this.updateDocumentDirtyState(true);
|
|
3135
3267
|
}
|
|
3136
3268
|
}
|
|
@@ -3186,9 +3318,9 @@ export class ContainerRuntime
|
|
|
3186
3318
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
3187
3319
|
|
|
3188
3320
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
3189
|
-
return this.
|
|
3190
|
-
? this.
|
|
3191
|
-
: this.
|
|
3321
|
+
return this.submitSummaryFn !== undefined
|
|
3322
|
+
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
3323
|
+
: this.submitFn(MessageType.Summarize, contents, false);
|
|
3192
3324
|
}
|
|
3193
3325
|
|
|
3194
3326
|
/**
|
|
@@ -3243,38 +3375,38 @@ export class ContainerRuntime
|
|
|
3243
3375
|
|
|
3244
3376
|
private reSubmit(message: IPendingBatchMessage) {
|
|
3245
3377
|
// Need to parse from string for back-compat
|
|
3246
|
-
const
|
|
3247
|
-
this.reSubmitCore(
|
|
3378
|
+
const containerRuntimeMessage = this.parseOpContent(message.content);
|
|
3379
|
+
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
3248
3380
|
}
|
|
3249
3381
|
|
|
3250
3382
|
/**
|
|
3251
3383
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
3252
3384
|
* reconnect and there are pending messages.
|
|
3253
|
-
* @param
|
|
3385
|
+
* @param message - The original ContainerRuntimeMessage.
|
|
3254
3386
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
3255
3387
|
*/
|
|
3256
3388
|
private reSubmitCore(
|
|
3257
|
-
|
|
3258
|
-
content: any,
|
|
3389
|
+
message: ContainerRuntimeMessage,
|
|
3259
3390
|
localOpMetadata: unknown,
|
|
3260
3391
|
opMetadata: Record<string, unknown> | undefined,
|
|
3261
3392
|
) {
|
|
3262
|
-
|
|
3393
|
+
const contents = message.contents;
|
|
3394
|
+
switch (message.type) {
|
|
3263
3395
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3264
3396
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3265
3397
|
// and trigger resubmission on it.
|
|
3266
|
-
this.dataStores.resubmitDataStoreOp(
|
|
3398
|
+
this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
|
|
3267
3399
|
break;
|
|
3268
3400
|
case ContainerMessageType.Attach:
|
|
3269
3401
|
case ContainerMessageType.Alias:
|
|
3270
|
-
this.submit(
|
|
3402
|
+
this.submit(message, localOpMetadata);
|
|
3271
3403
|
break;
|
|
3272
3404
|
case ContainerMessageType.IdAllocation:
|
|
3273
3405
|
// Remove the stashedState from the op if it's a stashed op
|
|
3274
|
-
if (
|
|
3275
|
-
delete
|
|
3406
|
+
if (contents.stashedState !== undefined) {
|
|
3407
|
+
delete contents.stashedState;
|
|
3276
3408
|
}
|
|
3277
|
-
this.submit(
|
|
3409
|
+
this.submit(message, localOpMetadata);
|
|
3278
3410
|
break;
|
|
3279
3411
|
case ContainerMessageType.ChunkedOp:
|
|
3280
3412
|
throw new Error(`chunkedOp not expected here`);
|
|
@@ -3282,10 +3414,13 @@ export class ContainerRuntime
|
|
|
3282
3414
|
this.blobManager.reSubmit(opMetadata);
|
|
3283
3415
|
break;
|
|
3284
3416
|
case ContainerMessageType.Rejoin:
|
|
3285
|
-
this.submit(
|
|
3417
|
+
this.submit(message);
|
|
3286
3418
|
break;
|
|
3287
3419
|
default:
|
|
3288
|
-
unreachableCase(
|
|
3420
|
+
unreachableCase(
|
|
3421
|
+
message.type,
|
|
3422
|
+
`Unknown ContainerMessageType [type: ${message.type}]`,
|
|
3423
|
+
);
|
|
3289
3424
|
}
|
|
3290
3425
|
}
|
|
3291
3426
|
|
|
@@ -3348,7 +3483,7 @@ export class ContainerRuntime
|
|
|
3348
3483
|
* change that started fetching latest snapshot always.
|
|
3349
3484
|
*/
|
|
3350
3485
|
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3351
|
-
fetchResult = await this.
|
|
3486
|
+
fetchResult = await this.fetchSnapshotFromStorageAndClose(
|
|
3352
3487
|
summaryLogger,
|
|
3353
3488
|
{
|
|
3354
3489
|
eventName: "RefreshLatestSummaryAckFetchBackCompat",
|
|
@@ -3455,10 +3590,15 @@ export class ContainerRuntime
|
|
|
3455
3590
|
event: ITelemetryGenericEvent,
|
|
3456
3591
|
readAndParseBlob: ReadAndParseBlob,
|
|
3457
3592
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3458
|
-
return this.
|
|
3593
|
+
return this.fetchSnapshotFromStorageAndClose(
|
|
3594
|
+
logger,
|
|
3595
|
+
event,
|
|
3596
|
+
readAndParseBlob,
|
|
3597
|
+
null /* latest */,
|
|
3598
|
+
);
|
|
3459
3599
|
}
|
|
3460
3600
|
|
|
3461
|
-
private async
|
|
3601
|
+
private async fetchSnapshotFromStorageAndClose(
|
|
3462
3602
|
logger: ITelemetryLoggerExt,
|
|
3463
3603
|
event: ITelemetryGenericEvent,
|
|
3464
3604
|
readAndParseBlob: ReadAndParseBlob,
|
|
@@ -3514,9 +3654,7 @@ export class ContainerRuntime
|
|
|
3514
3654
|
// We choose to close the summarizer after the snapshot cache is updated to avoid
|
|
3515
3655
|
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
3516
3656
|
// loads the summarizer from cache.
|
|
3517
|
-
if (this.summaryStateUpdateMethod
|
|
3518
|
-
const error = new GenericError("Restarting summarizer instead of refreshing");
|
|
3519
|
-
|
|
3657
|
+
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
3520
3658
|
this.mc.logger.sendTelemetryEvent(
|
|
3521
3659
|
{
|
|
3522
3660
|
...event,
|
|
@@ -3526,14 +3664,13 @@ export class ContainerRuntime
|
|
|
3526
3664
|
versionId: versionId != null ? versionId : undefined,
|
|
3527
3665
|
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
3528
3666
|
},
|
|
3529
|
-
|
|
3667
|
+
new GenericError("Restarting summarizer instead of refreshing"),
|
|
3530
3668
|
);
|
|
3531
3669
|
|
|
3532
|
-
// Delay
|
|
3670
|
+
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3533
3671
|
await delay(this.closeSummarizerDelayMs);
|
|
3534
3672
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
3535
|
-
this.
|
|
3536
|
-
throw error;
|
|
3673
|
+
this.disposeFn();
|
|
3537
3674
|
}
|
|
3538
3675
|
|
|
3539
3676
|
return snapshotResults;
|
|
@@ -3557,7 +3694,7 @@ export class ContainerRuntime
|
|
|
3557
3694
|
}
|
|
3558
3695
|
|
|
3559
3696
|
public readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"] = (...args) => {
|
|
3560
|
-
if (this.
|
|
3697
|
+
if (this.isSummarizerClient) {
|
|
3561
3698
|
return this.summarizer.summarizeOnDemand(...args);
|
|
3562
3699
|
} else if (this.summaryManager !== undefined) {
|
|
3563
3700
|
return this.summaryManager.summarizeOnDemand(...args);
|
|
@@ -3570,7 +3707,7 @@ export class ContainerRuntime
|
|
|
3570
3707
|
};
|
|
3571
3708
|
|
|
3572
3709
|
public readonly enqueueSummarize: ISummarizer["enqueueSummarize"] = (...args) => {
|
|
3573
|
-
if (this.
|
|
3710
|
+
if (this.isSummarizerClient) {
|
|
3574
3711
|
return this.summarizer.enqueueSummarize(...args);
|
|
3575
3712
|
} else if (this.summaryManager !== undefined) {
|
|
3576
3713
|
return this.summaryManager.enqueueSummarize(...args);
|