@fluidframework/container-runtime 2.1.0-276985 → 2.1.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 +4 -0
- package/README.md +71 -18
- 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/blobManager.d.ts +10 -0
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +19 -0
- package/dist/blobManager/blobManager.js.map +1 -1
- 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 +14 -5
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +151 -99
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +4 -0
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +9 -3
- 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 +14 -8
- 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/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 +2 -2
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +3 -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 +10 -8
- package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +39 -15
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.d.ts +37 -13
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +95 -45
- 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/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.map +1 -1
- package/dist/summary/summaryFormat.js +4 -1
- package/dist/summary/summaryFormat.js.map +1 -1
- package/internal.d.ts +1 -1
- package/legacy.d.ts +1 -1
- package/lib/blobManager/blobManager.d.ts +10 -0
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +19 -0
- package/lib/blobManager/blobManager.js.map +1 -1
- 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 +14 -5
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +152 -100
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +4 -0
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +10 -4
- 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 +14 -8
- 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/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 +2 -2
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +2 -2
- 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 +10 -8
- package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +37 -14
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.d.ts +37 -13
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +95 -45
- 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/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.map +1 -1
- package/lib/summary/summaryFormat.js +4 -1
- package/lib/summary/summaryFormat.js.map +1 -1
- package/package.json +46 -31
- package/src/blobManager/blobManager.ts +19 -0
- package/src/channelCollection.ts +48 -11
- package/src/containerRuntime.ts +203 -133
- package/src/dataStoreContext.ts +22 -4
- package/src/gc/garbageCollection.ts +15 -10
- package/src/gc/gcDefinitions.ts +7 -2
- package/src/gc/gcHelpers.ts +18 -6
- package/src/gc/gcTelemetry.ts +20 -8
- package/src/metadata.ts +11 -1
- package/src/opLifecycle/README.md +0 -8
- package/src/opLifecycle/batchManager.ts +49 -16
- package/src/opLifecycle/definitions.ts +1 -1
- package/src/opLifecycle/index.ts +13 -2
- 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 +56 -17
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +173 -74
- package/src/scheduleManager.ts +6 -2
- package/src/summary/README.md +81 -0
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -1
- package/src/summary/summaryFormat.ts +3 -1
- package/src/summary/summaryFormats.md +69 -8
- package/tsconfig.json +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/src/containerRuntime.ts
CHANGED
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
MessageType,
|
|
62
62
|
ISequencedDocumentMessage,
|
|
63
63
|
ISignalMessage,
|
|
64
|
+
type ISummaryContext,
|
|
64
65
|
} from "@fluidframework/driver-definitions/internal";
|
|
65
66
|
import { readAndParse } from "@fluidframework/driver-utils/internal";
|
|
66
67
|
import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
@@ -91,7 +92,6 @@ import {
|
|
|
91
92
|
} from "@fluidframework/runtime-definitions/internal";
|
|
92
93
|
import {
|
|
93
94
|
GCDataBuilder,
|
|
94
|
-
ReadAndParseBlob,
|
|
95
95
|
RequestParser,
|
|
96
96
|
TelemetryContext,
|
|
97
97
|
addBlobToSummary,
|
|
@@ -169,7 +169,9 @@ import {
|
|
|
169
169
|
} from "./messageTypes.js";
|
|
170
170
|
import { IBatchMetadata, ISavedOpMetadata } from "./metadata.js";
|
|
171
171
|
import {
|
|
172
|
+
BatchId,
|
|
172
173
|
BatchMessage,
|
|
174
|
+
ensureContentsDeserialized,
|
|
173
175
|
IBatch,
|
|
174
176
|
IBatchCheckpoint,
|
|
175
177
|
OpCompressor,
|
|
@@ -181,7 +183,7 @@ import {
|
|
|
181
183
|
} from "./opLifecycle/index.js";
|
|
182
184
|
import { pkgVersion } from "./packageVersion.js";
|
|
183
185
|
import {
|
|
184
|
-
|
|
186
|
+
PendingMessageResubmitData,
|
|
185
187
|
IPendingLocalState,
|
|
186
188
|
PendingStateManager,
|
|
187
189
|
} from "./pendingStateManager.js";
|
|
@@ -668,7 +670,7 @@ export const makeLegacySendBatchFn =
|
|
|
668
670
|
(batch: IBatch) => {
|
|
669
671
|
// Default to negative one to match Container.submitBatch behavior
|
|
670
672
|
let clientSequenceNumber: number = -1;
|
|
671
|
-
for (const message of batch.
|
|
673
|
+
for (const message of batch.messages) {
|
|
672
674
|
clientSequenceNumber = submitFn(
|
|
673
675
|
MessageType.Operation,
|
|
674
676
|
// For back-compat (submitFn only works on deserialized content)
|
|
@@ -693,7 +695,7 @@ export const makeLegacySendBatchFn =
|
|
|
693
695
|
type MessageWithContext = {
|
|
694
696
|
local: boolean;
|
|
695
697
|
savedOp?: boolean;
|
|
696
|
-
|
|
698
|
+
localOpMetadata?: unknown;
|
|
697
699
|
} & (
|
|
698
700
|
| {
|
|
699
701
|
message: InboundSequencedContainerRuntimeMessage;
|
|
@@ -988,11 +990,7 @@ export class ContainerRuntime
|
|
|
988
990
|
}
|
|
989
991
|
};
|
|
990
992
|
|
|
991
|
-
const disableCompression = mc.config.getBoolean(
|
|
992
|
-
"Fluid.ContainerRuntime.CompressionDisabled",
|
|
993
|
-
);
|
|
994
993
|
const compressionLz4 =
|
|
995
|
-
disableCompression !== true &&
|
|
996
994
|
compressionOptions.minimumBatchSizeInBytes !== Infinity &&
|
|
997
995
|
compressionOptions.compressionAlgorithm === "lz4";
|
|
998
996
|
|
|
@@ -1012,9 +1010,7 @@ export class ContainerRuntime
|
|
|
1012
1010
|
},
|
|
1013
1011
|
);
|
|
1014
1012
|
|
|
1015
|
-
const featureGatesForTelemetry: Record<string, boolean | number | undefined> = {
|
|
1016
|
-
disableCompression,
|
|
1017
|
-
};
|
|
1013
|
+
const featureGatesForTelemetry: Record<string, boolean | number | undefined> = {};
|
|
1018
1014
|
|
|
1019
1015
|
const runtime = new containerRuntimeCtor(
|
|
1020
1016
|
context,
|
|
@@ -1360,6 +1356,13 @@ export class ContainerRuntime
|
|
|
1360
1356
|
*/
|
|
1361
1357
|
private readonly loadedFromVersionId: string | undefined;
|
|
1362
1358
|
|
|
1359
|
+
private readonly isSnapshotInstanceOfISnapshot: boolean | undefined;
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1362
|
+
* The summary context of the last acked summary. The properties from this as used when uploading a summary.
|
|
1363
|
+
*/
|
|
1364
|
+
private lastAckedSummaryContext: ISummaryContext | undefined;
|
|
1365
|
+
|
|
1363
1366
|
/**
|
|
1364
1367
|
* It a cache for holding mapping for loading groupIds with its snapshot from the service. Add expiry policy of 1 minute.
|
|
1365
1368
|
* Starting with 1 min and based on recorded usage we can tweak it later on.
|
|
@@ -1512,9 +1515,6 @@ export class ContainerRuntime
|
|
|
1512
1515
|
this.disableAttachReorder = this.mc.config.getBoolean(
|
|
1513
1516
|
"Fluid.ContainerRuntime.disableAttachOpReorder",
|
|
1514
1517
|
);
|
|
1515
|
-
const disableChunking = this.mc.config.getBoolean(
|
|
1516
|
-
"Fluid.ContainerRuntime.CompressionChunkingDisabled",
|
|
1517
|
-
);
|
|
1518
1518
|
|
|
1519
1519
|
const opGroupingManager = new OpGroupingManager(
|
|
1520
1520
|
{
|
|
@@ -1531,7 +1531,7 @@ export class ContainerRuntime
|
|
|
1531
1531
|
const opSplitter = new OpSplitter(
|
|
1532
1532
|
chunks,
|
|
1533
1533
|
this.submitBatchFn,
|
|
1534
|
-
|
|
1534
|
+
runtimeOptions.chunkSizeInBytes,
|
|
1535
1535
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1536
1536
|
this.mc.logger,
|
|
1537
1537
|
);
|
|
@@ -1549,10 +1549,6 @@ export class ContainerRuntime
|
|
|
1549
1549
|
clientId: () => this.clientId,
|
|
1550
1550
|
close: this.closeFn,
|
|
1551
1551
|
connected: () => this.connected,
|
|
1552
|
-
reSubmit: (message: IPendingBatchMessage) => {
|
|
1553
|
-
this.reSubmit(message);
|
|
1554
|
-
this.flush();
|
|
1555
|
-
},
|
|
1556
1552
|
reSubmitBatch: this.reSubmitBatch.bind(this),
|
|
1557
1553
|
isActiveConnection: () => this.innerDeltaManager.active,
|
|
1558
1554
|
isAttached: () => this.attachState !== AttachState.Detached,
|
|
@@ -1665,6 +1661,10 @@ export class ContainerRuntime
|
|
|
1665
1661
|
|
|
1666
1662
|
const parentContext = wrapContext(this);
|
|
1667
1663
|
|
|
1664
|
+
if (snapshotWithContents !== undefined) {
|
|
1665
|
+
this.isSnapshotInstanceOfISnapshot = true;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
1668
|
// Due to a mismatch between different layers in terms of
|
|
1669
1669
|
// what is the interface of passing signals, we need the
|
|
1670
1670
|
// downstream stores to wrap the signal.
|
|
@@ -1921,7 +1921,6 @@ export class ContainerRuntime
|
|
|
1921
1921
|
sessionRuntimeSchema: JSON.stringify(this.sessionSchema),
|
|
1922
1922
|
featureGates: JSON.stringify({
|
|
1923
1923
|
...featureGatesForTelemetry,
|
|
1924
|
-
disableChunking,
|
|
1925
1924
|
disableAttachReorder: this.disableAttachReorder,
|
|
1926
1925
|
disablePartialFlush,
|
|
1927
1926
|
closeSummarizerDelayOverride,
|
|
@@ -2167,9 +2166,13 @@ export class ContainerRuntime
|
|
|
2167
2166
|
let childTree = snapshotTree;
|
|
2168
2167
|
for (const part of pathParts) {
|
|
2169
2168
|
if (hasIsolatedChannels) {
|
|
2170
|
-
|
|
2169
|
+
// TODO Why are we non null asserting here
|
|
2170
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2171
|
+
childTree = childTree.trees[channelsTreeName]!;
|
|
2171
2172
|
}
|
|
2172
|
-
|
|
2173
|
+
// TODO Why are we non null asserting here
|
|
2174
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2175
|
+
childTree = childTree.trees[part]!;
|
|
2173
2176
|
}
|
|
2174
2177
|
return childTree;
|
|
2175
2178
|
}
|
|
@@ -2221,7 +2224,9 @@ export class ContainerRuntime
|
|
|
2221
2224
|
}
|
|
2222
2225
|
|
|
2223
2226
|
if (id === blobManagerBasePath && requestParser.isLeaf(2)) {
|
|
2224
|
-
|
|
2227
|
+
// TODO why are we non null asserting here?
|
|
2228
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2229
|
+
const blob = await this.blobManager.getBlob(requestParser.pathParts[1]!);
|
|
2225
2230
|
return blob
|
|
2226
2231
|
? {
|
|
2227
2232
|
status: 200,
|
|
@@ -2612,40 +2617,55 @@ export class ContainerRuntime
|
|
|
2612
2617
|
// or something different, like a system message.
|
|
2613
2618
|
const modernRuntimeMessage = messageArg.type === MessageType.Operation;
|
|
2614
2619
|
|
|
2620
|
+
const savedOp = (messageArg.metadata as ISavedOpMetadata)?.savedOp;
|
|
2621
|
+
|
|
2622
|
+
// There is some ancient back-compat code that we'd like to instrument
|
|
2623
|
+
// to understand if/when it is hit.
|
|
2624
|
+
const logLegacyCase = (codePath: string) =>
|
|
2625
|
+
this.logger.sendTelemetryEvent({
|
|
2626
|
+
eventName: "LegacyMessageFormat",
|
|
2627
|
+
details: { codePath, type: messageArg.type },
|
|
2628
|
+
});
|
|
2629
|
+
|
|
2615
2630
|
// Do shallow copy of message, as the processing flow will modify it.
|
|
2616
2631
|
// There might be multiple container instances receiving the same message.
|
|
2617
2632
|
// We do not need to make a deep copy. Each layer will just replace message.contents itself,
|
|
2618
2633
|
// but will not modify the contents object (likely it will replace it on the message).
|
|
2619
2634
|
const messageCopy = { ...messageArg };
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
if (
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2635
|
+
// We expect runtime messages to have JSON contents - deserialize it in place.
|
|
2636
|
+
ensureContentsDeserialized(messageCopy, modernRuntimeMessage, logLegacyCase);
|
|
2637
|
+
if (modernRuntimeMessage) {
|
|
2638
|
+
const processResult = this.remoteMessageProcessor.process(messageCopy, logLegacyCase);
|
|
2639
|
+
if (processResult === undefined) {
|
|
2640
|
+
// This means the incoming message is an incomplete part of a message or batch
|
|
2641
|
+
// and we need to process more messages before the rest of the system can understand it.
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
const batchStartCsn = processResult.batchStartCsn;
|
|
2645
|
+
const batch = processResult.messages;
|
|
2646
|
+
const messages: {
|
|
2647
|
+
message: InboundSequencedContainerRuntimeMessage;
|
|
2648
|
+
localOpMetadata: unknown;
|
|
2649
|
+
}[] = local
|
|
2650
|
+
? this.pendingStateManager.processPendingLocalBatch(batch, batchStartCsn)
|
|
2651
|
+
: batch.map((message) => ({ message, localOpMetadata: undefined }));
|
|
2652
|
+
messages.forEach(({ message, localOpMetadata }) => {
|
|
2653
|
+
const msg: MessageWithContext = {
|
|
2654
|
+
message,
|
|
2655
|
+
local,
|
|
2656
|
+
modernRuntimeMessage,
|
|
2657
|
+
savedOp,
|
|
2658
|
+
localOpMetadata,
|
|
2659
|
+
};
|
|
2660
|
+
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
2661
|
+
});
|
|
2662
|
+
} else {
|
|
2663
|
+
const msg: MessageWithContext = {
|
|
2664
|
+
message: messageCopy as InboundSequencedContainerRuntimeMessageOrSystemMessage,
|
|
2665
|
+
local,
|
|
2666
|
+
modernRuntimeMessage,
|
|
2667
|
+
savedOp,
|
|
2668
|
+
};
|
|
2649
2669
|
this.ensureNoDataModelChanges(() => this.processCore(msg));
|
|
2650
2670
|
}
|
|
2651
2671
|
}
|
|
@@ -2656,7 +2676,7 @@ export class ContainerRuntime
|
|
|
2656
2676
|
* Direct the message to the correct subsystem for processing, and implement other side effects
|
|
2657
2677
|
*/
|
|
2658
2678
|
private processCore(messageWithContext: MessageWithContext) {
|
|
2659
|
-
const { message, local } = messageWithContext;
|
|
2679
|
+
const { message, local, localOpMetadata } = messageWithContext;
|
|
2660
2680
|
|
|
2661
2681
|
// Intercept to reduce minimum sequence number to the delta manager's minimum sequence number.
|
|
2662
2682
|
// Sequence numbers are not guaranteed to follow any sort of order. Re-entrancy is one of those situations
|
|
@@ -2676,23 +2696,12 @@ export class ContainerRuntime
|
|
|
2676
2696
|
this._processedClientSequenceNumber = message.clientSequenceNumber;
|
|
2677
2697
|
|
|
2678
2698
|
try {
|
|
2679
|
-
//
|
|
2680
|
-
// These calls should be made for all but chunked ops:
|
|
2681
|
-
// 1) this.pendingStateManager.processPendingLocalMessage() below
|
|
2682
|
-
// 2) this.resetReconnectCount() below
|
|
2699
|
+
// RemoteMessageProcessor would have already reconstituted Chunked Ops into the original op type
|
|
2683
2700
|
assert(
|
|
2684
2701
|
message.type !== ContainerMessageType.ChunkedOp,
|
|
2685
2702
|
0x93b /* we should never get here with chunked ops */,
|
|
2686
2703
|
);
|
|
2687
2704
|
|
|
2688
|
-
let localOpMetadata: unknown;
|
|
2689
|
-
if (local && messageWithContext.modernRuntimeMessage) {
|
|
2690
|
-
localOpMetadata = this.pendingStateManager.processPendingLocalMessage(
|
|
2691
|
-
messageWithContext.message,
|
|
2692
|
-
messageWithContext.batchStartCsn,
|
|
2693
|
-
);
|
|
2694
|
-
}
|
|
2695
|
-
|
|
2696
2705
|
// If there are no more pending messages after processing a local message,
|
|
2697
2706
|
// the document is no longer dirty.
|
|
2698
2707
|
if (!this.hasPendingMessages()) {
|
|
@@ -2888,14 +2897,16 @@ export class ContainerRuntime
|
|
|
2888
2897
|
/**
|
|
2889
2898
|
* Flush the pending ops manually.
|
|
2890
2899
|
* This method is expected to be called at the end of a batch.
|
|
2900
|
+
* @param resubmittingBatchId - If defined, indicates this is a resubmission of a batch
|
|
2901
|
+
* with the given Batch ID, which must be preserved
|
|
2891
2902
|
*/
|
|
2892
|
-
private flush(): void {
|
|
2903
|
+
private flush(resubmittingBatchId?: BatchId): void {
|
|
2893
2904
|
assert(
|
|
2894
2905
|
this._orderSequentiallyCalls === 0,
|
|
2895
2906
|
0x24c /* "Cannot call `flush()` from `orderSequentially`'s callback" */,
|
|
2896
2907
|
);
|
|
2897
2908
|
|
|
2898
|
-
this.outbox.flush();
|
|
2909
|
+
this.outbox.flush(resubmittingBatchId);
|
|
2899
2910
|
assert(this.outbox.isEmpty, 0x3cf /* reentrancy */);
|
|
2900
2911
|
}
|
|
2901
2912
|
|
|
@@ -2909,7 +2920,7 @@ export class ContainerRuntime
|
|
|
2909
2920
|
// Note: we are not touching any batches other than mainBatch here, for two reasons:
|
|
2910
2921
|
// 1. It would not help, as other batches are flushed independently from main batch.
|
|
2911
2922
|
// 2. There is no way to undo process of data store creation, blob creation, ID compressor ops, or other things tracked by other batches.
|
|
2912
|
-
checkpoint = this.outbox.
|
|
2923
|
+
checkpoint = this.outbox.getBatchCheckpoints().mainBatch;
|
|
2913
2924
|
}
|
|
2914
2925
|
try {
|
|
2915
2926
|
this._orderSequentiallyCalls++;
|
|
@@ -3052,7 +3063,7 @@ export class ContainerRuntime
|
|
|
3052
3063
|
}
|
|
3053
3064
|
|
|
3054
3065
|
/**
|
|
3055
|
-
*
|
|
3066
|
+
* Typically ops are batched and later flushed together, but in some cases we want to flush immediately.
|
|
3056
3067
|
*/
|
|
3057
3068
|
private currentlyBatching() {
|
|
3058
3069
|
return this.flushMode !== FlushMode.Immediate || this._orderSequentiallyCalls !== 0;
|
|
@@ -3552,7 +3563,7 @@ export class ContainerRuntime
|
|
|
3552
3563
|
summaryRefSeqNum = this.deltaManager.lastSequenceNumber;
|
|
3553
3564
|
const minimumSequenceNumber = this.deltaManager.minimumSequenceNumber;
|
|
3554
3565
|
const message = `Summary @${summaryRefSeqNum}:${this.deltaManager.minimumSequenceNumber}`;
|
|
3555
|
-
const
|
|
3566
|
+
const lastAckedContext = this.lastAckedSummaryContext;
|
|
3556
3567
|
|
|
3557
3568
|
const startSummaryResult = this.summarizerNode.startSummary(
|
|
3558
3569
|
summaryRefSeqNum,
|
|
@@ -3619,10 +3630,10 @@ export class ContainerRuntime
|
|
|
3619
3630
|
0x395 /* it's one and the same thing */,
|
|
3620
3631
|
);
|
|
3621
3632
|
|
|
3622
|
-
if (
|
|
3633
|
+
if (lastAckedContext !== this.lastAckedSummaryContext) {
|
|
3623
3634
|
return {
|
|
3624
3635
|
continue: false,
|
|
3625
|
-
error: `Last summary changed while summarizing. ${this.
|
|
3636
|
+
error: `Last summary changed while summarizing. ${this.lastAckedSummaryContext} !== ${lastAckedContext}`,
|
|
3626
3637
|
};
|
|
3627
3638
|
}
|
|
3628
3639
|
return { continue: true };
|
|
@@ -3694,7 +3705,9 @@ export class ContainerRuntime
|
|
|
3694
3705
|
// Counting dataStores and handles
|
|
3695
3706
|
// Because handles are unchanged dataStores in the current logic,
|
|
3696
3707
|
// summarized dataStore count is total dataStore count minus handle count
|
|
3697
|
-
|
|
3708
|
+
// TODO why are we non null asserting here
|
|
3709
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
3710
|
+
const dataStoreTree = summaryTree.tree[channelsTreeName]!;
|
|
3698
3711
|
|
|
3699
3712
|
assert(dataStoreTree.type === SummaryType.Tree, 0x1fc /* "summary is not a tree" */);
|
|
3700
3713
|
const handleCount = Object.values(dataStoreTree.tree).filter(
|
|
@@ -3730,18 +3743,11 @@ export class ContainerRuntime
|
|
|
3730
3743
|
};
|
|
3731
3744
|
}
|
|
3732
3745
|
|
|
3733
|
-
const summaryContext =
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3739
|
-
}
|
|
3740
|
-
: {
|
|
3741
|
-
proposalHandle: lastAck.summaryOp.contents.handle,
|
|
3742
|
-
ackHandle: lastAck.summaryAck.contents.handle,
|
|
3743
|
-
referenceSequenceNumber: summaryRefSeqNum,
|
|
3744
|
-
};
|
|
3746
|
+
const summaryContext: ISummaryContext = {
|
|
3747
|
+
proposalHandle: this.lastAckedSummaryContext?.proposalHandle ?? undefined,
|
|
3748
|
+
ackHandle: this.lastAckedSummaryContext?.ackHandle ?? this.loadedFromVersionId,
|
|
3749
|
+
referenceSequenceNumber: summaryRefSeqNum,
|
|
3750
|
+
};
|
|
3745
3751
|
|
|
3746
3752
|
let handle: string;
|
|
3747
3753
|
try {
|
|
@@ -4032,7 +4038,9 @@ export class ContainerRuntime
|
|
|
4032
4038
|
this.outbox.submit(message);
|
|
4033
4039
|
}
|
|
4034
4040
|
|
|
4035
|
-
if
|
|
4041
|
+
// Note: Technically, the system "always" batches - if this case is true we'll just have a single-message batch.
|
|
4042
|
+
const flushImmediatelyOnSubmit = !this.currentlyBatching();
|
|
4043
|
+
if (flushImmediatelyOnSubmit) {
|
|
4036
4044
|
this.flush();
|
|
4037
4045
|
} else {
|
|
4038
4046
|
this.scheduleFlush();
|
|
@@ -4113,16 +4121,22 @@ export class ContainerRuntime
|
|
|
4113
4121
|
}
|
|
4114
4122
|
}
|
|
4115
4123
|
|
|
4116
|
-
private reSubmitBatch(batch:
|
|
4124
|
+
private reSubmitBatch(batch: PendingMessageResubmitData[], batchId: BatchId) {
|
|
4117
4125
|
this.orderSequentially(() => {
|
|
4118
4126
|
for (const message of batch) {
|
|
4119
4127
|
this.reSubmit(message);
|
|
4120
4128
|
}
|
|
4121
4129
|
});
|
|
4122
|
-
|
|
4130
|
+
|
|
4131
|
+
// Only include Batch ID if "Offline Load" feature is enabled
|
|
4132
|
+
// It's only needed to identify batches across container forks arising from misuse of offline load.
|
|
4133
|
+
const includeBatchId =
|
|
4134
|
+
this.mc.config.getBoolean("Fluid.Container.enableOfflineLoad") ?? false;
|
|
4135
|
+
|
|
4136
|
+
this.flush(includeBatchId ? batchId : undefined);
|
|
4123
4137
|
}
|
|
4124
4138
|
|
|
4125
|
-
private reSubmit(message:
|
|
4139
|
+
private reSubmit(message: PendingMessageResubmitData) {
|
|
4126
4140
|
// Need to parse from string for back-compat
|
|
4127
4141
|
const containerRuntimeMessage = this.parseLocalOpContent(message.content);
|
|
4128
4142
|
this.reSubmitCore(containerRuntimeMessage, message.localOpMetadata, message.opMetadata);
|
|
@@ -4225,84 +4239,140 @@ export class ContainerRuntime
|
|
|
4225
4239
|
const { proposalHandle, ackHandle, summaryRefSeq, summaryLogger } = options;
|
|
4226
4240
|
// proposalHandle is always passed from RunningSummarizer.
|
|
4227
4241
|
assert(proposalHandle !== undefined, 0x766 /* proposalHandle should be available */);
|
|
4228
|
-
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
4229
4242
|
const result = await this.summarizerNode.refreshLatestSummary(
|
|
4230
4243
|
proposalHandle,
|
|
4231
4244
|
summaryRefSeq,
|
|
4232
4245
|
);
|
|
4233
4246
|
|
|
4247
|
+
/* eslint-disable jsdoc/check-indentation */
|
|
4234
4248
|
/**
|
|
4235
|
-
*
|
|
4236
|
-
*
|
|
4237
|
-
*
|
|
4238
|
-
*
|
|
4249
|
+
* If the snapshot corresponding to the ack is not tracked by this client, it was submitted by another client.
|
|
4250
|
+
* Take action as per the following scenarios:
|
|
4251
|
+
* 1. If that snapshot is older than the one tracked by this client, ignore the ack because only the latest
|
|
4252
|
+
* snapshot is tracked.
|
|
4253
|
+
* 2. If that snapshot is newer, attempt to fetch the latest snapshot and do one of the following:
|
|
4254
|
+
* 2.1. If the fetched snapshot is same or newer than the one for which ack was received, close this client.
|
|
4255
|
+
* The next summarizer client will likely start from this snapshot and get out of this state. Fetching
|
|
4256
|
+
* the snapshot updates the cache for this client so if it's re-elected as summarizer, this will prevent
|
|
4257
|
+
* any thrashing.
|
|
4258
|
+
* 2.2. If the fetched snapshot is older than the one for which ack was received, ignore the ack. This can
|
|
4259
|
+
* happen in scenarios where the snapshot for the ack was lost in storage (in scenarios like DB rollback,
|
|
4260
|
+
* etc.) but the summary ack is still there because it's tracked a different service. In such cases,
|
|
4261
|
+
* ignoring the ack is the correct thing to do because the latest snapshot in storage is not the one for
|
|
4262
|
+
* the ack but is still the one tracked by this client. If we were to close the summarizer like in the
|
|
4263
|
+
* previous scenario, it will result in this document stuck in this state in a loop.
|
|
4239
4264
|
*/
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
ackHandle,
|
|
4246
|
-
targetSequenceNumber: summaryRefSeq,
|
|
4247
|
-
},
|
|
4248
|
-
readAndParseBlob,
|
|
4249
|
-
);
|
|
4265
|
+
/* eslint-enable jsdoc/check-indentation */
|
|
4266
|
+
if (!result.isSummaryTracked) {
|
|
4267
|
+
if (result.isSummaryNewer) {
|
|
4268
|
+
await this.fetchLatestSnapshotAndMaybeClose(summaryRefSeq, ackHandle, summaryLogger);
|
|
4269
|
+
}
|
|
4250
4270
|
return;
|
|
4251
4271
|
}
|
|
4252
4272
|
|
|
4253
4273
|
// Notify the garbage collector so it can update its latest summary state.
|
|
4254
4274
|
await this.garbageCollector.refreshLatestSummary(result);
|
|
4275
|
+
|
|
4276
|
+
// If we here, the ack was tracked by this client. Update the summary context of the last ack.
|
|
4277
|
+
this.lastAckedSummaryContext = {
|
|
4278
|
+
proposalHandle,
|
|
4279
|
+
ackHandle,
|
|
4280
|
+
referenceSequenceNumber: summaryRefSeq,
|
|
4281
|
+
};
|
|
4255
4282
|
}
|
|
4256
4283
|
|
|
4257
4284
|
/**
|
|
4258
|
-
* Fetches the latest snapshot from storage
|
|
4259
|
-
*
|
|
4260
|
-
*
|
|
4285
|
+
* Fetches the latest snapshot from storage. If the fetched snapshot is same or newer than the one for which ack
|
|
4286
|
+
* was received, close this client. Fetching the snapshot will update the cache for this client so if it's
|
|
4287
|
+
* re-elected as summarizer, this will prevent any thrashing.
|
|
4288
|
+
* If the fetched snapshot is older than the one for which ack was received, ignore the ack and return. This can
|
|
4289
|
+
* happen in scenarios where the snapshot for the ack was lost in storage in scenarios like DB rollback, etc.
|
|
4261
4290
|
*/
|
|
4262
|
-
private async
|
|
4291
|
+
private async fetchLatestSnapshotAndMaybeClose(
|
|
4292
|
+
targetRefSeq: number,
|
|
4293
|
+
targetAckHandle: string,
|
|
4263
4294
|
logger: ITelemetryLoggerExt,
|
|
4264
|
-
event: ITelemetryGenericEventExt,
|
|
4265
|
-
readAndParseBlob: ReadAndParseBlob,
|
|
4266
4295
|
) {
|
|
4267
|
-
await PerformanceEvent.timedExecAsync(
|
|
4296
|
+
const fetchedSnapshotRefSeq = await PerformanceEvent.timedExecAsync(
|
|
4268
4297
|
logger,
|
|
4269
|
-
|
|
4298
|
+
{ eventName: "RefreshLatestSummaryAckFetch" },
|
|
4270
4299
|
async (perfEvent: {
|
|
4271
4300
|
end: (arg0: {
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4301
|
+
details: {
|
|
4302
|
+
getVersionDuration?: number | undefined;
|
|
4303
|
+
getSnapshotDuration?: number | undefined;
|
|
4304
|
+
snapshotRefSeq?: number | undefined;
|
|
4305
|
+
snapshotVersion?: string | undefined;
|
|
4306
|
+
newerSnapshotPresent?: boolean | undefined;
|
|
4307
|
+
targetRefSeq?: number | undefined;
|
|
4308
|
+
targetAckHandle?: string | undefined;
|
|
4309
|
+
};
|
|
4276
4310
|
}) => void;
|
|
4277
4311
|
}) => {
|
|
4278
|
-
const
|
|
4312
|
+
const props: {
|
|
4279
4313
|
getVersionDuration?: number;
|
|
4280
4314
|
getSnapshotDuration?: number;
|
|
4281
4315
|
snapshotRefSeq?: number;
|
|
4282
4316
|
snapshotVersion?: string;
|
|
4283
|
-
|
|
4317
|
+
newerSnapshotPresent?: boolean | undefined;
|
|
4318
|
+
targetRefSeq?: number | undefined;
|
|
4319
|
+
targetAckHandle?: string | undefined;
|
|
4320
|
+
} = { targetRefSeq, targetAckHandle };
|
|
4284
4321
|
const trace = Trace.start();
|
|
4285
4322
|
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4323
|
+
let snapshotTree: ISnapshotTree | null;
|
|
4324
|
+
const scenarioName = "RefreshLatestSummaryAckFetch";
|
|
4325
|
+
// If loader supplied us the ISnapshot when loading, the new getSnapshotApi is supported and feature gate is ON, then use the
|
|
4326
|
+
// new API, otherwise it will reduce the service performance because the service will need to recalculate the full snapshot
|
|
4327
|
+
// in case previously getSnapshotApi was used and now we use the getVersions API.
|
|
4328
|
+
if (
|
|
4329
|
+
this.isSnapshotInstanceOfISnapshot &&
|
|
4330
|
+
this.storage.getSnapshot !== undefined &&
|
|
4331
|
+
this.mc.config.getBoolean("Fluid.Container.UseLoadingGroupIdForSnapshotFetch2") ===
|
|
4332
|
+
true
|
|
4333
|
+
) {
|
|
4334
|
+
const snapshot = await this.storage.getSnapshot({
|
|
4335
|
+
scenarioName,
|
|
4336
|
+
fetchSource: FetchSource.noCache,
|
|
4337
|
+
});
|
|
4338
|
+
const id = snapshot.snapshotTree.id;
|
|
4339
|
+
assert(id !== undefined, 0x9d0 /* id of the fetched snapshot should be defined */);
|
|
4340
|
+
props.snapshotVersion = id;
|
|
4341
|
+
snapshotTree = snapshot.snapshotTree;
|
|
4342
|
+
} else {
|
|
4343
|
+
const versions = await this.storage.getVersions(
|
|
4344
|
+
null,
|
|
4345
|
+
1,
|
|
4346
|
+
scenarioName,
|
|
4347
|
+
FetchSource.noCache,
|
|
4348
|
+
);
|
|
4349
|
+
assert(
|
|
4350
|
+
!!versions && !!versions[0],
|
|
4351
|
+
0x137 /* "Failed to get version from storage" */,
|
|
4352
|
+
);
|
|
4353
|
+
snapshotTree = await this.storage.getSnapshotTree(versions[0]);
|
|
4354
|
+
assert(!!snapshotTree, 0x138 /* "Failed to get snapshot from storage" */);
|
|
4355
|
+
props.snapshotVersion = versions[0].id;
|
|
4356
|
+
}
|
|
4294
4357
|
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
stats.snapshotVersion = versions[0].id;
|
|
4358
|
+
props.getSnapshotDuration = trace.trace().duration;
|
|
4359
|
+
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
4360
|
+
const snapshotRefSeq = await seqFromTree(snapshotTree, readAndParseBlob);
|
|
4361
|
+
props.snapshotRefSeq = snapshotRefSeq;
|
|
4362
|
+
props.newerSnapshotPresent = snapshotRefSeq >= targetRefSeq;
|
|
4301
4363
|
|
|
4302
|
-
perfEvent.end(
|
|
4364
|
+
perfEvent.end({ details: props });
|
|
4365
|
+
return snapshotRefSeq;
|
|
4303
4366
|
},
|
|
4304
4367
|
);
|
|
4305
4368
|
|
|
4369
|
+
// If the snapshot that was fetched is older than the target snapshot, return. The summarizer will not be closed
|
|
4370
|
+
// because the snapshot is likely deleted from storage and it so, closing the summarizer will result in the
|
|
4371
|
+
// document being stuck in this state.
|
|
4372
|
+
if (fetchedSnapshotRefSeq < targetRefSeq) {
|
|
4373
|
+
return;
|
|
4374
|
+
}
|
|
4375
|
+
|
|
4306
4376
|
await delay(this.closeSummarizerDelayMs);
|
|
4307
4377
|
this._summarizer?.stop("latestSummaryStateStale");
|
|
4308
4378
|
this.disposeFn();
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -59,7 +59,6 @@ import {
|
|
|
59
59
|
isSnapshotFetchRequiredForLoadingGroupId,
|
|
60
60
|
} from "@fluidframework/runtime-utils/internal";
|
|
61
61
|
import {
|
|
62
|
-
DataCorruptionError,
|
|
63
62
|
DataProcessingError,
|
|
64
63
|
LoggingError,
|
|
65
64
|
MonitoringContext,
|
|
@@ -305,6 +304,13 @@ export abstract class FluidDataStoreContext
|
|
|
305
304
|
return this._isInMemoryRoot;
|
|
306
305
|
}
|
|
307
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Returns the count of pending messages that are stored until the data store is realized.
|
|
309
|
+
*/
|
|
310
|
+
public get pendingCount(): number {
|
|
311
|
+
return this.pending?.length ?? 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
308
314
|
protected registry: IFluidDataStoreRegistry | undefined;
|
|
309
315
|
|
|
310
316
|
protected detachedRuntimeCreation = false;
|
|
@@ -567,8 +573,10 @@ export abstract class FluidDataStoreContext
|
|
|
567
573
|
// "verifyNotClosed" which logs tombstone errors. Throw error if tombstoned and throwing on load is configured.
|
|
568
574
|
this.verifyNotClosed("process", false /* checkTombstone */, safeTelemetryProps);
|
|
569
575
|
if (this.tombstoned && this.gcThrowOnTombstoneUsage) {
|
|
570
|
-
throw
|
|
576
|
+
throw DataProcessingError.create(
|
|
571
577
|
"Context is tombstoned! Call site [process]",
|
|
578
|
+
"process",
|
|
579
|
+
undefined /* sequencedMessage */,
|
|
572
580
|
safeTelemetryProps,
|
|
573
581
|
);
|
|
574
582
|
}
|
|
@@ -961,7 +969,12 @@ export abstract class FluidDataStoreContext
|
|
|
961
969
|
) {
|
|
962
970
|
if (this.deleted) {
|
|
963
971
|
const messageString = `Context is deleted! Call site [${callSite}]`;
|
|
964
|
-
const error =
|
|
972
|
+
const error = DataProcessingError.create(
|
|
973
|
+
messageString,
|
|
974
|
+
callSite,
|
|
975
|
+
undefined /* sequencedMessage */,
|
|
976
|
+
safeTelemetryProps,
|
|
977
|
+
);
|
|
965
978
|
this.mc.logger.sendErrorEvent(
|
|
966
979
|
{
|
|
967
980
|
eventName: "GC_Deleted_DataStore_Changed",
|
|
@@ -979,7 +992,12 @@ export abstract class FluidDataStoreContext
|
|
|
979
992
|
|
|
980
993
|
if (checkTombstone && this.tombstoned) {
|
|
981
994
|
const messageString = `Context is tombstoned! Call site [${callSite}]`;
|
|
982
|
-
const error =
|
|
995
|
+
const error = DataProcessingError.create(
|
|
996
|
+
messageString,
|
|
997
|
+
callSite,
|
|
998
|
+
undefined /* sequencedMessage */,
|
|
999
|
+
safeTelemetryProps,
|
|
1000
|
+
);
|
|
983
1001
|
|
|
984
1002
|
sendGCUnexpectedUsageEvent(
|
|
985
1003
|
this.mc,
|