@fluidframework/container-runtime 2.0.0-internal.5.3.2 → 2.0.0-internal.6.0.0
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 +80 -0
- package/dist/batchTracker.d.ts +2 -1
- 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 +13 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +103 -25
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +12 -4
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +69 -22
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +344 -238
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +11 -2
- 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 +40 -44
- 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 +21 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +102 -58
- 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 +29 -25
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +13 -11
- package/dist/gc/gcConfigs.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 +5 -6
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +4 -6
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +44 -33
- 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 +52 -52
- package/dist/id-compressor/idCompressor.js.map +1 -1
- package/dist/id-compressor/idRange.js +2 -2
- package/dist/id-compressor/idRange.js.map +1 -1
- package/dist/id-compressor/sessionIdNormalizer.js +11 -16
- package/dist/id-compressor/sessionIdNormalizer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/opLifecycle/batchManager.js +10 -6
- package/dist/opLifecycle/batchManager.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 +7 -2
- 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 +12 -10
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +13 -5
- package/dist/opLifecycle/opGroupingManager.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 +11 -7
- 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 +6 -14
- 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 +8 -2
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/opProperties.js +1 -2
- package/dist/opProperties.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 +6 -3
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +41 -32
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/scheduleManager.d.ts.map +1 -1
- package/dist/scheduleManager.js +15 -11
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -1
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +18 -19
- 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 +42 -66
- package/dist/summary/runningSummarizer.js.map +1 -1
- package/dist/summary/summarizer.js +5 -8
- package/dist/summary/summarizer.js.map +1 -1
- package/dist/summary/summarizerClientElection.js +5 -9
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerHeuristics.js +8 -12
- package/dist/summary/summarizerHeuristics.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 +26 -22
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -4
- package/dist/summary/summarizerNode/summarizerNodeUtils.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 +13 -16
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summaryCollection.js +3 -5
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryFormat.js +1 -2
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryGenerator.js +67 -21
- 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 +9 -7
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +2 -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 +13 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +103 -25
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +13 -5
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +69 -22
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +343 -238
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +11 -2
- 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 +42 -46
- 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 +21 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +103 -59
- 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 +30 -26
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcConfigs.js +13 -11
- package/lib/gc/gcConfigs.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 +5 -6
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +4 -6
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +45 -34
- 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 +52 -52
- package/lib/id-compressor/idCompressor.js.map +1 -1
- package/lib/id-compressor/idRange.js +2 -2
- package/lib/id-compressor/idRange.js.map +1 -1
- package/lib/id-compressor/sessionIdNormalizer.js +11 -16
- package/lib/id-compressor/sessionIdNormalizer.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/opLifecycle/batchManager.js +10 -6
- package/lib/opLifecycle/batchManager.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 +8 -3
- 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 +13 -11
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +13 -5
- package/lib/opLifecycle/opGroupingManager.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 +12 -8
- 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 +7 -15
- 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 +8 -2
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/opProperties.js +1 -2
- package/lib/opProperties.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 +6 -3
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +41 -32
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/scheduleManager.d.ts.map +1 -1
- package/lib/scheduleManager.js +16 -12
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -1
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +19 -20
- 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 +43 -67
- package/lib/summary/runningSummarizer.js.map +1 -1
- package/lib/summary/summarizer.js +6 -9
- package/lib/summary/summarizer.js.map +1 -1
- package/lib/summary/summarizerClientElection.js +5 -9
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerHeuristics.js +8 -12
- package/lib/summary/summarizerHeuristics.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 +27 -23
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -4
- package/lib/summary/summarizerNode/summarizerNodeUtils.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 +14 -17
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summaryCollection.js +3 -5
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryFormat.js +1 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/lib/summary/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryGenerator.js +68 -22
- 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 +10 -8
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +30 -18
- package/src/batchTracker.ts +4 -3
- package/src/blobManager.ts +113 -15
- package/src/connectionTelemetry.ts +7 -3
- package/src/containerRuntime.ts +354 -194
- package/src/dataStore.ts +10 -1
- package/src/dataStoreContext.ts +31 -33
- package/src/dataStoreContexts.ts +2 -2
- package/src/dataStores.ts +108 -71
- 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 +13 -10
- package/src/id-compressor/idCompressor.ts +6 -5
- package/src/index.ts +0 -1
- 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 +34 -25
- package/src/scheduleManager.ts +2 -2
- package/src/summary/orderedClientElection.ts +4 -3
- 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,
|
|
@@ -443,14 +445,6 @@ export interface IContainerRuntimeOptions {
|
|
|
443
445
|
readonly enableGroupedBatching?: boolean;
|
|
444
446
|
}
|
|
445
447
|
|
|
446
|
-
/**
|
|
447
|
-
* The summary tree returned by the root node. It adds state relevant to the root of the tree.
|
|
448
|
-
*/
|
|
449
|
-
export interface IRootSummaryTreeWithStats extends ISummaryTreeWithStats {
|
|
450
|
-
/** The garbage collection stats if GC ran, undefined otherwise. */
|
|
451
|
-
gcStats?: IGCStats;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
448
|
/**
|
|
455
449
|
* Accepted header keys for requests coming to the runtime.
|
|
456
450
|
*/
|
|
@@ -540,7 +534,7 @@ const defaultChunkSizeInBytes = 204800;
|
|
|
540
534
|
* of the current system, we should close the summarizer and let it recover.
|
|
541
535
|
* This delay's goal is to prevent tight restart loops
|
|
542
536
|
*/
|
|
543
|
-
const defaultCloseSummarizerDelayMs =
|
|
537
|
+
const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
544
538
|
|
|
545
539
|
/**
|
|
546
540
|
* @deprecated - use ContainerRuntimeMessage instead
|
|
@@ -582,6 +576,30 @@ export function getDeviceSpec() {
|
|
|
582
576
|
return {};
|
|
583
577
|
}
|
|
584
578
|
|
|
579
|
+
/**
|
|
580
|
+
* Older loader doesn't have a submitBatchFn member, this is the older way of submitting a batch.
|
|
581
|
+
* Rather than exposing the submitFn (now deprecated) and IDeltaManager (dangerous to hand out) to the Outbox,
|
|
582
|
+
* we can provide a partially-applied function to keep those items private to the ContainerRuntime.
|
|
583
|
+
*/
|
|
584
|
+
export const makeLegacySendBatchFn =
|
|
585
|
+
(
|
|
586
|
+
submitFn: (type: MessageType, contents: any, batch: boolean, appData?: any) => number,
|
|
587
|
+
deltaManager: Pick<IDeltaManager<unknown, unknown>, "flush">,
|
|
588
|
+
) =>
|
|
589
|
+
(batch: IBatch) => {
|
|
590
|
+
for (const message of batch.content) {
|
|
591
|
+
submitFn(
|
|
592
|
+
MessageType.Operation,
|
|
593
|
+
// For back-compat (submitFn only works on deserialized content)
|
|
594
|
+
message.contents === undefined ? undefined : JSON.parse(message.contents),
|
|
595
|
+
true, // batch
|
|
596
|
+
message.metadata,
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
deltaManager.flush();
|
|
601
|
+
};
|
|
602
|
+
|
|
585
603
|
/**
|
|
586
604
|
* Represents the runtime of the container. Contains helper functions/state of the container.
|
|
587
605
|
* It will define the store level mappings.
|
|
@@ -590,6 +608,9 @@ export class ContainerRuntime
|
|
|
590
608
|
extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
591
609
|
implements IContainerRuntime, IRuntime, ISummarizerRuntime, ISummarizerInternalsProvider
|
|
592
610
|
{
|
|
611
|
+
/**
|
|
612
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
613
|
+
*/
|
|
593
614
|
public get IFluidRouter() {
|
|
594
615
|
return this;
|
|
595
616
|
}
|
|
@@ -671,9 +692,12 @@ export class ContainerRuntime
|
|
|
671
692
|
const passLogger =
|
|
672
693
|
backCompatContext.taggedLogger ??
|
|
673
694
|
new TaggedLoggerAdapter((backCompatContext as OldContainerContextWithLogger).logger);
|
|
674
|
-
const logger =
|
|
675
|
-
|
|
676
|
-
|
|
695
|
+
const logger = createChildLogger({
|
|
696
|
+
logger: passLogger,
|
|
697
|
+
properties: {
|
|
698
|
+
all: {
|
|
699
|
+
runtimeVersion: pkgVersion,
|
|
700
|
+
},
|
|
677
701
|
},
|
|
678
702
|
});
|
|
679
703
|
|
|
@@ -714,8 +738,6 @@ export class ContainerRuntime
|
|
|
714
738
|
tryFetchBlob<SerializedIdCompressorWithNoSession>(idCompressorBlobName),
|
|
715
739
|
]);
|
|
716
740
|
|
|
717
|
-
const loadExisting = existing === true || context.existing === true;
|
|
718
|
-
|
|
719
741
|
// read snapshot blobs needed for BlobManager to load
|
|
720
742
|
const blobManagerSnapshot = await BlobManager.load(
|
|
721
743
|
context.baseSnapshot?.trees[blobsTreeName],
|
|
@@ -750,9 +772,7 @@ export class ContainerRuntime
|
|
|
750
772
|
if (loadSequenceNumberVerification === "log") {
|
|
751
773
|
logger.sendErrorEvent({ eventName: "SequenceNumberMismatch" }, error);
|
|
752
774
|
} else {
|
|
753
|
-
// Call both close and dispose as closeFn implementation will no longer dispose runtime in future
|
|
754
775
|
context.closeFn(error);
|
|
755
|
-
context.disposeFn?.(error);
|
|
756
776
|
}
|
|
757
777
|
}
|
|
758
778
|
}
|
|
@@ -789,7 +809,7 @@ export class ContainerRuntime
|
|
|
789
809
|
},
|
|
790
810
|
containerScope,
|
|
791
811
|
logger,
|
|
792
|
-
|
|
812
|
+
existing,
|
|
793
813
|
blobManagerSnapshot,
|
|
794
814
|
context.storage,
|
|
795
815
|
idCompressor,
|
|
@@ -808,49 +828,48 @@ export class ContainerRuntime
|
|
|
808
828
|
return runtime;
|
|
809
829
|
}
|
|
810
830
|
|
|
811
|
-
public
|
|
812
|
-
return this.context.options;
|
|
813
|
-
}
|
|
831
|
+
public readonly options: ILoaderOptions;
|
|
814
832
|
|
|
833
|
+
private readonly _getClientId: () => string | undefined;
|
|
815
834
|
public get clientId(): string | undefined {
|
|
816
|
-
return this.
|
|
835
|
+
return this._getClientId();
|
|
817
836
|
}
|
|
818
837
|
|
|
819
|
-
public
|
|
820
|
-
return this.context.clientDetails;
|
|
821
|
-
}
|
|
838
|
+
public readonly clientDetails: IClientDetails;
|
|
822
839
|
|
|
823
840
|
public get storage(): IDocumentStorageService {
|
|
824
841
|
return this._storage;
|
|
825
842
|
}
|
|
826
843
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
public get disposeFn(): (error?: ICriticalContainerError) => void {
|
|
838
|
-
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
839
|
-
return this.context.disposeFn ?? this.context.closeFn;
|
|
844
|
+
/** @deprecated - The functionality is no longer exposed publicly */
|
|
845
|
+
public get reSubmitFn() {
|
|
846
|
+
return (
|
|
847
|
+
type: ContainerMessageType,
|
|
848
|
+
contents: any,
|
|
849
|
+
localOpMetadata: unknown,
|
|
850
|
+
opMetadata: Record<string, unknown> | undefined,
|
|
851
|
+
) => this.reSubmitCore({ type, contents }, localOpMetadata, opMetadata);
|
|
840
852
|
}
|
|
841
853
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
+
private readonly submitFn: (
|
|
855
|
+
type: MessageType,
|
|
856
|
+
contents: any,
|
|
857
|
+
batch: boolean,
|
|
858
|
+
appData?: any,
|
|
859
|
+
) => number;
|
|
860
|
+
/**
|
|
861
|
+
* Although current IContainerContext guarantees submitBatchFn, it is not available on older loaders.
|
|
862
|
+
*/
|
|
863
|
+
private readonly submitBatchFn:
|
|
864
|
+
| ((batch: IBatchMessage[], referenceSequenceNumber?: number) => number)
|
|
865
|
+
| undefined;
|
|
866
|
+
private readonly submitSummaryFn: (
|
|
867
|
+
summaryOp: ISummaryContent,
|
|
868
|
+
referenceSequenceNumber?: number,
|
|
869
|
+
) => number;
|
|
870
|
+
private readonly submitSignalFn: (contents: any) => void;
|
|
871
|
+
public readonly disposeFn: (error?: ICriticalContainerError) => void;
|
|
872
|
+
public readonly closeFn: (error?: ICriticalContainerError) => void;
|
|
854
873
|
|
|
855
874
|
public get flushMode(): FlushMode {
|
|
856
875
|
return this._flushMode;
|
|
@@ -864,8 +883,9 @@ export class ContainerRuntime
|
|
|
864
883
|
return this.registry;
|
|
865
884
|
}
|
|
866
885
|
|
|
886
|
+
private readonly _getAttachState: () => AttachState;
|
|
867
887
|
public get attachState(): AttachState {
|
|
868
|
-
return this.
|
|
888
|
+
return this._getAttachState();
|
|
869
889
|
}
|
|
870
890
|
|
|
871
891
|
public idCompressor: (IIdCompressor & IIdCompressorCore) | undefined;
|
|
@@ -1056,11 +1076,21 @@ export class ContainerRuntime
|
|
|
1056
1076
|
*/
|
|
1057
1077
|
private readonly idCompressorEnabled: boolean;
|
|
1058
1078
|
|
|
1079
|
+
/**
|
|
1080
|
+
* Whether this client is the summarizer client itself (type is summarizerClientType)
|
|
1081
|
+
*/
|
|
1082
|
+
private readonly isSummarizerClient: boolean;
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* The id of the version used to initially load this runtime, or undefined if it's newly created.
|
|
1086
|
+
*/
|
|
1087
|
+
private readonly loadedFromVersionId: string | undefined;
|
|
1088
|
+
|
|
1059
1089
|
/**
|
|
1060
1090
|
* @internal
|
|
1061
1091
|
*/
|
|
1062
1092
|
protected constructor(
|
|
1063
|
-
|
|
1093
|
+
context: IContainerContext,
|
|
1064
1094
|
private readonly registry: IFluidDataStoreRegistry,
|
|
1065
1095
|
metadata: IContainerRuntimeMetadata | undefined,
|
|
1066
1096
|
electedSummarizerData: ISerializedElection | undefined,
|
|
@@ -1087,10 +1117,64 @@ export class ContainerRuntime
|
|
|
1087
1117
|
) {
|
|
1088
1118
|
super();
|
|
1089
1119
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1120
|
+
const {
|
|
1121
|
+
options,
|
|
1122
|
+
clientDetails,
|
|
1123
|
+
connected,
|
|
1124
|
+
baseSnapshot,
|
|
1125
|
+
submitFn,
|
|
1126
|
+
submitBatchFn,
|
|
1127
|
+
submitSummaryFn,
|
|
1128
|
+
submitSignalFn,
|
|
1129
|
+
disposeFn,
|
|
1130
|
+
closeFn,
|
|
1131
|
+
deltaManager,
|
|
1132
|
+
quorum,
|
|
1133
|
+
audience,
|
|
1134
|
+
loader,
|
|
1135
|
+
pendingLocalState,
|
|
1136
|
+
supportedFeatures,
|
|
1137
|
+
} = context;
|
|
1138
|
+
|
|
1139
|
+
this.innerDeltaManager = deltaManager;
|
|
1140
|
+
this.deltaManager = new DeltaManagerSummarizerProxy(this.innerDeltaManager);
|
|
1141
|
+
|
|
1142
|
+
// Here we could wrap/intercept on these functions to block/modify outgoing messages if needed.
|
|
1143
|
+
// This makes ContainerRuntime the final gatekeeper for outgoing messages.
|
|
1144
|
+
this.submitFn = submitFn;
|
|
1145
|
+
this.submitBatchFn = submitBatchFn;
|
|
1146
|
+
this.submitSummaryFn = submitSummaryFn;
|
|
1147
|
+
this.submitSignalFn = submitSignalFn;
|
|
1148
|
+
|
|
1149
|
+
this.options = options;
|
|
1150
|
+
this.clientDetails = clientDetails;
|
|
1151
|
+
this.isSummarizerClient = this.clientDetails.type === summarizerClientType;
|
|
1152
|
+
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
1153
|
+
this._getClientId = () => context.clientId;
|
|
1154
|
+
this._getAttachState = () => context.attachState;
|
|
1155
|
+
this.getAbsoluteUrl = async (relativeUrl: string) => {
|
|
1156
|
+
if (context.getAbsoluteUrl === undefined) {
|
|
1157
|
+
throw new Error("Driver does not implement getAbsoluteUrl");
|
|
1158
|
+
}
|
|
1159
|
+
if (this.attachState !== AttachState.Attached) {
|
|
1160
|
+
return undefined;
|
|
1161
|
+
}
|
|
1162
|
+
return context.getAbsoluteUrl(relativeUrl);
|
|
1163
|
+
};
|
|
1164
|
+
// TODO: Consider that the Container could just listen to these events itself, or even more appropriately maybe the
|
|
1165
|
+
// customer should observe dirty state on the runtime (the owner of dirty state) directly, rather than on the IContainer.
|
|
1166
|
+
this.on("dirty", () => context.updateDirtyContainerState(true));
|
|
1167
|
+
this.on("saved", () => context.updateDirtyContainerState(false));
|
|
1168
|
+
|
|
1169
|
+
// In old loaders without dispose functionality, closeFn is equivalent but will also switch container to readonly mode
|
|
1170
|
+
this.disposeFn = disposeFn ?? closeFn;
|
|
1171
|
+
// In cases of summarizer, we want to dispose instead since consumer doesn't interact with this container
|
|
1172
|
+
this.closeFn = this.isSummarizerClient ? this.disposeFn : closeFn;
|
|
1092
1173
|
|
|
1093
|
-
this.mc =
|
|
1174
|
+
this.mc = createChildMonitoringContext({
|
|
1175
|
+
logger: this.logger,
|
|
1176
|
+
namespace: "ContainerRuntime",
|
|
1177
|
+
});
|
|
1094
1178
|
|
|
1095
1179
|
let loadSummaryNumber: number;
|
|
1096
1180
|
// Get the container creation metadata. For new container, we initialize these. For existing containers,
|
|
@@ -1122,7 +1206,9 @@ export class ContainerRuntime
|
|
|
1122
1206
|
|
|
1123
1207
|
this.messageAtLastSummary = metadata?.message;
|
|
1124
1208
|
|
|
1125
|
-
|
|
1209
|
+
// Note that we only need to pull the *initial* connected state from the context.
|
|
1210
|
+
// Later updates come through calls to setConnectionState.
|
|
1211
|
+
this._connected = connected;
|
|
1126
1212
|
|
|
1127
1213
|
this.gcTombstoneEnforcementAllowed = shouldAllowGcTombstoneEnforcement(
|
|
1128
1214
|
metadata?.gcFeatureMatrix?.tombstoneGeneration /* persisted */,
|
|
@@ -1151,7 +1237,7 @@ export class ContainerRuntime
|
|
|
1151
1237
|
|
|
1152
1238
|
const opSplitter = new OpSplitter(
|
|
1153
1239
|
chunks,
|
|
1154
|
-
this.
|
|
1240
|
+
this.submitBatchFn,
|
|
1155
1241
|
disableChunking === true ? Number.POSITIVE_INFINITY : runtimeOptions.chunkSizeInBytes,
|
|
1156
1242
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1157
1243
|
this.mc.logger,
|
|
@@ -1192,7 +1278,7 @@ export class ContainerRuntime
|
|
|
1192
1278
|
|
|
1193
1279
|
if (
|
|
1194
1280
|
runtimeOptions.flushMode === (FlushModeExperimental.Async as unknown as FlushMode) &&
|
|
1195
|
-
|
|
1281
|
+
supportedFeatures?.get("referenceSequenceNumbers") !== true
|
|
1196
1282
|
) {
|
|
1197
1283
|
// The loader does not support reference sequence numbers, falling back on FlushMode.TurnBased
|
|
1198
1284
|
this.mc.logger.sendErrorEvent({ eventName: "FlushModeFallback" });
|
|
@@ -1201,7 +1287,7 @@ export class ContainerRuntime
|
|
|
1201
1287
|
this._flushMode = runtimeOptions.flushMode;
|
|
1202
1288
|
}
|
|
1203
1289
|
|
|
1204
|
-
const pendingRuntimeState =
|
|
1290
|
+
const pendingRuntimeState = pendingLocalState as IPendingRuntimeState | undefined;
|
|
1205
1291
|
|
|
1206
1292
|
const maxSnapshotCacheDurationMs = this._storage?.policies?.maximumCacheDurationMs;
|
|
1207
1293
|
if (
|
|
@@ -1217,12 +1303,12 @@ export class ContainerRuntime
|
|
|
1217
1303
|
this.garbageCollector = GarbageCollector.create({
|
|
1218
1304
|
runtime: this,
|
|
1219
1305
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
1220
|
-
baseSnapshot
|
|
1306
|
+
baseSnapshot,
|
|
1221
1307
|
baseLogger: this.mc.logger,
|
|
1222
1308
|
existing,
|
|
1223
1309
|
metadata,
|
|
1224
1310
|
createContainerMetadata: this.createContainerMetadata,
|
|
1225
|
-
isSummarizerClient: this.
|
|
1311
|
+
isSummarizerClient: this.isSummarizerClient,
|
|
1226
1312
|
getNodePackagePath: async (nodePath: string) => this.getGCNodePackagePath(nodePath),
|
|
1227
1313
|
getLastSummaryTimestampMs: () => this.messageAtLastSummary?.timestamp,
|
|
1228
1314
|
readAndParseBlob: async <T>(id: string) => readAndParse<T>(this.storage, id),
|
|
@@ -1233,14 +1319,14 @@ export class ContainerRuntime
|
|
|
1233
1319
|
|
|
1234
1320
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
1235
1321
|
this.summarizerNode = createRootSummarizerNodeWithGC(
|
|
1236
|
-
|
|
1322
|
+
createChildLogger({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
1237
1323
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
1238
1324
|
async (fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext) =>
|
|
1239
1325
|
this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
1240
1326
|
// Latest change sequence number, no changes since summary applied yet
|
|
1241
1327
|
loadedFromSequenceNumber,
|
|
1242
1328
|
// Summary reference sequence number, undefined if no summary yet
|
|
1243
|
-
|
|
1329
|
+
baseSnapshot !== undefined ? loadedFromSequenceNumber : undefined,
|
|
1244
1330
|
{
|
|
1245
1331
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1246
1332
|
// a summary with an older protocol state.
|
|
@@ -1257,14 +1343,14 @@ export class ContainerRuntime
|
|
|
1257
1343
|
async () => this.garbageCollector.getBaseGCDetails(),
|
|
1258
1344
|
);
|
|
1259
1345
|
|
|
1260
|
-
if (
|
|
1261
|
-
this.summarizerNode.updateBaseSummaryState(
|
|
1346
|
+
if (baseSnapshot) {
|
|
1347
|
+
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1262
1348
|
}
|
|
1263
1349
|
|
|
1264
1350
|
this.dataStores = new DataStores(
|
|
1265
|
-
getSummaryForDatastores(
|
|
1351
|
+
getSummaryForDatastores(baseSnapshot, metadata),
|
|
1266
1352
|
this,
|
|
1267
|
-
(attachMsg) => this.submit(ContainerMessageType.Attach, attachMsg),
|
|
1353
|
+
(attachMsg) => this.submit({ type: ContainerMessageType.Attach, contents: attachMsg }),
|
|
1268
1354
|
(id: string, createParam: CreateChildSummarizerNodeParam) =>
|
|
1269
1355
|
(
|
|
1270
1356
|
summarizeInternal: SummarizeInternalFn,
|
|
@@ -1291,10 +1377,14 @@ export class ContainerRuntime
|
|
|
1291
1377
|
() => this.storage,
|
|
1292
1378
|
(localId: string, blobId?: string) => {
|
|
1293
1379
|
if (!this.disposed) {
|
|
1294
|
-
this.submit(
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1380
|
+
this.submit(
|
|
1381
|
+
{ type: ContainerMessageType.BlobAttach, contents: undefined },
|
|
1382
|
+
undefined,
|
|
1383
|
+
{
|
|
1384
|
+
localId,
|
|
1385
|
+
blobId,
|
|
1386
|
+
},
|
|
1387
|
+
);
|
|
1298
1388
|
}
|
|
1299
1389
|
},
|
|
1300
1390
|
(blobPath: string) => this.garbageCollector.nodeUpdated(blobPath, "Loaded"),
|
|
@@ -1305,10 +1395,10 @@ export class ContainerRuntime
|
|
|
1305
1395
|
);
|
|
1306
1396
|
|
|
1307
1397
|
this.scheduleManager = new ScheduleManager(
|
|
1308
|
-
|
|
1398
|
+
this.innerDeltaManager,
|
|
1309
1399
|
this,
|
|
1310
1400
|
() => this.clientId,
|
|
1311
|
-
|
|
1401
|
+
createChildLogger({ logger: this.logger, namespace: "ScheduleManager" }),
|
|
1312
1402
|
);
|
|
1313
1403
|
|
|
1314
1404
|
this.pendingStateManager = new PendingStateManager(
|
|
@@ -1319,8 +1409,10 @@ export class ContainerRuntime
|
|
|
1319
1409
|
connected: () => this.connected,
|
|
1320
1410
|
reSubmit: this.reSubmit.bind(this),
|
|
1321
1411
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1412
|
+
isActiveConnection: () => this.innerDeltaManager.active,
|
|
1322
1413
|
},
|
|
1323
1414
|
pendingRuntimeState?.pending,
|
|
1415
|
+
this.logger,
|
|
1324
1416
|
);
|
|
1325
1417
|
|
|
1326
1418
|
const disableCompression = this.mc.config.getBoolean(
|
|
@@ -1337,10 +1429,14 @@ export class ContainerRuntime
|
|
|
1337
1429
|
const disablePartialFlush = this.mc.config.getBoolean(
|
|
1338
1430
|
"Fluid.ContainerRuntime.DisablePartialFlush",
|
|
1339
1431
|
);
|
|
1432
|
+
|
|
1433
|
+
const legacySendBatchFn = makeLegacySendBatchFn(this.submitFn, this.innerDeltaManager);
|
|
1434
|
+
|
|
1340
1435
|
this.outbox = new Outbox({
|
|
1341
1436
|
shouldSend: () => this.canSendOps(),
|
|
1342
1437
|
pendingStateManager: this.pendingStateManager,
|
|
1343
|
-
|
|
1438
|
+
submitBatchFn: this.submitBatchFn,
|
|
1439
|
+
legacySendBatchFn,
|
|
1344
1440
|
compressor: new OpCompressor(this.mc.logger),
|
|
1345
1441
|
splitter: opSplitter,
|
|
1346
1442
|
config: {
|
|
@@ -1360,10 +1456,14 @@ export class ContainerRuntime
|
|
|
1360
1456
|
closeContainer: this.closeFn,
|
|
1361
1457
|
});
|
|
1362
1458
|
|
|
1363
|
-
this.
|
|
1459
|
+
this._quorum = quorum;
|
|
1460
|
+
this._quorum.on("removeMember", (clientId: string) => {
|
|
1364
1461
|
this.remoteMessageProcessor.clearPartialMessagesFor(clientId);
|
|
1365
1462
|
});
|
|
1366
1463
|
|
|
1464
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1465
|
+
this._audience = audience!;
|
|
1466
|
+
|
|
1367
1467
|
this.summaryStateUpdateMethod = this.mc.config.getString(
|
|
1368
1468
|
"Fluid.ContainerRuntime.Test.SummaryStateUpdateMethodV2",
|
|
1369
1469
|
);
|
|
@@ -1378,23 +1478,26 @@ export class ContainerRuntime
|
|
|
1378
1478
|
this.summaryCollection = new SummaryCollection(this.deltaManager, this.logger);
|
|
1379
1479
|
|
|
1380
1480
|
this.dirtyContainer =
|
|
1381
|
-
this.
|
|
1481
|
+
this.attachState !== AttachState.Attached ||
|
|
1382
1482
|
this.pendingStateManager.hasPendingMessages();
|
|
1383
|
-
|
|
1483
|
+
context.updateDirtyContainerState(this.dirtyContainer);
|
|
1384
1484
|
|
|
1385
1485
|
if (this.summariesDisabled) {
|
|
1386
1486
|
this.mc.logger.sendTelemetryEvent({ eventName: "SummariesDisabled" });
|
|
1387
1487
|
} else {
|
|
1388
|
-
const orderedClientLogger =
|
|
1488
|
+
const orderedClientLogger = createChildLogger({
|
|
1489
|
+
logger: this.logger,
|
|
1490
|
+
namespace: "OrderedClientElection",
|
|
1491
|
+
});
|
|
1389
1492
|
const orderedClientCollection = new OrderedClientCollection(
|
|
1390
1493
|
orderedClientLogger,
|
|
1391
|
-
this.
|
|
1392
|
-
this.
|
|
1494
|
+
this.innerDeltaManager,
|
|
1495
|
+
this._quorum,
|
|
1393
1496
|
);
|
|
1394
1497
|
const orderedClientElectionForSummarizer = new OrderedClientElection(
|
|
1395
1498
|
orderedClientLogger,
|
|
1396
1499
|
orderedClientCollection,
|
|
1397
|
-
electedSummarizerData ?? this.
|
|
1500
|
+
electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber,
|
|
1398
1501
|
SummarizerClientElection.isClientEligible,
|
|
1399
1502
|
);
|
|
1400
1503
|
|
|
@@ -1405,7 +1508,7 @@ export class ContainerRuntime
|
|
|
1405
1508
|
this.maxOpsSinceLastSummary,
|
|
1406
1509
|
);
|
|
1407
1510
|
|
|
1408
|
-
if (this.
|
|
1511
|
+
if (this.isSummarizerClient) {
|
|
1409
1512
|
this._summarizer = new Summarizer(
|
|
1410
1513
|
this /* ISummarizerRuntime */,
|
|
1411
1514
|
() => this.summaryConfiguration,
|
|
@@ -1420,19 +1523,19 @@ export class ContainerRuntime
|
|
|
1420
1523
|
() => this.innerDeltaManager.active,
|
|
1421
1524
|
),
|
|
1422
1525
|
);
|
|
1423
|
-
} else if (
|
|
1424
|
-
SummarizerClientElection.clientDetailsPermitElection(this.context.clientDetails)
|
|
1425
|
-
) {
|
|
1526
|
+
} else if (SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
1426
1527
|
// Only create a SummaryManager and SummarizerClientElection
|
|
1427
1528
|
// if summaries are enabled and we are not the summarizer client.
|
|
1428
1529
|
const defaultAction = () => {
|
|
1429
1530
|
if (this.summaryCollection.opsSinceLastAck > this.maxOpsSinceLastSummary) {
|
|
1430
|
-
this.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
1531
|
+
this.mc.logger.sendTelemetryEvent({ eventName: "SummaryStatus:Behind" });
|
|
1431
1532
|
// unregister default to no log on every op after falling behind
|
|
1432
1533
|
// and register summary ack handler to re-register this handler
|
|
1433
1534
|
// after successful summary
|
|
1434
1535
|
this.summaryCollection.once(MessageType.SummaryAck, () => {
|
|
1435
|
-
this.logger.sendTelemetryEvent({
|
|
1536
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1537
|
+
eventName: "SummaryStatus:CaughtUp",
|
|
1538
|
+
});
|
|
1436
1539
|
// we've caught up, so re-register the default action to monitor for
|
|
1437
1540
|
// falling behind, and unregister ourself
|
|
1438
1541
|
this.summaryCollection.on("default", defaultAction);
|
|
@@ -1449,7 +1552,7 @@ export class ContainerRuntime
|
|
|
1449
1552
|
this, // IConnectedState
|
|
1450
1553
|
this.summaryCollection,
|
|
1451
1554
|
this.logger,
|
|
1452
|
-
this.formRequestSummarizerFn(
|
|
1555
|
+
this.formRequestSummarizerFn(loader),
|
|
1453
1556
|
new Throttler(
|
|
1454
1557
|
60 * 1000, // 60 sec delay window
|
|
1455
1558
|
30 * 1000, // 30 sec max delay
|
|
@@ -1500,7 +1603,7 @@ export class ContainerRuntime
|
|
|
1500
1603
|
...getDeviceSpec(),
|
|
1501
1604
|
});
|
|
1502
1605
|
|
|
1503
|
-
this.logger.sendTelemetryEvent({
|
|
1606
|
+
this.mc.logger.sendTelemetryEvent({
|
|
1504
1607
|
eventName: "ContainerLoadStats",
|
|
1505
1608
|
...this.createContainerMetadata,
|
|
1506
1609
|
...this.dataStores.containerLoadStats,
|
|
@@ -1523,11 +1626,11 @@ export class ContainerRuntime
|
|
|
1523
1626
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
1524
1627
|
});
|
|
1525
1628
|
|
|
1526
|
-
ReportOpPerfTelemetry(this.
|
|
1629
|
+
ReportOpPerfTelemetry(this.clientId, this.deltaManager, this.logger);
|
|
1527
1630
|
BindBatchTracker(this, this.logger);
|
|
1528
1631
|
|
|
1529
1632
|
this.entryPoint = new LazyPromise(async () => {
|
|
1530
|
-
if (this.
|
|
1633
|
+
if (this.isSummarizerClient) {
|
|
1531
1634
|
assert(
|
|
1532
1635
|
this._summarizer !== undefined,
|
|
1533
1636
|
0x5bf /* Summarizer object is undefined in a summarizer client */,
|
|
@@ -1551,7 +1654,7 @@ export class ContainerRuntime
|
|
|
1551
1654
|
}
|
|
1552
1655
|
this._disposed = true;
|
|
1553
1656
|
|
|
1554
|
-
this.logger.sendTelemetryEvent(
|
|
1657
|
+
this.mc.logger.sendTelemetryEvent(
|
|
1555
1658
|
{
|
|
1556
1659
|
eventName: "ContainerRuntimeDisposed",
|
|
1557
1660
|
isDirty: this.isDirty,
|
|
@@ -1575,6 +1678,7 @@ export class ContainerRuntime
|
|
|
1575
1678
|
/**
|
|
1576
1679
|
* Notifies this object about the request made to the container.
|
|
1577
1680
|
* @param request - Request made to the handler.
|
|
1681
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
1578
1682
|
*/
|
|
1579
1683
|
public async request(request: IRequest): Promise<IResponse> {
|
|
1580
1684
|
try {
|
|
@@ -1841,14 +1945,11 @@ export class ContainerRuntime
|
|
|
1841
1945
|
* Parse an op's type and actual content from given serialized content
|
|
1842
1946
|
* ! Note: this format needs to be in-line with what is set in the "ContainerRuntime.submit(...)" method
|
|
1843
1947
|
*/
|
|
1844
|
-
private parseOpContent(serializedContent?: string): {
|
|
1845
|
-
type: ContainerMessageType;
|
|
1846
|
-
contents: unknown;
|
|
1847
|
-
} {
|
|
1948
|
+
private parseOpContent(serializedContent?: string): ContainerRuntimeMessage {
|
|
1848
1949
|
assert(serializedContent !== undefined, 0x6d5 /* content must be defined */);
|
|
1849
|
-
const
|
|
1850
|
-
assert(
|
|
1851
|
-
return { type
|
|
1950
|
+
const { type, contents } = JSON.parse(serializedContent);
|
|
1951
|
+
assert(type !== undefined, 0x6d6 /* incorrect op content format */);
|
|
1952
|
+
return { type, contents };
|
|
1852
1953
|
}
|
|
1853
1954
|
|
|
1854
1955
|
private async applyStashedOp(op: string): Promise<unknown> {
|
|
@@ -1926,6 +2027,14 @@ export class ContainerRuntime
|
|
|
1926
2027
|
// There might be no change of state due to Container calling this API after loading runtime.
|
|
1927
2028
|
const changeOfState = this._connected !== connected;
|
|
1928
2029
|
const reconnection = changeOfState && !connected;
|
|
2030
|
+
|
|
2031
|
+
// We need to flush the ops currently collected by Outbox to preserve original order.
|
|
2032
|
+
// This flush NEEDS to happen before we set the ContainerRuntime to "connected".
|
|
2033
|
+
// We want these ops to get to the PendingStateManager without sending to service and have them return to the Outbox upon calling "replayPendingStates".
|
|
2034
|
+
if (changeOfState && connected) {
|
|
2035
|
+
this.flush();
|
|
2036
|
+
}
|
|
2037
|
+
|
|
1929
2038
|
this._connected = connected;
|
|
1930
2039
|
|
|
1931
2040
|
if (!connected) {
|
|
@@ -1991,6 +2100,12 @@ export class ContainerRuntime
|
|
|
1991
2100
|
|
|
1992
2101
|
private _processedClientSequenceNumber: number | undefined;
|
|
1993
2102
|
|
|
2103
|
+
/**
|
|
2104
|
+
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2105
|
+
* @param message - The unpacked message. Likely a ContainerRuntimeMessage, but could also be a system op
|
|
2106
|
+
* @param local - Did this client send the op?
|
|
2107
|
+
* @param runtimeMessage - Does this appear like a current ContainerRuntimeMessage? If true, certain validation will occur.
|
|
2108
|
+
*/
|
|
1994
2109
|
private processCore(
|
|
1995
2110
|
message: ISequencedDocumentMessage,
|
|
1996
2111
|
local: boolean,
|
|
@@ -2059,9 +2174,7 @@ export class ContainerRuntime
|
|
|
2059
2174
|
}
|
|
2060
2175
|
}
|
|
2061
2176
|
|
|
2062
|
-
|
|
2063
|
-
this.emit("op", message, runtimeMessage);
|
|
2064
|
-
}
|
|
2177
|
+
this.emit("op", message, runtimeMessage);
|
|
2065
2178
|
|
|
2066
2179
|
this.scheduleManager.afterOpProcessing(undefined, message);
|
|
2067
2180
|
|
|
@@ -2091,7 +2204,7 @@ export class ContainerRuntime
|
|
|
2091
2204
|
*/
|
|
2092
2205
|
private sendSignalTelemetryEvent(clientSignalSequenceNumber: number) {
|
|
2093
2206
|
const duration = Date.now() - this._perfSignalData.signalTimestamp;
|
|
2094
|
-
this.logger.sendPerformanceEvent({
|
|
2207
|
+
this.mc.logger.sendPerformanceEvent({
|
|
2095
2208
|
eventName: "SignalLatency",
|
|
2096
2209
|
duration,
|
|
2097
2210
|
signalsLost: this._perfSignalData.signalsLost,
|
|
@@ -2119,7 +2232,7 @@ export class ContainerRuntime
|
|
|
2119
2232
|
) {
|
|
2120
2233
|
this._perfSignalData.signalsLost++;
|
|
2121
2234
|
this._perfSignalData.trackingSignalSequenceNumber = undefined;
|
|
2122
|
-
this.logger.sendErrorEvent({
|
|
2235
|
+
this.mc.logger.sendErrorEvent({
|
|
2123
2236
|
eventName: "SignalLost",
|
|
2124
2237
|
type: envelope.contents.type,
|
|
2125
2238
|
signalsLost: this._perfSignalData.signalsLost,
|
|
@@ -2147,6 +2260,12 @@ export class ContainerRuntime
|
|
|
2147
2260
|
this.dataStores.processSignal(envelope.address, transformed, local);
|
|
2148
2261
|
}
|
|
2149
2262
|
|
|
2263
|
+
/**
|
|
2264
|
+
* Returns the runtime of the data store.
|
|
2265
|
+
* @param id - Id supplied during creating the data store.
|
|
2266
|
+
* @param wait - True if you want to wait for it.
|
|
2267
|
+
* @deprecated - Use getAliasedDataStoreEntryPoint instead to get an aliased data store's entry point.
|
|
2268
|
+
*/
|
|
2150
2269
|
public async getRootDataStore(id: string, wait = true): Promise<IFluidRouter> {
|
|
2151
2270
|
return this.getRootDataStoreChannel(id, wait);
|
|
2152
2271
|
}
|
|
@@ -2222,15 +2341,30 @@ export class ContainerRuntime
|
|
|
2222
2341
|
return result;
|
|
2223
2342
|
}
|
|
2224
2343
|
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2344
|
+
/**
|
|
2345
|
+
* Returns the aliased data store's entryPoint, given the alias.
|
|
2346
|
+
* @param alias - The alias for the data store.
|
|
2347
|
+
* @returns - The data store's entry point (IFluidHandle) if it exists and is aliased. Returns undefined if no
|
|
2348
|
+
* data store has been assigned the given alias.
|
|
2349
|
+
*/
|
|
2350
|
+
public async getAliasedDataStoreEntryPoint(
|
|
2351
|
+
alias: string,
|
|
2352
|
+
): Promise<IFluidHandle<FluidObject> | undefined> {
|
|
2353
|
+
await this.dataStores.waitIfPendingAlias(alias);
|
|
2354
|
+
const internalId = this.internalId(alias);
|
|
2355
|
+
const context = await this.dataStores.getDataStoreIfAvailable(internalId, { wait: false });
|
|
2356
|
+
// If the data store is not available or not an alias, return undefined.
|
|
2357
|
+
if (context === undefined || !(await context.isRoot())) {
|
|
2358
|
+
return undefined;
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
const channel = await context.realize();
|
|
2362
|
+
if (channel.entryPoint === undefined) {
|
|
2363
|
+
throw new UsageError(
|
|
2364
|
+
"entryPoint must be defined on data store runtime for using getAliasedDataStoreEntryPoint",
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
return channel.entryPoint;
|
|
2234
2368
|
}
|
|
2235
2369
|
|
|
2236
2370
|
public createDetachedRootDataStore(
|
|
@@ -2247,25 +2381,37 @@ export class ContainerRuntime
|
|
|
2247
2381
|
return this.dataStores.createDetachedDataStoreCore(pkg, false);
|
|
2248
2382
|
}
|
|
2249
2383
|
|
|
2384
|
+
public async createDataStore(pkg: string | string[]): Promise<IDataStore> {
|
|
2385
|
+
const id = uuid();
|
|
2386
|
+
return channelToDataStore(
|
|
2387
|
+
await this.dataStores
|
|
2388
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id)
|
|
2389
|
+
.realize(),
|
|
2390
|
+
id,
|
|
2391
|
+
this,
|
|
2392
|
+
this.dataStores,
|
|
2393
|
+
this.mc.logger,
|
|
2394
|
+
);
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
/**
|
|
2398
|
+
* @deprecated 0.16 Issue #1537, #3631
|
|
2399
|
+
* @internal
|
|
2400
|
+
*/
|
|
2250
2401
|
public async _createDataStoreWithProps(
|
|
2251
2402
|
pkg: string | string[],
|
|
2252
2403
|
props?: any,
|
|
2253
2404
|
id = uuid(),
|
|
2254
2405
|
): Promise<IDataStore> {
|
|
2255
|
-
|
|
2256
|
-
.
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
props?: any,
|
|
2265
|
-
): Promise<IFluidDataStoreChannel> {
|
|
2266
|
-
return this.dataStores
|
|
2267
|
-
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
|
|
2268
|
-
.realize();
|
|
2406
|
+
return channelToDataStore(
|
|
2407
|
+
await this.dataStores
|
|
2408
|
+
._createFluidDataStoreContext(Array.isArray(pkg) ? pkg : [pkg], id, props)
|
|
2409
|
+
.realize(),
|
|
2410
|
+
id,
|
|
2411
|
+
this,
|
|
2412
|
+
this.dataStores,
|
|
2413
|
+
this.mc.logger,
|
|
2414
|
+
);
|
|
2269
2415
|
}
|
|
2270
2416
|
|
|
2271
2417
|
private canSendOps() {
|
|
@@ -2281,13 +2427,14 @@ export class ContainerRuntime
|
|
|
2281
2427
|
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
2282
2428
|
}
|
|
2283
2429
|
|
|
2430
|
+
private readonly _quorum: IQuorumClients;
|
|
2284
2431
|
public getQuorum(): IQuorumClients {
|
|
2285
|
-
return this.
|
|
2432
|
+
return this._quorum;
|
|
2286
2433
|
}
|
|
2287
2434
|
|
|
2435
|
+
private readonly _audience: IAudience;
|
|
2288
2436
|
public getAudience(): IAudience {
|
|
2289
|
-
|
|
2290
|
-
return this.context.audience!;
|
|
2437
|
+
return this._audience;
|
|
2291
2438
|
}
|
|
2292
2439
|
|
|
2293
2440
|
/**
|
|
@@ -2298,7 +2445,7 @@ export class ContainerRuntime
|
|
|
2298
2445
|
return this.dirtyContainer;
|
|
2299
2446
|
}
|
|
2300
2447
|
|
|
2301
|
-
private isContainerMessageDirtyable(type
|
|
2448
|
+
private isContainerMessageDirtyable({ type, contents }: ContainerRuntimeMessage) {
|
|
2302
2449
|
// For legacy purposes, exclude the old built-in AgentScheduler from dirty consideration as a special-case.
|
|
2303
2450
|
// Ultimately we should have no special-cases from the ContainerRuntime's perspective.
|
|
2304
2451
|
if (type === ContainerMessageType.Attach) {
|
|
@@ -2347,12 +2494,12 @@ export class ContainerRuntime
|
|
|
2347
2494
|
public submitSignal(type: string, content: any) {
|
|
2348
2495
|
this.verifyNotClosed();
|
|
2349
2496
|
const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
|
|
2350
|
-
return this.
|
|
2497
|
+
return this.submitSignalFn(envelope);
|
|
2351
2498
|
}
|
|
2352
2499
|
|
|
2353
2500
|
public submitDataStoreSignal(address: string, type: string, content: any) {
|
|
2354
2501
|
const envelope = this.createNewSignalEnvelope(address, type, content);
|
|
2355
|
-
return this.
|
|
2502
|
+
return this.submitSignalFn(envelope);
|
|
2356
2503
|
}
|
|
2357
2504
|
|
|
2358
2505
|
public setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void {
|
|
@@ -2404,15 +2551,7 @@ export class ContainerRuntime
|
|
|
2404
2551
|
return summarizeResult.summary;
|
|
2405
2552
|
}
|
|
2406
2553
|
|
|
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
|
-
}
|
|
2554
|
+
public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>;
|
|
2416
2555
|
|
|
2417
2556
|
private async summarizeInternal(
|
|
2418
2557
|
fullTree: boolean,
|
|
@@ -2453,7 +2592,7 @@ export class ContainerRuntime
|
|
|
2453
2592
|
fullGC?: boolean;
|
|
2454
2593
|
/** True to run GC sweep phase after the mark phase */
|
|
2455
2594
|
runSweep?: boolean;
|
|
2456
|
-
}): Promise<
|
|
2595
|
+
}): Promise<ISummaryTreeWithStats> {
|
|
2457
2596
|
this.verifyNotClosed();
|
|
2458
2597
|
|
|
2459
2598
|
const {
|
|
@@ -2476,9 +2615,8 @@ export class ContainerRuntime
|
|
|
2476
2615
|
});
|
|
2477
2616
|
|
|
2478
2617
|
try {
|
|
2479
|
-
let gcStats: IGCStats | undefined;
|
|
2480
2618
|
if (runGC) {
|
|
2481
|
-
|
|
2619
|
+
await this.collectGarbage(
|
|
2482
2620
|
{ logger: summaryLogger, runSweep, fullGC },
|
|
2483
2621
|
telemetryContext,
|
|
2484
2622
|
);
|
|
@@ -2495,9 +2633,9 @@ export class ContainerRuntime
|
|
|
2495
2633
|
0x12f /* "Container Runtime's summarize should always return a tree" */,
|
|
2496
2634
|
);
|
|
2497
2635
|
|
|
2498
|
-
return { stats, summary
|
|
2636
|
+
return { stats, summary };
|
|
2499
2637
|
} finally {
|
|
2500
|
-
this.logger.sendTelemetryEvent({
|
|
2638
|
+
this.mc.logger.sendTelemetryEvent({
|
|
2501
2639
|
eventName: "SummarizeTelemetry",
|
|
2502
2640
|
details: telemetryContext.serialize(),
|
|
2503
2641
|
});
|
|
@@ -2700,8 +2838,11 @@ export class ContainerRuntime
|
|
|
2700
2838
|
// The summary number for this summary. This will be updated during the summary process, so get it now and
|
|
2701
2839
|
// use it for all events logged during this summary.
|
|
2702
2840
|
const summaryNumber = this.nextSummaryNumber;
|
|
2703
|
-
const summaryNumberLogger =
|
|
2704
|
-
|
|
2841
|
+
const summaryNumberLogger = createChildLogger({
|
|
2842
|
+
logger: summaryLogger,
|
|
2843
|
+
properties: {
|
|
2844
|
+
all: { summaryNumber },
|
|
2845
|
+
},
|
|
2705
2846
|
});
|
|
2706
2847
|
|
|
2707
2848
|
assert(this.outbox.isEmpty, 0x3d1 /* Can't trigger summary in the middle of a batch */);
|
|
@@ -2709,7 +2850,11 @@ export class ContainerRuntime
|
|
|
2709
2850
|
let latestSnapshotVersionId: string | undefined;
|
|
2710
2851
|
if (refreshLatestAck) {
|
|
2711
2852
|
const latestSnapshotInfo = await this.refreshLatestSummaryAckFromServer(
|
|
2712
|
-
|
|
2853
|
+
createChildLogger({
|
|
2854
|
+
logger: summaryNumberLogger,
|
|
2855
|
+
namespace: undefined,
|
|
2856
|
+
properties: { all: { safeSummary: true } },
|
|
2857
|
+
}),
|
|
2713
2858
|
);
|
|
2714
2859
|
const latestSnapshotRefSeq = latestSnapshotInfo.latestSnapshotRefSeq;
|
|
2715
2860
|
latestSnapshotVersionId = latestSnapshotInfo.latestSnapshotVersionId;
|
|
@@ -2788,7 +2933,7 @@ export class ContainerRuntime
|
|
|
2788
2933
|
}
|
|
2789
2934
|
|
|
2790
2935
|
const trace = Trace.start();
|
|
2791
|
-
let summarizeResult:
|
|
2936
|
+
let summarizeResult: ISummaryTreeWithStats;
|
|
2792
2937
|
// If the GC state needs to be reset, we need to force a full tree summary and update the unreferenced
|
|
2793
2938
|
// state of all the nodes.
|
|
2794
2939
|
const forcedFullTree = this.garbageCollector.summaryStateNeedsReset;
|
|
@@ -2881,7 +3026,7 @@ export class ContainerRuntime
|
|
|
2881
3026
|
} else if (lastAck === undefined) {
|
|
2882
3027
|
summaryContext = {
|
|
2883
3028
|
proposalHandle: undefined,
|
|
2884
|
-
ackHandle: this.
|
|
3029
|
+
ackHandle: this.loadedFromVersionId,
|
|
2885
3030
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2886
3031
|
};
|
|
2887
3032
|
} else {
|
|
@@ -2982,7 +3127,6 @@ export class ContainerRuntime
|
|
|
2982
3127
|
this.dirtyContainer = dirty;
|
|
2983
3128
|
if (this.emitDirtyDocumentEvent) {
|
|
2984
3129
|
this.emit(dirty ? "dirty" : "saved");
|
|
2985
|
-
this.context.updateDirtyContainerState(dirty);
|
|
2986
3130
|
}
|
|
2987
3131
|
}
|
|
2988
3132
|
|
|
@@ -2995,7 +3139,10 @@ export class ContainerRuntime
|
|
|
2995
3139
|
address: id,
|
|
2996
3140
|
contents,
|
|
2997
3141
|
};
|
|
2998
|
-
this.submit(
|
|
3142
|
+
this.submit(
|
|
3143
|
+
{ type: ContainerMessageType.FluidDataStoreOp, contents: envelope },
|
|
3144
|
+
localOpMetadata,
|
|
3145
|
+
);
|
|
2999
3146
|
}
|
|
3000
3147
|
|
|
3001
3148
|
public submitDataStoreAliasOp(contents: any, localOpMetadata: unknown): void {
|
|
@@ -3004,12 +3151,15 @@ export class ContainerRuntime
|
|
|
3004
3151
|
throw new UsageError("malformedDataStoreAliasMessage");
|
|
3005
3152
|
}
|
|
3006
3153
|
|
|
3007
|
-
this.submit(ContainerMessageType.Alias, contents, localOpMetadata);
|
|
3154
|
+
this.submit({ type: ContainerMessageType.Alias, contents }, localOpMetadata);
|
|
3008
3155
|
}
|
|
3009
3156
|
|
|
3010
|
-
public async uploadBlob(
|
|
3157
|
+
public async uploadBlob(
|
|
3158
|
+
blob: ArrayBufferLike,
|
|
3159
|
+
signal?: AbortSignal,
|
|
3160
|
+
): Promise<IFluidHandle<ArrayBufferLike>> {
|
|
3011
3161
|
this.verifyNotClosed();
|
|
3012
|
-
return this.blobManager.createBlob(blob);
|
|
3162
|
+
return this.blobManager.createBlob(blob, signal);
|
|
3013
3163
|
}
|
|
3014
3164
|
|
|
3015
3165
|
private maybeSubmitIdAllocationOp(type: ContainerMessageType) {
|
|
@@ -3047,8 +3197,7 @@ export class ContainerRuntime
|
|
|
3047
3197
|
}
|
|
3048
3198
|
|
|
3049
3199
|
private submit(
|
|
3050
|
-
|
|
3051
|
-
contents: any,
|
|
3200
|
+
containerRuntimeMessage: ContainerRuntimeMessage,
|
|
3052
3201
|
localOpMetadata: unknown = undefined,
|
|
3053
3202
|
metadata: Record<string, unknown> | undefined = undefined,
|
|
3054
3203
|
): void {
|
|
@@ -3061,17 +3210,18 @@ export class ContainerRuntime
|
|
|
3061
3210
|
0x132 /* "sending ops in detached container" */,
|
|
3062
3211
|
);
|
|
3063
3212
|
|
|
3064
|
-
const serializedContent = JSON.stringify(
|
|
3213
|
+
const serializedContent = JSON.stringify(containerRuntimeMessage);
|
|
3065
3214
|
|
|
3066
3215
|
// Note that the real (non-proxy) delta manager is used here to get the readonly info. This is because
|
|
3067
3216
|
// container runtime's ability to submit ops depend on the actual readonly state of the delta manager.
|
|
3068
3217
|
if (this.innerDeltaManager.readOnlyInfo.readonly) {
|
|
3069
|
-
this.logger.sendTelemetryEvent({
|
|
3218
|
+
this.mc.logger.sendTelemetryEvent({
|
|
3070
3219
|
eventName: "SubmitOpInReadonly",
|
|
3071
3220
|
connected: this.connected,
|
|
3072
3221
|
});
|
|
3073
3222
|
}
|
|
3074
3223
|
|
|
3224
|
+
const type = containerRuntimeMessage.type;
|
|
3075
3225
|
const message: BatchMessage = {
|
|
3076
3226
|
contents: serializedContent,
|
|
3077
3227
|
type,
|
|
@@ -3130,7 +3280,7 @@ export class ContainerRuntime
|
|
|
3130
3280
|
throw error;
|
|
3131
3281
|
}
|
|
3132
3282
|
|
|
3133
|
-
if (this.isContainerMessageDirtyable(
|
|
3283
|
+
if (this.isContainerMessageDirtyable(containerRuntimeMessage)) {
|
|
3134
3284
|
this.updateDocumentDirtyState(true);
|
|
3135
3285
|
}
|
|
3136
3286
|
}
|
|
@@ -3186,9 +3336,9 @@ export class ContainerRuntime
|
|
|
3186
3336
|
assert(this.outbox.isEmpty, 0x3d4 /* System op in the middle of a batch */);
|
|
3187
3337
|
|
|
3188
3338
|
// back-compat: ADO #1385: Make this call unconditional in the future
|
|
3189
|
-
return this.
|
|
3190
|
-
? this.
|
|
3191
|
-
: this.
|
|
3339
|
+
return this.submitSummaryFn !== undefined
|
|
3340
|
+
? this.submitSummaryFn(contents, referenceSequenceNumber)
|
|
3341
|
+
: this.submitFn(MessageType.Summarize, contents, false);
|
|
3192
3342
|
}
|
|
3193
3343
|
|
|
3194
3344
|
/**
|
|
@@ -3243,38 +3393,38 @@ export class ContainerRuntime
|
|
|
3243
3393
|
|
|
3244
3394
|
private reSubmit(message: IPendingBatchMessage) {
|
|
3245
3395
|
// Need to parse from string for back-compat
|
|
3246
|
-
const
|
|
3247
|
-
this.reSubmitCore(
|
|
3396
|
+
const containerRuntimeMessage = this.parseOpContent(message.content);
|
|
3397
|
+
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
3248
3398
|
}
|
|
3249
3399
|
|
|
3250
3400
|
/**
|
|
3251
3401
|
* Finds the right store and asks it to resubmit the message. This typically happens when we
|
|
3252
3402
|
* reconnect and there are pending messages.
|
|
3253
|
-
* @param
|
|
3403
|
+
* @param message - The original ContainerRuntimeMessage.
|
|
3254
3404
|
* @param localOpMetadata - The local metadata associated with the original message.
|
|
3255
3405
|
*/
|
|
3256
3406
|
private reSubmitCore(
|
|
3257
|
-
|
|
3258
|
-
content: any,
|
|
3407
|
+
message: ContainerRuntimeMessage,
|
|
3259
3408
|
localOpMetadata: unknown,
|
|
3260
3409
|
opMetadata: Record<string, unknown> | undefined,
|
|
3261
3410
|
) {
|
|
3262
|
-
|
|
3411
|
+
const contents = message.contents;
|
|
3412
|
+
switch (message.type) {
|
|
3263
3413
|
case ContainerMessageType.FluidDataStoreOp:
|
|
3264
3414
|
// For Operations, call resubmitDataStoreOp which will find the right store
|
|
3265
3415
|
// and trigger resubmission on it.
|
|
3266
|
-
this.dataStores.resubmitDataStoreOp(
|
|
3416
|
+
this.dataStores.resubmitDataStoreOp(contents, localOpMetadata);
|
|
3267
3417
|
break;
|
|
3268
3418
|
case ContainerMessageType.Attach:
|
|
3269
3419
|
case ContainerMessageType.Alias:
|
|
3270
|
-
this.submit(
|
|
3420
|
+
this.submit(message, localOpMetadata);
|
|
3271
3421
|
break;
|
|
3272
3422
|
case ContainerMessageType.IdAllocation:
|
|
3273
3423
|
// Remove the stashedState from the op if it's a stashed op
|
|
3274
|
-
if (
|
|
3275
|
-
delete
|
|
3424
|
+
if (contents.stashedState !== undefined) {
|
|
3425
|
+
delete contents.stashedState;
|
|
3276
3426
|
}
|
|
3277
|
-
this.submit(
|
|
3427
|
+
this.submit(message, localOpMetadata);
|
|
3278
3428
|
break;
|
|
3279
3429
|
case ContainerMessageType.ChunkedOp:
|
|
3280
3430
|
throw new Error(`chunkedOp not expected here`);
|
|
@@ -3282,10 +3432,13 @@ export class ContainerRuntime
|
|
|
3282
3432
|
this.blobManager.reSubmit(opMetadata);
|
|
3283
3433
|
break;
|
|
3284
3434
|
case ContainerMessageType.Rejoin:
|
|
3285
|
-
this.submit(
|
|
3435
|
+
this.submit(message);
|
|
3286
3436
|
break;
|
|
3287
3437
|
default:
|
|
3288
|
-
unreachableCase(
|
|
3438
|
+
unreachableCase(
|
|
3439
|
+
message.type,
|
|
3440
|
+
`Unknown ContainerMessageType [type: ${message.type}]`,
|
|
3441
|
+
);
|
|
3289
3442
|
}
|
|
3290
3443
|
}
|
|
3291
3444
|
|
|
@@ -3348,7 +3501,7 @@ export class ContainerRuntime
|
|
|
3348
3501
|
* change that started fetching latest snapshot always.
|
|
3349
3502
|
*/
|
|
3350
3503
|
if (fetchResult.latestSnapshotRefSeq < summaryRefSeq) {
|
|
3351
|
-
fetchResult = await this.
|
|
3504
|
+
fetchResult = await this.fetchSnapshotFromStorageAndClose(
|
|
3352
3505
|
summaryLogger,
|
|
3353
3506
|
{
|
|
3354
3507
|
eventName: "RefreshLatestSummaryAckFetchBackCompat",
|
|
@@ -3381,7 +3534,7 @@ export class ContainerRuntime
|
|
|
3381
3534
|
fetchedSnapshotRefSeq: fetchResult.latestSnapshotRefSeq,
|
|
3382
3535
|
},
|
|
3383
3536
|
);
|
|
3384
|
-
this.
|
|
3537
|
+
this.disposeFn(error);
|
|
3385
3538
|
throw error;
|
|
3386
3539
|
}
|
|
3387
3540
|
|
|
@@ -3455,10 +3608,15 @@ export class ContainerRuntime
|
|
|
3455
3608
|
event: ITelemetryGenericEvent,
|
|
3456
3609
|
readAndParseBlob: ReadAndParseBlob,
|
|
3457
3610
|
): Promise<{ snapshotTree: ISnapshotTree; versionId: string; latestSnapshotRefSeq: number }> {
|
|
3458
|
-
return this.
|
|
3611
|
+
return this.fetchSnapshotFromStorageAndClose(
|
|
3612
|
+
logger,
|
|
3613
|
+
event,
|
|
3614
|
+
readAndParseBlob,
|
|
3615
|
+
null /* latest */,
|
|
3616
|
+
);
|
|
3459
3617
|
}
|
|
3460
3618
|
|
|
3461
|
-
private async
|
|
3619
|
+
private async fetchSnapshotFromStorageAndClose(
|
|
3462
3620
|
logger: ITelemetryLoggerExt,
|
|
3463
3621
|
event: ITelemetryGenericEvent,
|
|
3464
3622
|
readAndParseBlob: ReadAndParseBlob,
|
|
@@ -3514,9 +3672,7 @@ export class ContainerRuntime
|
|
|
3514
3672
|
// We choose to close the summarizer after the snapshot cache is updated to avoid
|
|
3515
3673
|
// situations which the main client (which is likely to be re-elected as the leader again)
|
|
3516
3674
|
// loads the summarizer from cache.
|
|
3517
|
-
if (this.summaryStateUpdateMethod
|
|
3518
|
-
const error = new GenericError("Restarting summarizer instead of refreshing");
|
|
3519
|
-
|
|
3675
|
+
if (this.summaryStateUpdateMethod !== "refreshFromSnapshot") {
|
|
3520
3676
|
this.mc.logger.sendTelemetryEvent(
|
|
3521
3677
|
{
|
|
3522
3678
|
...event,
|
|
@@ -3526,14 +3682,13 @@ export class ContainerRuntime
|
|
|
3526
3682
|
versionId: versionId != null ? versionId : undefined,
|
|
3527
3683
|
closeSummarizerDelayMs: this.closeSummarizerDelayMs,
|
|
3528
3684
|
},
|
|
3529
|
-
|
|
3685
|
+
new GenericError("Restarting summarizer instead of refreshing"),
|
|
3530
3686
|
);
|
|
3531
3687
|
|
|
3532
|
-
// Delay
|
|
3688
|
+
// Delay before restarting summarizer to prevent the summarizer from restarting too frequently.
|
|
3533
3689
|
await delay(this.closeSummarizerDelayMs);
|
|
3534
3690
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
3535
|
-
this.
|
|
3536
|
-
throw error;
|
|
3691
|
+
this.disposeFn();
|
|
3537
3692
|
}
|
|
3538
3693
|
|
|
3539
3694
|
return snapshotResults;
|
|
@@ -3541,10 +3696,15 @@ export class ContainerRuntime
|
|
|
3541
3696
|
|
|
3542
3697
|
public notifyAttaching() {} // do nothing (deprecated method)
|
|
3543
3698
|
|
|
3544
|
-
public getPendingLocalState(
|
|
3699
|
+
public async getPendingLocalState(props?: {
|
|
3700
|
+
notifyImminentClosure: boolean;
|
|
3701
|
+
}): Promise<unknown> {
|
|
3702
|
+
this.verifyNotClosed();
|
|
3703
|
+
const waitBlobsToAttach = props?.notifyImminentClosure;
|
|
3545
3704
|
if (this._orderSequentiallyCalls !== 0) {
|
|
3546
3705
|
throw new UsageError("can't get state during orderSequentially");
|
|
3547
3706
|
}
|
|
3707
|
+
const pendingAttachmentBlobs = await this.blobManager.getPendingBlobs(waitBlobsToAttach);
|
|
3548
3708
|
// Flush pending batch.
|
|
3549
3709
|
// getPendingLocalState() is only exposed through Container.closeAndGetPendingLocalState(), so it's safe
|
|
3550
3710
|
// to close current batch.
|
|
@@ -3552,12 +3712,12 @@ export class ContainerRuntime
|
|
|
3552
3712
|
|
|
3553
3713
|
return {
|
|
3554
3714
|
pending: this.pendingStateManager.getLocalState(),
|
|
3555
|
-
pendingAttachmentBlobs
|
|
3715
|
+
pendingAttachmentBlobs,
|
|
3556
3716
|
};
|
|
3557
3717
|
}
|
|
3558
3718
|
|
|
3559
3719
|
public readonly summarizeOnDemand: ISummarizer["summarizeOnDemand"] = (...args) => {
|
|
3560
|
-
if (this.
|
|
3720
|
+
if (this.isSummarizerClient) {
|
|
3561
3721
|
return this.summarizer.summarizeOnDemand(...args);
|
|
3562
3722
|
} else if (this.summaryManager !== undefined) {
|
|
3563
3723
|
return this.summaryManager.summarizeOnDemand(...args);
|
|
@@ -3570,7 +3730,7 @@ export class ContainerRuntime
|
|
|
3570
3730
|
};
|
|
3571
3731
|
|
|
3572
3732
|
public readonly enqueueSummarize: ISummarizer["enqueueSummarize"] = (...args) => {
|
|
3573
|
-
if (this.
|
|
3733
|
+
if (this.isSummarizerClient) {
|
|
3574
3734
|
return this.summarizer.enqueueSummarize(...args);
|
|
3575
3735
|
} else if (this.summaryManager !== undefined) {
|
|
3576
3736
|
return this.summaryManager.enqueueSummarize(...args);
|