@fluidframework/container-runtime 2.4.0-294316 → 2.4.0-297385
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/container-runtime.test-files.tar +0 -0
- package/dist/containerRuntime.d.ts +1 -3
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +11 -12
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +0 -3
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.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/summary/orderedClientElection.d.ts +0 -7
- package/dist/summary/orderedClientElection.d.ts.map +1 -1
- package/dist/summary/orderedClientElection.js +0 -16
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts +30 -13
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +84 -102
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +15 -42
- package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeUtils.js +10 -88
- package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +5 -6
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +28 -38
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/containerRuntime.d.ts +1 -3
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +9 -10
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +0 -3
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.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/summary/orderedClientElection.d.ts +0 -7
- package/lib/summary/orderedClientElection.d.ts.map +1 -1
- package/lib/summary/orderedClientElection.js +0 -16
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts +30 -13
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +85 -103
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +15 -42
- package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeUtils.js +8 -84
- package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +5 -6
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +29 -39
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/package.json +24 -20
- package/src/containerRuntime.ts +10 -10
- package/src/dataStoreContext.ts +0 -3
- package/src/index.ts +0 -1
- package/src/packageVersion.ts +1 -1
- package/src/summary/orderedClientElection.ts +0 -19
- package/src/summary/summarizerNode/summarizerNode.ts +90 -123
- package/src/summary/summarizerNode/summarizerNodeUtils.ts +19 -99
- package/src/summary/summarizerNode/summarizerNodeWithGc.ts +37 -53
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-runtime",
|
|
3
|
-
"version": "2.4.0-
|
|
3
|
+
"version": "2.4.0-297385",
|
|
4
4
|
"description": "Fluid container runtime",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -127,18 +127,18 @@
|
|
|
127
127
|
"temp-directory": "nyc/.nyc_output"
|
|
128
128
|
},
|
|
129
129
|
"dependencies": {
|
|
130
|
-
"@fluid-internal/client-utils": "2.4.0-
|
|
131
|
-
"@fluidframework/container-definitions": "2.4.0-
|
|
132
|
-
"@fluidframework/container-runtime-definitions": "2.4.0-
|
|
133
|
-
"@fluidframework/core-interfaces": "2.4.0-
|
|
134
|
-
"@fluidframework/core-utils": "2.4.0-
|
|
135
|
-
"@fluidframework/datastore": "2.4.0-
|
|
136
|
-
"@fluidframework/driver-definitions": "2.4.0-
|
|
137
|
-
"@fluidframework/driver-utils": "2.4.0-
|
|
138
|
-
"@fluidframework/id-compressor": "2.4.0-
|
|
139
|
-
"@fluidframework/runtime-definitions": "2.4.0-
|
|
140
|
-
"@fluidframework/runtime-utils": "2.4.0-
|
|
141
|
-
"@fluidframework/telemetry-utils": "2.4.0-
|
|
130
|
+
"@fluid-internal/client-utils": "2.4.0-297385",
|
|
131
|
+
"@fluidframework/container-definitions": "2.4.0-297385",
|
|
132
|
+
"@fluidframework/container-runtime-definitions": "2.4.0-297385",
|
|
133
|
+
"@fluidframework/core-interfaces": "2.4.0-297385",
|
|
134
|
+
"@fluidframework/core-utils": "2.4.0-297385",
|
|
135
|
+
"@fluidframework/datastore": "2.4.0-297385",
|
|
136
|
+
"@fluidframework/driver-definitions": "2.4.0-297385",
|
|
137
|
+
"@fluidframework/driver-utils": "2.4.0-297385",
|
|
138
|
+
"@fluidframework/id-compressor": "2.4.0-297385",
|
|
139
|
+
"@fluidframework/runtime-definitions": "2.4.0-297385",
|
|
140
|
+
"@fluidframework/runtime-utils": "2.4.0-297385",
|
|
141
|
+
"@fluidframework/telemetry-utils": "2.4.0-297385",
|
|
142
142
|
"@tylerbu/sorted-btree-es6": "^1.8.0",
|
|
143
143
|
"double-ended-queue": "^2.1.0-0",
|
|
144
144
|
"lz4js": "^0.2.0",
|
|
@@ -147,16 +147,16 @@
|
|
|
147
147
|
"devDependencies": {
|
|
148
148
|
"@arethetypeswrong/cli": "^0.15.2",
|
|
149
149
|
"@biomejs/biome": "~1.8.3",
|
|
150
|
-
"@fluid-internal/mocha-test-setup": "2.4.0-
|
|
151
|
-
"@fluid-private/stochastic-test-utils": "2.4.0-
|
|
152
|
-
"@fluid-private/test-pairwise-generator": "2.4.0-
|
|
150
|
+
"@fluid-internal/mocha-test-setup": "2.4.0-297385",
|
|
151
|
+
"@fluid-private/stochastic-test-utils": "2.4.0-297385",
|
|
152
|
+
"@fluid-private/test-pairwise-generator": "2.4.0-297385",
|
|
153
153
|
"@fluid-tools/benchmark": "^0.50.0",
|
|
154
154
|
"@fluid-tools/build-cli": "^0.46.0",
|
|
155
155
|
"@fluidframework/build-common": "^2.0.3",
|
|
156
156
|
"@fluidframework/build-tools": "^0.46.0",
|
|
157
|
-
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime
|
|
157
|
+
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@~2.3.0",
|
|
158
158
|
"@fluidframework/eslint-config-fluid": "^5.4.0",
|
|
159
|
-
"@fluidframework/test-runtime-utils": "2.4.0-
|
|
159
|
+
"@fluidframework/test-runtime-utils": "2.4.0-297385",
|
|
160
160
|
"@microsoft/api-extractor": "7.47.8",
|
|
161
161
|
"@types/double-ended-queue": "^2.1.0",
|
|
162
162
|
"@types/mocha": "^9.1.1",
|
|
@@ -178,8 +178,12 @@
|
|
|
178
178
|
"typescript": "~5.4.5"
|
|
179
179
|
},
|
|
180
180
|
"typeValidation": {
|
|
181
|
-
"broken": {
|
|
182
|
-
|
|
181
|
+
"broken": {
|
|
182
|
+
"Function_isRuntimeMessage": {
|
|
183
|
+
"backCompat": false
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"entrypoint": "legacy"
|
|
183
187
|
},
|
|
184
188
|
"scripts": {
|
|
185
189
|
"api": "fluid-build . --task api",
|
package/src/containerRuntime.ts
CHANGED
|
@@ -633,10 +633,8 @@ const defaultCloseSummarizerDelayMs = 5000; // 5 seconds
|
|
|
633
633
|
|
|
634
634
|
/**
|
|
635
635
|
* Checks whether a message.type is one of the values in ContainerMessageType
|
|
636
|
-
* @deprecated please use version in driver-utils
|
|
637
|
-
* @internal
|
|
638
636
|
*/
|
|
639
|
-
export function
|
|
637
|
+
export function isUnpackedRuntimeMessage(message: ISequencedDocumentMessage): boolean {
|
|
640
638
|
return (Object.values(ContainerMessageType) as string[]).includes(message.type);
|
|
641
639
|
}
|
|
642
640
|
|
|
@@ -1713,6 +1711,13 @@ export class ContainerRuntime
|
|
|
1713
1711
|
});
|
|
1714
1712
|
|
|
1715
1713
|
const loadedFromSequenceNumber = this.deltaManager.initialSequenceNumber;
|
|
1714
|
+
// If the base snapshot was generated when isolated channels were disabled, set the summary reference
|
|
1715
|
+
// sequence to undefined so that this snapshot will not be used for incremental summaries. This is for
|
|
1716
|
+
// back-compat and will rarely happen so its okay to re-summarize everything in the first summary.
|
|
1717
|
+
const summaryReferenceSequenceNumber =
|
|
1718
|
+
baseSnapshot === undefined || metadata?.disableIsolatedChannels === true
|
|
1719
|
+
? undefined
|
|
1720
|
+
: loadedFromSequenceNumber;
|
|
1716
1721
|
this.summarizerNode = createRootSummarizerNodeWithGC(
|
|
1717
1722
|
createChildLogger({ logger: this.logger, namespace: "SummarizerNode" }),
|
|
1718
1723
|
// Summarize function to call when summarize is called. Summarizer node always tracks summary state.
|
|
@@ -1720,8 +1725,7 @@ export class ContainerRuntime
|
|
|
1720
1725
|
this.summarizeInternal(fullTree, trackState, telemetryContext),
|
|
1721
1726
|
// Latest change sequence number, no changes since summary applied yet
|
|
1722
1727
|
loadedFromSequenceNumber,
|
|
1723
|
-
|
|
1724
|
-
baseSnapshot !== undefined ? loadedFromSequenceNumber : undefined,
|
|
1728
|
+
summaryReferenceSequenceNumber,
|
|
1725
1729
|
{
|
|
1726
1730
|
// Must set to false to prevent sending summary handle which would be pointing to
|
|
1727
1731
|
// a summary with an older protocol state.
|
|
@@ -1735,10 +1739,6 @@ export class ContainerRuntime
|
|
|
1735
1739
|
async () => this.garbageCollector.getBaseGCDetails(),
|
|
1736
1740
|
);
|
|
1737
1741
|
|
|
1738
|
-
if (baseSnapshot) {
|
|
1739
|
-
this.summarizerNode.updateBaseSummaryState(baseSnapshot);
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
1742
|
const parentContext = wrapContext(this);
|
|
1743
1743
|
|
|
1744
1744
|
if (snapshotWithContents !== undefined) {
|
|
@@ -2808,7 +2808,7 @@ export class ContainerRuntime
|
|
|
2808
2808
|
{ batchStart: true, batchEnd: true }, // Single message
|
|
2809
2809
|
local,
|
|
2810
2810
|
savedOp,
|
|
2811
|
-
|
|
2811
|
+
isUnpackedRuntimeMessage(messageCopy) /* runtimeBatch */,
|
|
2812
2812
|
);
|
|
2813
2813
|
}
|
|
2814
2814
|
|
package/src/dataStoreContext.ts
CHANGED
|
@@ -1034,9 +1034,6 @@ export class RemoteFluidDataStoreContext extends FluidDataStoreContext {
|
|
|
1034
1034
|
this._baseSnapshot = props.snapshot;
|
|
1035
1035
|
this.isSnapshotInISnapshotFormat = false;
|
|
1036
1036
|
}
|
|
1037
|
-
if (this._baseSnapshot !== undefined) {
|
|
1038
|
-
this.summarizerNode.updateBaseSummaryState(this._baseSnapshot);
|
|
1039
|
-
}
|
|
1040
1037
|
}
|
|
1041
1038
|
|
|
1042
1039
|
/*
|
package/src/index.ts
CHANGED
package/src/packageVersion.ts
CHANGED
|
@@ -270,8 +270,6 @@ export interface IOrderedClientElection extends IEventProvider<IOrderedClientEle
|
|
|
270
270
|
readonly electedParent: ITrackedClient | undefined;
|
|
271
271
|
/** Sequence number of most recent election. */
|
|
272
272
|
readonly electionSequenceNumber: number;
|
|
273
|
-
/** Marks the currently elected client as invalid, and elects the next eligible client. */
|
|
274
|
-
incrementElectedClient(sequenceNumber: number): void;
|
|
275
273
|
/** Resets the currently elected client back to the oldest eligible client. */
|
|
276
274
|
resetElectedClient(sequenceNumber: number): void;
|
|
277
275
|
/** Peeks at what the next elected client would be if incrementElectedClient were called. */
|
|
@@ -581,23 +579,6 @@ export class OrderedClientElection
|
|
|
581
579
|
return this.orderedClientCollection.getAllClients().filter(this.isEligibleFn);
|
|
582
580
|
}
|
|
583
581
|
|
|
584
|
-
/**
|
|
585
|
-
* Advance election to the next-oldest client. This is called if the current parent is leaving the quorum,
|
|
586
|
-
* or if the current summarizer is not responsive and we want to stop it and spawn a new one.
|
|
587
|
-
*/
|
|
588
|
-
public incrementElectedClient(sequenceNumber: number): void {
|
|
589
|
-
const nextClient =
|
|
590
|
-
this.findFirstEligibleParent(this._electedParent?.youngerClient) ??
|
|
591
|
-
this.findFirstEligibleParent(this.orderedClientCollection.oldestClient);
|
|
592
|
-
if (this._electedClient === undefined || this._electedClient === this._electedParent) {
|
|
593
|
-
this.tryElectingClient(nextClient, sequenceNumber, "IncrementElectedClient");
|
|
594
|
-
} else {
|
|
595
|
-
// The _electedClient is a summarizer and should not be replaced until it leaves the quorum.
|
|
596
|
-
// Changing the _electedParent will stop the summarizer.
|
|
597
|
-
this.tryElectingParent(nextClient, sequenceNumber, "IncrementElectedClient");
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
582
|
/**
|
|
602
583
|
* (Re-)start election with the oldest client in the quorum. This is called if we need to summarize
|
|
603
584
|
* and no client has been elected.
|
|
@@ -37,9 +37,8 @@ import {
|
|
|
37
37
|
IRefreshSummaryResult,
|
|
38
38
|
IStartSummaryResult,
|
|
39
39
|
ISummarizerNodeRootContract,
|
|
40
|
-
SummaryNode,
|
|
41
40
|
ValidateSummaryResult,
|
|
42
|
-
|
|
41
|
+
PendingSummaryInfo,
|
|
43
42
|
} from "./summarizerNodeUtils.js";
|
|
44
43
|
|
|
45
44
|
export interface IRootSummarizerNode extends ISummarizerNode, ISummarizerNodeRootContract {}
|
|
@@ -63,13 +62,30 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
63
62
|
* Returns 0 if there is not yet an acked summary.
|
|
64
63
|
*/
|
|
65
64
|
public get referenceSequenceNumber() {
|
|
66
|
-
return this.
|
|
65
|
+
return this._lastSummaryReferenceSequenceNumber ?? 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* returns the handle of the last successful summary of this summarizerNode in string format
|
|
70
|
+
* (this getter is primarily only used in the test code)
|
|
71
|
+
*/
|
|
72
|
+
public get summaryHandleId(): string {
|
|
73
|
+
return this._summaryHandleId.toString();
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
protected readonly children = new Map<string, SummarizerNode>();
|
|
70
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Key value pair of summaries submitted by this client which are not yet acked.
|
|
79
|
+
* Key is the proposalHandle and value is the summary op's referece sequence number.
|
|
80
|
+
*/
|
|
81
|
+
protected readonly pendingSummaries = new Map<string, PendingSummaryInfo>();
|
|
71
82
|
protected wipReferenceSequenceNumber: number | undefined;
|
|
72
|
-
|
|
83
|
+
/**
|
|
84
|
+
* True if the current node was summarized during the current summary process
|
|
85
|
+
* This flag is used to identify scenarios where summarize was not called on a node.
|
|
86
|
+
* For example, this node was created after its parent was already summarized due to out-of-order realization via application code.
|
|
87
|
+
*/
|
|
88
|
+
private wipSummarizeCalled: boolean = false;
|
|
73
89
|
private wipSkipRecursion = false;
|
|
74
90
|
|
|
75
91
|
protected readonly logger: ITelemetryLoggerExt;
|
|
@@ -82,9 +98,11 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
82
98
|
baseLogger: ITelemetryBaseLogger,
|
|
83
99
|
private readonly summarizeInternalFn: SummarizeInternalFn,
|
|
84
100
|
config: ISummarizerNodeConfig,
|
|
101
|
+
/** Encoded handle or path to the node */
|
|
102
|
+
private readonly _summaryHandleId: EscapedPath,
|
|
85
103
|
private _changeSequenceNumber: number,
|
|
86
|
-
/**
|
|
87
|
-
private
|
|
104
|
+
/** Summary reference sequence number, i.e. last sequence number seen when last successful summary was created */
|
|
105
|
+
private _lastSummaryReferenceSequenceNumber?: number,
|
|
88
106
|
protected wipSummaryLogger?: ITelemetryBaseLogger,
|
|
89
107
|
/** A unique id of this node to be logged when sending telemetry. */
|
|
90
108
|
protected telemetryNodeId?: string,
|
|
@@ -124,10 +142,10 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
124
142
|
0x1a0 /* "Already tracking a summary" */,
|
|
125
143
|
);
|
|
126
144
|
|
|
127
|
-
let nodes = 1;
|
|
145
|
+
let nodes = 1; // number of summarizerNodes at the start of the summary
|
|
128
146
|
let invalidNodes = 0;
|
|
129
147
|
const sequenceNumberMismatchKeySet = new Set<string>();
|
|
130
|
-
const nodeLatestSummaryRefSeqNum = this.
|
|
148
|
+
const nodeLatestSummaryRefSeqNum = this._lastSummaryReferenceSequenceNumber;
|
|
131
149
|
if (
|
|
132
150
|
nodeLatestSummaryRefSeqNum !== undefined &&
|
|
133
151
|
latestSummaryRefSeqNum !== nodeLatestSummaryRefSeqNum
|
|
@@ -170,21 +188,19 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
170
188
|
return this.summarizeInternalFn(fullTree, trackState, telemetryContext);
|
|
171
189
|
}
|
|
172
190
|
|
|
191
|
+
// Set to wipSummarizeCalled true to represent that current node was included in the summary process.
|
|
192
|
+
this.wipSummarizeCalled = true;
|
|
193
|
+
|
|
173
194
|
// Try to reuse the tree if unchanged
|
|
174
195
|
if (this.canReuseHandle && !fullTree && !this.hasChanged()) {
|
|
175
|
-
|
|
176
|
-
if (latestSummary !== undefined) {
|
|
177
|
-
this.wipLocalPaths = {
|
|
178
|
-
localPath: latestSummary.localPath,
|
|
179
|
-
additionalPath: latestSummary.additionalPath,
|
|
180
|
-
};
|
|
196
|
+
if (this._lastSummaryReferenceSequenceNumber !== undefined) {
|
|
181
197
|
this.wipSkipRecursion = true;
|
|
182
198
|
const stats = mergeStats();
|
|
183
199
|
stats.handleNodeCount++;
|
|
184
200
|
return {
|
|
185
201
|
summary: {
|
|
186
202
|
type: SummaryType.Handle,
|
|
187
|
-
handle:
|
|
203
|
+
handle: this.summaryHandleId,
|
|
188
204
|
handleType: SummaryType.Tree,
|
|
189
205
|
},
|
|
190
206
|
stats,
|
|
@@ -199,12 +215,12 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
199
215
|
0x5df /* Summarize should not be called when not tracking the summary */,
|
|
200
216
|
);
|
|
201
217
|
incrementalSummaryContext =
|
|
202
|
-
this.
|
|
218
|
+
this._lastSummaryReferenceSequenceNumber !== undefined
|
|
203
219
|
? {
|
|
204
220
|
summarySequenceNumber: this.wipReferenceSequenceNumber,
|
|
205
|
-
latestSummarySequenceNumber: this.
|
|
206
|
-
// TODO: remove summaryPath
|
|
207
|
-
summaryPath: this.
|
|
221
|
+
latestSummarySequenceNumber: this._lastSummaryReferenceSequenceNumber,
|
|
222
|
+
// TODO: remove summaryPath.
|
|
223
|
+
summaryPath: this.summaryHandleId,
|
|
208
224
|
}
|
|
209
225
|
: undefined;
|
|
210
226
|
}
|
|
@@ -215,12 +231,7 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
215
231
|
telemetryContext,
|
|
216
232
|
incrementalSummaryContext,
|
|
217
233
|
);
|
|
218
|
-
|
|
219
|
-
if (result.pathPartsForChildren !== undefined) {
|
|
220
|
-
this.wipLocalPaths.additionalPath = EscapedPath.createAndConcat(
|
|
221
|
-
result.pathPartsForChildren,
|
|
222
|
-
);
|
|
223
|
-
}
|
|
234
|
+
|
|
224
235
|
return { summary: result.summary, stats: result.stats };
|
|
225
236
|
}
|
|
226
237
|
|
|
@@ -280,8 +291,8 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
280
291
|
|
|
281
292
|
// If the parent node skipped recursion, it did not call summarize on this node. So, summarize was not missed
|
|
282
293
|
// but was intentionally not called.
|
|
283
|
-
// Otherwise, summarize should have been called on this node and
|
|
284
|
-
if (parentSkipRecursion || this.
|
|
294
|
+
// Otherwise, summarize should have been called on this node and wipSummarizeCalled must be set.
|
|
295
|
+
if (parentSkipRecursion || this.wipSummarizeCalled) {
|
|
285
296
|
return false;
|
|
286
297
|
}
|
|
287
298
|
|
|
@@ -307,11 +318,7 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
307
318
|
* @param proposalHandle - The handle of the summary that was uploaded to the server.
|
|
308
319
|
*/
|
|
309
320
|
public completeSummary(proposalHandle: string) {
|
|
310
|
-
this.completeSummaryCore(
|
|
311
|
-
proposalHandle,
|
|
312
|
-
undefined /* parentPath */,
|
|
313
|
-
false /* parentSkipRecursion */,
|
|
314
|
-
);
|
|
321
|
+
this.completeSummaryCore(proposalHandle, false /* parentSkipRecursion */);
|
|
315
322
|
}
|
|
316
323
|
|
|
317
324
|
/**
|
|
@@ -322,31 +329,13 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
322
329
|
* In that case, the children will not have work-in-progress state.
|
|
323
330
|
* @param validate - true to validate that the in-progress summary is correct for all nodes.
|
|
324
331
|
*/
|
|
325
|
-
protected completeSummaryCore(
|
|
326
|
-
proposalHandle: string,
|
|
327
|
-
parentPath: EscapedPath | undefined,
|
|
328
|
-
parentSkipRecursion: boolean,
|
|
329
|
-
) {
|
|
332
|
+
protected completeSummaryCore(proposalHandle: string, parentSkipRecursion: boolean) {
|
|
330
333
|
assert(
|
|
331
334
|
this.wipReferenceSequenceNumber !== undefined,
|
|
332
335
|
0x1a4 /* "Not tracking a summary" */,
|
|
333
336
|
);
|
|
334
|
-
let localPathsToUse = this.wipLocalPaths;
|
|
335
|
-
|
|
336
337
|
if (parentSkipRecursion) {
|
|
337
|
-
|
|
338
|
-
if (latestSummary !== undefined) {
|
|
339
|
-
// This case the parent node created a failure summary or was reused.
|
|
340
|
-
// This node and all children should only try to reference their path
|
|
341
|
-
// by its last known good state in the actual summary tree.
|
|
342
|
-
// If parent fails or is reused, the child summarize is not called so
|
|
343
|
-
// it did not get a chance to change its paths.
|
|
344
|
-
// In this case, essentially only propagate the new summary ref seq num.
|
|
345
|
-
localPathsToUse = {
|
|
346
|
-
localPath: latestSummary.localPath,
|
|
347
|
-
additionalPath: latestSummary.additionalPath,
|
|
348
|
-
};
|
|
349
|
-
} else {
|
|
338
|
+
if (this._lastSummaryReferenceSequenceNumber === undefined) {
|
|
350
339
|
// This case the child is added after the latest non-failure summary.
|
|
351
340
|
// This node and all children should consider themselves as still not
|
|
352
341
|
// having a successful summary yet.
|
|
@@ -358,21 +347,8 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
358
347
|
}
|
|
359
348
|
}
|
|
360
349
|
|
|
361
|
-
// If localPathsToUse is undefined, it means summarize didn't run for this node and in that case the validate
|
|
362
|
-
// step should have failed.
|
|
363
|
-
assert(localPathsToUse !== undefined, 0x6fe /* summarize didn't run for node */);
|
|
364
|
-
const summary = new SummaryNode({
|
|
365
|
-
...localPathsToUse,
|
|
366
|
-
referenceSequenceNumber: this.wipReferenceSequenceNumber,
|
|
367
|
-
basePath: parentPath,
|
|
368
|
-
});
|
|
369
|
-
const fullPathForChildren = summary.fullPathForChildren;
|
|
370
350
|
for (const child of this.children.values()) {
|
|
371
|
-
child.completeSummaryCore(
|
|
372
|
-
proposalHandle,
|
|
373
|
-
fullPathForChildren,
|
|
374
|
-
this.wipSkipRecursion || parentSkipRecursion,
|
|
375
|
-
);
|
|
351
|
+
child.completeSummaryCore(proposalHandle, this.wipSkipRecursion || parentSkipRecursion);
|
|
376
352
|
}
|
|
377
353
|
// Note that this overwrites existing pending summary with
|
|
378
354
|
// the same proposalHandle. If proposalHandle is something like
|
|
@@ -380,13 +356,15 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
380
356
|
// can return the same proposalHandle for a different summary,
|
|
381
357
|
// this should still be okay, because we should be proposing the
|
|
382
358
|
// newer one later which would have to overwrite the previous one.
|
|
383
|
-
this.pendingSummaries.set(proposalHandle,
|
|
359
|
+
this.pendingSummaries.set(proposalHandle, {
|
|
360
|
+
referenceSequenceNumber: this.wipReferenceSequenceNumber,
|
|
361
|
+
});
|
|
384
362
|
this.clearSummary();
|
|
385
363
|
}
|
|
386
364
|
|
|
387
365
|
public clearSummary() {
|
|
388
366
|
this.wipReferenceSequenceNumber = undefined;
|
|
389
|
-
this.
|
|
367
|
+
this.wipSummarizeCalled = false;
|
|
390
368
|
this.wipSkipRecursion = false;
|
|
391
369
|
this.wipSummaryLogger = undefined;
|
|
392
370
|
for (const child of this.children.values()) {
|
|
@@ -398,7 +376,8 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
398
376
|
* Refreshes the latest summary tracked by this node. If we have a pending summary for the given proposal handle,
|
|
399
377
|
* it becomes the latest summary. If the current summary is already ahead, we skip the update.
|
|
400
378
|
* If the current summary is behind, then we do not refresh.
|
|
401
|
-
*
|
|
379
|
+
* @param proposalHandle - Handle of the generated / uploaded summary.
|
|
380
|
+
* @param summaryRefSeq - Reference sequence of the acked summary
|
|
402
381
|
* @returns true if the summary is tracked by this node, false otherwise.
|
|
403
382
|
*/
|
|
404
383
|
public async refreshLatestSummary(
|
|
@@ -437,13 +416,17 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
437
416
|
if (summaryRefSeq > this.referenceSequenceNumber) {
|
|
438
417
|
isSummaryNewer = true;
|
|
439
418
|
}
|
|
440
|
-
|
|
441
|
-
|
|
419
|
+
|
|
420
|
+
// If the acked summary is found in the pendingSummaries, it means the summary was created and tracked by the current client
|
|
421
|
+
// so set the isSummaryTracked to true.
|
|
422
|
+
const pendingSummary = this.pendingSummaries.get(proposalHandle);
|
|
423
|
+
if (pendingSummary?.referenceSequenceNumber !== undefined) {
|
|
424
|
+
isSummaryTracked = true;
|
|
425
|
+
// update the pendingSummariesMap for the root and all child summarizerNodes
|
|
442
426
|
this.refreshLatestSummaryFromPending(
|
|
443
427
|
proposalHandle,
|
|
444
|
-
|
|
428
|
+
pendingSummary.referenceSequenceNumber,
|
|
445
429
|
);
|
|
446
|
-
isSummaryTracked = true;
|
|
447
430
|
}
|
|
448
431
|
event.end({ ...eventProps, isSummaryNewer, pendingSummaryFound: isSummaryTracked });
|
|
449
432
|
return { isSummaryTracked, isSummaryNewer };
|
|
@@ -461,17 +444,17 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
461
444
|
proposalHandle: string,
|
|
462
445
|
referenceSequenceNumber: number,
|
|
463
446
|
): void {
|
|
464
|
-
const
|
|
465
|
-
if (
|
|
447
|
+
const pendingSummary = this.pendingSummaries.get(proposalHandle);
|
|
448
|
+
if (pendingSummary === undefined) {
|
|
466
449
|
// This should only happen if parent skipped recursion AND no prior summary existed.
|
|
467
450
|
assert(
|
|
468
|
-
this.
|
|
451
|
+
this._lastSummaryReferenceSequenceNumber === undefined,
|
|
469
452
|
0x1a6 /* "Not found pending summary, but this node has previously completed a summary" */,
|
|
470
453
|
);
|
|
471
454
|
return;
|
|
472
455
|
} else {
|
|
473
456
|
assert(
|
|
474
|
-
referenceSequenceNumber ===
|
|
457
|
+
referenceSequenceNumber === pendingSummary.referenceSequenceNumber,
|
|
475
458
|
0x1a7 /* Pending summary reference sequence number should be consistent */,
|
|
476
459
|
);
|
|
477
460
|
|
|
@@ -479,30 +462,22 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
479
462
|
this.pendingSummaries.delete(proposalHandle);
|
|
480
463
|
}
|
|
481
464
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
465
|
+
// Delete all summaries whose reference sequence number is smaller than the one just acked.
|
|
466
|
+
for (const [key, summary] of this.pendingSummaries) {
|
|
467
|
+
if (summary.referenceSequenceNumber < referenceSequenceNumber) {
|
|
468
|
+
this.pendingSummaries.delete(key);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Update the latest successful summary reference number
|
|
472
|
+
this._lastSummaryReferenceSequenceNumber = pendingSummary.referenceSequenceNumber;
|
|
485
473
|
// Propagate update to all child nodes
|
|
486
474
|
for (const child of this.children.values()) {
|
|
487
475
|
child.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);
|
|
488
476
|
}
|
|
489
477
|
}
|
|
490
478
|
|
|
491
|
-
private refreshLatestSummaryCore(referenceSequenceNumber: number): void {
|
|
492
|
-
for (const [key, value] of this.pendingSummaries) {
|
|
493
|
-
if (value.referenceSequenceNumber < referenceSequenceNumber) {
|
|
494
|
-
this.pendingSummaries.delete(key);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
479
|
public updateBaseSummaryState(snapshot: ISnapshotTree) {
|
|
500
|
-
//
|
|
501
|
-
// separating child SummarizerNodes. Checks for .channels subtrees.
|
|
502
|
-
const { childrenPathPart } = parseSummaryForSubtrees(snapshot);
|
|
503
|
-
if (childrenPathPart !== undefined && this._latestSummary !== undefined) {
|
|
504
|
-
this._latestSummary.additionalPath = EscapedPath.create(childrenPathPart);
|
|
505
|
-
}
|
|
480
|
+
// Function deprecated. Empty declaration is kept around to compat failures.
|
|
506
481
|
}
|
|
507
482
|
|
|
508
483
|
public recordChange(op: ISequencedDocumentMessage): void {
|
|
@@ -524,10 +499,6 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
524
499
|
return this._changeSequenceNumber > this.referenceSequenceNumber;
|
|
525
500
|
}
|
|
526
501
|
|
|
527
|
-
public get latestSummary(): Readonly<SummaryNode> | undefined {
|
|
528
|
-
return this._latestSummary;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
502
|
protected readonly canReuseHandle: boolean;
|
|
532
503
|
|
|
533
504
|
public createChild(
|
|
@@ -550,8 +521,9 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
550
521
|
this.logger,
|
|
551
522
|
summarizeInternalFn,
|
|
552
523
|
config,
|
|
524
|
+
createDetails.summaryHandleId,
|
|
553
525
|
createDetails.changeSequenceNumber,
|
|
554
|
-
createDetails.
|
|
526
|
+
createDetails.lastSummaryReferenceSequenceNumber,
|
|
555
527
|
this.wipSummaryLogger,
|
|
556
528
|
createDetails.telemetryNodeId,
|
|
557
529
|
);
|
|
@@ -579,26 +551,26 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
579
551
|
id: string,
|
|
580
552
|
createParam: CreateChildSummarizerNodeParam,
|
|
581
553
|
): ICreateChildDetails {
|
|
582
|
-
let
|
|
554
|
+
let childLastSummaryReferenceSequenceNumber: number | undefined;
|
|
583
555
|
let changeSequenceNumber: number;
|
|
584
556
|
|
|
585
|
-
const
|
|
557
|
+
const parentLastSummaryReferenceSequenceNumber = this._lastSummaryReferenceSequenceNumber;
|
|
586
558
|
switch (createParam.type) {
|
|
587
559
|
case CreateSummarizerNodeSource.FromAttach: {
|
|
588
560
|
if (
|
|
589
|
-
|
|
590
|
-
createParam.sequenceNumber <=
|
|
561
|
+
parentLastSummaryReferenceSequenceNumber !== undefined &&
|
|
562
|
+
createParam.sequenceNumber <= parentLastSummaryReferenceSequenceNumber
|
|
591
563
|
) {
|
|
592
564
|
// Prioritize latest summary if it was after this node was attached.
|
|
593
|
-
|
|
565
|
+
childLastSummaryReferenceSequenceNumber = parentLastSummaryReferenceSequenceNumber;
|
|
594
566
|
}
|
|
595
567
|
changeSequenceNumber = createParam.sequenceNumber;
|
|
596
568
|
break;
|
|
597
569
|
}
|
|
598
570
|
case CreateSummarizerNodeSource.FromSummary:
|
|
599
571
|
case CreateSummarizerNodeSource.Local: {
|
|
600
|
-
|
|
601
|
-
changeSequenceNumber =
|
|
572
|
+
childLastSummaryReferenceSequenceNumber = parentLastSummaryReferenceSequenceNumber;
|
|
573
|
+
changeSequenceNumber = parentLastSummaryReferenceSequenceNumber ?? -1;
|
|
602
574
|
break;
|
|
603
575
|
}
|
|
604
576
|
default: {
|
|
@@ -608,11 +580,13 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
608
580
|
}
|
|
609
581
|
|
|
610
582
|
const childTelemetryNodeId = `${this.telemetryNodeId ?? ""}/${id}`;
|
|
583
|
+
const childSummaryHandleId = this._summaryHandleId.createChildPath(EscapedPath.create(id));
|
|
611
584
|
|
|
612
585
|
return {
|
|
613
|
-
latestSummary,
|
|
614
586
|
changeSequenceNumber,
|
|
615
587
|
telemetryNodeId: childTelemetryNodeId,
|
|
588
|
+
summaryHandleId: childSummaryHandleId,
|
|
589
|
+
lastSummaryReferenceSequenceNumber: childLastSummaryReferenceSequenceNumber,
|
|
616
590
|
};
|
|
617
591
|
}
|
|
618
592
|
|
|
@@ -632,21 +606,15 @@ export class SummarizerNode implements IRootSummarizerNode {
|
|
|
632
606
|
child.wipReferenceSequenceNumber = this.wipReferenceSequenceNumber;
|
|
633
607
|
}
|
|
634
608
|
// In case we have pending summaries on the parent, let's initialize it on the child.
|
|
635
|
-
if (child.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
basePath: child._latestSummary.basePath,
|
|
640
|
-
localPath: child._latestSummary.localPath,
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
child.addPendingSummary(key, newLatestSummaryNode);
|
|
644
|
-
}
|
|
609
|
+
if (child._lastSummaryReferenceSequenceNumber !== undefined) {
|
|
610
|
+
this.pendingSummaries.forEach((pendingSummaryInfo, proposedHandle) => {
|
|
611
|
+
child.addPendingSummary(proposedHandle, pendingSummaryInfo);
|
|
612
|
+
});
|
|
645
613
|
}
|
|
646
614
|
}
|
|
647
615
|
|
|
648
|
-
protected addPendingSummary(key: string,
|
|
649
|
-
this.pendingSummaries.set(key,
|
|
616
|
+
protected addPendingSummary(key: string, pendingSummaryInfo: PendingSummaryInfo) {
|
|
617
|
+
this.pendingSummaries.set(key, pendingSummaryInfo);
|
|
650
618
|
}
|
|
651
619
|
|
|
652
620
|
/**
|
|
@@ -692,10 +660,9 @@ export const createRootSummarizerNode = (
|
|
|
692
660
|
logger,
|
|
693
661
|
summarizeInternalFn,
|
|
694
662
|
config,
|
|
663
|
+
EscapedPath.create("") /* summaryHandleId */,
|
|
695
664
|
changeSequenceNumber,
|
|
696
|
-
referenceSequenceNumber
|
|
697
|
-
? undefined
|
|
698
|
-
: SummaryNode.createForRoot(referenceSequenceNumber),
|
|
665
|
+
referenceSequenceNumber,
|
|
699
666
|
undefined /* wipSummaryLogger */,
|
|
700
667
|
"" /* telemetryNodeId */,
|
|
701
668
|
);
|