@fluidframework/runtime-utils 0.47.0-36362 → 0.48.0-38105
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.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.js +0 -1
- package/dist/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts +9 -4
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.js +74 -23
- package/dist/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summaryUtils.d.ts.map +1 -1
- package/dist/summaryUtils.js +1 -3
- package/dist/summaryUtils.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/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.js +0 -1
- package/lib/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts +9 -4
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.js +75 -24
- package/lib/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summaryUtils.d.ts.map +1 -1
- package/lib/summaryUtils.js +2 -4
- package/lib/summaryUtils.js.map +1 -1
- package/package.json +9 -8
- package/src/packageVersion.ts +1 -1
- package/src/summarizerNode/summarizerNodeUtils.ts +0 -1
- package/src/summarizerNode/summarizerNodeWithGc.ts +102 -32
- package/src/summaryUtils.ts +3 -5
package/dist/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 = "0.
|
|
8
|
+
export declare const pkgVersion = "0.48.0-38105";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/runtime-utils";
|
|
11
|
-
exports.pkgVersion = "0.
|
|
11
|
+
exports.pkgVersion = "0.48.0-38105";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,+BAA+B,CAAC;AAC1C,QAAA,UAAU,GAAG,cAAc,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 = \"0.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,+BAA+B,CAAC;AAC1C,QAAA,UAAU,GAAG,cAAc,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 = \"0.48.0-38105\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeUtils.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"summarizerNodeUtils.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -130,7 +130,6 @@ function decodeSummary(snapshot, logger) {
|
|
|
130
130
|
if (newEarliestSeq <= latestSeq) {
|
|
131
131
|
logger.sendTelemetryEvent({
|
|
132
132
|
eventName: "DuplicateOutstandingOps",
|
|
133
|
-
category: "generic",
|
|
134
133
|
// eslint-disable-next-line max-len
|
|
135
134
|
message: `newEarliestSeq <= latestSeq in decodeSummary: ${newEarliestSeq} <= ${latestSeq}`,
|
|
136
135
|
});
|
|
@@ -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 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 category: \"generic\",\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 { 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 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"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
-
import { ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
6
|
+
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
7
7
|
import { CreateChildSummarizerNodeParam, IGarbageCollectionData, IGarbageCollectionSummaryDetails, ISummarizeInternalResult, ISummarizeResult, ISummarizerNodeConfigWithGC, ISummarizerNodeWithGC } from "@fluidframework/runtime-definitions";
|
|
8
8
|
import { ReadAndParseBlob } from "../utils";
|
|
9
9
|
import { SummarizerNode } from "./summarizerNode";
|
|
@@ -25,11 +25,13 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
25
25
|
private readonly getGCDataFn?;
|
|
26
26
|
private wipSerializedUsedRoutes;
|
|
27
27
|
private referenceUsedRoutes;
|
|
28
|
-
private
|
|
28
|
+
private gcDetailsInInitialSummaryP;
|
|
29
29
|
private gcData;
|
|
30
30
|
private usedRoutes;
|
|
31
|
-
private
|
|
32
|
-
|
|
31
|
+
private unreferencedTimestampMs;
|
|
32
|
+
private readonly maxUnreferencedDurationMs;
|
|
33
|
+
private readonly unreferencedTimer;
|
|
34
|
+
private inactive;
|
|
33
35
|
private readonly gcDisabled;
|
|
34
36
|
/**
|
|
35
37
|
* Do not call constructor directly.
|
|
@@ -38,6 +40,7 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
38
40
|
constructor(logger: ITelemetryLogger, summarizeFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>, config: ISummarizerNodeConfigWithGC, changeSequenceNumber: number,
|
|
39
41
|
/** Undefined means created without summary */
|
|
40
42
|
latestSummary?: SummaryNode, initialSummary?: IInitialSummary, wipSummaryLogger?: ITelemetryLogger, getGCDataFn?: ((fullGC?: boolean | undefined) => Promise<IGarbageCollectionData>) | undefined, getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>);
|
|
43
|
+
getGCSummaryDetails(): IGarbageCollectionSummaryDetails;
|
|
41
44
|
/**
|
|
42
45
|
* Loads state from this node's initial GC summary details. This contains the following data from the last summary
|
|
43
46
|
* seen by the server for this client:
|
|
@@ -99,6 +102,8 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
99
102
|
getChild(id: string): ISummarizerNodeWithGC | undefined;
|
|
100
103
|
isReferenced(): boolean;
|
|
101
104
|
updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): void;
|
|
105
|
+
recordChange(op: ISequencedDocumentMessage): void;
|
|
106
|
+
private logErrorIfInactive;
|
|
102
107
|
/**
|
|
103
108
|
* Override the hasChanged method. If this node data or its used state changed, the node is considered changed.
|
|
104
109
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeWithGc.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"summarizerNodeWithGc.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ const garbage_collector_1 = require("@fluidframework/garbage-collector");
|
|
|
10
10
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
11
11
|
const summarizerNode_1 = require("./summarizerNode");
|
|
12
12
|
const summarizerNodeUtils_1 = require("./summarizerNodeUtils");
|
|
13
|
+
const defaultMaxUnreferencedDurationMs = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
13
14
|
// Extend SummaryNode to add used routes tracking to it.
|
|
14
15
|
class SummaryNodeWithGC extends summarizerNodeUtils_1.SummaryNode {
|
|
15
16
|
constructor(serializedUsedRoutes, summary) {
|
|
@@ -35,6 +36,7 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
35
36
|
constructor(logger, summarizeFn, config, changeSequenceNumber,
|
|
36
37
|
/** Undefined means created without summary */
|
|
37
38
|
latestSummary, initialSummary, wipSummaryLogger, getGCDataFn, getInitialGCSummaryDetailsFn) {
|
|
39
|
+
var _a;
|
|
38
40
|
super(logger, async (fullTree) => summarizeFn(fullTree, true /* trackState */), config, changeSequenceNumber, latestSummary, initialSummary, wipSummaryLogger);
|
|
39
41
|
this.summarizeFn = summarizeFn;
|
|
40
42
|
this.getGCDataFn = getGCDataFn;
|
|
@@ -42,20 +44,26 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
42
44
|
// that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is
|
|
43
45
|
// removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.
|
|
44
46
|
this.usedRoutes = [""];
|
|
47
|
+
// Tracks whether this node is inactive after being unreferenced for maxUnreferencedDurationMs.
|
|
48
|
+
this.inactive = false;
|
|
45
49
|
this.gcDisabled = config.gcDisabled === true;
|
|
50
|
+
this.maxUnreferencedDurationMs = (_a = config.maxUnreferencedDurationMs) !== null && _a !== void 0 ? _a : defaultMaxUnreferencedDurationMs;
|
|
46
51
|
this.gcDetailsInInitialSummaryP = new common_utils_1.LazyPromise(async () => {
|
|
47
52
|
// back-compat: 0.32. getInitialGCSummaryDetailsFn() returns undefined in 0.31. Remove undefined check
|
|
48
53
|
// when N > 34.
|
|
49
54
|
const gcSummaryDetails = await (getInitialGCSummaryDetailsFn === null || getInitialGCSummaryDetailsFn === void 0 ? void 0 : getInitialGCSummaryDetailsFn());
|
|
50
55
|
return gcSummaryDetails !== null && gcSummaryDetails !== void 0 ? gcSummaryDetails : { usedRoutes: [] };
|
|
51
56
|
});
|
|
57
|
+
this.unreferencedTimer = new common_utils_1.Timer(this.maxUnreferencedDurationMs, () => {
|
|
58
|
+
this.inactive = true;
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
|
-
// Returns the GC details that
|
|
61
|
+
// Returns the GC details that may be added to this node's summary.
|
|
54
62
|
getGCSummaryDetails() {
|
|
55
63
|
return {
|
|
56
64
|
gcData: this.gcData,
|
|
57
65
|
usedRoutes: this.usedRoutes,
|
|
58
|
-
unrefTimestamp: this.
|
|
66
|
+
unrefTimestamp: this.unreferencedTimestampMs,
|
|
59
67
|
};
|
|
60
68
|
}
|
|
61
69
|
/**
|
|
@@ -65,22 +73,18 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
65
73
|
* - gcData: The garbage collection data of this node that is required for running GC.
|
|
66
74
|
*/
|
|
67
75
|
async loadInitialGCSummaryDetails() {
|
|
68
|
-
|
|
69
|
-
if (this.referenceUsedRoutes !== undefined) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const gcDetailsInInitialSummary = await this.gcDetailsInInitialSummaryP;
|
|
73
|
-
// Possible re-entrancy. It's possible that referenceUsedRoutes was set while we were waiting to get the
|
|
74
|
-
// initial GC details.
|
|
75
|
-
if (this.referenceUsedRoutes !== undefined) {
|
|
76
|
+
if (this.gcDetailsInInitialSummaryP === undefined) {
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
+
const gcDetailsInInitialSummaryP = this.gcDetailsInInitialSummaryP;
|
|
80
|
+
this.gcDetailsInInitialSummaryP = undefined;
|
|
81
|
+
const gcDetailsInInitialSummary = await gcDetailsInInitialSummaryP;
|
|
79
82
|
// If the GC details has GC data, initialize our GC data from it.
|
|
80
83
|
if (gcDetailsInInitialSummary.gcData !== undefined) {
|
|
81
84
|
this.gcData = garbage_collector_1.cloneGCData(gcDetailsInInitialSummary.gcData);
|
|
82
85
|
}
|
|
83
|
-
this.
|
|
86
|
+
this.referenceUsedRoutes = gcDetailsInInitialSummary.usedRoutes;
|
|
87
|
+
this.unreferencedTimestampMs = gcDetailsInInitialSummary.unrefTimestamp;
|
|
84
88
|
}
|
|
85
89
|
async summarize(fullTree, trackState = true) {
|
|
86
90
|
// If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this
|
|
@@ -202,12 +206,12 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
202
206
|
* Attach information if it is created from an attach op.
|
|
203
207
|
*/
|
|
204
208
|
createParam, config = {}, getGCDataFn, getInitialGCSummaryDetailsFn) {
|
|
205
|
-
var _a;
|
|
209
|
+
var _a, _b;
|
|
206
210
|
common_utils_1.assert(!this.children.has(id), 0x1b6 /* "Create SummarizerNode child already exists" */);
|
|
207
211
|
const createDetails = this.getCreateDetailsForChild(id, createParam);
|
|
208
212
|
const child = new SummarizerNodeWithGC(this.defaultLogger, summarizeInternalFn, Object.assign(Object.assign({}, config), {
|
|
209
213
|
// Propagate our gcDisabled state to the child if its not explicity specified in child's config.
|
|
210
|
-
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled }), createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger, getGCDataFn, getInitialGCSummaryDetailsFn);
|
|
214
|
+
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled, maxUnreferencedDurationMs: (_b = config.maxUnreferencedDurationMs) !== null && _b !== void 0 ? _b : this.maxUnreferencedDurationMs }), createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger, getGCDataFn, getInitialGCSummaryDetailsFn);
|
|
211
215
|
// back-compat: 0.33 - If a child is created during summarize, its wip used routes will updated in
|
|
212
216
|
// `updateUsedRoutes` method. For older clients, do it here since that method does not exist.
|
|
213
217
|
// There may be additional state that has to be updated in this child. For example, if a summary is being
|
|
@@ -235,20 +239,67 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
235
239
|
// Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()
|
|
236
240
|
// are in the same order.
|
|
237
241
|
this.usedRoutes = usedRoutes.sort();
|
|
238
|
-
// If this node is referenced, clear unreferencedTimestamp, if any.
|
|
239
|
-
// If this node is not referenced and unreferencedTimestamp is undefined, it just became unreferenced. Update
|
|
240
|
-
// unreferencedTimestamp to the gcTimestamp.
|
|
241
|
-
if (this.isReferenced()) {
|
|
242
|
-
this.unreferencedTimestamp = undefined;
|
|
243
|
-
}
|
|
244
|
-
else if (this.unreferencedTimestamp === undefined) {
|
|
245
|
-
this.unreferencedTimestamp = gcTimestamp;
|
|
246
|
-
}
|
|
247
242
|
// If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can
|
|
248
243
|
// be tracked for this summary.
|
|
249
244
|
if (!this.gcDisabled && this.isTrackingInProgress()) {
|
|
250
245
|
this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);
|
|
251
246
|
}
|
|
247
|
+
if (this.isReferenced()) {
|
|
248
|
+
// If this node has been unreferenced for longer than maxUnreferencedDurationMs and is being referenced,
|
|
249
|
+
// log an error as this may mean the maxUnreferencedDurationMs is not long enough.
|
|
250
|
+
this.logErrorIfInactive("inactiveObjectRevived", gcTimestamp);
|
|
251
|
+
// Clear unreferenced / inactive state, if any.
|
|
252
|
+
this.inactive = false;
|
|
253
|
+
this.unreferencedTimestampMs = undefined;
|
|
254
|
+
this.unreferencedTimer.clear();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// This node is unreferenced. We need to check if this node is inative or if we need to start the unreferenced
|
|
258
|
+
// timer which would mark the node as inactive.
|
|
259
|
+
// If there is no timestamp when GC was run, we don't have enough information to determine whether this content
|
|
260
|
+
// should become inactive.
|
|
261
|
+
if (gcTimestamp === undefined) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// If unreferencedTimestampMs is not present, this node just became unreferenced. Update unreferencedTimestampMs
|
|
265
|
+
// and start the unreferenced timer.
|
|
266
|
+
// Note that it's possible this node has been unreferenced before but the unreferencedTimestampMs was not added.
|
|
267
|
+
// For example, older versions where this concept did not exist or if gcTimestamp wasn't available. In such
|
|
268
|
+
// cases, we track them as if the content just became unreferenced.
|
|
269
|
+
if (this.unreferencedTimestampMs === undefined) {
|
|
270
|
+
this.unreferencedTimestampMs = gcTimestamp;
|
|
271
|
+
this.unreferencedTimer.start();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// If we are here, this node was unreferenced earlier.
|
|
275
|
+
// If it is already inactive or has an unreferenced timer running, there is no more work to be done.
|
|
276
|
+
if (this.inactive || this.unreferencedTimer.hasTimer) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// If it has been unreferenced longer than maxUnreferencedDurationMs, mark it as inactive. Otherwise, start the
|
|
280
|
+
// unreferenced timer for the duration left for it to reach maxUnreferencedDurationMs.
|
|
281
|
+
const currentUnreferencedDurationMs = gcTimestamp - this.unreferencedTimestampMs;
|
|
282
|
+
if (currentUnreferencedDurationMs >= this.maxUnreferencedDurationMs) {
|
|
283
|
+
this.inactive = true;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
this.unreferencedTimer.start(this.maxUnreferencedDurationMs - currentUnreferencedDurationMs);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
recordChange(op) {
|
|
290
|
+
// If the node is changed after it is inactive, log an error as this may mean use-after-delete.
|
|
291
|
+
this.logErrorIfInactive("inactiveObjectChanged");
|
|
292
|
+
super.recordChange(op);
|
|
293
|
+
}
|
|
294
|
+
logErrorIfInactive(eventName, currentTimestampMs) {
|
|
295
|
+
if (this.inactive) {
|
|
296
|
+
common_utils_1.assert(this.unreferencedTimestampMs !== undefined, "Node should not become inactive without setting unreferencedTimestampMs first");
|
|
297
|
+
this.defaultLogger.sendErrorEvent({
|
|
298
|
+
eventName,
|
|
299
|
+
unreferencedDuratonMs: (currentTimestampMs !== null && currentTimestampMs !== void 0 ? currentTimestampMs : Date.now()) - this.unreferencedTimestampMs,
|
|
300
|
+
maxUnreferencedDurationMs: this.maxUnreferencedDurationMs,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
252
303
|
}
|
|
253
304
|
/**
|
|
254
305
|
* Override the hasChanged method. If this node data or its used state changed, the node is considered changed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeWithGc.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.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, LazyPromise } from \"@fluidframework/common-utils\";\nimport { cloneGCData } from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n CreateChildSummarizerNodeParam,\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionSummaryDetails,\n ISummarizeInternalResult,\n ISummarizeResult,\n ISummarizerNodeConfigWithGC,\n ISummarizerNodeWithGC,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n EscapedPath,\n ICreateChildDetails,\n IInitialSummary,\n ISummarizerNodeRootContract,\n SummaryNode,\n} from \"./summarizerNodeUtils\";\n\nexport interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n constructor(\n public readonly serializedUsedRoutes: string,\n summary: {\n readonly referenceSequenceNumber: number,\n readonly basePath: EscapedPath | undefined,\n readonly localPath: EscapedPath,\n additionalPath?: EscapedPath,\n },\n ) {\n super(summary);\n }\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n * - Adds a new API `getGCData` to return GC data of this node.\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n * - Adds GC data to the result of summarize.\n * - Manages the used routes of this node. These are used to identify if this node is referenced in the document\n * and to determine if the node's used state changed since last summary.\n * - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls\n * directly into summarizeInternal method.\n */\nexport class SummarizerNodeWithGC extends SummarizerNode implements IRootSummarizerNodeWithGC {\n // Tracks the work-in-progress used routes during summary.\n private wipSerializedUsedRoutes: string | undefined;\n\n // This is the last known used routes of this node as seen by the server as part of a summary.\n private referenceUsedRoutes: string[] | undefined;\n\n // The GC details of this node in the initial summary.\n private readonly gcDetailsInInitialSummaryP: LazyPromise<IGarbageCollectionSummaryDetails>;\n\n private gcData: IGarbageCollectionData | undefined;\n\n // Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n // that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n // removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n private usedRoutes: string[] = [\"\"];\n\n // If this node is marked as unreferenced, the time when it marked as such.\n private unreferencedTimestamp: number | undefined;\n\n // Returns the GC details that my be added to this node's summary.\n public getGCSummaryDetails(): IGarbageCollectionSummaryDetails {\n return {\n gcData: this.gcData,\n usedRoutes: this.usedRoutes,\n unrefTimestamp: this.unreferencedTimestamp,\n };\n }\n\n // True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n private readonly gcDisabled: boolean;\n\n /**\n * Do not call constructor directly.\n * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n */\n public constructor(\n logger: ITelemetryLogger,\n private readonly summarizeFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n config: ISummarizerNodeConfigWithGC,\n changeSequenceNumber: number,\n /** Undefined means created without summary */\n latestSummary?: SummaryNode,\n initialSummary?: IInitialSummary,\n wipSummaryLogger?: ITelemetryLogger,\n private readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ) {\n super(\n logger,\n async (fullTree: boolean) => summarizeFn(fullTree, true /* trackState */),\n config,\n changeSequenceNumber,\n latestSummary,\n initialSummary,\n wipSummaryLogger,\n );\n\n this.gcDisabled = config.gcDisabled === true;\n\n this.gcDetailsInInitialSummaryP = new LazyPromise(async () => {\n // back-compat: 0.32. getInitialGCSummaryDetailsFn() returns undefined in 0.31. Remove undefined check\n // when N > 34.\n const gcSummaryDetails = await getInitialGCSummaryDetailsFn?.();\n return gcSummaryDetails ?? { usedRoutes: [] };\n });\n }\n\n /**\n * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n * seen by the server for this client:\n * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n * - gcData: The garbage collection data of this node that is required for running GC.\n */\n private async loadInitialGCSummaryDetails() {\n // If referenceUsedRoutes exists, don't do anything because we have already initialized.\n if (this.referenceUsedRoutes !== undefined) {\n return;\n }\n\n const gcDetailsInInitialSummary = await this.gcDetailsInInitialSummaryP;\n\n // Possible re-entrancy. It's possible that referenceUsedRoutes was set while we were waiting to get the\n // initial GC details.\n if (this.referenceUsedRoutes !== undefined) {\n return;\n }\n\n this.referenceUsedRoutes = gcDetailsInInitialSummary.usedRoutes;\n // If the GC details has GC data, initialize our GC data from it.\n if (gcDetailsInInitialSummary.gcData !== undefined) {\n this.gcData = cloneGCData(gcDetailsInInitialSummary.gcData);\n }\n this.unreferencedTimestamp = gcDetailsInInitialSummary.unrefTimestamp;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean = true): Promise<ISummarizeResult> {\n // If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this\n // summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n assert(this.wipSerializedUsedRoutes !== undefined,\n 0x1b1 /* \"wip used routes should be set if tracking a summary\" */);\n }\n\n // If trackState is true, get summary from base summarizer node which tracks summary state.\n // If trackState is false, get summary from summarizeInternal.\n return trackState ? super.summarize(fullTree) : this.summarizeFn(fullTree, trackState);\n }\n\n /**\n * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n assert(!this.gcDisabled, 0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */);\n assert(this.getGCDataFn !== undefined, 0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */);\n\n // Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n // called and the node's data has not changed since last summary, the GC data in initial details is returned.\n await this.loadInitialGCSummaryDetails();\n\n // If there is no new data since last summary and we have GC data from the previous run, return it. We may not\n // have data from previous GC run for clients with older summary format before GC was added. They won't have\n // GC details in their initial summary.\n if (!fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n return cloneGCData(this.gcData);\n }\n\n const gcData = await this.getGCDataFn(fullGC);\n this.gcData = cloneGCData(gcData);\n return gcData;\n }\n\n /**\n * Called during the start of a summary. Updates the work-in-progress used routes.\n */\n public startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n // If GC is disabled, skip setting wip used routes since we should not track GC state.\n if (!this.gcDisabled) {\n assert(\n this.wipSerializedUsedRoutes === undefined,\n 0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */);\n\n // back-compat: 0.33 - This will be done in `updateUsedRoutes`. Older clients do not have that method, so\n // keeping this one for now.\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n super.startSummary(referenceSequenceNumber, summaryLogger);\n }\n\n /**\n * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n * summary queue. We track this until we get an ack from the server for this summary.\n */\n protected completeSummaryCore(\n proposalHandle: string,\n parentPath: EscapedPath | undefined,\n parentSkipRecursion: boolean,\n ) {\n let wipSerializedUsedRoutes: string | undefined;\n // If GC is disabled, don't set wip used routes.\n if (!this.gcDisabled) {\n wipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n assert(wipSerializedUsedRoutes !== undefined, 0x1b5 /* \"We should have been tracking used routes\" */);\n }\n\n super.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n // If GC is disabled, skip setting pending summary with GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle);\n if (summaryNode !== undefined) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const summaryNodeWithGC = new SummaryNodeWithGC(wipSerializedUsedRoutes!, summaryNode);\n this.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n }\n }\n }\n\n /**\n * Clears the work-in-progress state.\n */\n public clearSummary() {\n this.wipSerializedUsedRoutes = undefined;\n super.clearSummary();\n }\n\n /**\n * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n * from the state in the pending summary queue.\n */\n protected refreshLatestSummaryFromPending(\n proposalHandle: string,\n referenceSequenceNumber: number,\n ): void {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n if (summaryNode !== undefined) {\n this.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n }\n }\n\n return super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n }\n\n /**\n * Called when we need to upload the reference state from the given summary. Read the GC blob and get the state\n * to upload from it.\n */\n protected async refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber: number,\n snapshotTree: ISnapshotTree,\n basePath: EscapedPath | undefined,\n localPath: EscapedPath,\n correlatedSummaryLogger: ITelemetryLogger,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const gcDetailsBlob = snapshotTree.blobs[gcBlobKey];\n if (gcDetailsBlob !== undefined) {\n const gcDetails = await readAndParseBlob<IGarbageCollectionSummaryDetails>(gcDetailsBlob);\n\n // Possible re-entrancy. If we have already seen a summary later than this one, ignore it.\n if (this.referenceSequenceNumber >= referenceSequenceNumber) {\n return;\n }\n\n this.referenceUsedRoutes = gcDetails.usedRoutes;\n }\n }\n\n return super.refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber,\n snapshotTree,\n basePath,\n localPath,\n correlatedSummaryLogger,\n readAndParseBlob,\n );\n }\n\n /**\n * Override the createChild method to return an instance of SummarizerNodeWithGC.\n */\n public createChild(\n /** Summarize function */\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n /** Initial id or path part of this node */\n id: string,\n /**\n * Information needed to create the node.\n * If it is from a base summary, it will assert that a summary has been seen.\n * Attach information if it is created from an attach op.\n */\n createParam: CreateChildSummarizerNodeParam,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ): ISummarizerNodeWithGC {\n assert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n const createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n const child = new SummarizerNodeWithGC(\n this.defaultLogger,\n summarizeInternalFn,\n {\n ...config,\n // Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n gcDisabled: config.gcDisabled ?? this.gcDisabled,\n },\n createDetails.changeSequenceNumber,\n createDetails.latestSummary,\n createDetails.initialSummary,\n this.wipSummaryLogger,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n );\n\n // back-compat: 0.33 - If a child is created during summarize, its wip used routes will updated in\n // `updateUsedRoutes` method. For older clients, do it here since that method does not exist.\n\n // There may be additional state that has to be updated in this child. For example, if a summary is being\n // tracked, the child's summary tracking state needs to be updated too.\n this.maybeUpdateChildState(child);\n\n this.children.set(id, child);\n return child;\n }\n\n /**\n * Deletes the child node with the given id.\n */\n public deleteChild(id: string): void {\n this.children.delete(id);\n }\n\n /**\n * Override the getChild method to return an instance of SummarizerNodeWithGC.\n */\n public getChild(id: string): ISummarizerNodeWithGC | undefined {\n return this.children.get(id) as SummarizerNodeWithGC;\n }\n\n public isReferenced(): boolean {\n return this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n }\n\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number) {\n // Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n // are in the same order.\n this.usedRoutes = usedRoutes.sort();\n\n // If this node is referenced, clear unreferencedTimestamp, if any.\n // If this node is not referenced and unreferencedTimestamp is undefined, it just became unreferenced. Update\n // unreferencedTimestamp to the gcTimestamp.\n if (this.isReferenced()) {\n this.unreferencedTimestamp = undefined;\n } else if (this.unreferencedTimestamp === undefined) {\n this.unreferencedTimestamp = gcTimestamp;\n }\n\n // If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can\n // be tracked for this summary.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n }\n\n /**\n * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n */\n protected hasChanged(): boolean {\n return this.hasDataChanged() || this.hasUsedStateChanged();\n }\n\n /**\n * This tells whether the data in this node has changed or not.\n */\n private hasDataChanged(): boolean {\n return super.hasChanged();\n }\n\n /**\n * This tells whether the used state of this node has changed since last successful summary. If the used routes\n * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n * was previously used and became unused (or vice versa), its used state has changed.\n */\n private hasUsedStateChanged(): boolean {\n // If GC is disabled, we are not tracking used state, return false.\n if (this.gcDisabled) {\n return false;\n }\n\n return this.referenceUsedRoutes === undefined ||\n JSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes);\n }\n\n /**\n * Updates the work-in-progress state of the child if summary is in progress.\n * @param child - The child node to be updated.\n */\n protected maybeUpdateChildState(child: SummarizerNodeWithGC) {\n if (this.isTrackingInProgress()) {\n // Update the child's work-in-progress used routes.\n child.updateUsedRoutes(child.usedRoutes);\n }\n super.maybeUpdateChildState(child);\n }\n}\n\n/**\n * Creates a root summarizer node with GC functionality built-in.\n * @param logger - Logger to use within SummarizerNode\n * @param summarizeInternalFn - Function to generate summary\n * @param changeSequenceNumber - Sequence number of latest change to new node/subtree\n * @param referenceSequenceNumber - Reference sequence number of last acked summary,\n * or undefined if not loaded from summary\n * @param config - Configure behavior of summarizer node\n * @param getGCDataFn - Function to get the GC data of this node\n * @param gcDetailsInInitialSummaryP - Function to get the initial GC details of this node\n */\nexport const createRootSummarizerNodeWithGC = (\n logger: ITelemetryLogger,\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n changeSequenceNumber: number,\n referenceSequenceNumber: number | undefined,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n): IRootSummarizerNodeWithGC => new SummarizerNodeWithGC(\n logger,\n summarizeInternalFn,\n config,\n changeSequenceNumber,\n referenceSequenceNumber === undefined ? undefined : SummaryNode.createForRoot(referenceSequenceNumber),\n undefined /* initialSummary */,\n undefined /* wipSummaryLogger */,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n);\n"]}
|
|
1
|
+
{"version":3,"file":"summarizerNodeWithGc.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.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, LazyPromise, Timer } from \"@fluidframework/common-utils\";\nimport { cloneGCData } from \"@fluidframework/garbage-collector\";\nimport { ISequencedDocumentMessage, ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n CreateChildSummarizerNodeParam,\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionSummaryDetails,\n ISummarizeInternalResult,\n ISummarizeResult,\n ISummarizerNodeConfigWithGC,\n ISummarizerNodeWithGC,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n EscapedPath,\n ICreateChildDetails,\n IInitialSummary,\n ISummarizerNodeRootContract,\n SummaryNode,\n} from \"./summarizerNodeUtils\";\n\nconst defaultMaxUnreferencedDurationMs = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n constructor(\n public readonly serializedUsedRoutes: string,\n summary: {\n readonly referenceSequenceNumber: number,\n readonly basePath: EscapedPath | undefined,\n readonly localPath: EscapedPath,\n additionalPath?: EscapedPath,\n },\n ) {\n super(summary);\n }\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n * - Adds a new API `getGCData` to return GC data of this node.\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n * - Adds GC data to the result of summarize.\n * - Manages the used routes of this node. These are used to identify if this node is referenced in the document\n * and to determine if the node's used state changed since last summary.\n * - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls\n * directly into summarizeInternal method.\n */\nexport class SummarizerNodeWithGC extends SummarizerNode implements IRootSummarizerNodeWithGC {\n // Tracks the work-in-progress used routes during summary.\n private wipSerializedUsedRoutes: string | undefined;\n\n // This is the last known used routes of this node as seen by the server as part of a summary.\n private referenceUsedRoutes: string[] | undefined;\n\n // The GC details of this node in the initial summary.\n private gcDetailsInInitialSummaryP: LazyPromise<IGarbageCollectionSummaryDetails> | undefined;\n\n private gcData: IGarbageCollectionData | undefined;\n\n // Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n // that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n // removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n private usedRoutes: string[] = [\"\"];\n\n // If this node is marked as unreferenced, the time when it marked as such.\n private unreferencedTimestampMs: number | undefined;\n\n // The max duration for which this node can be unreferenced before it is eligible for deletion.\n private readonly maxUnreferencedDurationMs: number;\n\n // The timer that runs when the node is marked unreferenced.\n private readonly unreferencedTimer: Timer;\n\n // Tracks whether this node is inactive after being unreferenced for maxUnreferencedDurationMs.\n private inactive: boolean = false;\n\n // True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n private readonly gcDisabled: boolean;\n\n /**\n * Do not call constructor directly.\n * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n */\n public constructor(\n logger: ITelemetryLogger,\n private readonly summarizeFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n config: ISummarizerNodeConfigWithGC,\n changeSequenceNumber: number,\n /** Undefined means created without summary */\n latestSummary?: SummaryNode,\n initialSummary?: IInitialSummary,\n wipSummaryLogger?: ITelemetryLogger,\n private readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ) {\n super(\n logger,\n async (fullTree: boolean) => summarizeFn(fullTree, true /* trackState */),\n config,\n changeSequenceNumber,\n latestSummary,\n initialSummary,\n wipSummaryLogger,\n );\n\n this.gcDisabled = config.gcDisabled === true;\n this.maxUnreferencedDurationMs = config.maxUnreferencedDurationMs ?? defaultMaxUnreferencedDurationMs;\n\n this.gcDetailsInInitialSummaryP = new LazyPromise(async () => {\n // back-compat: 0.32. getInitialGCSummaryDetailsFn() returns undefined in 0.31. Remove undefined check\n // when N > 34.\n const gcSummaryDetails = await getInitialGCSummaryDetailsFn?.();\n return gcSummaryDetails ?? { usedRoutes: [] };\n });\n\n this.unreferencedTimer = new Timer(this.maxUnreferencedDurationMs, () => {\n this.inactive = true;\n });\n }\n\n // Returns the GC details that may be added to this node's summary.\n public getGCSummaryDetails(): IGarbageCollectionSummaryDetails {\n return {\n gcData: this.gcData,\n usedRoutes: this.usedRoutes,\n unrefTimestamp: this.unreferencedTimestampMs,\n };\n }\n\n /**\n * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n * seen by the server for this client:\n * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n * - gcData: The garbage collection data of this node that is required for running GC.\n */\n private async loadInitialGCSummaryDetails() {\n if (this.gcDetailsInInitialSummaryP === undefined) {\n return;\n }\n\n const gcDetailsInInitialSummaryP = this.gcDetailsInInitialSummaryP;\n this.gcDetailsInInitialSummaryP = undefined;\n\n const gcDetailsInInitialSummary = await gcDetailsInInitialSummaryP;\n // If the GC details has GC data, initialize our GC data from it.\n if (gcDetailsInInitialSummary.gcData !== undefined) {\n this.gcData = cloneGCData(gcDetailsInInitialSummary.gcData);\n }\n this.referenceUsedRoutes = gcDetailsInInitialSummary.usedRoutes;\n this.unreferencedTimestampMs = gcDetailsInInitialSummary.unrefTimestamp;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean = true): Promise<ISummarizeResult> {\n // If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this\n // summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n assert(this.wipSerializedUsedRoutes !== undefined,\n 0x1b1 /* \"wip used routes should be set if tracking a summary\" */);\n }\n\n // If trackState is true, get summary from base summarizer node which tracks summary state.\n // If trackState is false, get summary from summarizeInternal.\n return trackState ? super.summarize(fullTree) : this.summarizeFn(fullTree, trackState);\n }\n\n /**\n * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n assert(!this.gcDisabled, 0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */);\n assert(this.getGCDataFn !== undefined, 0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */);\n\n // Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n // called and the node's data has not changed since last summary, the GC data in initial details is returned.\n await this.loadInitialGCSummaryDetails();\n\n // If there is no new data since last summary and we have GC data from the previous run, return it. We may not\n // have data from previous GC run for clients with older summary format before GC was added. They won't have\n // GC details in their initial summary.\n if (!fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n return cloneGCData(this.gcData);\n }\n\n const gcData = await this.getGCDataFn(fullGC);\n this.gcData = cloneGCData(gcData);\n return gcData;\n }\n\n /**\n * Called during the start of a summary. Updates the work-in-progress used routes.\n */\n public startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n // If GC is disabled, skip setting wip used routes since we should not track GC state.\n if (!this.gcDisabled) {\n assert(\n this.wipSerializedUsedRoutes === undefined,\n 0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */);\n\n // back-compat: 0.33 - This will be done in `updateUsedRoutes`. Older clients do not have that method, so\n // keeping this one for now.\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n super.startSummary(referenceSequenceNumber, summaryLogger);\n }\n\n /**\n * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n * summary queue. We track this until we get an ack from the server for this summary.\n */\n protected completeSummaryCore(\n proposalHandle: string,\n parentPath: EscapedPath | undefined,\n parentSkipRecursion: boolean,\n ) {\n let wipSerializedUsedRoutes: string | undefined;\n // If GC is disabled, don't set wip used routes.\n if (!this.gcDisabled) {\n wipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n assert(wipSerializedUsedRoutes !== undefined, 0x1b5 /* \"We should have been tracking used routes\" */);\n }\n\n super.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n // If GC is disabled, skip setting pending summary with GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle);\n if (summaryNode !== undefined) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const summaryNodeWithGC = new SummaryNodeWithGC(wipSerializedUsedRoutes!, summaryNode);\n this.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n }\n }\n }\n\n /**\n * Clears the work-in-progress state.\n */\n public clearSummary() {\n this.wipSerializedUsedRoutes = undefined;\n super.clearSummary();\n }\n\n /**\n * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n * from the state in the pending summary queue.\n */\n protected refreshLatestSummaryFromPending(\n proposalHandle: string,\n referenceSequenceNumber: number,\n ): void {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n if (summaryNode !== undefined) {\n this.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n }\n }\n\n return super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n }\n\n /**\n * Called when we need to upload the reference state from the given summary. Read the GC blob and get the state\n * to upload from it.\n */\n protected async refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber: number,\n snapshotTree: ISnapshotTree,\n basePath: EscapedPath | undefined,\n localPath: EscapedPath,\n correlatedSummaryLogger: ITelemetryLogger,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const gcDetailsBlob = snapshotTree.blobs[gcBlobKey];\n if (gcDetailsBlob !== undefined) {\n const gcDetails = await readAndParseBlob<IGarbageCollectionSummaryDetails>(gcDetailsBlob);\n\n // Possible re-entrancy. If we have already seen a summary later than this one, ignore it.\n if (this.referenceSequenceNumber >= referenceSequenceNumber) {\n return;\n }\n\n this.referenceUsedRoutes = gcDetails.usedRoutes;\n }\n }\n\n return super.refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber,\n snapshotTree,\n basePath,\n localPath,\n correlatedSummaryLogger,\n readAndParseBlob,\n );\n }\n\n /**\n * Override the createChild method to return an instance of SummarizerNodeWithGC.\n */\n public createChild(\n /** Summarize function */\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n /** Initial id or path part of this node */\n id: string,\n /**\n * Information needed to create the node.\n * If it is from a base summary, it will assert that a summary has been seen.\n * Attach information if it is created from an attach op.\n */\n createParam: CreateChildSummarizerNodeParam,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ): ISummarizerNodeWithGC {\n assert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n const createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n const child = new SummarizerNodeWithGC(\n this.defaultLogger,\n summarizeInternalFn,\n {\n ...config,\n // Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n gcDisabled: config.gcDisabled ?? this.gcDisabled,\n maxUnreferencedDurationMs: config.maxUnreferencedDurationMs ?? this.maxUnreferencedDurationMs,\n },\n createDetails.changeSequenceNumber,\n createDetails.latestSummary,\n createDetails.initialSummary,\n this.wipSummaryLogger,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n );\n\n // back-compat: 0.33 - If a child is created during summarize, its wip used routes will updated in\n // `updateUsedRoutes` method. For older clients, do it here since that method does not exist.\n\n // There may be additional state that has to be updated in this child. For example, if a summary is being\n // tracked, the child's summary tracking state needs to be updated too.\n this.maybeUpdateChildState(child);\n\n this.children.set(id, child);\n return child;\n }\n\n /**\n * Deletes the child node with the given id.\n */\n public deleteChild(id: string): void {\n this.children.delete(id);\n }\n\n /**\n * Override the getChild method to return an instance of SummarizerNodeWithGC.\n */\n public getChild(id: string): ISummarizerNodeWithGC | undefined {\n return this.children.get(id) as SummarizerNodeWithGC;\n }\n\n public isReferenced(): boolean {\n return this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n }\n\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number) {\n // Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n // are in the same order.\n this.usedRoutes = usedRoutes.sort();\n\n // If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can\n // be tracked for this summary.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n\n if (this.isReferenced()) {\n // If this node has been unreferenced for longer than maxUnreferencedDurationMs and is being referenced,\n // log an error as this may mean the maxUnreferencedDurationMs is not long enough.\n this.logErrorIfInactive(\"inactiveObjectRevived\", gcTimestamp);\n\n // Clear unreferenced / inactive state, if any.\n this.inactive = false;\n this.unreferencedTimestampMs = undefined;\n this.unreferencedTimer.clear();\n return;\n }\n\n // This node is unreferenced. We need to check if this node is inative or if we need to start the unreferenced\n // timer which would mark the node as inactive.\n\n // If there is no timestamp when GC was run, we don't have enough information to determine whether this content\n // should become inactive.\n if (gcTimestamp === undefined) {\n return;\n }\n\n // If unreferencedTimestampMs is not present, this node just became unreferenced. Update unreferencedTimestampMs\n // and start the unreferenced timer.\n // Note that it's possible this node has been unreferenced before but the unreferencedTimestampMs was not added.\n // For example, older versions where this concept did not exist or if gcTimestamp wasn't available. In such\n // cases, we track them as if the content just became unreferenced.\n if (this.unreferencedTimestampMs === undefined) {\n this.unreferencedTimestampMs = gcTimestamp;\n this.unreferencedTimer.start();\n return;\n }\n\n // If we are here, this node was unreferenced earlier.\n\n // If it is already inactive or has an unreferenced timer running, there is no more work to be done.\n if (this.inactive || this.unreferencedTimer.hasTimer) {\n return;\n }\n\n // If it has been unreferenced longer than maxUnreferencedDurationMs, mark it as inactive. Otherwise, start the\n // unreferenced timer for the duration left for it to reach maxUnreferencedDurationMs.\n const currentUnreferencedDurationMs = gcTimestamp - this.unreferencedTimestampMs;\n if (currentUnreferencedDurationMs >= this.maxUnreferencedDurationMs) {\n this.inactive = true;\n } else {\n this.unreferencedTimer.start(this.maxUnreferencedDurationMs - currentUnreferencedDurationMs);\n }\n }\n\n public recordChange(op: ISequencedDocumentMessage): void {\n // If the node is changed after it is inactive, log an error as this may mean use-after-delete.\n this.logErrorIfInactive(\"inactiveObjectChanged\");\n super.recordChange(op);\n }\n\n private logErrorIfInactive(eventName: string, currentTimestampMs?: number) {\n if (this.inactive) {\n assert(\n this.unreferencedTimestampMs !== undefined,\n \"Node should not become inactive without setting unreferencedTimestampMs first\");\n this.defaultLogger.sendErrorEvent({\n eventName,\n unreferencedDuratonMs: (currentTimestampMs ?? Date.now()) - this.unreferencedTimestampMs,\n maxUnreferencedDurationMs: this.maxUnreferencedDurationMs,\n });\n }\n }\n\n /**\n * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n */\n protected hasChanged(): boolean {\n return this.hasDataChanged() || this.hasUsedStateChanged();\n }\n\n /**\n * This tells whether the data in this node has changed or not.\n */\n private hasDataChanged(): boolean {\n return super.hasChanged();\n }\n\n /**\n * This tells whether the used state of this node has changed since last successful summary. If the used routes\n * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n * was previously used and became unused (or vice versa), its used state has changed.\n */\n private hasUsedStateChanged(): boolean {\n // If GC is disabled, we are not tracking used state, return false.\n if (this.gcDisabled) {\n return false;\n }\n\n return this.referenceUsedRoutes === undefined ||\n JSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes);\n }\n\n /**\n * Updates the work-in-progress state of the child if summary is in progress.\n * @param child - The child node to be updated.\n */\n protected maybeUpdateChildState(child: SummarizerNodeWithGC) {\n if (this.isTrackingInProgress()) {\n // Update the child's work-in-progress used routes.\n child.updateUsedRoutes(child.usedRoutes);\n }\n super.maybeUpdateChildState(child);\n }\n}\n\n/**\n * Creates a root summarizer node with GC functionality built-in.\n * @param logger - Logger to use within SummarizerNode\n * @param summarizeInternalFn - Function to generate summary\n * @param changeSequenceNumber - Sequence number of latest change to new node/subtree\n * @param referenceSequenceNumber - Reference sequence number of last acked summary,\n * or undefined if not loaded from summary\n * @param config - Configure behavior of summarizer node\n * @param getGCDataFn - Function to get the GC data of this node\n * @param gcDetailsInInitialSummaryP - Function to get the initial GC details of this node\n */\nexport const createRootSummarizerNodeWithGC = (\n logger: ITelemetryLogger,\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n changeSequenceNumber: number,\n referenceSequenceNumber: number | undefined,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n): IRootSummarizerNodeWithGC => new SummarizerNodeWithGC(\n logger,\n summarizeInternalFn,\n config,\n changeSequenceNumber,\n referenceSequenceNumber === undefined ? undefined : SummaryNode.createForRoot(referenceSequenceNumber),\n undefined /* initialSummary */,\n undefined /* wipSummaryLogger */,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summaryUtils.d.ts","sourceRoot":"","sources":["../src/summaryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"summaryUtils.d.ts","sourceRoot":"","sources":["../src/summaryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,EACH,KAAK,EACL,WAAW,EACX,YAAY,EAEZ,YAAY,EAGZ,aAAa,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAE7G;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,aAAa,EAAE,GAAG,aAAa,CAgBnE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAelD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,GAAG,MAAM,CAMpE;AAwBD,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa,CAInE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAQhH;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,gBAAgB,GAAG,IAAI,CAGrH;AAED,qBAAa,kBAAmB,YAAW,qBAAqB;IAC5D,OAAO,CAAC,iBAAiB,CAAa;IAEtC,IAAW,OAAO,IAAI,YAAY,CAKjC;IAED,IAAW,KAAK,IAAI,QAAQ,CAAC,aAAa,CAAC,CAE1C;;IAOD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,YAAY,CAAgB;IAE7B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAWxD,SAAS,CACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,UAAU,EACxE,MAAM,EAAE,MAAM,GAAG,IAAI;IAUlB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,gBAAgB,GAAG,IAAI;IAKlE,aAAa,CAAC,EAAE,EAAE,MAAM;IAIxB,cAAc,IAAI,qBAAqB;CAGjD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CACzC,QAAQ,EAAE,KAAK,EACf,QAAQ,GAAE,OAAe,GAC1B,qBAAqB,CAwCvB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,KAAK,EACf,QAAQ,GAAE,OAAe,GAC1B,gBAAgB,CAgBlB;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC5C,QAAQ,EAAE,aAAa,GACxB,qBAAqB,CA8BvB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAuC1E"}
|
package/dist/summaryUtils.js
CHANGED
|
@@ -177,8 +177,6 @@ function convertToSummaryTreeWithStats(snapshot, fullTree = false) {
|
|
|
177
177
|
builder.addAttachment(id);
|
|
178
178
|
break;
|
|
179
179
|
}
|
|
180
|
-
case protocol_definitions_1.TreeEntry.Commit:
|
|
181
|
-
throw new Error("Should not have Commit TreeEntry in summary");
|
|
182
180
|
default:
|
|
183
181
|
throw new Error("Unexpected TreeEntry type");
|
|
184
182
|
}
|
|
@@ -225,7 +223,7 @@ function convertSnapshotTreeToSummaryTree(snapshot) {
|
|
|
225
223
|
if (snapshot.blobsContents !== undefined) {
|
|
226
224
|
const content = snapshot.blobsContents[id];
|
|
227
225
|
if (content !== undefined) {
|
|
228
|
-
decoded =
|
|
226
|
+
decoded = common_utils_1.bufferToString(content, "utf-8");
|
|
229
227
|
}
|
|
230
228
|
// 0.44 back-compat We still put contents in same blob for back-compat so need to add blob
|
|
231
229
|
// only for blobPath -> blobId mapping and not for blobId -> blob value contents.
|