@fluidframework/container-runtime 2.1.0-276326 → 2.1.0-281041
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/README.md +74 -21
- package/api-extractor/api-extractor.current.json +5 -0
- package/api-extractor/api-extractor.legacy.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/container-runtime.legacy.public.api.md +9 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
- package/dist/blobManager/blobManager.d.ts.map +1 -0
- package/dist/{blobManager.js → blobManager/blobManager.js} +42 -83
- package/dist/blobManager/blobManager.js.map +1 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts +30 -0
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -0
- package/dist/blobManager/blobManagerSnapSum.js +82 -0
- package/dist/blobManager/blobManagerSnapSum.js.map +1 -0
- package/dist/blobManager/index.d.ts +7 -0
- package/dist/blobManager/index.d.ts.map +1 -0
- package/dist/blobManager/index.js +16 -0
- package/dist/blobManager/index.js.map +1 -0
- package/dist/channelCollection.d.ts +1 -1
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +40 -8
- package/dist/channelCollection.js.map +1 -1
- package/dist/containerRuntime.d.ts +15 -10
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +199 -162
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +5 -0
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +16 -5
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +1 -1
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +16 -10
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +4 -2
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcHelpers.d.ts.map +1 -1
- package/dist/gc/gcHelpers.js +12 -0
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +3 -2
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js +6 -6
- package/dist/gc/gcTelemetry.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/legacy.d.ts +1 -1
- package/dist/metadata.d.ts +7 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +6 -0
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts +8 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +37 -16
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/definitions.d.ts +1 -1
- package/dist/opLifecycle/definitions.d.ts.map +1 -1
- package/dist/opLifecycle/definitions.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +1 -1
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js +12 -8
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +14 -11
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +11 -6
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts +22 -6
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +43 -21
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.d.ts +22 -6
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +59 -9
- 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 +39 -13
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +98 -33
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/public.d.ts +1 -1
- package/dist/scheduleManager.js +4 -0
- package/dist/scheduleManager.js.map +1 -1
- package/dist/summary/index.d.ts +1 -1
- package/dist/summary/index.d.ts.map +1 -1
- package/dist/summary/index.js +1 -2
- package/dist/summary/index.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +2 -0
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts +0 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +7 -4
- package/dist/summary/summaryFormat.js.map +1 -1
- package/internal.d.ts +1 -1
- package/legacy.d.ts +1 -1
- package/lib/{blobManager.d.ts → blobManager/blobManager.d.ts} +19 -29
- package/lib/blobManager/blobManager.d.ts.map +1 -0
- package/lib/{blobManager.js → blobManager/blobManager.js} +40 -83
- package/lib/blobManager/blobManager.js.map +1 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts +30 -0
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -0
- package/lib/blobManager/blobManagerSnapSum.js +75 -0
- package/lib/blobManager/blobManagerSnapSum.js.map +1 -0
- package/lib/blobManager/index.d.ts +7 -0
- package/lib/blobManager/index.d.ts.map +1 -0
- package/lib/blobManager/index.js +7 -0
- package/lib/blobManager/index.js.map +1 -0
- package/lib/channelCollection.d.ts +1 -1
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +40 -8
- package/lib/channelCollection.js.map +1 -1
- package/lib/containerRuntime.d.ts +15 -10
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +149 -112
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +5 -0
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +17 -6
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +1 -1
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +16 -10
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +4 -2
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcHelpers.d.ts.map +1 -1
- package/lib/gc/gcHelpers.js +12 -0
- package/lib/gc/gcHelpers.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +3 -2
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js +6 -6
- package/lib/gc/gcTelemetry.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/legacy.d.ts +1 -1
- package/lib/metadata.d.ts +7 -1
- package/lib/metadata.d.ts.map +1 -1
- package/lib/metadata.js +4 -1
- package/lib/metadata.js.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts +8 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +35 -15
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/definitions.d.ts +1 -1
- package/lib/opLifecycle/definitions.d.ts.map +1 -1
- package/lib/opLifecycle/definitions.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +1 -1
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +1 -1
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js +12 -8
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +14 -11
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +11 -6
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts +22 -6
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +44 -22
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.d.ts +22 -6
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +57 -7
- 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 +39 -13
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +99 -34
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/scheduleManager.js +4 -0
- package/lib/scheduleManager.js.map +1 -1
- package/lib/summary/index.d.ts +1 -1
- package/lib/summary/index.d.ts.map +1 -1
- package/lib/summary/index.js +1 -1
- package/lib/summary/index.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +2 -0
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts +0 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryFormat.js +5 -2
- package/lib/summary/summaryFormat.js.map +1 -1
- package/package.json +49 -34
- package/src/{blobManager.ts → blobManager/blobManager.ts} +57 -123
- package/src/blobManager/blobManagerSnapSum.ts +133 -0
- package/src/blobManager/index.ts +19 -0
- package/src/channelCollection.ts +48 -11
- package/src/containerRuntime.ts +213 -158
- package/src/dataStoreContext.ts +30 -6
- package/src/gc/garbageCollection.ts +17 -12
- package/src/gc/gcDefinitions.ts +7 -2
- package/src/gc/gcHelpers.ts +18 -6
- package/src/gc/gcTelemetry.ts +20 -8
- package/src/index.ts +1 -1
- package/src/metadata.ts +11 -1
- package/src/opLifecycle/README.md +0 -8
- package/src/opLifecycle/batchManager.ts +46 -16
- package/src/opLifecycle/definitions.ts +1 -1
- package/src/opLifecycle/index.ts +8 -1
- package/src/opLifecycle/opCompressor.ts +12 -8
- package/src/opLifecycle/opGroupingManager.ts +14 -11
- package/src/opLifecycle/opSplitter.ts +10 -6
- package/src/opLifecycle/outbox.ts +64 -26
- package/src/opLifecycle/remoteMessageProcessor.ts +84 -11
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +177 -60
- package/src/scheduleManager.ts +6 -2
- package/src/summary/README.md +81 -0
- package/src/summary/index.ts +0 -1
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -1
- package/src/summary/summaryFormat.ts +4 -2
- package/src/summary/summaryFormats.md +69 -8
- package/tsconfig.json +0 -1
- package/dist/blobManager.d.ts.map +0 -1
- package/dist/blobManager.js.map +0 -1
- package/lib/blobManager.d.ts.map +0 -1
- package/lib/blobManager.js.map +0 -1
- package/src/summary/images/appTree.png +0 -0
- package/src/summary/images/protocolAndAppTree.png +0 -0
- package/src/summary/images/summaryTree.png +0 -0
package/dist/containerRuntime.js
CHANGED
|
@@ -17,20 +17,20 @@ const internal_6 = require("@fluidframework/runtime-utils/internal");
|
|
|
17
17
|
const internal_7 = require("@fluidframework/telemetry-utils/internal");
|
|
18
18
|
const uuid_1 = require("uuid");
|
|
19
19
|
const batchTracker_js_1 = require("./batchTracker.js");
|
|
20
|
-
const
|
|
20
|
+
const index_js_1 = require("./blobManager/index.js");
|
|
21
21
|
const channelCollection_js_1 = require("./channelCollection.js");
|
|
22
22
|
const connectionTelemetry_js_1 = require("./connectionTelemetry.js");
|
|
23
23
|
const containerHandleContext_js_1 = require("./containerHandleContext.js");
|
|
24
24
|
const dataStore_js_1 = require("./dataStore.js");
|
|
25
25
|
const dataStoreRegistry_js_1 = require("./dataStoreRegistry.js");
|
|
26
26
|
const deltaManagerProxies_js_1 = require("./deltaManagerProxies.js");
|
|
27
|
-
const
|
|
27
|
+
const index_js_2 = require("./gc/index.js");
|
|
28
28
|
const messageTypes_js_1 = require("./messageTypes.js");
|
|
29
|
-
const
|
|
29
|
+
const index_js_3 = require("./opLifecycle/index.js");
|
|
30
30
|
const packageVersion_js_1 = require("./packageVersion.js");
|
|
31
31
|
const pendingStateManager_js_1 = require("./pendingStateManager.js");
|
|
32
32
|
const scheduleManager_js_1 = require("./scheduleManager.js");
|
|
33
|
-
const
|
|
33
|
+
const index_js_4 = require("./summary/index.js");
|
|
34
34
|
const throttler_js_1 = require("./throttler.js");
|
|
35
35
|
/**
|
|
36
36
|
* Utility to implement compat behaviors given an unknown message type
|
|
@@ -164,7 +164,7 @@ exports.getDeviceSpec = getDeviceSpec;
|
|
|
164
164
|
const makeLegacySendBatchFn = (submitFn, deltaManager) => (batch) => {
|
|
165
165
|
// Default to negative one to match Container.submitBatch behavior
|
|
166
166
|
let clientSequenceNumber = -1;
|
|
167
|
-
for (const message of batch.
|
|
167
|
+
for (const message of batch.messages) {
|
|
168
168
|
clientSequenceNumber = submitFn(internal_3.MessageType.Operation,
|
|
169
169
|
// For back-compat (submitFn only works on deserialized content)
|
|
170
170
|
message.contents === undefined ? undefined : JSON.parse(message.contents), true, // batch
|
|
@@ -184,7 +184,7 @@ async function createSummarizer(loader, url) {
|
|
|
184
184
|
[internal_1.LoaderHeader.cache]: false,
|
|
185
185
|
[internal_1.LoaderHeader.clientDetails]: {
|
|
186
186
|
capabilities: { interactive: false },
|
|
187
|
-
type:
|
|
187
|
+
type: index_js_4.summarizerClientType,
|
|
188
188
|
},
|
|
189
189
|
[internal_3.DriverHeader.summarizingClient]: true,
|
|
190
190
|
[internal_1.LoaderHeader.reconnect]: false,
|
|
@@ -274,19 +274,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
274
274
|
}
|
|
275
275
|
};
|
|
276
276
|
const [chunks, metadata, electedSummarizerData, aliases, serializedIdCompressor] = await Promise.all([
|
|
277
|
-
tryFetchBlob(
|
|
278
|
-
tryFetchBlob(
|
|
279
|
-
tryFetchBlob(
|
|
280
|
-
tryFetchBlob(
|
|
281
|
-
tryFetchBlob(
|
|
277
|
+
tryFetchBlob(index_js_4.chunksBlobName),
|
|
278
|
+
tryFetchBlob(index_js_4.metadataBlobName),
|
|
279
|
+
tryFetchBlob(index_js_4.electedSummarizerBlobName),
|
|
280
|
+
tryFetchBlob(index_js_4.aliasBlobName),
|
|
281
|
+
tryFetchBlob(index_js_4.idCompressorBlobName),
|
|
282
282
|
]);
|
|
283
283
|
// read snapshot blobs needed for BlobManager to load
|
|
284
|
-
const blobManagerSnapshot = await
|
|
285
|
-
// IContainerContext storage api return type still has undefined in 0.39 package version.
|
|
286
|
-
// So once we release 0.40 container-defn package we can remove this check.
|
|
287
|
-
(0, internal_2.assert)(context.storage !== undefined, 0x256 /* "storage undefined in attached container" */);
|
|
288
|
-
return (0, internal_4.readAndParse)(context.storage, id);
|
|
289
|
-
});
|
|
284
|
+
const blobManagerSnapshot = await (0, index_js_1.loadBlobManagerLoadInfo)(context);
|
|
290
285
|
const messageAtLastSummary = lastMessageFromMetadata(metadata);
|
|
291
286
|
// Verify summary runtime sequence number matches protocol sequence number.
|
|
292
287
|
const runtimeSequenceNumber = messageAtLastSummary?.sequenceNumber;
|
|
@@ -384,11 +379,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
384
379
|
return createIdCompressor(compressorLogger);
|
|
385
380
|
}
|
|
386
381
|
};
|
|
387
|
-
const
|
|
388
|
-
const compressionLz4 = disableCompression !== true &&
|
|
389
|
-
compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
382
|
+
const compressionLz4 = compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
390
383
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
391
|
-
const documentSchemaController = new
|
|
384
|
+
const documentSchemaController = new index_js_4.DocumentsSchemaController(existing, protocolSequenceNumber, metadata?.documentSchema, {
|
|
392
385
|
explicitSchemaControl,
|
|
393
386
|
compressionLz4,
|
|
394
387
|
idCompressorMode,
|
|
@@ -397,9 +390,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
397
390
|
}, (schema) => {
|
|
398
391
|
runtime.onSchemaChange(schema);
|
|
399
392
|
});
|
|
400
|
-
const featureGatesForTelemetry = {
|
|
401
|
-
disableCompression,
|
|
402
|
-
};
|
|
393
|
+
const featureGatesForTelemetry = {};
|
|
403
394
|
const runtime = new containerRuntimeCtor(context, registry, metadata, electedSummarizerData, chunks ?? [], aliases ?? [], {
|
|
404
395
|
summaryOptions,
|
|
405
396
|
gcOptions,
|
|
@@ -615,7 +606,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
615
606
|
// Values are generally expected to be set from the runtime side.
|
|
616
607
|
this.options = options ?? {};
|
|
617
608
|
this.clientDetails = clientDetails;
|
|
618
|
-
this.isSummarizerClient = this.clientDetails.type ===
|
|
609
|
+
this.isSummarizerClient = this.clientDetails.type === index_js_4.summarizerClientType;
|
|
619
610
|
this.loadedFromVersionId = context.getLoadedFromVersion()?.id;
|
|
620
611
|
this._getClientId = () => context.clientId;
|
|
621
612
|
this._getAttachState = () => context.attachState;
|
|
@@ -664,30 +655,25 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
664
655
|
eventName: "GCFeatureMatrix",
|
|
665
656
|
metadataValue: JSON.stringify(metadata?.gcFeatureMatrix),
|
|
666
657
|
inputs: JSON.stringify({
|
|
667
|
-
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[
|
|
658
|
+
gcOptions_gcGeneration: this.runtimeOptions.gcOptions[index_js_2.gcGenerationOptionName],
|
|
668
659
|
}),
|
|
669
660
|
});
|
|
670
661
|
this.telemetryDocumentId = metadata?.telemetryDocumentId ?? (0, uuid_1.v4)();
|
|
671
662
|
this.disableAttachReorder = this.mc.config.getBoolean("Fluid.ContainerRuntime.disableAttachOpReorder");
|
|
672
|
-
const
|
|
673
|
-
const opGroupingManager = new index_js_2.OpGroupingManager({
|
|
663
|
+
const opGroupingManager = new index_js_3.OpGroupingManager({
|
|
674
664
|
groupedBatchingEnabled: this.groupedBatchingEnabled,
|
|
675
665
|
opCountThreshold: this.mc.config.getNumber("Fluid.ContainerRuntime.GroupedBatchingOpCount") ?? 2,
|
|
676
666
|
reentrantBatchGroupingEnabled: this.mc.config.getBoolean("Fluid.ContainerRuntime.GroupedBatchingReentrancy") ??
|
|
677
667
|
true,
|
|
678
668
|
}, this.mc.logger);
|
|
679
|
-
const opSplitter = new
|
|
680
|
-
this.remoteMessageProcessor = new
|
|
669
|
+
const opSplitter = new index_js_3.OpSplitter(chunks, this.submitBatchFn, runtimeOptions.chunkSizeInBytes, runtimeOptions.maxBatchSizeInBytes, this.mc.logger);
|
|
670
|
+
this.remoteMessageProcessor = new index_js_3.RemoteMessageProcessor(opSplitter, new index_js_3.OpDecompressor(this.mc.logger), opGroupingManager);
|
|
681
671
|
const pendingRuntimeState = pendingLocalState;
|
|
682
672
|
this.pendingStateManager = new pendingStateManager_js_1.PendingStateManager({
|
|
683
673
|
applyStashedOp: this.applyStashedOp.bind(this),
|
|
684
674
|
clientId: () => this.clientId,
|
|
685
675
|
close: this.closeFn,
|
|
686
676
|
connected: () => this.connected,
|
|
687
|
-
reSubmit: (message) => {
|
|
688
|
-
this.reSubmit(message);
|
|
689
|
-
this.flush();
|
|
690
|
-
},
|
|
691
677
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
692
678
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
693
679
|
isAttached: () => this.attachState !== container_definitions_1.AttachState.Detached,
|
|
@@ -733,7 +719,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
733
719
|
throw new internal_7.UsageError("Driver's maximumCacheDurationMs policy cannot exceed 5 days");
|
|
734
720
|
}
|
|
735
721
|
}
|
|
736
|
-
this.garbageCollector =
|
|
722
|
+
this.garbageCollector = index_js_2.GarbageCollector.create({
|
|
737
723
|
runtime: this,
|
|
738
724
|
gcOptions: this.runtimeOptions.gcOptions,
|
|
739
725
|
baseSnapshot,
|
|
@@ -749,7 +735,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
749
735
|
sessionExpiryTimerStarted: pendingRuntimeState?.sessionExpiryTimerStarted,
|
|
750
736
|
});
|
|
751
737
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
752
|
-
this.summarizerNode = (0,
|
|
738
|
+
this.summarizerNode = (0, index_js_4.createRootSummarizerNodeWithGC)((0, internal_7.createChildLogger)({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
753
739
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
754
740
|
async (fullTree, trackState, telemetryContext) => this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
755
741
|
// Latest change sequence number, no changes since summary applied yet
|
|
@@ -770,6 +756,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
770
756
|
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
771
757
|
}
|
|
772
758
|
const parentContext = (0, channelCollection_js_1.wrapContext)(this);
|
|
759
|
+
if (snapshotWithContents !== undefined) {
|
|
760
|
+
this.isSnapshotInstanceOfISnapshot = true;
|
|
761
|
+
}
|
|
773
762
|
// Due to a mismatch between different layers in terms of
|
|
774
763
|
// what is the interface of passing signals, we need the
|
|
775
764
|
// downstream stores to wrap the signal.
|
|
@@ -789,7 +778,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
789
778
|
...props,
|
|
790
779
|
timestampMs: props.timestampMs ?? this.getCurrentReferenceTimestampMs(),
|
|
791
780
|
}), (path) => this.garbageCollector.isNodeDeleted(path), new Map(dataStoreAliasMap), async (runtime) => provideEntryPoint);
|
|
792
|
-
this.blobManager = new
|
|
781
|
+
this.blobManager = new index_js_1.BlobManager({
|
|
793
782
|
routeContext: this.handleContext,
|
|
794
783
|
snapshot: blobManagerSnapshot,
|
|
795
784
|
getStorage: () => this.storage,
|
|
@@ -814,12 +803,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
814
803
|
this.scheduleManager = new scheduleManager_js_1.ScheduleManager(this.innerDeltaManager, this, () => this.clientId, (0, internal_7.createChildLogger)({ logger: this.logger, namespace: "ScheduleManager" }));
|
|
815
804
|
const disablePartialFlush = this.mc.config.getBoolean("Fluid.ContainerRuntime.DisablePartialFlush");
|
|
816
805
|
const legacySendBatchFn = (0, exports.makeLegacySendBatchFn)(this.submitFn, this.innerDeltaManager);
|
|
817
|
-
this.outbox = new
|
|
806
|
+
this.outbox = new index_js_3.Outbox({
|
|
818
807
|
shouldSend: () => this.canSendOps(),
|
|
819
808
|
pendingStateManager: this.pendingStateManager,
|
|
820
809
|
submitBatchFn: this.submitBatchFn,
|
|
821
810
|
legacySendBatchFn,
|
|
822
|
-
compressor: new
|
|
811
|
+
compressor: new index_js_3.OpCompressor(this.mc.logger),
|
|
823
812
|
splitter: opSplitter,
|
|
824
813
|
config: {
|
|
825
814
|
compressionOptions,
|
|
@@ -864,7 +853,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
864
853
|
const closeSummarizerDelayOverride = this.mc.config.getNumber("Fluid.ContainerRuntime.Test.CloseSummarizerDelayOverrideMs");
|
|
865
854
|
this.closeSummarizerDelayMs =
|
|
866
855
|
closeSummarizerDelayOverride ?? defaultCloseSummarizerDelayMs;
|
|
867
|
-
this.summaryCollection = new
|
|
856
|
+
this.summaryCollection = new index_js_4.SummaryCollection(this.deltaManager, this.logger);
|
|
868
857
|
this.dirtyContainer =
|
|
869
858
|
this.attachState !== container_definitions_1.AttachState.Attached || this.hasPendingMessages();
|
|
870
859
|
context.updateDirtyContainerState(this.dirtyContainer);
|
|
@@ -876,16 +865,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
876
865
|
logger: this.logger,
|
|
877
866
|
namespace: "OrderedClientElection",
|
|
878
867
|
});
|
|
879
|
-
const orderedClientCollection = new
|
|
880
|
-
const orderedClientElectionForSummarizer = new
|
|
881
|
-
this.summarizerClientElection = new
|
|
868
|
+
const orderedClientCollection = new index_js_4.OrderedClientCollection(orderedClientLogger, this.innerDeltaManager, this._quorum);
|
|
869
|
+
const orderedClientElectionForSummarizer = new index_js_4.OrderedClientElection(orderedClientLogger, orderedClientCollection, electedSummarizerData ?? this.innerDeltaManager.lastSequenceNumber, index_js_4.SummarizerClientElection.isClientEligible, this.mc.config.getBoolean("Fluid.ContainerRuntime.OrderedClientElection.EnablePerformanceEvents"));
|
|
870
|
+
this.summarizerClientElection = new index_js_4.SummarizerClientElection(orderedClientLogger, this.summaryCollection, orderedClientElectionForSummarizer, this.maxOpsSinceLastSummary);
|
|
882
871
|
if (this.isSummarizerClient) {
|
|
883
|
-
this._summarizer = new
|
|
872
|
+
this._summarizer = new index_js_4.Summarizer(this /* ISummarizerRuntime */, () => this.summaryConfiguration, this /* ISummarizerInternalsProvider */, this.handleContext, this.summaryCollection, async (runtime) => index_js_4.RunWhileConnectedCoordinator.create(runtime,
|
|
884
873
|
// Summarization runs in summarizer client and needs access to the real (non-proxy) active
|
|
885
874
|
// information. The proxy delta manager would always return false for summarizer client.
|
|
886
875
|
() => this.innerDeltaManager.active));
|
|
887
876
|
}
|
|
888
|
-
else if (
|
|
877
|
+
else if (index_js_4.SummarizerClientElection.clientDetailsPermitElection(this.clientDetails)) {
|
|
889
878
|
// Only create a SummaryManager and SummarizerClientElection
|
|
890
879
|
// if summaries are enabled and we are not the summarizer client.
|
|
891
880
|
const defaultAction = () => {
|
|
@@ -907,7 +896,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
907
896
|
};
|
|
908
897
|
this.summaryCollection.on("default", defaultAction);
|
|
909
898
|
// Create the SummaryManager and mark the initial state
|
|
910
|
-
this.summaryManager = new
|
|
899
|
+
this.summaryManager = new index_js_4.SummaryManager(this.summarizerClientElection, this, // IConnectedState
|
|
911
900
|
this.summaryCollection, this.logger, this.formCreateSummarizerFn(loader), new throttler_js_1.Throttler(60 * 1000, // 60 sec delay window
|
|
912
901
|
30 * 1000, // 30 sec max delay
|
|
913
902
|
// throttling function increases exponentially (0ms, 40ms, 80ms, 160ms, etc)
|
|
@@ -939,7 +928,6 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
939
928
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
940
929
|
featureGates: JSON.stringify({
|
|
941
930
|
...featureGatesForTelemetry,
|
|
942
|
-
disableChunking,
|
|
943
931
|
disableAttachReorder: this.disableAttachReorder,
|
|
944
932
|
disablePartialFlush,
|
|
945
933
|
closeSummarizerDelayOverride,
|
|
@@ -1055,7 +1043,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1055
1043
|
}),
|
|
1056
1044
|
});
|
|
1057
1045
|
// Find the snapshotTree inside the returned snapshot based on the path as given in the request.
|
|
1058
|
-
const hasIsolatedChannels = (0,
|
|
1046
|
+
const hasIsolatedChannels = (0, index_js_4.rootHasIsolatedChannels)(this.metadata);
|
|
1059
1047
|
const snapshotTreeForPath = this.getSnapshotTreeForPath(snapshot.snapshotTree, pathParts, hasIsolatedChannels);
|
|
1060
1048
|
(0, internal_2.assert)(snapshotTreeForPath !== undefined, 0x8ef /* no snapshotTree for the path */);
|
|
1061
1049
|
const snapshotSeqNumber = snapshot.sequenceNumber;
|
|
@@ -1118,9 +1106,13 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1118
1106
|
let childTree = snapshotTree;
|
|
1119
1107
|
for (const part of pathParts) {
|
|
1120
1108
|
if (hasIsolatedChannels) {
|
|
1121
|
-
|
|
1109
|
+
// TODO Why are we non null asserting here
|
|
1110
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1111
|
+
childTree = childTree.trees[internal_5.channelsTreeName];
|
|
1122
1112
|
}
|
|
1123
|
-
|
|
1113
|
+
// TODO Why are we non null asserting here
|
|
1114
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1115
|
+
childTree = childTree.trees[part];
|
|
1124
1116
|
}
|
|
1125
1117
|
return childTree;
|
|
1126
1118
|
}
|
|
@@ -1166,7 +1158,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1166
1158
|
// eslint-disable-next-line @typescript-eslint/return-await -- Adding an await here causes test failures
|
|
1167
1159
|
return this.resolveHandle(requestParser.createSubRequest(1));
|
|
1168
1160
|
}
|
|
1169
|
-
if (id ===
|
|
1161
|
+
if (id === index_js_1.blobManagerBasePath && requestParser.isLeaf(2)) {
|
|
1162
|
+
// TODO why are we non null asserting here?
|
|
1163
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1170
1164
|
const blob = await this.blobManager.getBlob(requestParser.pathParts[1]);
|
|
1171
1165
|
return blob
|
|
1172
1166
|
? {
|
|
@@ -1198,7 +1192,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1198
1192
|
addMetadataToSummary(summaryTree) {
|
|
1199
1193
|
// The last message processed at the time of summary. If there are no new messages, use the message from the
|
|
1200
1194
|
// last summary.
|
|
1201
|
-
const message = (0,
|
|
1195
|
+
const message = (0, index_js_4.extractSummaryMetadataMessage)(this.deltaManager.lastMessage) ??
|
|
1202
1196
|
this.messageAtLastSummary;
|
|
1203
1197
|
const documentSchema = this.documentsSchemaController.summarizeDocumentSchema(this.deltaManager.lastSequenceNumber);
|
|
1204
1198
|
// Is document schema explicit control on?
|
|
@@ -1221,31 +1215,31 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1221
1215
|
lastMessage: explicitSchemaControl ? message : undefined,
|
|
1222
1216
|
documentSchema,
|
|
1223
1217
|
};
|
|
1224
|
-
(0, internal_6.addBlobToSummary)(summaryTree,
|
|
1218
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_4.metadataBlobName, JSON.stringify(metadata));
|
|
1225
1219
|
}
|
|
1226
1220
|
addContainerStateToSummary(summaryTree, fullTree, trackState, telemetryContext) {
|
|
1227
1221
|
this.addMetadataToSummary(summaryTree);
|
|
1228
1222
|
if (this._idCompressor) {
|
|
1229
1223
|
const idCompressorState = JSON.stringify(this._idCompressor.serialize(false));
|
|
1230
|
-
(0, internal_6.addBlobToSummary)(summaryTree,
|
|
1224
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_4.idCompressorBlobName, idCompressorState);
|
|
1231
1225
|
}
|
|
1232
1226
|
if (this.remoteMessageProcessor.partialMessages.size > 0) {
|
|
1233
1227
|
const content = JSON.stringify([...this.remoteMessageProcessor.partialMessages]);
|
|
1234
|
-
(0, internal_6.addBlobToSummary)(summaryTree,
|
|
1228
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_4.chunksBlobName, content);
|
|
1235
1229
|
}
|
|
1236
1230
|
const dataStoreAliases = this.channelCollection.aliases;
|
|
1237
1231
|
if (dataStoreAliases.size > 0) {
|
|
1238
|
-
(0, internal_6.addBlobToSummary)(summaryTree,
|
|
1232
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_4.aliasBlobName, JSON.stringify([...dataStoreAliases]));
|
|
1239
1233
|
}
|
|
1240
1234
|
if (this.summarizerClientElection) {
|
|
1241
1235
|
const electedSummarizerContent = JSON.stringify(this.summarizerClientElection?.serialize());
|
|
1242
|
-
(0, internal_6.addBlobToSummary)(summaryTree,
|
|
1236
|
+
(0, internal_6.addBlobToSummary)(summaryTree, index_js_4.electedSummarizerBlobName, electedSummarizerContent);
|
|
1243
1237
|
}
|
|
1244
1238
|
const blobManagerSummary = this.blobManager.summarize();
|
|
1245
1239
|
// Some storage (like git) doesn't allow empty tree, so we can omit it.
|
|
1246
1240
|
// and the blob manager can handle the tree not existing when loading
|
|
1247
1241
|
if (Object.keys(blobManagerSummary.summary.tree).length > 0) {
|
|
1248
|
-
(0, internal_6.addSummarizeResultToSummary)(summaryTree,
|
|
1242
|
+
(0, internal_6.addSummarizeResultToSummary)(summaryTree, index_js_1.blobsTreeName, blobManagerSummary);
|
|
1249
1243
|
}
|
|
1250
1244
|
const gcSummary = this.garbageCollector.summarize(fullTree, trackState, telemetryContext);
|
|
1251
1245
|
if (gcSummary !== undefined) {
|
|
@@ -1480,25 +1474,36 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1480
1474
|
// but will not modify the contents object (likely it will replace it on the message).
|
|
1481
1475
|
const messageCopy = { ...messageArg };
|
|
1482
1476
|
const savedOp = messageCopy.metadata?.savedOp;
|
|
1483
|
-
|
|
1484
|
-
const
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1477
|
+
if (modernRuntimeMessage) {
|
|
1478
|
+
const processResult = this.remoteMessageProcessor.process(messageCopy);
|
|
1479
|
+
if (processResult === undefined) {
|
|
1480
|
+
// This means the incoming message is an incomplete part of a message or batch
|
|
1481
|
+
// and we need to process more messages before the rest of the system can understand it.
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
const batchStartCsn = processResult.batchStartCsn;
|
|
1485
|
+
const batch = processResult.messages;
|
|
1486
|
+
const messages = local
|
|
1487
|
+
? this.pendingStateManager.processPendingLocalBatch(batch, batchStartCsn)
|
|
1488
|
+
: batch.map((message) => ({ message, localOpMetadata: undefined }));
|
|
1489
|
+
messages.forEach(({ message, localOpMetadata }) => {
|
|
1490
|
+
const msg = {
|
|
1491
|
+
message,
|
|
1491
1492
|
local,
|
|
1492
1493
|
modernRuntimeMessage,
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
msg
|
|
1501
|
-
|
|
1494
|
+
savedOp,
|
|
1495
|
+
localOpMetadata,
|
|
1496
|
+
};
|
|
1497
|
+
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
else {
|
|
1501
|
+
const msg = {
|
|
1502
|
+
message: messageCopy,
|
|
1503
|
+
local,
|
|
1504
|
+
modernRuntimeMessage,
|
|
1505
|
+
savedOp,
|
|
1506
|
+
};
|
|
1502
1507
|
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
1503
1508
|
}
|
|
1504
1509
|
}
|
|
@@ -1506,7 +1511,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1506
1511
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
1507
1512
|
*/
|
|
1508
1513
|
processCore(messageWithContext) {
|
|
1509
|
-
const { message, local } = messageWithContext;
|
|
1514
|
+
const { message, local, localOpMetadata } = messageWithContext;
|
|
1510
1515
|
// Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
|
|
1511
1516
|
// Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
|
|
1512
1517
|
if (this.deltaManager.minimumSequenceNumber <
|
|
@@ -1520,15 +1525,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1520
1525
|
this.scheduleManager.beforeOpProcessing(message);
|
|
1521
1526
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
1522
1527
|
try {
|
|
1523
|
-
//
|
|
1524
|
-
// These calls should be made for all but chunked ops:
|
|
1525
|
-
// 1) this.pendingStateManager.processPendingLocalMessage() below
|
|
1526
|
-
// 2) this.resetReconnectCount() below
|
|
1528
|
+
// RemoteMessageProcessor would have already reconstituted Chunked Ops into the original op type
|
|
1527
1529
|
(0, internal_2.assert)(message.type !== messageTypes_js_1.ContainerMessageType.ChunkedOp, 0x93b /* we should never get here with chunked ops */);
|
|
1528
|
-
let localOpMetadata;
|
|
1529
|
-
if (local && messageWithContext.modernRuntimeMessage) {
|
|
1530
|
-
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(messageWithContext.message);
|
|
1531
|
-
}
|
|
1532
1530
|
// If there are no more pending messages after processing a local message,
|
|
1533
1531
|
// the document is no longer dirty.
|
|
1534
1532
|
if (!this.hasPendingMessages()) {
|
|
@@ -1687,10 +1685,12 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1687
1685
|
/**
|
|
1688
1686
|
* Flush the pending ops manually.
|
|
1689
1687
|
* This method is expected to be called at the end of a batch.
|
|
1688
|
+
* @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch
|
|
1689
|
+
* with the given Batch ID, which must be preserved
|
|
1690
1690
|
*/
|
|
1691
|
-
flush() {
|
|
1691
|
+
flush(resubmittingBatchId) {
|
|
1692
1692
|
(0, internal_2.assert)(this._orderSequentiallyCalls === 0, 0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */);
|
|
1693
|
-
this.outbox.flush();
|
|
1693
|
+
this.outbox.flush(resubmittingBatchId);
|
|
1694
1694
|
(0, internal_2.assert)(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
1695
1695
|
}
|
|
1696
1696
|
/**
|
|
@@ -1703,7 +1703,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1703
1703
|
// Note: we are not touching any batches other than mainBatch here, for two reasons:
|
|
1704
1704
|
// 1. It would not help, as other batches are flushed independently from main batch.
|
|
1705
1705
|
// 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
|
|
1706
|
-
checkpoint = this.outbox.
|
|
1706
|
+
checkpoint = this.outbox.getBatchCheckpoints().mainBatch;
|
|
1707
1707
|
}
|
|
1708
1708
|
try {
|
|
1709
1709
|
this._orderSequentiallyCalls++;
|
|
@@ -1794,7 +1794,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1794
1794
|
return (this.connected && !this.innerDeltaManager.readOnlyInfo.readonly && !this.imminentClosure);
|
|
1795
1795
|
}
|
|
1796
1796
|
/**
|
|
1797
|
-
*
|
|
1797
|
+
* Typically ops are batched and later flushed together, but in some cases we want to flush immediately.
|
|
1798
1798
|
*/
|
|
1799
1799
|
currentlyBatching() {
|
|
1800
1800
|
return this.flushMode !== internal_5.FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
@@ -1899,14 +1899,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
1899
1899
|
}
|
|
1900
1900
|
const summarizeResult = this.channelCollection.getAttachSummary(telemetryContext);
|
|
1901
1901
|
// Wrap data store summaries in .channels subtree.
|
|
1902
|
-
(0,
|
|
1902
|
+
(0, index_js_4.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1903
1903
|
this.addContainerStateToSummary(summarizeResult, true /* fullTree */, false /* trackState */, telemetryContext);
|
|
1904
1904
|
return summarizeResult.summary;
|
|
1905
1905
|
}
|
|
1906
1906
|
async summarizeInternal(fullTree, trackState, telemetryContext) {
|
|
1907
1907
|
const summarizeResult = await this.channelCollection.summarize(fullTree, trackState, telemetryContext);
|
|
1908
1908
|
// Wrap data store summaries in .channels subtree.
|
|
1909
|
-
(0,
|
|
1909
|
+
(0, index_js_4.wrapSummaryInChannelsTree)(summarizeResult);
|
|
1910
1910
|
const pathPartsForChildren = [internal_5.channelsTreeName];
|
|
1911
1911
|
// Ensure that ID compressor had a chance to load, if we are using delayed mode.
|
|
1912
1912
|
await this.loadIdCompressor();
|
|
@@ -2011,10 +2011,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2011
2011
|
* blob manager.
|
|
2012
2012
|
*/
|
|
2013
2013
|
getNodeType(nodePath) {
|
|
2014
|
-
if (
|
|
2015
|
-
return
|
|
2014
|
+
if ((0, index_js_1.isBlobPath)(nodePath)) {
|
|
2015
|
+
return index_js_2.GCNodeType.Blob;
|
|
2016
2016
|
}
|
|
2017
|
-
return this.channelCollection.getGCNodeType(nodePath) ??
|
|
2017
|
+
return this.channelCollection.getGCNodeType(nodePath) ?? index_js_2.GCNodeType.Other;
|
|
2018
2018
|
}
|
|
2019
2019
|
/**
|
|
2020
2020
|
* Called by GC to retrieve the package path of the node with the given path. The node should belong to a
|
|
@@ -2027,25 +2027,15 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2027
2027
|
return ["_gcRoot"];
|
|
2028
2028
|
}
|
|
2029
2029
|
switch (this.getNodeType(nodePath)) {
|
|
2030
|
-
case
|
|
2031
|
-
return [
|
|
2032
|
-
case
|
|
2033
|
-
case
|
|
2030
|
+
case index_js_2.GCNodeType.Blob:
|
|
2031
|
+
return [index_js_1.blobManagerBasePath];
|
|
2032
|
+
case index_js_2.GCNodeType.DataStore:
|
|
2033
|
+
case index_js_2.GCNodeType.SubDataStore:
|
|
2034
2034
|
return this.channelCollection.getDataStorePackagePath(nodePath);
|
|
2035
2035
|
default:
|
|
2036
2036
|
(0, internal_2.assert)(false, 0x2de /* "Package path requested for unsupported node type." */);
|
|
2037
2037
|
}
|
|
2038
2038
|
}
|
|
2039
|
-
/**
|
|
2040
|
-
* Returns whether a given path is for attachment blobs that are in the format - "/BlobManager.basePath/...".
|
|
2041
|
-
*/
|
|
2042
|
-
isBlobPath(path) {
|
|
2043
|
-
const pathParts = path.split("/");
|
|
2044
|
-
if (pathParts.length < 2 || pathParts[1] !== blobManager_js_1.BlobManager.basePath) {
|
|
2045
|
-
return false;
|
|
2046
|
-
}
|
|
2047
|
-
return true;
|
|
2048
|
-
}
|
|
2049
2039
|
/**
|
|
2050
2040
|
* From a given list of routes, separate and return routes that belong to blob manager and data stores.
|
|
2051
2041
|
* @param routes - A list of routes that can belong to data stores or blob manager.
|
|
@@ -2056,7 +2046,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2056
2046
|
const blobManagerRoutes = [];
|
|
2057
2047
|
const dataStoreRoutes = [];
|
|
2058
2048
|
for (const route of routes) {
|
|
2059
|
-
if (
|
|
2049
|
+
if ((0, index_js_1.isBlobPath)(route)) {
|
|
2060
2050
|
blobManagerRoutes.push(route);
|
|
2061
2051
|
}
|
|
2062
2052
|
else {
|
|
@@ -2165,7 +2155,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2165
2155
|
summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
2166
2156
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
2167
2157
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
2168
|
-
const
|
|
2158
|
+
const lastAckedContext = this.lastAckedSummaryContext;
|
|
2169
2159
|
const startSummaryResult = this.summarizerNode.startSummary(summaryRefSeqNum, summaryNumberLogger, latestSummaryRefSeqNum);
|
|
2170
2160
|
/**
|
|
2171
2161
|
* This was added to validate that the summarizer node tree has the same reference sequence number from the
|
|
@@ -2188,7 +2178,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2188
2178
|
stage: "base",
|
|
2189
2179
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2190
2180
|
minimumSequenceNumber,
|
|
2191
|
-
error: new
|
|
2181
|
+
error: new index_js_4.RetriableSummaryError(`Summarizer node state inconsistent with summarizer state.`),
|
|
2192
2182
|
};
|
|
2193
2183
|
}
|
|
2194
2184
|
}
|
|
@@ -2217,10 +2207,10 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2217
2207
|
};
|
|
2218
2208
|
}
|
|
2219
2209
|
(0, internal_2.assert)(summaryRefSeqNum === this.deltaManager.lastMessage?.sequenceNumber, 0x395 /* it's one and the same thing */);
|
|
2220
|
-
if (
|
|
2210
|
+
if (lastAckedContext !== this.lastAckedSummaryContext) {
|
|
2221
2211
|
return {
|
|
2222
2212
|
continue: false,
|
|
2223
|
-
error: `Last summary changed while summarizing. ${this.
|
|
2213
|
+
error: `Last summary changed while summarizing. ${this.lastAckedSummaryContext} !== ${lastAckedContext}`,
|
|
2224
2214
|
};
|
|
2225
2215
|
}
|
|
2226
2216
|
return { continue: true };
|
|
@@ -2231,7 +2221,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2231
2221
|
stage: "base",
|
|
2232
2222
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2233
2223
|
minimumSequenceNumber,
|
|
2234
|
-
error: new
|
|
2224
|
+
error: new index_js_4.RetriableSummaryError(continueResult.error),
|
|
2235
2225
|
};
|
|
2236
2226
|
}
|
|
2237
2227
|
const trace = client_utils_1.Trace.start();
|
|
@@ -2249,14 +2239,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2249
2239
|
stage: "base",
|
|
2250
2240
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
2251
2241
|
minimumSequenceNumber,
|
|
2252
|
-
error: (0, internal_7.wrapError)(error, (msg) => new
|
|
2242
|
+
error: (0, internal_7.wrapError)(error, (msg) => new index_js_4.RetriableSummaryError(msg)),
|
|
2253
2243
|
};
|
|
2254
2244
|
}
|
|
2255
2245
|
// Validate that the summary generated by summarizer nodes is correct before uploading.
|
|
2256
2246
|
const validateResult = this.summarizerNode.validateSummary();
|
|
2257
2247
|
if (!validateResult.success) {
|
|
2258
2248
|
const { success, ...loggingProps } = validateResult;
|
|
2259
|
-
const error = new
|
|
2249
|
+
const error = new index_js_4.RetriableSummaryError(validateResult.reason, validateResult.retryAfterSeconds, { ...loggingProps });
|
|
2260
2250
|
return {
|
|
2261
2251
|
stage: "base",
|
|
2262
2252
|
referenceSequenceNumber: summaryRefSeqNum,
|
|
@@ -2276,6 +2266,8 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2276
2266
|
// Counting dataStores and handles
|
|
2277
2267
|
// Because handles are unchanged dataStores in the current logic,
|
|
2278
2268
|
// summarized dataStore count is total dataStore count minus handle count
|
|
2269
|
+
// TODO why are we non null asserting here
|
|
2270
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2279
2271
|
const dataStoreTree = summaryTree.tree[internal_5.channelsTreeName];
|
|
2280
2272
|
(0, internal_2.assert)(dataStoreTree.type === driver_definitions_1.SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
2281
2273
|
const handleCount = Object.values(dataStoreTree.tree).filter((value) => value.type === driver_definitions_1.SummaryType.Handle).length;
|
|
@@ -2303,20 +2295,14 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2303
2295
|
return {
|
|
2304
2296
|
stage: "generate",
|
|
2305
2297
|
...generateSummaryData,
|
|
2306
|
-
error: new
|
|
2298
|
+
error: new index_js_4.RetriableSummaryError(continueResult.error),
|
|
2307
2299
|
};
|
|
2308
2300
|
}
|
|
2309
|
-
const summaryContext =
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
}
|
|
2315
|
-
: {
|
|
2316
|
-
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
2317
|
-
ackHandle: lastAck.summaryAck.contents.handle,
|
|
2318
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
2319
|
-
};
|
|
2301
|
+
const summaryContext = {
|
|
2302
|
+
proposalHandle: this.lastAckedSummaryContext?.proposalHandle ?? undefined,
|
|
2303
|
+
ackHandle: this.lastAckedSummaryContext?.ackHandle ?? this.loadedFromVersionId,
|
|
2304
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
2305
|
+
};
|
|
2320
2306
|
let handle;
|
|
2321
2307
|
try {
|
|
2322
2308
|
handle = await this.storage.uploadSummaryWithContext(summarizeResult.summary, summaryContext);
|
|
@@ -2325,7 +2311,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2325
2311
|
return {
|
|
2326
2312
|
stage: "generate",
|
|
2327
2313
|
...generateSummaryData,
|
|
2328
|
-
error: (0, internal_7.wrapError)(error, (msg) => new
|
|
2314
|
+
error: (0, internal_7.wrapError)(error, (msg) => new index_js_4.RetriableSummaryError(msg)),
|
|
2329
2315
|
};
|
|
2330
2316
|
}
|
|
2331
2317
|
const parent = summaryContext.ackHandle;
|
|
@@ -2346,7 +2332,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2346
2332
|
return {
|
|
2347
2333
|
stage: "upload",
|
|
2348
2334
|
...uploadData,
|
|
2349
|
-
error: new
|
|
2335
|
+
error: new index_js_4.RetriableSummaryError(continueResult.error),
|
|
2350
2336
|
};
|
|
2351
2337
|
}
|
|
2352
2338
|
let clientSequenceNumber;
|
|
@@ -2357,7 +2343,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2357
2343
|
return {
|
|
2358
2344
|
stage: "upload",
|
|
2359
2345
|
...uploadData,
|
|
2360
|
-
error: (0, internal_7.wrapError)(error, (msg) => new
|
|
2346
|
+
error: (0, internal_7.wrapError)(error, (msg) => new index_js_4.RetriableSummaryError(msg)),
|
|
2361
2347
|
};
|
|
2362
2348
|
}
|
|
2363
2349
|
const submitData = {
|
|
@@ -2373,7 +2359,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2373
2359
|
return {
|
|
2374
2360
|
stage: "upload",
|
|
2375
2361
|
...uploadData,
|
|
2376
|
-
error: (0, internal_7.wrapError)(error, (msg) => new
|
|
2362
|
+
error: (0, internal_7.wrapError)(error, (msg) => new index_js_4.RetriableSummaryError(msg)),
|
|
2377
2363
|
};
|
|
2378
2364
|
}
|
|
2379
2365
|
return submitData;
|
|
@@ -2422,7 +2408,7 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2422
2408
|
// based on telemetry while we decide on a stable number.
|
|
2423
2409
|
const retryDelayMs = this.mc.config.getNumber("Fluid.Summarizer.PendingOpsRetryDelayMs") ??
|
|
2424
2410
|
exports.defaultPendingOpsRetryDelayMs;
|
|
2425
|
-
const error = new
|
|
2411
|
+
const error = new index_js_4.RetriableSummaryError("PendingOpsWhileSummarizing", retryDelayMs / 1000, {
|
|
2426
2412
|
count: this.pendingMessagesCount,
|
|
2427
2413
|
beforeGenerate: beforeSummaryGeneration,
|
|
2428
2414
|
});
|
|
@@ -2536,7 +2522,9 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2536
2522
|
else {
|
|
2537
2523
|
this.outbox.submit(message);
|
|
2538
2524
|
}
|
|
2539
|
-
if
|
|
2525
|
+
// Note: Technically, the system "always" batches - if this case is true we'll just have a single-message batch.
|
|
2526
|
+
const flushImmediatelyOnSubmit = !this.currentlyBatching();
|
|
2527
|
+
if (flushImmediatelyOnSubmit) {
|
|
2540
2528
|
this.flush();
|
|
2541
2529
|
}
|
|
2542
2530
|
else {
|
|
@@ -2603,13 +2591,16 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2603
2591
|
throw new Error("Runtime is closed");
|
|
2604
2592
|
}
|
|
2605
2593
|
}
|
|
2606
|
-
reSubmitBatch(batch) {
|
|
2594
|
+
reSubmitBatch(batch, batchId) {
|
|
2607
2595
|
this.orderSequentially(() => {
|
|
2608
2596
|
for (const message of batch) {
|
|
2609
2597
|
this.reSubmit(message);
|
|
2610
2598
|
}
|
|
2611
2599
|
});
|
|
2612
|
-
|
|
2600
|
+
// Only include Batch ID if "Offline Load" feature is enabled
|
|
2601
|
+
// It's only needed to identify batches across container forks arising from misuse of offline load.
|
|
2602
|
+
const includeBatchId = this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ?? false;
|
|
2603
|
+
this.flush(includeBatchId ? batchId : undefined);
|
|
2613
2604
|
}
|
|
2614
2605
|
reSubmit(message) {
|
|
2615
2606
|
// Need to parse from string for back-compat
|
|
@@ -2700,45 +2691,91 @@ class ContainerRuntime extends client_utils_1.TypedEventEmitter {
|
|
|
2700
2691
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
2701
2692
|
// proposalHandle is always passed from RunningSummarizer.
|
|
2702
2693
|
(0, internal_2.assert)(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
2703
|
-
const readAndParseBlob = async (id) => (0, internal_4.readAndParse)(this.storage, id);
|
|
2704
2694
|
const result = await this.summarizerNode.refreshLatestSummary(proposalHandle, summaryRefSeq);
|
|
2695
|
+
/* eslint-disable jsdoc/check-indentation */
|
|
2705
2696
|
/**
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
*
|
|
2709
|
-
*
|
|
2697
|
+
* If the snapshot corresponding to the ack is not tracked by this client, it was submitted by another client.
|
|
2698
|
+
* Take action as per the following scenarios:
|
|
2699
|
+
* 1. If that snapshot is older than the one tracked by this client, ignore the ack because only the latest
|
|
2700
|
+
* snapshot is tracked.
|
|
2701
|
+
* 2. If that snapshot is newer, attempt to fetch the latest snapshot and do one of the following:
|
|
2702
|
+
* 2.1. If the fetched snapshot is same or newer than the one for which ack was received, close this client.
|
|
2703
|
+
* The next summarizer client will likely start from this snapshot and get out of this state. Fetching
|
|
2704
|
+
* the snapshot updates the cache for this client so if it's re-elected as summarizer, this will prevent
|
|
2705
|
+
* any thrashing.
|
|
2706
|
+
* 2.2. If the fetched snapshot is older than the one for which ack was received, ignore the ack. This can
|
|
2707
|
+
* happen in scenarios where the snapshot for the ack was lost in storage (in scenarios like DB rollback,
|
|
2708
|
+
* etc.) but the summary ack is still there because it's tracked a different service. In such cases,
|
|
2709
|
+
* ignoring the ack is the correct thing to do because the latest snapshot in storage is not the one for
|
|
2710
|
+
* the ack but is still the one tracked by this client. If we were to close the summarizer like in the
|
|
2711
|
+
* previous scenario, it will result in this document stuck in this state in a loop.
|
|
2710
2712
|
*/
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
ackHandle,
|
|
2715
|
-
|
|
2716
|
-
}, readAndParseBlob);
|
|
2713
|
+
/* eslint-enable jsdoc/check-indentation */
|
|
2714
|
+
if (!result.isSummaryTracked) {
|
|
2715
|
+
if (result.isSummaryNewer) {
|
|
2716
|
+
await this.fetchLatestSnapshotAndMaybeClose(summaryRefSeq, ackHandle, summaryLogger);
|
|
2717
|
+
}
|
|
2717
2718
|
return;
|
|
2718
2719
|
}
|
|
2719
2720
|
// Notify the garbage collector so it can update its latest summary state.
|
|
2720
2721
|
await this.garbageCollector.refreshLatestSummary(result);
|
|
2722
|
+
// If we here, the ack was tracked by this client. Update the summary context of the last ack.
|
|
2723
|
+
this.lastAckedSummaryContext = {
|
|
2724
|
+
proposalHandle,
|
|
2725
|
+
ackHandle,
|
|
2726
|
+
referenceSequenceNumber: summaryRefSeq,
|
|
2727
|
+
};
|
|
2721
2728
|
}
|
|
2722
2729
|
/**
|
|
2723
|
-
* Fetches the latest snapshot from storage
|
|
2724
|
-
*
|
|
2725
|
-
*
|
|
2730
|
+
* Fetches the latest snapshot from storage. If the fetched snapshot is same or newer than the one for which ack
|
|
2731
|
+
* was received, close this client. Fetching the snapshot will update the cache for this client so if it's
|
|
2732
|
+
* re-elected as summarizer, this will prevent any thrashing.
|
|
2733
|
+
* If the fetched snapshot is older than the one for which ack was received, ignore the ack and return. This can
|
|
2734
|
+
* happen in scenarios where the snapshot for the ack was lost in storage in scenarios like DB rollback, etc.
|
|
2726
2735
|
*/
|
|
2727
|
-
async
|
|
2728
|
-
await internal_7.PerformanceEvent.timedExecAsync(logger,
|
|
2729
|
-
const
|
|
2736
|
+
async fetchLatestSnapshotAndMaybeClose(targetRefSeq, targetAckHandle, logger) {
|
|
2737
|
+
const fetchedSnapshotRefSeq = await internal_7.PerformanceEvent.timedExecAsync(logger, { eventName: "RefreshLatestSummaryAckFetch" }, async (perfEvent) => {
|
|
2738
|
+
const props = { targetRefSeq, targetAckHandle };
|
|
2730
2739
|
const trace = client_utils_1.Trace.start();
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2740
|
+
let snapshotTree;
|
|
2741
|
+
const scenarioName = "RefreshLatestSummaryAckFetch";
|
|
2742
|
+
// If loader supplied us the ISnapshot when loading, the new getSnapshotApi is supported and feature gate is ON, then use the
|
|
2743
|
+
// new API, otherwise it will reduce the service performance because the service will need to recalculate the full snapshot
|
|
2744
|
+
// in case previously getSnapshotApi was used and now we use the getVersions API.
|
|
2745
|
+
if (this.isSnapshotInstanceOfISnapshot &&
|
|
2746
|
+
this.storage.getSnapshot !== undefined &&
|
|
2747
|
+
this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch2") ===
|
|
2748
|
+
true) {
|
|
2749
|
+
const snapshot = await this.storage.getSnapshot({
|
|
2750
|
+
scenarioName,
|
|
2751
|
+
fetchSource: internal_3.FetchSource.noCache,
|
|
2752
|
+
});
|
|
2753
|
+
const id = snapshot.snapshotTree.id;
|
|
2754
|
+
(0, internal_2.assert)(id !== undefined, "id of the fetched snapshot should be defined");
|
|
2755
|
+
props.snapshotVersion = id;
|
|
2756
|
+
snapshotTree = snapshot.snapshotTree;
|
|
2757
|
+
}
|
|
2758
|
+
else {
|
|
2759
|
+
const versions = await this.storage.getVersions(null, 1, scenarioName, internal_3.FetchSource.noCache);
|
|
2760
|
+
(0, internal_2.assert)(!!versions && !!versions[0], 0x137 /* "Failed to get version from storage" */);
|
|
2761
|
+
snapshotTree = await this.storage.getSnapshotTree(versions[0]);
|
|
2762
|
+
(0, internal_2.assert)(!!snapshotTree, 0x138 /* "Failed to get snapshot from storage" */);
|
|
2763
|
+
props.snapshotVersion = versions[0].id;
|
|
2764
|
+
}
|
|
2765
|
+
props.getSnapshotDuration = trace.trace().duration;
|
|
2766
|
+
const readAndParseBlob = async (id) => (0, internal_4.readAndParse)(this.storage, id);
|
|
2767
|
+
const snapshotRefSeq = await (0, internal_6.seqFromTree)(snapshotTree, readAndParseBlob);
|
|
2768
|
+
props.snapshotRefSeq = snapshotRefSeq;
|
|
2769
|
+
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
2770
|
+
perfEvent.end({ details: props });
|
|
2771
|
+
return snapshotRefSeq;
|
|
2741
2772
|
});
|
|
2773
|
+
// If the snapshot that was fetched is older than the target snapshot, return. The summarizer will not be closed
|
|
2774
|
+
// because the snapshot is likely deleted from storage and it so, closing the summarizer will result in the
|
|
2775
|
+
// document being stuck in this state.
|
|
2776
|
+
if (fetchedSnapshotRefSeq < targetRefSeq) {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2742
2779
|
await (0, internal_2.delay)(this.closeSummarizerDelayMs);
|
|
2743
2780
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
2744
2781
|
this.disposeFn();
|