@fluidframework/runtime-utils 1.2.1 → 2.0.0-internal.1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/summarizerNode/summarizerNode.d.ts +10 -12
- package/dist/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNode.js +37 -82
- package/dist/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.d.ts +1 -37
- package/dist/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.js +1 -94
- package/dist/summarizerNode/summarizerNodeUtils.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/summarizerNode/summarizerNode.d.ts +10 -12
- package/lib/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNode.js +38 -83
- package/lib/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.d.ts +1 -37
- package/lib/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.js +0 -91
- package/lib/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/package.json +15 -15
- package/src/packageVersion.ts +1 -1
- package/src/summarizerNode/summarizerNode.ts +39 -106
- package/src/summarizerNode/summarizerNodeUtils.ts +0 -126
|
@@ -4,14 +4,8 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.parseSummaryTreeForSubtrees = exports.parseSummaryForSubtrees = exports.
|
|
8
|
-
const common_utils_1 = require("@fluidframework/common-utils");
|
|
9
|
-
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
7
|
+
exports.parseSummaryTreeForSubtrees = exports.parseSummaryForSubtrees = exports.SummaryNode = exports.EscapedPath = void 0;
|
|
10
8
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
11
|
-
const summaryUtils_1 = require("../summaryUtils");
|
|
12
|
-
const baseSummaryTreeKey = "_baseSummary";
|
|
13
|
-
const outstandingOpsBlobKey = "_outstandingOps";
|
|
14
|
-
const maxDecodeDepth = 100;
|
|
15
9
|
/** Path for nodes in a tree with escaped special characters */
|
|
16
10
|
class EscapedPath {
|
|
17
11
|
constructor(path) {
|
|
@@ -95,93 +89,6 @@ class SummaryNode {
|
|
|
95
89
|
}
|
|
96
90
|
}
|
|
97
91
|
exports.SummaryNode = SummaryNode;
|
|
98
|
-
/**
|
|
99
|
-
* Checks if the snapshot is created by referencing a previous successful
|
|
100
|
-
* summary plus outstanding ops. If so, it will recursively "decode" it until
|
|
101
|
-
* it gets to the last successful summary (the base summary) and returns that
|
|
102
|
-
* as well as a function for fetching the outstanding ops. Also returns the
|
|
103
|
-
* full path to the previous base summary for child summarizer nodes to use as
|
|
104
|
-
* their base path when necessary.
|
|
105
|
-
* @param snapshot - snapshot tree to decode
|
|
106
|
-
*/
|
|
107
|
-
function decodeSummary(snapshot, logger) {
|
|
108
|
-
let baseSummary = snapshot;
|
|
109
|
-
const pathParts = [];
|
|
110
|
-
const opsBlobs = [];
|
|
111
|
-
for (let i = 0;; i++) {
|
|
112
|
-
if (i > maxDecodeDepth) {
|
|
113
|
-
logger.sendTelemetryEvent({
|
|
114
|
-
eventName: "DecodeSummaryMaxDepth",
|
|
115
|
-
maxDecodeDepth,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
const outstandingOpsBlob = baseSummary.blobs[outstandingOpsBlobKey];
|
|
119
|
-
const newBaseSummary = baseSummary.trees[baseSummaryTreeKey];
|
|
120
|
-
if (outstandingOpsBlob === undefined && newBaseSummary === undefined) {
|
|
121
|
-
return {
|
|
122
|
-
baseSummary,
|
|
123
|
-
pathParts,
|
|
124
|
-
async getOutstandingOps(readAndParseBlob) {
|
|
125
|
-
let outstandingOps = [];
|
|
126
|
-
for (const opsBlob of opsBlobs) {
|
|
127
|
-
const newOutstandingOps = await readAndParseBlob(opsBlob);
|
|
128
|
-
if (outstandingOps.length > 0 && newOutstandingOps.length > 0) {
|
|
129
|
-
const latestSeq = outstandingOps[outstandingOps.length - 1].sequenceNumber;
|
|
130
|
-
const newEarliestSeq = newOutstandingOps[0].sequenceNumber;
|
|
131
|
-
if (newEarliestSeq <= latestSeq) {
|
|
132
|
-
logger.sendTelemetryEvent({
|
|
133
|
-
eventName: "DuplicateOutstandingOps",
|
|
134
|
-
// eslint-disable-next-line max-len
|
|
135
|
-
message: `newEarliestSeq <= latestSeq in decodeSummary: ${newEarliestSeq} <= ${latestSeq}`,
|
|
136
|
-
});
|
|
137
|
-
while (newOutstandingOps.length > 0
|
|
138
|
-
&& newOutstandingOps[0].sequenceNumber <= latestSeq) {
|
|
139
|
-
newOutstandingOps.shift();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
outstandingOps = outstandingOps.concat(newOutstandingOps);
|
|
144
|
-
}
|
|
145
|
-
return outstandingOps;
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
(0, common_utils_1.assert)(!!outstandingOpsBlob, 0x1af /* "Outstanding ops blob missing, but base summary tree exists" */);
|
|
150
|
-
(0, common_utils_1.assert)(newBaseSummary !== undefined, 0x1b0 /* "Base summary tree missing, but outstanding ops blob exists" */);
|
|
151
|
-
baseSummary = newBaseSummary;
|
|
152
|
-
pathParts.push(baseSummaryTreeKey);
|
|
153
|
-
opsBlobs.unshift(outstandingOpsBlob);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
exports.decodeSummary = decodeSummary;
|
|
157
|
-
/**
|
|
158
|
-
* Creates a summary tree which is a handle of the previous successfully acked summary
|
|
159
|
-
* and a blob of the outstanding ops since that summary. If there is no acked summary yet,
|
|
160
|
-
* it will create with the tree found in the initial attach op and the blob of outstanding ops.
|
|
161
|
-
* @param summaryParam - information about last acked summary and paths to encode if from summary,
|
|
162
|
-
* otherwise the initial summary from the attach op.
|
|
163
|
-
* @param outstandingOps - outstanding ops since last acked summary
|
|
164
|
-
*/
|
|
165
|
-
function encodeSummary(summaryParam, outstandingOps) {
|
|
166
|
-
let additionalPath = EscapedPath.create(baseSummaryTreeKey);
|
|
167
|
-
const builder = new summaryUtils_1.SummaryTreeBuilder();
|
|
168
|
-
builder.addBlob(outstandingOpsBlobKey, JSON.stringify(outstandingOps));
|
|
169
|
-
if (summaryParam.fromSummary) {
|
|
170
|
-
// Create using handle of latest acked summary
|
|
171
|
-
const summaryNode = summaryParam.summaryNode;
|
|
172
|
-
if (summaryNode.additionalPath !== undefined) {
|
|
173
|
-
additionalPath = additionalPath.concat(summaryNode.additionalPath);
|
|
174
|
-
}
|
|
175
|
-
builder.addHandle(baseSummaryTreeKey, protocol_definitions_1.SummaryType.Tree, summaryNode.fullPath.path);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
// Create using initial summary from attach op
|
|
179
|
-
builder.addWithStats(baseSummaryTreeKey, summaryParam.initialSummary);
|
|
180
|
-
}
|
|
181
|
-
const summary = builder.getSummaryTree();
|
|
182
|
-
return Object.assign(Object.assign({}, summary), { additionalPath });
|
|
183
|
-
}
|
|
184
|
-
exports.encodeSummary = encodeSummary;
|
|
185
92
|
/**
|
|
186
93
|
* Checks if the summary contains .channels subtree where the children subtrees
|
|
187
94
|
* would be located if exists.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeUtils.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport {\n ISnapshotTree,\n ISequencedDocumentMessage,\n SummaryType,\n ISummaryTree,\n SummaryObject,\n} from \"@fluidframework/protocol-definitions\";\nimport { channelsTreeName, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { SummaryTreeBuilder } from \"../summaryUtils\";\nimport { ReadAndParseBlob } from \"../utils\";\n\nconst baseSummaryTreeKey = \"_baseSummary\";\nconst outstandingOpsBlobKey = \"_outstandingOps\";\nconst maxDecodeDepth = 100;\n\n/**\n * Return value of refreshSummaryAck function. There can be three different scenarios based on the passed params:\n * 1. The latest summary was not udpated.\n * 2. The latest summary was updated and the summary corresponding to the params was tracked by this client.\n * 3. The latest summary was updated but the summary corresponding to the params was not tracked. In this case, the\n * latest summary is updated based on the downloaded snapshot which is also returned.\n */\nexport type RefreshSummaryResult = {\n latestSummaryUpdated: false;\n} | {\n latestSummaryUpdated: true;\n wasSummaryTracked: true;\n} | {\n latestSummaryUpdated: true;\n wasSummaryTracked: false;\n snapshot: ISnapshotTree;\n};\n\nexport interface ISummarizerNodeRootContract {\n startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;\n completeSummary(proposalHandle: string): void;\n clearSummary(): void;\n refreshLatestSummary(\n proposalHandle: string | undefined,\n summaryRefSeq: number,\n getSnapshot: () => Promise<ISnapshotTree>,\n readAndParseBlob: ReadAndParseBlob,\n correlatedSummaryLogger: ITelemetryLogger,\n ): Promise<RefreshSummaryResult>;\n}\n\n/** Path for nodes in a tree with escaped special characters */\nexport class EscapedPath {\n private constructor(public readonly path: string) { }\n public static create(path: string): EscapedPath {\n return new EscapedPath(encodeURIComponent(path));\n }\n public static createAndConcat(pathParts: string[]): EscapedPath {\n let ret = EscapedPath.create(pathParts[0] ?? \"\");\n for (let i = 1; i < pathParts.length; i++) {\n ret = ret.concat(EscapedPath.create(pathParts[i]));\n }\n return ret;\n }\n public toString(): string {\n return this.path;\n }\n public concat(path: EscapedPath): EscapedPath {\n return new EscapedPath(`${this.path}/${path.path}`);\n }\n}\n\n/** Information about a summary relevant to a specific node in the tree */\nexport class SummaryNode {\n /** Creates an instance that is valid for the root with specific basePath and localPath */\n public static createForRoot(referenceSequenceNumber: number): SummaryNode {\n return new SummaryNode({\n referenceSequenceNumber,\n basePath: undefined,\n localPath: EscapedPath.create(\"\"), // root hard-coded to \"\"\n });\n }\n\n /** Summary reference sequence number, i.e. last sequence number seen when it was created */\n public get referenceSequenceNumber(): number {\n return this.summary.referenceSequenceNumber;\n }\n /** Full path to parent node, or undefined if this is the root */\n public get basePath(): EscapedPath | undefined {\n return this.summary.basePath;\n }\n /** Relative path to this node from its parent node */\n public get localPath(): EscapedPath {\n return this.summary.localPath;\n }\n /** Relative path from this node to its node innermost base summary */\n public get additionalPath(): EscapedPath | undefined {\n return this.summary.additionalPath;\n }\n public set additionalPath(additionalPath: EscapedPath | undefined) {\n this.summary.additionalPath = additionalPath;\n }\n constructor(private readonly summary: {\n readonly referenceSequenceNumber: number;\n readonly basePath: EscapedPath | undefined;\n readonly localPath: EscapedPath;\n additionalPath?: EscapedPath;\n }) { }\n\n /** Gets the full path to this node, to be used when sending a handle */\n public get fullPath(): EscapedPath {\n return this.basePath?.concat(this.localPath) ?? this.localPath;\n }\n\n /**\n * Gets the full path to this node's innermost base summary.\n * The children nodes can use this as their basePath to determine their path.\n */\n public get fullPathForChildren(): EscapedPath {\n return this.additionalPath !== undefined\n ? this.fullPath.concat(this.additionalPath)\n : this.fullPath;\n }\n\n /**\n * Creates a new node within the same summary for a child of this node.\n * @param id - id of the child node\n */\n public createForChild(id: string): SummaryNode {\n return new SummaryNode({\n referenceSequenceNumber: this.referenceSequenceNumber,\n basePath: this.fullPathForChildren,\n localPath: EscapedPath.create(id),\n });\n }\n}\n\n/** Result from decoding summary which may have been a differential summary. */\ninterface IDecodedSummary {\n /** The innermost base summary which is not itself a differential summary */\n readonly baseSummary: ISnapshotTree;\n /** The entire path name to the innermost base summary */\n readonly pathParts: string[];\n /** Function to fetch all outstanding ops since the innermost base summary */\n getOutstandingOps(readAndParseBlob: ReadAndParseBlob): Promise<ISequencedDocumentMessage[]>;\n}\n\n/**\n * Checks if the snapshot is created by referencing a previous successful\n * summary plus outstanding ops. If so, it will recursively \"decode\" it until\n * it gets to the last successful summary (the base summary) and returns that\n * as well as a function for fetching the outstanding ops. Also returns the\n * full path to the previous base summary for child summarizer nodes to use as\n * their base path when necessary.\n * @param snapshot - snapshot tree to decode\n */\nexport function decodeSummary(\n snapshot: ISnapshotTree,\n logger: Pick<ITelemetryLogger, \"sendTelemetryEvent\">,\n): IDecodedSummary {\n let baseSummary = snapshot;\n const pathParts: string[] = [];\n const opsBlobs: string[] = [];\n\n for (let i = 0; ; i++) {\n if (i > maxDecodeDepth) {\n logger.sendTelemetryEvent({\n eventName: \"DecodeSummaryMaxDepth\",\n maxDecodeDepth,\n });\n }\n const outstandingOpsBlob = baseSummary.blobs[outstandingOpsBlobKey];\n const newBaseSummary = baseSummary.trees[baseSummaryTreeKey];\n if (outstandingOpsBlob === undefined && newBaseSummary === undefined) {\n return {\n baseSummary,\n pathParts,\n async getOutstandingOps(readAndParseBlob: ReadAndParseBlob) {\n let outstandingOps: ISequencedDocumentMessage[] = [];\n for (const opsBlob of opsBlobs) {\n const newOutstandingOps = await readAndParseBlob<ISequencedDocumentMessage[]>(opsBlob);\n if (outstandingOps.length > 0 && newOutstandingOps.length > 0) {\n const latestSeq = outstandingOps[outstandingOps.length - 1].sequenceNumber;\n const newEarliestSeq = newOutstandingOps[0].sequenceNumber;\n if (newEarliestSeq <= latestSeq) {\n logger.sendTelemetryEvent({\n eventName: \"DuplicateOutstandingOps\",\n // eslint-disable-next-line max-len\n message: `newEarliestSeq <= latestSeq in decodeSummary: ${newEarliestSeq} <= ${latestSeq}`,\n });\n while (newOutstandingOps.length > 0\n && newOutstandingOps[0].sequenceNumber <= latestSeq) {\n newOutstandingOps.shift();\n }\n }\n }\n outstandingOps = outstandingOps.concat(newOutstandingOps);\n }\n return outstandingOps;\n },\n };\n }\n\n assert(!!outstandingOpsBlob, 0x1af /* \"Outstanding ops blob missing, but base summary tree exists\" */);\n assert(newBaseSummary !== undefined, 0x1b0 /* \"Base summary tree missing, but outstanding ops blob exists\" */);\n baseSummary = newBaseSummary;\n pathParts.push(baseSummaryTreeKey);\n opsBlobs.unshift(outstandingOpsBlob);\n }\n}\n\n/**\n * Summary tree which is a handle of the previous successfully acked summary\n * and a blob of the outstanding ops since that summary.\n */\ninterface IEncodedSummary extends ISummaryTreeWithStats {\n readonly additionalPath: EscapedPath;\n}\n\n/**\n * Parameter to help encode summary with conditional behavior.\n * When fromSummary is true, it will contain the SummaryNode of\n * its previous summary, which it can use to point to with a handle.\n * When fromSummary is false, it will use an actual summary tree\n * as its base summary in case the first summary is a differential summary.\n */\nexport type EncodeSummaryParam = {\n fromSummary: true;\n summaryNode: SummaryNode;\n} | {\n fromSummary: false;\n initialSummary: ISummaryTreeWithStats;\n};\n\n/**\n * Creates a summary tree which is a handle of the previous successfully acked summary\n * and a blob of the outstanding ops since that summary. If there is no acked summary yet,\n * it will create with the tree found in the initial attach op and the blob of outstanding ops.\n * @param summaryParam - information about last acked summary and paths to encode if from summary,\n * otherwise the initial summary from the attach op.\n * @param outstandingOps - outstanding ops since last acked summary\n */\nexport function encodeSummary(\n summaryParam: EncodeSummaryParam,\n outstandingOps: ISequencedDocumentMessage[],\n): IEncodedSummary {\n let additionalPath = EscapedPath.create(baseSummaryTreeKey);\n\n const builder = new SummaryTreeBuilder();\n builder.addBlob(outstandingOpsBlobKey, JSON.stringify(outstandingOps));\n\n if (summaryParam.fromSummary) {\n // Create using handle of latest acked summary\n const summaryNode = summaryParam.summaryNode;\n if (summaryNode.additionalPath !== undefined) {\n additionalPath = additionalPath.concat(summaryNode.additionalPath);\n }\n builder.addHandle(baseSummaryTreeKey, SummaryType.Tree, summaryNode.fullPath.path);\n } else {\n // Create using initial summary from attach op\n builder.addWithStats(baseSummaryTreeKey, summaryParam.initialSummary);\n }\n\n const summary = builder.getSummaryTree();\n return {\n ...summary,\n additionalPath,\n };\n}\n\n/**\n * Information about the initial summary tree found from an attach op.\n */\nexport interface IInitialSummary {\n sequenceNumber: number;\n id: string;\n summary: ISummaryTreeWithStats | undefined;\n}\n\n/**\n * Represents the details needed to create a child summarizer node.\n */\nexport interface ICreateChildDetails {\n /** Summary from attach op if known */\n initialSummary: IInitialSummary | undefined;\n /** Latest summary from server node data */\n latestSummary: SummaryNode | undefined;\n /** Sequence number of latest known change to the node */\n changeSequenceNumber: number;\n}\n\nexport interface ISubtreeInfo<T extends ISnapshotTree | SummaryObject> {\n /** Tree to use to find children subtrees */\n childrenTree: T;\n /** Additional path part where children are isolated */\n childrenPathPart: string | undefined;\n}\n\n/**\n * Checks if the summary contains .channels subtree where the children subtrees\n * would be located if exists.\n * @param baseSummary - summary to check\n */\nexport function parseSummaryForSubtrees(baseSummary: ISnapshotTree): ISubtreeInfo<ISnapshotTree> {\n // New versions of snapshots have child nodes isolated in .channels subtree\n const channelsSubtree = baseSummary.trees[channelsTreeName];\n if (channelsSubtree !== undefined) {\n return {\n childrenTree: channelsSubtree,\n childrenPathPart: channelsTreeName,\n };\n }\n return {\n childrenTree: baseSummary,\n childrenPathPart: undefined,\n };\n}\n\n/**\n * Checks if the summary contains .channels subtree where the children subtrees\n * would be located if exists.\n * @param baseSummary - summary to check\n */\nexport function parseSummaryTreeForSubtrees(summary: ISummaryTree): ISubtreeInfo<SummaryObject> {\n // New versions of snapshots have child nodes isolated in .channels subtree\n const channelsSubtree = summary.tree[channelsTreeName];\n if (channelsSubtree !== undefined) {\n return {\n childrenTree: channelsSubtree,\n childrenPathPart: channelsTreeName,\n };\n }\n return {\n childrenTree: summary,\n childrenPathPart: undefined,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"summarizerNodeUtils.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport {\n ISnapshotTree,\n ISummaryTree,\n SummaryObject,\n} from \"@fluidframework/protocol-definitions\";\nimport { channelsTreeName, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\n\n/**\n * Return value of refreshSummaryAck function. There can be three different scenarios based on the passed params:\n * 1. The latest summary was not udpated.\n * 2. The latest summary was updated and the summary corresponding to the params was tracked by this client.\n * 3. The latest summary was updated but the summary corresponding to the params was not tracked. In this case, the\n * latest summary is updated based on the downloaded snapshot which is also returned.\n */\nexport type RefreshSummaryResult = {\n latestSummaryUpdated: false;\n} | {\n latestSummaryUpdated: true;\n wasSummaryTracked: true;\n} | {\n latestSummaryUpdated: true;\n wasSummaryTracked: false;\n snapshot: ISnapshotTree;\n};\n\nexport interface ISummarizerNodeRootContract {\n startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;\n completeSummary(proposalHandle: string): void;\n clearSummary(): void;\n refreshLatestSummary(\n proposalHandle: string | undefined,\n summaryRefSeq: number,\n getSnapshot: () => Promise<ISnapshotTree>,\n readAndParseBlob: ReadAndParseBlob,\n correlatedSummaryLogger: ITelemetryLogger,\n ): Promise<RefreshSummaryResult>;\n}\n\n/** Path for nodes in a tree with escaped special characters */\nexport class EscapedPath {\n private constructor(public readonly path: string) { }\n public static create(path: string): EscapedPath {\n return new EscapedPath(encodeURIComponent(path));\n }\n public static createAndConcat(pathParts: string[]): EscapedPath {\n let ret = EscapedPath.create(pathParts[0] ?? \"\");\n for (let i = 1; i < pathParts.length; i++) {\n ret = ret.concat(EscapedPath.create(pathParts[i]));\n }\n return ret;\n }\n public toString(): string {\n return this.path;\n }\n public concat(path: EscapedPath): EscapedPath {\n return new EscapedPath(`${this.path}/${path.path}`);\n }\n}\n\n/** Information about a summary relevant to a specific node in the tree */\nexport class SummaryNode {\n /** Creates an instance that is valid for the root with specific basePath and localPath */\n public static createForRoot(referenceSequenceNumber: number): SummaryNode {\n return new SummaryNode({\n referenceSequenceNumber,\n basePath: undefined,\n localPath: EscapedPath.create(\"\"), // root hard-coded to \"\"\n });\n }\n\n /** Summary reference sequence number, i.e. last sequence number seen when it was created */\n public get referenceSequenceNumber(): number {\n return this.summary.referenceSequenceNumber;\n }\n /** Full path to parent node, or undefined if this is the root */\n public get basePath(): EscapedPath | undefined {\n return this.summary.basePath;\n }\n /** Relative path to this node from its parent node */\n public get localPath(): EscapedPath {\n return this.summary.localPath;\n }\n /** Relative path from this node to its node innermost base summary */\n public get additionalPath(): EscapedPath | undefined {\n return this.summary.additionalPath;\n }\n public set additionalPath(additionalPath: EscapedPath | undefined) {\n this.summary.additionalPath = additionalPath;\n }\n constructor(private readonly summary: {\n readonly referenceSequenceNumber: number;\n readonly basePath: EscapedPath | undefined;\n readonly localPath: EscapedPath;\n additionalPath?: EscapedPath;\n }) { }\n\n /** Gets the full path to this node, to be used when sending a handle */\n public get fullPath(): EscapedPath {\n return this.basePath?.concat(this.localPath) ?? this.localPath;\n }\n\n /**\n * Gets the full path to this node's innermost base summary.\n * The children nodes can use this as their basePath to determine their path.\n */\n public get fullPathForChildren(): EscapedPath {\n return this.additionalPath !== undefined\n ? this.fullPath.concat(this.additionalPath)\n : this.fullPath;\n }\n\n /**\n * Creates a new node within the same summary for a child of this node.\n * @param id - id of the child node\n */\n public createForChild(id: string): SummaryNode {\n return new SummaryNode({\n referenceSequenceNumber: this.referenceSequenceNumber,\n basePath: this.fullPathForChildren,\n localPath: EscapedPath.create(id),\n });\n }\n}\n\n/**\n * Parameter to help encode summary with conditional behavior.\n * When fromSummary is true, it will contain the SummaryNode of\n * its previous summary, which it can use to point to with a handle.\n * When fromSummary is false, it will use an actual summary tree\n * as its base summary in case the first summary is a differential summary.\n */\nexport type EncodeSummaryParam = {\n fromSummary: true;\n summaryNode: SummaryNode;\n} | {\n fromSummary: false;\n initialSummary: ISummaryTreeWithStats;\n};\n\n/**\n * Information about the initial summary tree found from an attach op.\n */\nexport interface IInitialSummary {\n sequenceNumber: number;\n id: string;\n summary: ISummaryTreeWithStats | undefined;\n}\n\n/**\n * Represents the details needed to create a child summarizer node.\n */\nexport interface ICreateChildDetails {\n /** Summary from attach op if known */\n initialSummary: IInitialSummary | undefined;\n /** Latest summary from server node data */\n latestSummary: SummaryNode | undefined;\n /** Sequence number of latest known change to the node */\n changeSequenceNumber: number;\n}\n\nexport interface ISubtreeInfo<T extends ISnapshotTree | SummaryObject> {\n /** Tree to use to find children subtrees */\n childrenTree: T;\n /** Additional path part where children are isolated */\n childrenPathPart: string | undefined;\n}\n\n/**\n * Checks if the summary contains .channels subtree where the children subtrees\n * would be located if exists.\n * @param baseSummary - summary to check\n */\nexport function parseSummaryForSubtrees(baseSummary: ISnapshotTree): ISubtreeInfo<ISnapshotTree> {\n // New versions of snapshots have child nodes isolated in .channels subtree\n const channelsSubtree = baseSummary.trees[channelsTreeName];\n if (channelsSubtree !== undefined) {\n return {\n childrenTree: channelsSubtree,\n childrenPathPart: channelsTreeName,\n };\n }\n return {\n childrenTree: baseSummary,\n childrenPathPart: undefined,\n };\n}\n\n/**\n * Checks if the summary contains .channels subtree where the children subtrees\n * would be located if exists.\n * @param baseSummary - summary to check\n */\nexport function parseSummaryTreeForSubtrees(summary: ISummaryTree): ISubtreeInfo<SummaryObject> {\n // New versions of snapshots have child nodes isolated in .channels subtree\n const channelsSubtree = summary.tree[channelsTreeName];\n if (channelsSubtree !== undefined) {\n return {\n childrenTree: channelsSubtree,\n childrenPathPart: channelsTreeName,\n };\n }\n return {\n childrenTree: summary,\n childrenPathPart: undefined,\n };\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/runtime-utils";
|
|
8
|
-
export declare const pkgVersion = "1.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-internal.1.0.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,kCAAkC,CAAC;AACvD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,kCAAkC,CAAC;AACvD,eAAO,MAAM,UAAU,yBAAyB,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,+BAA+B,CAAC;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,+BAA+B,CAAC;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/runtime-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.0.0\";\n"]}
|
|
@@ -37,7 +37,6 @@ export declare class SummarizerNode implements IRootSummarizerNode {
|
|
|
37
37
|
get referenceSequenceNumber(): number;
|
|
38
38
|
protected readonly children: Map<string, SummarizerNode>;
|
|
39
39
|
protected readonly pendingSummaries: Map<string, SummaryNode>;
|
|
40
|
-
private readonly outstandingOps;
|
|
41
40
|
private wipReferenceSequenceNumber;
|
|
42
41
|
private wipLocalPaths;
|
|
43
42
|
private wipSkipRecursion;
|
|
@@ -64,14 +63,17 @@ export declare class SummarizerNode implements IRootSummarizerNode {
|
|
|
64
63
|
* case, the latest summary is updated based on the downloaded snapshot which is also returned.
|
|
65
64
|
*/
|
|
66
65
|
refreshLatestSummary(proposalHandle: string | undefined, summaryRefSeq: number, getSnapshot: () => Promise<ISnapshotTree>, readAndParseBlob: ReadAndParseBlob, correlatedSummaryLogger: ITelemetryLogger): Promise<RefreshSummaryResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Called when we get an ack from the server for a summary we've just sent. Updates the reference state of this node
|
|
68
|
+
* from the state in the pending summary queue.
|
|
69
|
+
* @param proposalHandle - Handle for the current proposal.
|
|
70
|
+
* @param referenceSequenceNumber - reference sequence number of sent summary.
|
|
71
|
+
*/
|
|
67
72
|
protected refreshLatestSummaryFromPending(proposalHandle: string, referenceSequenceNumber: number): void;
|
|
68
73
|
protected refreshLatestSummaryFromSnapshot(referenceSequenceNumber: number, snapshotTree: ISnapshotTree, basePath: EscapedPath | undefined, localPath: EscapedPath, correlatedSummaryLogger: ITelemetryLogger, readAndParseBlob: ReadAndParseBlob): Promise<void>;
|
|
69
74
|
private refreshLatestSummaryCore;
|
|
70
75
|
loadBaseSummaryWithoutDifferential(snapshot: ISnapshotTree): void;
|
|
71
|
-
loadBaseSummary(snapshot: ISnapshotTree, readAndParseBlob: ReadAndParseBlob): Promise<
|
|
72
|
-
baseSummary: ISnapshotTree;
|
|
73
|
-
outstandingOps: ISequencedDocumentMessage[];
|
|
74
|
-
}>;
|
|
76
|
+
loadBaseSummary(snapshot: ISnapshotTree, readAndParseBlob: ReadAndParseBlob): Promise<ISnapshotTree>;
|
|
75
77
|
recordChange(op: ISequencedDocumentMessage): void;
|
|
76
78
|
invalidate(sequenceNumber: number): void;
|
|
77
79
|
/**
|
|
@@ -82,13 +84,6 @@ export declare class SummarizerNode implements IRootSummarizerNode {
|
|
|
82
84
|
protected hasChanged(): boolean;
|
|
83
85
|
get latestSummary(): Readonly<SummaryNode> | undefined;
|
|
84
86
|
private readonly canReuseHandle;
|
|
85
|
-
private readonly throwOnError;
|
|
86
|
-
/**
|
|
87
|
-
* Sequence number of latest tracked op. This updates during recordChange,
|
|
88
|
-
* but not for invalidate since we don't have the op. If this drifts from
|
|
89
|
-
* changeSequenceNumber and we try to create a differential summary we assert.
|
|
90
|
-
*/
|
|
91
|
-
private trackingSequenceNumber;
|
|
92
87
|
/**
|
|
93
88
|
* Do not call constructor directly.
|
|
94
89
|
* Use createRootSummarizerNode to create root node, or createChild to create child nodes.
|
|
@@ -118,9 +113,12 @@ export declare class SummarizerNode implements IRootSummarizerNode {
|
|
|
118
113
|
/**
|
|
119
114
|
* Updates the state of the child if required. For example, if a summary is currently being tracked, the child's
|
|
120
115
|
* summary tracking state needs to be updated too.
|
|
116
|
+
* Also, in case a child node gets realized in between Summary Op and Summary Ack, let's initialize the child's
|
|
117
|
+
* pending summary as well.
|
|
121
118
|
* @param child - The child node whose state is to be updated.
|
|
122
119
|
*/
|
|
123
120
|
protected maybeUpdateChildState(child: SummarizerNode): void;
|
|
121
|
+
protected addPendingSummary(key: string, summary: SummaryNode): void;
|
|
124
122
|
/**
|
|
125
123
|
* Tells whether summary tracking is in progress. True if "startSummary" API is called before summarize.
|
|
126
124
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNode.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAEhB,8BAA8B,EAE9B,mBAAmB,EACnB,iBAAiB,EACpB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACH,yBAAyB,EAEzB,aAAa,EAEhB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"summarizerNode.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNode.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { CreateSummarizerNodeSource, } from "@fluidframework/runtime-definitions
|
|
|
6
6
|
import { SummaryType, } from "@fluidframework/protocol-definitions";
|
|
7
7
|
import { assert, unreachableCase } from "@fluidframework/common-utils";
|
|
8
8
|
import { mergeStats, convertToSummaryTree, calculateStats } from "../summaryUtils";
|
|
9
|
-
import {
|
|
9
|
+
import { EscapedPath, parseSummaryForSubtrees, parseSummaryTreeForSubtrees, SummaryNode, } from "./summarizerNodeUtils";
|
|
10
10
|
/**
|
|
11
11
|
* Encapsulates the summarizing work and state of an individual tree node in the
|
|
12
12
|
* summary tree. It tracks changes and allows for optimizations when unchanged, or
|
|
@@ -37,14 +37,8 @@ export class SummarizerNode {
|
|
|
37
37
|
this.wipSummaryLogger = wipSummaryLogger;
|
|
38
38
|
this.children = new Map();
|
|
39
39
|
this.pendingSummaries = new Map();
|
|
40
|
-
this.outstandingOps = [];
|
|
41
40
|
this.wipSkipRecursion = false;
|
|
42
41
|
this.canReuseHandle = (_a = config.canReuseHandle) !== null && _a !== void 0 ? _a : true;
|
|
43
|
-
// BUGBUG: Seeing issues with differential summaries.
|
|
44
|
-
// this will disable them, and throw instead
|
|
45
|
-
// while we continue to investigate
|
|
46
|
-
this.throwOnError = true; // config.throwOnFailure ?? false;
|
|
47
|
-
this.trackingSequenceNumber = this._changeSequenceNumber;
|
|
48
42
|
}
|
|
49
43
|
/**
|
|
50
44
|
* The reference sequence number of the most recent acked summary.
|
|
@@ -87,53 +81,12 @@ export class SummarizerNode {
|
|
|
87
81
|
};
|
|
88
82
|
}
|
|
89
83
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.wipLocalPaths.additionalPath = EscapedPath.createAndConcat(result.pathPartsForChildren);
|
|
95
|
-
}
|
|
96
|
-
return { summary: result.summary, stats: result.stats };
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
if (this.throwOnError || this.trackingSequenceNumber < this._changeSequenceNumber) {
|
|
100
|
-
throw error;
|
|
101
|
-
}
|
|
102
|
-
const latestSummary = this._latestSummary;
|
|
103
|
-
const initialSummary = this.initialSummary;
|
|
104
|
-
let encodeParam;
|
|
105
|
-
let localPath;
|
|
106
|
-
if (latestSummary !== undefined) {
|
|
107
|
-
// Create using handle of latest acked summary
|
|
108
|
-
encodeParam = {
|
|
109
|
-
fromSummary: true,
|
|
110
|
-
summaryNode: latestSummary,
|
|
111
|
-
};
|
|
112
|
-
localPath = latestSummary.localPath;
|
|
113
|
-
}
|
|
114
|
-
else if ((initialSummary === null || initialSummary === void 0 ? void 0 : initialSummary.summary) !== undefined) {
|
|
115
|
-
// Create using initial summary from attach op
|
|
116
|
-
encodeParam = {
|
|
117
|
-
fromSummary: false,
|
|
118
|
-
initialSummary: initialSummary.summary,
|
|
119
|
-
};
|
|
120
|
-
localPath = EscapedPath.create(initialSummary.id);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
// No base summary to reference
|
|
124
|
-
throw error;
|
|
125
|
-
}
|
|
126
|
-
this.wipSummaryLogger.sendErrorEvent({
|
|
127
|
-
eventName: "SummarizingWithBasePlusOps",
|
|
128
|
-
}, error);
|
|
129
|
-
const summary = encodeSummary(encodeParam, this.outstandingOps);
|
|
130
|
-
this.wipLocalPaths = {
|
|
131
|
-
localPath,
|
|
132
|
-
additionalPath: summary.additionalPath,
|
|
133
|
-
};
|
|
134
|
-
this.wipSkipRecursion = true;
|
|
135
|
-
return { summary: summary.summary, stats: summary.stats };
|
|
84
|
+
const result = await this.summarizeInternalFn(fullTree, true, telemetryContext);
|
|
85
|
+
this.wipLocalPaths = { localPath: EscapedPath.create(result.id) };
|
|
86
|
+
if (result.pathPartsForChildren !== undefined) {
|
|
87
|
+
this.wipLocalPaths.additionalPath = EscapedPath.createAndConcat(result.pathPartsForChildren);
|
|
136
88
|
}
|
|
89
|
+
return { summary: result.summary, stats: result.stats };
|
|
137
90
|
}
|
|
138
91
|
/**
|
|
139
92
|
* Complete the WIP summary for the given proposalHandle
|
|
@@ -227,6 +180,12 @@ export class SummarizerNode {
|
|
|
227
180
|
await this.refreshLatestSummaryFromSnapshot(summaryRefSeq, snapshotTree, undefined, EscapedPath.create(""), correlatedSummaryLogger, readAndParseBlob);
|
|
228
181
|
return { latestSummaryUpdated: true, wasSummaryTracked: false, snapshot: snapshotTree };
|
|
229
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Called when we get an ack from the server for a summary we've just sent. Updates the reference state of this node
|
|
185
|
+
* from the state in the pending summary queue.
|
|
186
|
+
* @param proposalHandle - Handle for the current proposal.
|
|
187
|
+
* @param referenceSequenceNumber - reference sequence number of sent summary.
|
|
188
|
+
*/
|
|
230
189
|
refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber) {
|
|
231
190
|
const summaryNode = this.pendingSummaries.get(proposalHandle);
|
|
232
191
|
if (summaryNode === undefined) {
|
|
@@ -252,13 +211,13 @@ export class SummarizerNode {
|
|
|
252
211
|
return;
|
|
253
212
|
}
|
|
254
213
|
this.refreshLatestSummaryCore(referenceSequenceNumber);
|
|
255
|
-
const { baseSummary, pathParts } = decodeSummary(snapshotTree, correlatedSummaryLogger);
|
|
256
214
|
this._latestSummary = new SummaryNode({
|
|
257
215
|
referenceSequenceNumber,
|
|
258
216
|
basePath,
|
|
259
217
|
localPath,
|
|
260
218
|
});
|
|
261
|
-
const
|
|
219
|
+
const pathParts = [];
|
|
220
|
+
const { childrenTree, childrenPathPart } = parseSummaryForSubtrees(snapshotTree);
|
|
262
221
|
if (childrenPathPart !== undefined) {
|
|
263
222
|
pathParts.push(childrenPathPart);
|
|
264
223
|
}
|
|
@@ -282,11 +241,6 @@ export class SummarizerNode {
|
|
|
282
241
|
this.pendingSummaries.delete(key);
|
|
283
242
|
}
|
|
284
243
|
}
|
|
285
|
-
// Clear earlier outstanding ops
|
|
286
|
-
while (this.outstandingOps.length > 0
|
|
287
|
-
&& this.outstandingOps[0].sequenceNumber <= referenceSequenceNumber) {
|
|
288
|
-
this.outstandingOps.shift();
|
|
289
|
-
}
|
|
290
244
|
}
|
|
291
245
|
loadBaseSummaryWithoutDifferential(snapshot) {
|
|
292
246
|
// Check base summary to see if it has any additional path parts
|
|
@@ -297,34 +251,18 @@ export class SummarizerNode {
|
|
|
297
251
|
}
|
|
298
252
|
}
|
|
299
253
|
async loadBaseSummary(snapshot, readAndParseBlob) {
|
|
300
|
-
const
|
|
301
|
-
const
|
|
302
|
-
const { childrenPathPart } = parseSummaryForSubtrees(decodedSummary.baseSummary);
|
|
254
|
+
const pathParts = [];
|
|
255
|
+
const { childrenPathPart } = parseSummaryForSubtrees(snapshot);
|
|
303
256
|
if (childrenPathPart !== undefined) {
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
if (decodedSummary.pathParts.length > 0 && this._latestSummary !== undefined) {
|
|
307
|
-
this._latestSummary.additionalPath = EscapedPath.createAndConcat(decodedSummary.pathParts);
|
|
257
|
+
pathParts.push(childrenPathPart);
|
|
308
258
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (outstandingOps.length > 0) {
|
|
312
|
-
const newOpsLatestSeq = outstandingOps[outstandingOps.length - 1].sequenceNumber;
|
|
313
|
-
assert(newOpsLatestSeq <= this.trackingSequenceNumber, 0x1a9 /* "When loading base summary, expected outstanding ops <= tracking sequence number" */);
|
|
259
|
+
if (pathParts.length > 0 && this._latestSummary !== undefined) {
|
|
260
|
+
this._latestSummary.additionalPath = EscapedPath.createAndConcat(pathParts);
|
|
314
261
|
}
|
|
315
|
-
return
|
|
316
|
-
baseSummary: decodedSummary.baseSummary,
|
|
317
|
-
outstandingOps,
|
|
318
|
-
};
|
|
262
|
+
return snapshot;
|
|
319
263
|
}
|
|
320
264
|
recordChange(op) {
|
|
321
|
-
const lastOp = this.outstandingOps[this.outstandingOps.length - 1];
|
|
322
|
-
if (lastOp !== undefined) {
|
|
323
|
-
assert(lastOp.sequenceNumber < op.sequenceNumber, 0x1aa /* Out of order change recorded */);
|
|
324
|
-
}
|
|
325
265
|
this.invalidate(op.sequenceNumber);
|
|
326
|
-
this.trackingSequenceNumber = op.sequenceNumber;
|
|
327
|
-
this.outstandingOps.push(op);
|
|
328
266
|
}
|
|
329
267
|
invalidate(sequenceNumber) {
|
|
330
268
|
if (sequenceNumber > this._changeSequenceNumber) {
|
|
@@ -357,7 +295,8 @@ export class SummarizerNode {
|
|
|
357
295
|
const createDetails = this.getCreateDetailsForChild(id, createParam);
|
|
358
296
|
const child = new SummarizerNode(this.defaultLogger, summarizeInternalFn, config, createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger);
|
|
359
297
|
// There may be additional state that has to be updated in this child. For example, if a summary is being
|
|
360
|
-
// tracked, the child's summary tracking state needs to be updated too.
|
|
298
|
+
// tracked, the child's summary tracking state needs to be updated too. Same goes for pendingSummaries we might
|
|
299
|
+
// have outstanding on the parent in case we realize nodes in between Summary Op and Summary Ack.
|
|
361
300
|
this.maybeUpdateChildState(child);
|
|
362
301
|
this.children.set(id, child);
|
|
363
302
|
return child;
|
|
@@ -446,6 +385,8 @@ export class SummarizerNode {
|
|
|
446
385
|
/**
|
|
447
386
|
* Updates the state of the child if required. For example, if a summary is currently being tracked, the child's
|
|
448
387
|
* summary tracking state needs to be updated too.
|
|
388
|
+
* Also, in case a child node gets realized in between Summary Op and Summary Ack, let's initialize the child's
|
|
389
|
+
* pending summary as well.
|
|
449
390
|
* @param child - The child node whose state is to be updated.
|
|
450
391
|
*/
|
|
451
392
|
maybeUpdateChildState(child) {
|
|
@@ -454,6 +395,20 @@ export class SummarizerNode {
|
|
|
454
395
|
if (this.isTrackingInProgress()) {
|
|
455
396
|
child.wipReferenceSequenceNumber = this.wipReferenceSequenceNumber;
|
|
456
397
|
}
|
|
398
|
+
// In case we have pending summaries on the parent, let's initialize it on the child.
|
|
399
|
+
if (child._latestSummary !== undefined) {
|
|
400
|
+
for (const [key, value] of this.pendingSummaries.entries()) {
|
|
401
|
+
const newLatestSummaryNode = new SummaryNode({
|
|
402
|
+
referenceSequenceNumber: value.referenceSequenceNumber,
|
|
403
|
+
basePath: child._latestSummary.basePath,
|
|
404
|
+
localPath: child._latestSummary.localPath,
|
|
405
|
+
});
|
|
406
|
+
child.addPendingSummary(key, newLatestSummaryNode);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
addPendingSummary(key, summary) {
|
|
411
|
+
this.pendingSummaries.set(key, summary);
|
|
457
412
|
}
|
|
458
413
|
/**
|
|
459
414
|
* Tells whether summary tracking is in progress. True if "startSummary" API is called before summarize.
|