@fluidframework/container-runtime 2.101.1 → 2.103.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 +8 -0
- package/container-runtime.test-files.tar +0 -0
- package/dist/batchTracker.d.ts +1 -1
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +1 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.d.ts +2 -2
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.js.map +1 -1
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +16 -5
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +160 -18
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts +2 -2
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +1 -4
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.d.ts.map +1 -1
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/deltaScheduler.d.ts +2 -2
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/gc/garbageCollection.d.ts +2 -2
- package/dist/gc/garbageCollection.d.ts.map +1 -1
- package/dist/gc/garbageCollection.js +12 -5
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcDefinitions.d.ts +3 -3
- package/dist/gc/gcDefinitions.d.ts.map +1 -1
- package/dist/gc/gcDefinitions.js.map +1 -1
- package/dist/gc/gcTelemetry.d.ts +3 -3
- package/dist/gc/gcTelemetry.d.ts.map +1 -1
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/inboundBatchAggregator.d.ts +2 -2
- package/dist/inboundBatchAggregator.d.ts.map +1 -1
- package/dist/inboundBatchAggregator.js.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.d.ts +39 -3
- package/dist/opLifecycle/duplicateBatchDetector.d.ts.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.js +57 -15
- package/dist/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.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 +48 -1
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +54 -1
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runtimeLayerCompatState.d.ts +2 -2
- package/dist/signalTelemetryProcessing.d.ts +2 -2
- package/dist/signalTelemetryProcessing.d.ts.map +1 -1
- package/dist/signalTelemetryProcessing.js.map +1 -1
- package/dist/summary/documentSchema.d.ts +2 -2
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +35 -3
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/orderedClientElection.d.ts +2 -2
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts +2 -2
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +3 -3
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -2
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerTypes.d.ts +3 -3
- package/dist/summary/summarizerTypes.d.ts.map +1 -1
- package/dist/summary/summarizerTypes.js.map +1 -1
- package/dist/summary/summaryCollection.d.ts.map +1 -1
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts +2 -2
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizer.d.ts +2 -2
- package/dist/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts +2 -2
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +2 -2
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryManager.d.ts.map +1 -1
- package/dist/summary/summaryManager.js.map +1 -1
- package/lib/batchTracker.d.ts +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +1 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.d.ts +2 -2
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.js.map +1 -1
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +16 -5
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +160 -18
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts +2 -2
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +2 -5
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.d.ts.map +1 -1
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/deltaScheduler.d.ts +2 -2
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +1 -1
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/gc/garbageCollection.d.ts +2 -2
- package/lib/gc/garbageCollection.d.ts.map +1 -1
- package/lib/gc/garbageCollection.js +12 -5
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcDefinitions.d.ts +3 -3
- package/lib/gc/gcDefinitions.d.ts.map +1 -1
- package/lib/gc/gcDefinitions.js.map +1 -1
- package/lib/gc/gcTelemetry.d.ts +3 -3
- package/lib/gc/gcTelemetry.d.ts.map +1 -1
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/inboundBatchAggregator.d.ts +2 -2
- package/lib/inboundBatchAggregator.d.ts.map +1 -1
- package/lib/inboundBatchAggregator.js.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.d.ts +39 -3
- package/lib/opLifecycle/duplicateBatchDetector.d.ts.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.js +57 -15
- package/lib/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.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 +48 -1
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +54 -1
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runtimeLayerCompatState.d.ts +2 -2
- package/lib/signalTelemetryProcessing.d.ts +2 -2
- package/lib/signalTelemetryProcessing.d.ts.map +1 -1
- package/lib/signalTelemetryProcessing.js.map +1 -1
- package/lib/summary/documentSchema.d.ts +2 -2
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +35 -3
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/orderedClientElection.d.ts +2 -2
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts +2 -2
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +3 -3
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -2
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerTypes.d.ts +3 -3
- package/lib/summary/summarizerTypes.d.ts.map +1 -1
- package/lib/summary/summarizerTypes.js.map +1 -1
- package/lib/summary/summaryCollection.d.ts.map +1 -1
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts +2 -2
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizer.d.ts +2 -2
- package/lib/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts +2 -2
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts +2 -2
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryManager.d.ts.map +1 -1
- package/lib/summary/summaryManager.js.map +1 -1
- package/package.json +18 -18
- package/src/batchTracker.ts +3 -3
- package/src/blobManager/blobManagerSnapSum.ts +2 -2
- package/src/connectionTelemetry.ts +3 -3
- package/src/containerRuntime.ts +188 -25
- package/src/dataStore.ts +3 -3
- package/src/dataStoreContext.ts +2 -4
- package/src/dataStoreContexts.ts +2 -2
- package/src/deltaScheduler.ts +2 -5
- package/src/gc/garbageCollection.ts +16 -9
- package/src/gc/gcDefinitions.ts +3 -3
- package/src/gc/gcTelemetry.ts +3 -3
- package/src/inboundBatchAggregator.ts +2 -2
- package/src/opLifecycle/duplicateBatchDetector.ts +103 -23
- package/src/opLifecycle/opCompressor.ts +2 -2
- package/src/opLifecycle/opDecompressor.ts +2 -2
- package/src/opLifecycle/opGroupingManager.ts +2 -2
- package/src/opLifecycle/opSplitter.ts +2 -2
- package/src/opLifecycle/outbox.ts +2 -2
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +80 -2
- package/src/signalTelemetryProcessing.ts +2 -2
- package/src/summary/documentSchema.ts +58 -5
- package/src/summary/orderedClientElection.ts +3 -3
- package/src/summary/summarizerClientElection.ts +2 -2
- package/src/summary/summarizerNode/summarizerNode.ts +3 -3
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +2 -2
- package/src/summary/summarizerTypes.ts +3 -3
- package/src/summary/summaryCollection.ts +2 -2
- package/src/summary/summaryDelayLoadedModule/runningSummarizer.ts +2 -4
- package/src/summary/summaryDelayLoadedModule/summarizer.ts +3 -3
- package/src/summary/summaryDelayLoadedModule/summarizerHeuristics.ts +2 -2
- package/src/summary/summaryDelayLoadedModule/summaryGenerator.ts +2 -2
- package/src/summary/summaryManager.ts +2 -2
|
@@ -9,6 +9,41 @@ import type { ITelemetryContext } from "@fluidframework/runtime-definitions/inte
|
|
|
9
9
|
import { getEffectiveBatchId } from "./batchManager.js";
|
|
10
10
|
import type { BatchStartInfo } from "./remoteMessageProcessor.js";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Identifying info for a previously-recorded batch that we can include in DuplicateBatch telemetry
|
|
14
|
+
* to help diagnose where the duplicate came from.
|
|
15
|
+
*
|
|
16
|
+
* @remarks `batchIdExplicit` distinguishes the two main duplicate-source scenarios:
|
|
17
|
+
* - `true`: the batchId was stamped on the wire as explicit metadata, indicating a resubmit (PendingStateManager.replayPendingStates).
|
|
18
|
+
* - `false`: the batchId was derived from the wire `clientId` and `batchStartCsn`, indicating a fresh, non-resubmit batch.
|
|
19
|
+
*/
|
|
20
|
+
export interface RecordedBatchInfo {
|
|
21
|
+
/**
|
|
22
|
+
* Wire clientId on the message that started the batch (NOT necessarily the `originalClientId`
|
|
23
|
+
* encoded in the batchId for resubmits).
|
|
24
|
+
*/
|
|
25
|
+
readonly clientId: string;
|
|
26
|
+
/**
|
|
27
|
+
* Wire client sequence number at the start of the batch.
|
|
28
|
+
*/
|
|
29
|
+
readonly batchStartCsn: number;
|
|
30
|
+
/**
|
|
31
|
+
* True if the batchId came from explicit metadata on the wire (i.e. a resubmit),
|
|
32
|
+
* false if it was derived from clientId + batchStartCsn (i.e. a fresh submit).
|
|
33
|
+
*/
|
|
34
|
+
readonly batchIdExplicit: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface RecordedBatch {
|
|
38
|
+
readonly batchId: string;
|
|
39
|
+
/**
|
|
40
|
+
* Identifying info for the batch as observed at runtime.
|
|
41
|
+
* `undefined` if the batch was loaded from a summary snapshot (where only the
|
|
42
|
+
* `[seqNum, batchId]` pair is persisted).
|
|
43
|
+
*/
|
|
44
|
+
readonly info: RecordedBatchInfo | undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
12
47
|
/**
|
|
13
48
|
* Detects duplicate batches that can arise from the "parallel fork" scenario:
|
|
14
49
|
* Container 1 is serialized, and Containers 2 and 3 are rehydrated from that state.
|
|
@@ -24,9 +59,21 @@ export class DuplicateBatchDetector {
|
|
|
24
59
|
private readonly seqNumByBatchId = new Map<string, number>();
|
|
25
60
|
|
|
26
61
|
/**
|
|
27
|
-
*
|
|
62
|
+
* Map from sequenceNumber to the recorded batch info. Used to clear out old entries as MSN
|
|
63
|
+
* advances, and to report identifying info about the original occurrence when a duplicate
|
|
64
|
+
* is detected.
|
|
65
|
+
*/
|
|
66
|
+
private readonly batchesBySeqNum = new Map<number, RecordedBatch>();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Number of inbound batches processed since the last summary. Reset by getRecentBatchInfoForSummary.
|
|
70
|
+
*/
|
|
71
|
+
private processedBatchCount = 0;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Largest tracked-batch count observed since the last summary. Reset by getRecentBatchInfoForSummary.
|
|
28
75
|
*/
|
|
29
|
-
private
|
|
76
|
+
private peakTrackedBatchCount = 0;
|
|
30
77
|
|
|
31
78
|
/**
|
|
32
79
|
* Initialize from snapshot data if provided - otherwise initialize empty
|
|
@@ -34,22 +81,31 @@ export class DuplicateBatchDetector {
|
|
|
34
81
|
constructor(batchIdsFromSnapshot: [number, string][] | undefined) {
|
|
35
82
|
if (batchIdsFromSnapshot) {
|
|
36
83
|
for (const [seqNum, batchId] of batchIdsFromSnapshot) {
|
|
37
|
-
|
|
84
|
+
// Entries loaded from a snapshot don't carry the original clientId/csn/explicit-bit;
|
|
85
|
+
// we record them with `info: undefined` so duplicate telemetry can indicate that.
|
|
86
|
+
this.batchesBySeqNum.set(seqNum, { batchId, info: undefined });
|
|
38
87
|
this.seqNumByBatchId.set(batchId, seqNum);
|
|
39
88
|
}
|
|
89
|
+
this.peakTrackedBatchCount = this.batchesBySeqNum.size;
|
|
40
90
|
}
|
|
41
91
|
}
|
|
42
92
|
|
|
43
93
|
/**
|
|
44
94
|
* Records this batch's batchId, and checks if it's a duplicate of a batch we've already seen.
|
|
45
|
-
* If it's a duplicate, also return the sequence number of the other batch
|
|
95
|
+
* If it's a duplicate, also return the sequence number of the other batch (and identifying info,
|
|
96
|
+
* if the other batch was seen during this container session rather than loaded from snapshot) for logging.
|
|
46
97
|
*
|
|
47
98
|
* @remarks We also use the minimumSequenceNumber to clear out old batchIds that are no longer at risk for duplicates.
|
|
48
99
|
*/
|
|
49
|
-
public processInboundBatch(
|
|
50
|
-
|
|
51
|
-
|
|
100
|
+
public processInboundBatch(batchStart: BatchStartInfo):
|
|
101
|
+
| {
|
|
102
|
+
duplicate: true;
|
|
103
|
+
otherSequenceNumber: number;
|
|
104
|
+
otherBatchInfo: RecordedBatchInfo | undefined;
|
|
105
|
+
}
|
|
106
|
+
| { duplicate: false } {
|
|
52
107
|
const { sequenceNumber, minimumSequenceNumber } = batchStart.keyMessage;
|
|
108
|
+
this.processedBatchCount++;
|
|
53
109
|
|
|
54
110
|
// Glance at this batch's MSN. Any batchIds we're tracking with a lower sequence number are now safe to forget.
|
|
55
111
|
// Why? Because any other client holding the same batch locally would have seen the earlier batch and closed before submitting its duplicate.
|
|
@@ -64,22 +120,37 @@ export class DuplicateBatchDetector {
|
|
|
64
120
|
// O(1) duplicate check + get otherSequenceNumber in one lookup
|
|
65
121
|
const otherSequenceNumber = this.seqNumByBatchId.get(batchId);
|
|
66
122
|
if (otherSequenceNumber !== undefined) {
|
|
123
|
+
const other = this.batchesBySeqNum.get(otherSequenceNumber);
|
|
67
124
|
assert(
|
|
68
|
-
|
|
125
|
+
other?.batchId === batchId,
|
|
69
126
|
0xce0 /* batchIdToSeqNum and seqNumToBatchId should be in sync for duplicate */,
|
|
70
127
|
);
|
|
71
|
-
return {
|
|
128
|
+
return {
|
|
129
|
+
duplicate: true,
|
|
130
|
+
otherSequenceNumber,
|
|
131
|
+
otherBatchInfo: other.info,
|
|
132
|
+
};
|
|
72
133
|
}
|
|
73
134
|
|
|
74
135
|
// Now we know it's not a duplicate, so add it to the tracked batchIds and return.
|
|
75
136
|
assert(
|
|
76
|
-
!this.
|
|
137
|
+
!this.batchesBySeqNum.has(sequenceNumber),
|
|
77
138
|
0xce1 /* seqNumToBatchId and batchIdToSeqNum should be in sync */,
|
|
78
139
|
);
|
|
79
140
|
|
|
80
|
-
// Add new batch
|
|
81
|
-
|
|
141
|
+
// Add new batch. Record identifying info so we can report it if a future duplicate matches us.
|
|
142
|
+
const info: RecordedBatchInfo | undefined = {
|
|
143
|
+
clientId: batchStart.clientId,
|
|
144
|
+
batchStartCsn: batchStart.batchStartCsn,
|
|
145
|
+
// True iff the wire carried explicit batchId metadata (resubmit path).
|
|
146
|
+
// False indicates the batchId was derived from clientId + batchStartCsn (fresh submit).
|
|
147
|
+
batchIdExplicit: batchStart.batchId !== undefined,
|
|
148
|
+
};
|
|
149
|
+
this.batchesBySeqNum.set(sequenceNumber, { batchId, info });
|
|
82
150
|
this.seqNumByBatchId.set(batchId, sequenceNumber);
|
|
151
|
+
if (this.batchesBySeqNum.size > this.peakTrackedBatchCount) {
|
|
152
|
+
this.peakTrackedBatchCount = this.batchesBySeqNum.size;
|
|
153
|
+
}
|
|
83
154
|
|
|
84
155
|
return { duplicate: false };
|
|
85
156
|
}
|
|
@@ -89,10 +160,10 @@ export class DuplicateBatchDetector {
|
|
|
89
160
|
* since the batch start has been processed by all clients, and local batches are deduped and the forked client would close.
|
|
90
161
|
*/
|
|
91
162
|
private clearOldBatchIds(msn: number): void {
|
|
92
|
-
for (const [sequenceNumber,
|
|
163
|
+
for (const [sequenceNumber, recorded] of this.batchesBySeqNum) {
|
|
93
164
|
if (sequenceNumber < msn) {
|
|
94
|
-
this.
|
|
95
|
-
this.seqNumByBatchId.delete(batchId);
|
|
165
|
+
this.batchesBySeqNum.delete(sequenceNumber);
|
|
166
|
+
this.seqNumByBatchId.delete(recorded.batchId);
|
|
96
167
|
} else {
|
|
97
168
|
break;
|
|
98
169
|
}
|
|
@@ -108,16 +179,25 @@ export class DuplicateBatchDetector {
|
|
|
108
179
|
public getRecentBatchInfoForSummary(
|
|
109
180
|
telemetryContext?: ITelemetryContext,
|
|
110
181
|
): [number, string][] | undefined {
|
|
111
|
-
if (
|
|
112
|
-
|
|
182
|
+
if (telemetryContext !== undefined) {
|
|
183
|
+
const prefix = "fluid_DuplicateBatchDetector_";
|
|
184
|
+
telemetryContext.set(prefix, "recentBatchCount", this.batchesBySeqNum.size);
|
|
185
|
+
telemetryContext.set(prefix, "peakRecentBatchCount", this.peakTrackedBatchCount);
|
|
186
|
+
telemetryContext.set(prefix, "processedBatchCount", this.processedBatchCount);
|
|
113
187
|
}
|
|
114
188
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
189
|
+
// Reset per-window perf counters so each summary covers only the activity since the
|
|
190
|
+
// previous one. Peak resets to the current size (the floor for the next window).
|
|
191
|
+
this.processedBatchCount = 0;
|
|
192
|
+
this.peakTrackedBatchCount = this.batchesBySeqNum.size;
|
|
193
|
+
|
|
194
|
+
if (this.batchesBySeqNum.size === 0) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
120
197
|
|
|
121
|
-
return [...this.
|
|
198
|
+
return [...this.batchesBySeqNum.entries()].map(([seqNum, recorded]) => [
|
|
199
|
+
seqNum,
|
|
200
|
+
recorded.batchId,
|
|
201
|
+
]);
|
|
122
202
|
}
|
|
123
203
|
}
|
|
@@ -9,7 +9,7 @@ import { assert } from "@fluidframework/core-utils/internal";
|
|
|
9
9
|
import {
|
|
10
10
|
DataProcessingError,
|
|
11
11
|
createChildLogger,
|
|
12
|
-
type
|
|
12
|
+
type TelemetryLoggerExt,
|
|
13
13
|
} from "@fluidframework/telemetry-utils/internal";
|
|
14
14
|
import { compress } from "lz4js";
|
|
15
15
|
|
|
@@ -25,7 +25,7 @@ import { estimateSocketSize } from "./outbox.js";
|
|
|
25
25
|
* Use opGroupingManager to group a batch into a singleton batch suitable for compression.
|
|
26
26
|
*/
|
|
27
27
|
export class OpCompressor {
|
|
28
|
-
private readonly logger:
|
|
28
|
+
private readonly logger: TelemetryLoggerExt;
|
|
29
29
|
|
|
30
30
|
constructor(logger: ITelemetryBaseLogger) {
|
|
31
31
|
this.logger = createChildLogger({ logger, namespace: "OpCompressor" });
|
|
@@ -9,7 +9,7 @@ import { assert } from "@fluidframework/core-utils/internal";
|
|
|
9
9
|
import type { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
|
|
10
10
|
import {
|
|
11
11
|
createChildLogger,
|
|
12
|
-
type
|
|
12
|
+
type TelemetryLoggerExt,
|
|
13
13
|
} from "@fluidframework/telemetry-utils/internal";
|
|
14
14
|
import { decompress } from "lz4js";
|
|
15
15
|
|
|
@@ -40,7 +40,7 @@ export class OpDecompressor {
|
|
|
40
40
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
41
|
private rootMessageContents: any | undefined;
|
|
42
42
|
private processedCount = 0;
|
|
43
|
-
private readonly logger:
|
|
43
|
+
private readonly logger: TelemetryLoggerExt;
|
|
44
44
|
|
|
45
45
|
constructor(logger: ITelemetryBaseLogger) {
|
|
46
46
|
this.logger = createChildLogger({ logger, namespace: "OpDecompressor" });
|
|
@@ -8,7 +8,7 @@ import { assert } from "@fluidframework/core-utils/internal";
|
|
|
8
8
|
import type { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
|
|
9
9
|
import {
|
|
10
10
|
createChildLogger,
|
|
11
|
-
type
|
|
11
|
+
type TelemetryLoggerExt,
|
|
12
12
|
} from "@fluidframework/telemetry-utils/internal";
|
|
13
13
|
|
|
14
14
|
import type {
|
|
@@ -65,7 +65,7 @@ export interface EmptyGroupedBatch {
|
|
|
65
65
|
|
|
66
66
|
export class OpGroupingManager {
|
|
67
67
|
static readonly groupedBatchOp = "groupedBatch";
|
|
68
|
-
private readonly logger:
|
|
68
|
+
private readonly logger: TelemetryLoggerExt;
|
|
69
69
|
|
|
70
70
|
constructor(
|
|
71
71
|
private readonly config: OpGroupingManagerConfig,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
DataCorruptionError,
|
|
12
12
|
createChildLogger,
|
|
13
13
|
extractSafePropertiesFromMessage,
|
|
14
|
-
type
|
|
14
|
+
type TelemetryLoggerExt,
|
|
15
15
|
} from "@fluidframework/telemetry-utils/internal";
|
|
16
16
|
|
|
17
17
|
import {
|
|
@@ -45,7 +45,7 @@ function isChunkedContents(contents: unknown): contents is IChunkedContents {
|
|
|
45
45
|
export class OpSplitter {
|
|
46
46
|
// Local copy of incomplete received chunks.
|
|
47
47
|
private readonly chunkMap: Map<string, string[]>;
|
|
48
|
-
private readonly logger:
|
|
48
|
+
private readonly logger: TelemetryLoggerExt;
|
|
49
49
|
|
|
50
50
|
constructor(
|
|
51
51
|
chunks: [string, string[]][],
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
UsageError,
|
|
15
15
|
createChildLogger,
|
|
16
16
|
type IFluidErrorBase,
|
|
17
|
-
type
|
|
17
|
+
type TelemetryLoggerExt,
|
|
18
18
|
} from "@fluidframework/telemetry-utils/internal";
|
|
19
19
|
|
|
20
20
|
import type { ICompressionRuntimeOptions } from "../compressionDefinitions.js";
|
|
@@ -194,7 +194,7 @@ export const estimateSocketSize = (batch: OutboundBatch): number => {
|
|
|
194
194
|
* to support slight variation in semantics for each batch (e.g. support for rebasing or grouping).
|
|
195
195
|
*/
|
|
196
196
|
export class Outbox {
|
|
197
|
-
private readonly logger:
|
|
197
|
+
private readonly logger: TelemetryLoggerExt;
|
|
198
198
|
private readonly mainBatch: BatchManager;
|
|
199
199
|
private readonly blobAttachBatch: BatchManager;
|
|
200
200
|
private batchRebasesToReport = 5;
|
package/src/packageVersion.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { IDisposable, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
7
7
|
import { assert, Lazy } from "@fluidframework/core-utils/internal";
|
|
8
8
|
import {
|
|
9
|
-
type
|
|
9
|
+
type TelemetryLoggerExt,
|
|
10
10
|
DataProcessingError,
|
|
11
11
|
LoggingError,
|
|
12
12
|
extractSafePropertiesFromMessage,
|
|
@@ -142,6 +142,25 @@ export interface IRuntimeStateHandler {
|
|
|
142
142
|
isAttached: () => boolean;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Optional hooks invoked at the close of the stashed-op apply lifecycle.
|
|
147
|
+
*
|
|
148
|
+
* `onAfterStashedOpsApplied` fires synchronously the first time
|
|
149
|
+
* `initialMessages` drains during `applyStashedOpsAt`, immediately after
|
|
150
|
+
* `isApplyingStashedOps` flips to `false`. Fires at most once per PSM
|
|
151
|
+
* lifetime. If an apply throws, control never reaches the close site and
|
|
152
|
+
* the hook is not invoked — load is fatal in that case.
|
|
153
|
+
*
|
|
154
|
+
* No corresponding open hook is exposed. The apply window is opened eagerly
|
|
155
|
+
* in the PSM constructor, but at that point `ContainerRuntime` has not yet
|
|
156
|
+
* wired up the downstream observers (`channelCollection` is undefined), so a
|
|
157
|
+
* fanout fired from the constructor would be a no-op. Consumers that care
|
|
158
|
+
* about the open transition can read `isApplyingStashedOps` directly.
|
|
159
|
+
*/
|
|
160
|
+
export interface PendingStateManagerHooks {
|
|
161
|
+
onAfterStashedOpsApplied?: () => void;
|
|
162
|
+
}
|
|
163
|
+
|
|
145
164
|
function isEmptyBatchPendingMessage(message: IPendingMessageFromStash): boolean {
|
|
146
165
|
const content = JSON.parse(message.content) as Partial<EmptyGroupedBatch>;
|
|
147
166
|
return content.type === "groupedBatch" && content.contents?.length === 0;
|
|
@@ -366,17 +385,62 @@ export class PendingStateManager implements IDisposable {
|
|
|
366
385
|
};
|
|
367
386
|
}
|
|
368
387
|
|
|
369
|
-
private readonly logger:
|
|
388
|
+
private readonly logger: TelemetryLoggerExt;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* One-way lifecycle of the stashed-op apply window: `ended` → `applying` → `ended`.
|
|
392
|
+
*
|
|
393
|
+
* Default is `ended` — no stashed state means there's nothing to apply, so the window is
|
|
394
|
+
* closed before it ever opens. `ended` → `applying` happens in the constructor when
|
|
395
|
+
* stashed state is present (i.e. `initialMessages` is non-empty at construction). The
|
|
396
|
+
* open is eager so the runtime is readonly from the moment any DDS could possibly
|
|
397
|
+
* observe it. `applying` → `ended` happens the first time {@link applyStashedOpsAt}
|
|
398
|
+
* drains `initialMessages`. After that, local edits are safe — they queue FIFO behind
|
|
399
|
+
* any remaining `pendingMessages`, preserving server-side ordering.
|
|
400
|
+
*
|
|
401
|
+
* The window never reopens. After the close, subsequent `applyStashedOpsAt` calls (e.g.
|
|
402
|
+
* from late `notifyOpReplay`s) early-return at the empty guard.
|
|
403
|
+
*
|
|
404
|
+
* `pendingMessages` state is intentionally NOT part of the close condition. Those
|
|
405
|
+
* entries are drained transparently by {@link replayPendingStates} on connect via
|
|
406
|
+
* resubmit (each pop is matched by a fresh push), so the queue size is conserved across
|
|
407
|
+
* resubmit and DDSes can't distinguish a resubmit-ack from a normal ack. Holding the
|
|
408
|
+
* window open through resubmit would force resubmits to run while the runtime is
|
|
409
|
+
* readonly, which is the inverse of what we want ("never resubmit during apply stashed
|
|
410
|
+
* ops").
|
|
411
|
+
*
|
|
412
|
+
* An apply error leaves the lifecycle at `applying` because the queue isn't drained.
|
|
413
|
+
* That's fine: an error here is fatal for the load, the container is unusable, and
|
|
414
|
+
* there's no state to restore.
|
|
415
|
+
*/
|
|
416
|
+
private _applyLifecycle: "applying" | "ended" = "ended";
|
|
417
|
+
public get isApplyingStashedOps(): boolean {
|
|
418
|
+
return this._applyLifecycle === "applying";
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private readonly hooks: PendingStateManagerHooks;
|
|
370
422
|
|
|
371
423
|
constructor(
|
|
372
424
|
private readonly stateHandler: IRuntimeStateHandler,
|
|
373
425
|
stashedLocalState: IPendingLocalState | undefined,
|
|
374
426
|
logger: ITelemetryBaseLogger,
|
|
427
|
+
hooks: PendingStateManagerHooks = {},
|
|
375
428
|
) {
|
|
376
429
|
this.logger = createChildLogger({ logger });
|
|
430
|
+
this.hooks = hooks;
|
|
377
431
|
if (stashedLocalState?.pendingStates) {
|
|
378
432
|
this.initialMessages.push(...stashedLocalState.pendingStates);
|
|
379
433
|
}
|
|
434
|
+
// Open the apply window eagerly if there is any stashed work. The
|
|
435
|
+
// runtime is readonly while `isApplyingStashedOps` is true (see
|
|
436
|
+
// `ContainerRuntime.isReadOnly`); compliant DDSes consult `readOnly`
|
|
437
|
+
// at realize time and skip submits. No fanout fires here — downstream
|
|
438
|
+
// observers (`channelCollection`) are not yet constructed at this
|
|
439
|
+
// point in the runtime constructor, and the first real readonly read
|
|
440
|
+
// happens after the constructor returns.
|
|
441
|
+
if (!this.initialMessages.isEmpty()) {
|
|
442
|
+
this._applyLifecycle = "applying";
|
|
443
|
+
}
|
|
380
444
|
}
|
|
381
445
|
|
|
382
446
|
public get disposed(): boolean {
|
|
@@ -451,6 +515,10 @@ export class PendingStateManager implements IDisposable {
|
|
|
451
515
|
* @param seqNum - Sequence number at which to apply ops. Will apply all ops if seqNum is undefined.
|
|
452
516
|
*/
|
|
453
517
|
public async applyStashedOpsAt(seqNum?: number): Promise<void> {
|
|
518
|
+
if (this.initialMessages.isEmpty()) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
|
|
454
522
|
// apply stashed ops at sequence number
|
|
455
523
|
while (!this.initialMessages.isEmpty()) {
|
|
456
524
|
if (seqNum !== undefined) {
|
|
@@ -497,6 +565,16 @@ export class PendingStateManager implements IDisposable {
|
|
|
497
565
|
throw DataProcessingError.wrapIfUnrecognized(error, "applyStashedOp", nextMessage);
|
|
498
566
|
}
|
|
499
567
|
}
|
|
568
|
+
|
|
569
|
+
// The apply window was opened eagerly in the constructor when there
|
|
570
|
+
// was any stashed work. We close it on full successful drain only.
|
|
571
|
+
// If an apply throws above, control never reaches here and the
|
|
572
|
+
// lifecycle stays at "applying" — the load is fatal so there's no
|
|
573
|
+
// recoverable state.
|
|
574
|
+
if (this._applyLifecycle === "applying" && this.initialMessages.isEmpty()) {
|
|
575
|
+
this._applyLifecycle = "ended";
|
|
576
|
+
this.hooks.onAfterStashedOpsApplied?.();
|
|
577
|
+
}
|
|
500
578
|
}
|
|
501
579
|
|
|
502
580
|
/**
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ISignalEnvelope } from "@fluidframework/core-interfaces/internal";
|
|
7
7
|
import type {
|
|
8
|
-
|
|
8
|
+
TelemetryLoggerExt,
|
|
9
9
|
TelemetryEventPropertyTypeExt,
|
|
10
10
|
} from "@fluidframework/telemetry-utils/internal";
|
|
11
11
|
|
|
@@ -101,7 +101,7 @@ export class SignalTelemetryManager {
|
|
|
101
101
|
*/
|
|
102
102
|
public trackReceivedSignal(
|
|
103
103
|
envelope: ISignalEnvelope,
|
|
104
|
-
logger:
|
|
104
|
+
logger: TelemetryLoggerExt,
|
|
105
105
|
consecutiveReconnects: number,
|
|
106
106
|
): void {
|
|
107
107
|
const {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import type { SemanticVersion } from "@fluidframework/runtime-utils/internal";
|
|
8
|
-
import type {
|
|
8
|
+
import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
|
|
9
9
|
import { DataProcessingError } from "@fluidframework/telemetry-utils/internal";
|
|
10
10
|
import { gt, lt, parse } from "semver-ts";
|
|
11
11
|
|
|
@@ -303,6 +303,58 @@ const documentSchemaSupportedConfigs = {
|
|
|
303
303
|
disallowedVersions: new CheckVersions(),
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Entry in {@link retiredDocumentSchemaFeatures}.
|
|
308
|
+
*
|
|
309
|
+
* - `handler` validates/merges the persisted value (same as a "non-retired" feature).
|
|
310
|
+
* - `value` is the hardcoded value that this runtime will always use for the desired schema.
|
|
311
|
+
*/
|
|
312
|
+
interface IRetiredFeatureEntry {
|
|
313
|
+
handler: IProperty;
|
|
314
|
+
value: DocumentSchemaValueType;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Retired runtime features. A retired feature is one this runtime version no longer toggles
|
|
319
|
+
* via {@link IDocumentSchemaFeatures}, but that older documents may still carry in their
|
|
320
|
+
* persisted schema. Each entry bundles the property handler with the hardcoded value for the feature.
|
|
321
|
+
*
|
|
322
|
+
* Retired features participate in the normal merge / schema-change-op flow exactly like
|
|
323
|
+
* non-retired features — the only difference is that their values are hardcoded.
|
|
324
|
+
*/
|
|
325
|
+
const retiredDocumentSchemaFeatures = {
|
|
326
|
+
// Note: There are currently no retired retired features. To retire a feature, remove it from IDocumentSchemaFeatures
|
|
327
|
+
// and documentSchemaSupportedConfigs and add an entry here, e.g.:
|
|
328
|
+
// featureFoo: { handler: new TrueOrUndefined(), value: true },
|
|
329
|
+
} satisfies Record<string, IRetiredFeatureEntry> & {
|
|
330
|
+
// This ensures that retiredDocumentSchemaFeatures and IDocumentSchemaFeatures are mutually exclusive.
|
|
331
|
+
[K in keyof IDocumentSchemaFeatures]?: never;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Looks up the validator/merger for a given runtime property name across both supported and
|
|
336
|
+
* retired configs. Returns `undefined` if the property is unknown to this runtime.
|
|
337
|
+
*/
|
|
338
|
+
function getRuntimeConfigHandler(name: string): IProperty | undefined {
|
|
339
|
+
return (
|
|
340
|
+
(documentSchemaSupportedConfigs as Record<string, IProperty>)[name] ??
|
|
341
|
+
(retiredDocumentSchemaFeatures as Record<string, IRetiredFeatureEntry>)[name]?.handler
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Builds the `{ key: value }` for retired features (for building the desired schema).
|
|
347
|
+
*/
|
|
348
|
+
function retiredFeatureValues(): Record<string, DocumentSchemaValueType> {
|
|
349
|
+
const result: Record<string, DocumentSchemaValueType> = {};
|
|
350
|
+
for (const [key, entry] of Object.entries(
|
|
351
|
+
retiredDocumentSchemaFeatures as Record<string, IRetiredFeatureEntry>,
|
|
352
|
+
)) {
|
|
353
|
+
result[key] = entry.value;
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
|
|
306
358
|
/**
|
|
307
359
|
* Checks if a given schema is compatible with current code, i.e. if current code can understand all the features of that schema.
|
|
308
360
|
* If schema is not compatible with current code, it throws an exception.
|
|
@@ -343,7 +395,7 @@ function checkRuntimeCompatibility(
|
|
|
343
395
|
unknownProperty = "runtime";
|
|
344
396
|
} else {
|
|
345
397
|
for (const [name, value] of Object.entries(documentSchema.runtime)) {
|
|
346
|
-
const validator =
|
|
398
|
+
const validator = getRuntimeConfigHandler(name);
|
|
347
399
|
if (!(validator?.validate(value) ?? false)) {
|
|
348
400
|
unknownProperty = `runtime/${name}`;
|
|
349
401
|
}
|
|
@@ -377,7 +429,7 @@ function and(
|
|
|
377
429
|
...Object.keys(persistedSchema.runtime),
|
|
378
430
|
...Object.keys(providedSchema.runtime),
|
|
379
431
|
])) {
|
|
380
|
-
runtime[key] = (
|
|
432
|
+
runtime[key] = (getRuntimeConfigHandler(key) as IProperty).and(
|
|
381
433
|
persistedSchema.runtime[key],
|
|
382
434
|
providedSchema.runtime[key],
|
|
383
435
|
);
|
|
@@ -405,7 +457,7 @@ function or(
|
|
|
405
457
|
...Object.keys(persistedSchema.runtime),
|
|
406
458
|
...Object.keys(providedSchema.runtime),
|
|
407
459
|
])) {
|
|
408
|
-
runtime[key] = (
|
|
460
|
+
runtime[key] = (getRuntimeConfigHandler(key) as IProperty).or(
|
|
409
461
|
persistedSchema.runtime[key],
|
|
410
462
|
providedSchema.runtime[key],
|
|
411
463
|
);
|
|
@@ -581,7 +633,7 @@ export class DocumentsSchemaController {
|
|
|
581
633
|
features: IDocumentSchemaFeatures,
|
|
582
634
|
private readonly onSchemaChange: (schema: IDocumentSchemaCurrent) => void,
|
|
583
635
|
info: IDocumentSchemaInfo,
|
|
584
|
-
logger:
|
|
636
|
+
logger: TelemetryLoggerExt,
|
|
585
637
|
private readonly disableSchemaUpgrade: boolean,
|
|
586
638
|
) {
|
|
587
639
|
// For simplicity, let's only support new schema features for explicit schema control mode
|
|
@@ -625,6 +677,7 @@ export class DocumentsSchemaController {
|
|
|
625
677
|
opGroupingEnabled: boolToProp(features.opGroupingEnabled),
|
|
626
678
|
createBlobPayloadPending: features.createBlobPayloadPending,
|
|
627
679
|
disallowedVersions: arrayToProp(features.disallowedVersions),
|
|
680
|
+
...retiredFeatureValues(),
|
|
628
681
|
},
|
|
629
682
|
};
|
|
630
683
|
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
ISequencedClient,
|
|
20
20
|
} from "@fluidframework/driver-definitions";
|
|
21
21
|
import {
|
|
22
|
-
type
|
|
22
|
+
type TelemetryLoggerExt,
|
|
23
23
|
UsageError,
|
|
24
24
|
createChildLogger,
|
|
25
25
|
} from "@fluidframework/telemetry-utils/internal";
|
|
@@ -135,7 +135,7 @@ export class OrderedClientCollection
|
|
|
135
135
|
* Pointer to end of linked list, for optimized client adds.
|
|
136
136
|
*/
|
|
137
137
|
private _youngestClient: LinkNode = this.rootNode;
|
|
138
|
-
private readonly logger:
|
|
138
|
+
private readonly logger: TelemetryLoggerExt;
|
|
139
139
|
|
|
140
140
|
public get count(): number {
|
|
141
141
|
return this.clientMap.size;
|
|
@@ -413,7 +413,7 @@ export class OrderedClientElection
|
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
constructor(
|
|
416
|
-
private readonly logger:
|
|
416
|
+
private readonly logger: TelemetryLoggerExt,
|
|
417
417
|
private readonly orderedClientCollection: IOrderedClientCollection,
|
|
418
418
|
/**
|
|
419
419
|
* Serialized state from summary or current sequence number at time of load if new.
|
|
@@ -7,7 +7,7 @@ import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
|
7
7
|
import type { IEvent, IEventProvider } from "@fluidframework/core-interfaces";
|
|
8
8
|
import type { IClientDetails } from "@fluidframework/driver-definitions";
|
|
9
9
|
import { MessageType } from "@fluidframework/driver-definitions/internal";
|
|
10
|
-
import type {
|
|
10
|
+
import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
13
|
IOrderedClientElection,
|
|
@@ -58,7 +58,7 @@ export class SummarizerClientElection
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
constructor(
|
|
61
|
-
private readonly logger:
|
|
61
|
+
private readonly logger: TelemetryLoggerExt,
|
|
62
62
|
private readonly summaryCollection: IEventProvider<ISummaryCollectionOpEvents>,
|
|
63
63
|
public readonly clientElection: IOrderedClientElection,
|
|
64
64
|
private readonly maxOpsSinceLastSummary: number,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "@fluidframework/telemetry-utils/internal";
|
|
32
32
|
import type {
|
|
33
33
|
ITelemetryErrorEventExt,
|
|
34
|
-
|
|
34
|
+
TelemetryLoggerExt,
|
|
35
35
|
} from "@fluidframework/telemetry-utils/internal";
|
|
36
36
|
|
|
37
37
|
import type {
|
|
@@ -90,7 +90,7 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
90
90
|
private wipSummarizeCalled: boolean = false;
|
|
91
91
|
private wipSkipRecursion = false;
|
|
92
92
|
|
|
93
|
-
protected readonly logger:
|
|
93
|
+
protected readonly logger: TelemetryLoggerExt;
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Do not call constructor directly.
|
|
@@ -664,7 +664,7 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
664
664
|
* @param config - Configure behavior of summarizer node
|
|
665
665
|
*/
|
|
666
666
|
export const createRootSummarizerNode = (
|
|
667
|
-
logger:
|
|
667
|
+
logger: TelemetryLoggerExt,
|
|
668
668
|
summarizeInternalFn: SummarizeInternalFn,
|
|
669
669
|
changeSequenceNumber: number,
|
|
670
670
|
referenceSequenceNumber: number | undefined,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { SummaryObject } from "@fluidframework/driver-definitions";
|
|
7
7
|
import type { ISnapshotTree } from "@fluidframework/driver-definitions/internal";
|
|
8
8
|
import type {
|
|
9
|
-
|
|
9
|
+
TelemetryLoggerExt,
|
|
10
10
|
TelemetryDataTag,
|
|
11
11
|
} from "@fluidframework/telemetry-utils/internal";
|
|
12
12
|
|
|
@@ -67,7 +67,7 @@ export type ValidateSummaryResult =
|
|
|
67
67
|
export interface ISummarizerNodeRootContract {
|
|
68
68
|
startSummary(
|
|
69
69
|
referenceSequenceNumber: number,
|
|
70
|
-
summaryLogger:
|
|
70
|
+
summaryLogger: TelemetryLoggerExt,
|
|
71
71
|
latestSummaryRefSeqNum: number,
|
|
72
72
|
): IStartSummaryResult;
|
|
73
73
|
validateSummary(): ValidateSummaryResult;
|
|
@@ -24,7 +24,7 @@ import type {
|
|
|
24
24
|
import type { ISummaryStats } from "@fluidframework/runtime-definitions/internal";
|
|
25
25
|
import type { TelemetryContext } from "@fluidframework/runtime-utils/internal";
|
|
26
26
|
import type {
|
|
27
|
-
|
|
27
|
+
TelemetryLoggerExt,
|
|
28
28
|
ITelemetryLoggerPropertyBag,
|
|
29
29
|
} from "@fluidframework/telemetry-utils/internal";
|
|
30
30
|
|
|
@@ -79,7 +79,7 @@ export interface IRefreshSummaryAckOptions {
|
|
|
79
79
|
/**
|
|
80
80
|
* Telemetry logger to which telemetry events will be forwarded.
|
|
81
81
|
*/
|
|
82
|
-
readonly summaryLogger:
|
|
82
|
+
readonly summaryLogger: TelemetryLoggerExt;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -157,7 +157,7 @@ export interface ISubmitSummaryOptions extends ISummarizeOptions {
|
|
|
157
157
|
/**
|
|
158
158
|
* Logger to use for correlated summary events
|
|
159
159
|
*/
|
|
160
|
-
readonly summaryLogger:
|
|
160
|
+
readonly summaryLogger: TelemetryLoggerExt;
|
|
161
161
|
/**
|
|
162
162
|
* Tells when summary process should be cancelled
|
|
163
163
|
*/
|