@fluidframework/runtime-utils 2.0.0-internal.3.1.0 → 2.0.0-internal.3.2.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/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/summarizerNode/summarizerNode.d.ts +26 -11
- package/dist/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNode.js +116 -54
- package/dist/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.d.ts +12 -14
- package/dist/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts +8 -114
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.js +30 -12
- package/dist/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summaryUtils.d.ts +4 -0
- package/dist/summaryUtils.d.ts.map +1 -1
- package/dist/summaryUtils.js +9 -0
- package/dist/summaryUtils.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/summarizerNode/summarizerNode.d.ts +26 -11
- package/lib/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNode.js +116 -54
- package/lib/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.d.ts +12 -14
- package/lib/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts +8 -114
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.js +30 -11
- package/lib/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summaryUtils.d.ts +4 -0
- package/lib/summaryUtils.d.ts.map +1 -1
- package/lib/summaryUtils.js +9 -0
- package/lib/summaryUtils.js.map +1 -1
- package/package.json +110 -111
- package/src/index.ts +1 -0
- package/src/packageVersion.ts +1 -1
- package/src/summarizerNode/summarizerNode.ts +178 -79
- package/src/summarizerNode/summarizerNodeUtils.ts +12 -17
- package/src/summarizerNode/summarizerNodeWithGc.ts +33 -10
- package/src/summaryUtils.ts +14 -0
|
@@ -15,6 +15,9 @@ import { ReadAndParseBlob } from "../utils";
|
|
|
15
15
|
*
|
|
16
16
|
* 3. The latest summary was updated but the summary corresponding to the params was not tracked. In this case, the
|
|
17
17
|
* latest snapshot is fetched and the latest summary state is updated based on it.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
20
|
+
* upcoming release.
|
|
18
21
|
*/
|
|
19
22
|
export declare type RefreshSummaryResult = {
|
|
20
23
|
latestSummaryUpdated: false;
|
|
@@ -30,11 +33,18 @@ export declare type RefreshSummaryResult = {
|
|
|
30
33
|
};
|
|
31
34
|
/**
|
|
32
35
|
* Result of snapshot fetch during refreshing latest summary state.
|
|
36
|
+
*
|
|
37
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
38
|
+
* upcoming release.
|
|
33
39
|
*/
|
|
34
40
|
export interface IFetchSnapshotResult {
|
|
35
41
|
snapshotTree: ISnapshotTree;
|
|
36
42
|
snapshotRefSeq: number;
|
|
37
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
46
|
+
* upcoming release.
|
|
47
|
+
*/
|
|
38
48
|
export interface ISummarizerNodeRootContract {
|
|
39
49
|
startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;
|
|
40
50
|
completeSummary(proposalHandle: string): void;
|
|
@@ -83,20 +93,6 @@ export declare class SummaryNode {
|
|
|
83
93
|
*/
|
|
84
94
|
createForChild(id: string): SummaryNode;
|
|
85
95
|
}
|
|
86
|
-
/**
|
|
87
|
-
* Parameter to help encode summary with conditional behavior.
|
|
88
|
-
* When fromSummary is true, it will contain the SummaryNode of
|
|
89
|
-
* its previous summary, which it can use to point to with a handle.
|
|
90
|
-
* When fromSummary is false, it will use an actual summary tree
|
|
91
|
-
* as its base summary in case the first summary is a differential summary.
|
|
92
|
-
*/
|
|
93
|
-
export declare type EncodeSummaryParam = {
|
|
94
|
-
fromSummary: true;
|
|
95
|
-
summaryNode: SummaryNode;
|
|
96
|
-
} | {
|
|
97
|
-
fromSummary: false;
|
|
98
|
-
initialSummary: ISummaryTreeWithStats;
|
|
99
|
-
};
|
|
100
96
|
/**
|
|
101
97
|
* Information about the initial summary tree found from an attach op.
|
|
102
98
|
*/
|
|
@@ -115,6 +111,8 @@ export interface ICreateChildDetails {
|
|
|
115
111
|
latestSummary: SummaryNode | undefined;
|
|
116
112
|
/** Sequence number of latest known change to the node */
|
|
117
113
|
changeSequenceNumber: number;
|
|
114
|
+
/** A unique id of this child to be logged when sending telemetry. */
|
|
115
|
+
telemetryNodeId: string;
|
|
118
116
|
}
|
|
119
117
|
export interface ISubtreeInfo<T extends ISnapshotTree | SummaryObject> {
|
|
120
118
|
/** Tree to use to find children subtrees */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeUtils.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAClG,OAAO,EAAoB,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"summarizerNodeUtils.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 { ISnapshotTree, ISummaryTree, SummaryObject } from \"@fluidframework/protocol-definitions\";\nimport { channelsTreeName, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\n\n/**\n * Return type of refreshSummaryAck function. There can be three different scenarios based on the passed params:\n *\n * 1. The latest summary was not updated.\n *\n * 2. The latest summary was updated and the summary corresponding to the params was tracked by this client.\n *\n * 3. The latest summary was updated but the summary corresponding to the params was not tracked. In this case, the\n * latest snapshot is fetched and the latest summary state is updated based on it.\n */\nexport type RefreshSummaryResult =\n\t| {\n\t\t\tlatestSummaryUpdated: false;\n\t }\n\t| {\n\t\t\tlatestSummaryUpdated: true;\n\t\t\twasSummaryTracked: true;\n\t\t\tsummaryRefSeq: number;\n\t }\n\t| {\n\t\t\tlatestSummaryUpdated: true;\n\t\t\twasSummaryTracked: false;\n\t\t\tsnapshotTree: ISnapshotTree;\n\t\t\tsummaryRefSeq: number;\n\t };\n\n/**\n * Result of snapshot fetch during refreshing latest summary state.\n */\nexport interface IFetchSnapshotResult {\n\tsnapshotTree: ISnapshotTree;\n\tsnapshotRefSeq: number;\n}\n\nexport interface ISummarizerNodeRootContract {\n\tstartSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;\n\tcompleteSummary(proposalHandle: string): void;\n\tclearSummary(): void;\n\trefreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tsummaryRefSeq: number,\n\t\tfetchLatestSnapshot: () => Promise<IFetchSnapshotResult>,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t\tcorrelatedSummaryLogger: ITelemetryLogger,\n\t): Promise<RefreshSummaryResult>;\n}\n\n/** Path for nodes in a tree with escaped special characters */\nexport class EscapedPath {\n\tprivate constructor(public readonly path: string) {}\n\tpublic static create(path: string): EscapedPath {\n\t\treturn new EscapedPath(encodeURIComponent(path));\n\t}\n\tpublic static createAndConcat(pathParts: string[]): EscapedPath {\n\t\tlet ret = EscapedPath.create(pathParts[0] ?? \"\");\n\t\tfor (let i = 1; i < pathParts.length; i++) {\n\t\t\tret = ret.concat(EscapedPath.create(pathParts[i]));\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic toString(): string {\n\t\treturn this.path;\n\t}\n\tpublic concat(path: EscapedPath): EscapedPath {\n\t\treturn new EscapedPath(`${this.path}/${path.path}`);\n\t}\n}\n\n/** Information about a summary relevant to a specific node in the tree */\nexport class SummaryNode {\n\t/** Creates an instance that is valid for the root with specific basePath and localPath */\n\tpublic static createForRoot(referenceSequenceNumber: number): SummaryNode {\n\t\treturn new SummaryNode({\n\t\t\treferenceSequenceNumber,\n\t\t\tbasePath: undefined,\n\t\t\tlocalPath: EscapedPath.create(\"\"), // root hard-coded to \"\"\n\t\t});\n\t}\n\n\t/** Summary reference sequence number, i.e. last sequence number seen when it was created */\n\tpublic get referenceSequenceNumber(): number {\n\t\treturn this.summary.referenceSequenceNumber;\n\t}\n\t/** Full path to parent node, or undefined if this is the root */\n\tpublic get basePath(): EscapedPath | undefined {\n\t\treturn this.summary.basePath;\n\t}\n\t/** Relative path to this node from its parent node */\n\tpublic get localPath(): EscapedPath {\n\t\treturn this.summary.localPath;\n\t}\n\t/** Relative path from this node to its node innermost base summary */\n\tpublic get additionalPath(): EscapedPath | undefined {\n\t\treturn this.summary.additionalPath;\n\t}\n\tpublic set additionalPath(additionalPath: EscapedPath | undefined) {\n\t\tthis.summary.additionalPath = additionalPath;\n\t}\n\tconstructor(\n\t\tprivate readonly summary: {\n\t\t\treadonly referenceSequenceNumber: number;\n\t\t\treadonly basePath: EscapedPath | undefined;\n\t\t\treadonly localPath: EscapedPath;\n\t\t\tadditionalPath?: EscapedPath;\n\t\t},\n\t) {}\n\n\t/** Gets the full path to this node, to be used when sending a handle */\n\tpublic get fullPath(): EscapedPath {\n\t\treturn this.basePath?.concat(this.localPath) ?? this.localPath;\n\t}\n\n\t/**\n\t * Gets the full path to this node's innermost base summary.\n\t * The children nodes can use this as their basePath to determine their path.\n\t */\n\tpublic get fullPathForChildren(): EscapedPath {\n\t\treturn this.additionalPath !== undefined\n\t\t\t? this.fullPath.concat(this.additionalPath)\n\t\t\t: this.fullPath;\n\t}\n\n\t/**\n\t * Creates a new node within the same summary for a child of this node.\n\t * @param id - id of the child node\n\t */\n\tpublic createForChild(id: string): SummaryNode {\n\t\treturn new SummaryNode({\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tbasePath: this.fullPathForChildren,\n\t\t\tlocalPath: EscapedPath.create(id),\n\t\t});\n\t}\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\t| {\n\t\t\tfromSummary: true;\n\t\t\tsummaryNode: SummaryNode;\n\t }\n\t| {\n\t\t\tfromSummary: false;\n\t\t\tinitialSummary: ISummaryTreeWithStats;\n\t };\n\n/**\n * Information about the initial summary tree found from an attach op.\n */\nexport interface IInitialSummary {\n\tsequenceNumber: number;\n\tid: string;\n\tsummary: ISummaryTreeWithStats | undefined;\n}\n\n/**\n * Represents the details needed to create a child summarizer node.\n */\nexport interface ICreateChildDetails {\n\t/** Summary from attach op if known */\n\tinitialSummary: IInitialSummary | undefined;\n\t/** Latest summary from server node data */\n\tlatestSummary: SummaryNode | undefined;\n\t/** Sequence number of latest known change to the node */\n\tchangeSequenceNumber: number;\n}\n\nexport interface ISubtreeInfo<T extends ISnapshotTree | SummaryObject> {\n\t/** Tree to use to find children subtrees */\n\tchildrenTree: T;\n\t/** Additional path part where children are isolated */\n\tchildrenPathPart: 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\t// New versions of snapshots have child nodes isolated in .channels subtree\n\tconst channelsSubtree = baseSummary.trees[channelsTreeName];\n\tif (channelsSubtree !== undefined) {\n\t\treturn {\n\t\t\tchildrenTree: channelsSubtree,\n\t\t\tchildrenPathPart: channelsTreeName,\n\t\t};\n\t}\n\treturn {\n\t\tchildrenTree: baseSummary,\n\t\tchildrenPathPart: undefined,\n\t};\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\t// New versions of snapshots have child nodes isolated in .channels subtree\n\tconst channelsSubtree = summary.tree[channelsTreeName];\n\tif (channelsSubtree !== undefined) {\n\t\treturn {\n\t\t\tchildrenTree: channelsSubtree,\n\t\t\tchildrenPathPart: channelsTreeName,\n\t\t};\n\t}\n\treturn {\n\t\tchildrenTree: summary,\n\t\tchildrenPathPart: undefined,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"summarizerNodeUtils.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeUtils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,6EAA8F;AA4D9F,+DAA+D;AAC/D,MAAa,WAAW;IACvB,YAAoC,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,IAAY;QAChC,OAAO,IAAI,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,CAAC;IACM,MAAM,CAAC,eAAe,CAAC,SAAmB;;QAChD,IAAI,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,MAAA,SAAS,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC,CAAC;QACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC1C,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACnD;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IACM,QAAQ;QACd,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,IAAiB;QAC9B,OAAO,IAAI,WAAW,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;CACD;AAlBD,kCAkBC;AAED,0EAA0E;AAC1E,MAAa,WAAW;IA6BvB,YACkB,OAKhB;QALgB,YAAO,GAAP,OAAO,CAKvB;IACC,CAAC;IAnCJ,0FAA0F;IACnF,MAAM,CAAC,aAAa,CAAC,uBAA+B;QAC1D,OAAO,IAAI,WAAW,CAAC;YACtB,uBAAuB;YACvB,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,wBAAwB;SAC3D,CAAC,CAAC;IACJ,CAAC;IAED,4FAA4F;IAC5F,IAAW,uBAAuB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC;IAC7C,CAAC;IACD,iEAAiE;IACjE,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC9B,CAAC;IACD,sDAAsD;IACtD,IAAW,SAAS;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IAC/B,CAAC;IACD,sEAAsE;IACtE,IAAW,cAAc;QACxB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;IACpC,CAAC;IACD,IAAW,cAAc,CAAC,cAAuC;QAChE,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC;IAC9C,CAAC;IAUD,wEAAwE;IACxE,IAAW,QAAQ;;QAClB,OAAO,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,mCAAI,IAAI,CAAC,SAAS,CAAC;IAChE,CAAC;IAED;;;OAGG;IACH,IAAW,mBAAmB;QAC7B,OAAO,IAAI,CAAC,cAAc,KAAK,SAAS;YACvC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;YAC3C,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IAClB,CAAC;IAED;;;OAGG;IACI,cAAc,CAAC,EAAU;QAC/B,OAAO,IAAI,WAAW,CAAC;YACtB,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;YACrD,QAAQ,EAAE,IAAI,CAAC,mBAAmB;YAClC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;SACjC,CAAC,CAAC;IACJ,CAAC;CACD;AAhED,kCAgEC;AAgCD;;;;GAIG;AACH,SAAgB,uBAAuB,CAAC,WAA0B;IACjE,2EAA2E;IAC3E,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,CAAC,sCAAgB,CAAC,CAAC;IAC5D,IAAI,eAAe,KAAK,SAAS,EAAE;QAClC,OAAO;YACN,YAAY,EAAE,eAAe;YAC7B,gBAAgB,EAAE,sCAAgB;SAClC,CAAC;KACF;IACD,OAAO;QACN,YAAY,EAAE,WAAW;QACzB,gBAAgB,EAAE,SAAS;KAC3B,CAAC;AACH,CAAC;AAbD,0DAaC;AAED;;;;GAIG;AACH,SAAgB,2BAA2B,CAAC,OAAqB;IAChE,2EAA2E;IAC3E,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,sCAAgB,CAAC,CAAC;IACvD,IAAI,eAAe,KAAK,SAAS,EAAE;QAClC,OAAO;YACN,YAAY,EAAE,eAAe;YAC7B,gBAAgB,EAAE,sCAAgB;SAClC,CAAC;KACF;IACD,OAAO;QACN,YAAY,EAAE,OAAO;QACrB,gBAAgB,EAAE,SAAS;KAC3B,CAAC;AACH,CAAC;AAbD,kEAaC","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 { ISnapshotTree, ISummaryTree, SummaryObject } from \"@fluidframework/protocol-definitions\";\nimport { channelsTreeName, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\n\n/**\n * Return type of refreshSummaryAck function. There can be three different scenarios based on the passed params:\n *\n * 1. The latest summary was not updated.\n *\n * 2. The latest summary was updated and the summary corresponding to the params was tracked by this client.\n *\n * 3. The latest summary was updated but the summary corresponding to the params was not tracked. In this case, the\n * latest snapshot is fetched and the latest summary state is updated based on it.\n *\n * @deprecated Internal implementation detail and will no longer be exported in an\n * upcoming release.\n */\nexport type RefreshSummaryResult =\n\t| {\n\t\t\tlatestSummaryUpdated: false;\n\t }\n\t| {\n\t\t\tlatestSummaryUpdated: true;\n\t\t\twasSummaryTracked: true;\n\t\t\tsummaryRefSeq: number;\n\t }\n\t| {\n\t\t\tlatestSummaryUpdated: true;\n\t\t\twasSummaryTracked: false;\n\t\t\tsnapshotTree: ISnapshotTree;\n\t\t\tsummaryRefSeq: number;\n\t };\n\n/**\n * Result of snapshot fetch during refreshing latest summary state.\n *\n * @deprecated Internal implementation detail and will no longer be exported in an\n * upcoming release.\n */\nexport interface IFetchSnapshotResult {\n\tsnapshotTree: ISnapshotTree;\n\tsnapshotRefSeq: number;\n}\n\n/**\n * @deprecated Internal implementation detail and will no longer be exported in an\n * upcoming release.\n */\nexport interface ISummarizerNodeRootContract {\n\tstartSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;\n\tcompleteSummary(proposalHandle: string): void;\n\tclearSummary(): void;\n\trefreshLatestSummary(\n\t\tproposalHandle: string | undefined,\n\t\tsummaryRefSeq: number,\n\t\tfetchLatestSnapshot: () => Promise<IFetchSnapshotResult>,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t\tcorrelatedSummaryLogger: ITelemetryLogger,\n\t): Promise<RefreshSummaryResult>;\n}\n\n/** Path for nodes in a tree with escaped special characters */\nexport class EscapedPath {\n\tprivate constructor(public readonly path: string) {}\n\tpublic static create(path: string): EscapedPath {\n\t\treturn new EscapedPath(encodeURIComponent(path));\n\t}\n\tpublic static createAndConcat(pathParts: string[]): EscapedPath {\n\t\tlet ret = EscapedPath.create(pathParts[0] ?? \"\");\n\t\tfor (let i = 1; i < pathParts.length; i++) {\n\t\t\tret = ret.concat(EscapedPath.create(pathParts[i]));\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic toString(): string {\n\t\treturn this.path;\n\t}\n\tpublic concat(path: EscapedPath): EscapedPath {\n\t\treturn new EscapedPath(`${this.path}/${path.path}`);\n\t}\n}\n\n/** Information about a summary relevant to a specific node in the tree */\nexport class SummaryNode {\n\t/** Creates an instance that is valid for the root with specific basePath and localPath */\n\tpublic static createForRoot(referenceSequenceNumber: number): SummaryNode {\n\t\treturn new SummaryNode({\n\t\t\treferenceSequenceNumber,\n\t\t\tbasePath: undefined,\n\t\t\tlocalPath: EscapedPath.create(\"\"), // root hard-coded to \"\"\n\t\t});\n\t}\n\n\t/** Summary reference sequence number, i.e. last sequence number seen when it was created */\n\tpublic get referenceSequenceNumber(): number {\n\t\treturn this.summary.referenceSequenceNumber;\n\t}\n\t/** Full path to parent node, or undefined if this is the root */\n\tpublic get basePath(): EscapedPath | undefined {\n\t\treturn this.summary.basePath;\n\t}\n\t/** Relative path to this node from its parent node */\n\tpublic get localPath(): EscapedPath {\n\t\treturn this.summary.localPath;\n\t}\n\t/** Relative path from this node to its node innermost base summary */\n\tpublic get additionalPath(): EscapedPath | undefined {\n\t\treturn this.summary.additionalPath;\n\t}\n\tpublic set additionalPath(additionalPath: EscapedPath | undefined) {\n\t\tthis.summary.additionalPath = additionalPath;\n\t}\n\tconstructor(\n\t\tprivate readonly summary: {\n\t\t\treadonly referenceSequenceNumber: number;\n\t\t\treadonly basePath: EscapedPath | undefined;\n\t\t\treadonly localPath: EscapedPath;\n\t\t\tadditionalPath?: EscapedPath;\n\t\t},\n\t) {}\n\n\t/** Gets the full path to this node, to be used when sending a handle */\n\tpublic get fullPath(): EscapedPath {\n\t\treturn this.basePath?.concat(this.localPath) ?? this.localPath;\n\t}\n\n\t/**\n\t * Gets the full path to this node's innermost base summary.\n\t * The children nodes can use this as their basePath to determine their path.\n\t */\n\tpublic get fullPathForChildren(): EscapedPath {\n\t\treturn this.additionalPath !== undefined\n\t\t\t? this.fullPath.concat(this.additionalPath)\n\t\t\t: this.fullPath;\n\t}\n\n\t/**\n\t * Creates a new node within the same summary for a child of this node.\n\t * @param id - id of the child node\n\t */\n\tpublic createForChild(id: string): SummaryNode {\n\t\treturn new SummaryNode({\n\t\t\treferenceSequenceNumber: this.referenceSequenceNumber,\n\t\t\tbasePath: this.fullPathForChildren,\n\t\t\tlocalPath: EscapedPath.create(id),\n\t\t});\n\t}\n}\n\n/**\n * Information about the initial summary tree found from an attach op.\n */\nexport interface IInitialSummary {\n\tsequenceNumber: number;\n\tid: string;\n\tsummary: ISummaryTreeWithStats | undefined;\n}\n\n/**\n * Represents the details needed to create a child summarizer node.\n */\nexport interface ICreateChildDetails {\n\t/** Summary from attach op if known */\n\tinitialSummary: IInitialSummary | undefined;\n\t/** Latest summary from server node data */\n\tlatestSummary: SummaryNode | undefined;\n\t/** Sequence number of latest known change to the node */\n\tchangeSequenceNumber: number;\n\t/** A unique id of this child to be logged when sending telemetry. */\n\ttelemetryNodeId: string;\n}\n\nexport interface ISubtreeInfo<T extends ISnapshotTree | SummaryObject> {\n\t/** Tree to use to find children subtrees */\n\tchildrenTree: T;\n\t/** Additional path part where children are isolated */\n\tchildrenPathPart: 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\t// New versions of snapshots have child nodes isolated in .channels subtree\n\tconst channelsSubtree = baseSummary.trees[channelsTreeName];\n\tif (channelsSubtree !== undefined) {\n\t\treturn {\n\t\t\tchildrenTree: channelsSubtree,\n\t\t\tchildrenPathPart: channelsTreeName,\n\t\t};\n\t}\n\treturn {\n\t\tchildrenTree: baseSummary,\n\t\tchildrenPathPart: undefined,\n\t};\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\t// New versions of snapshots have child nodes isolated in .channels subtree\n\tconst channelsSubtree = summary.tree[channelsTreeName];\n\tif (channelsSubtree !== undefined) {\n\t\treturn {\n\t\t\tchildrenTree: channelsSubtree,\n\t\t\tchildrenPathPart: channelsTreeName,\n\t\t};\n\t}\n\treturn {\n\t\tchildrenTree: summary,\n\t\tchildrenPathPart: undefined,\n\t};\n}\n"]}
|
|
@@ -3,122 +3,13 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { ReadAndParseBlob } from "../utils";
|
|
9
|
-
import { SummarizerNode } from "./summarizerNode";
|
|
10
|
-
import { EscapedPath, IInitialSummary, ISummarizerNodeRootContract, SummaryNode } from "./summarizerNodeUtils";
|
|
11
|
-
export interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {
|
|
12
|
-
}
|
|
6
|
+
import { IGarbageCollectionData, IGarbageCollectionDetailsBase, ISummarizerNodeConfigWithGC, ISummarizerNodeWithGC, SummarizeInternalFn } from "@fluidframework/runtime-definitions";
|
|
7
|
+
import { ISummarizerNodeRootContract } from "./summarizerNodeUtils";
|
|
13
8
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - Adds a new API `getGCData` to return GC data of this node.
|
|
17
|
-
*
|
|
18
|
-
* - Caches the result of `getGCData` to be used if nothing changes between summaries.
|
|
19
|
-
*
|
|
20
|
-
* - Manages the used routes of this node. These are used to identify if this node is referenced in the document
|
|
21
|
-
* and to determine if the node's used state changed since last summary.
|
|
22
|
-
*
|
|
23
|
-
* - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls
|
|
24
|
-
* directly into summarizeInternal method.
|
|
9
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
10
|
+
* upcoming release.
|
|
25
11
|
*/
|
|
26
|
-
export
|
|
27
|
-
private readonly summarizeFn;
|
|
28
|
-
private readonly getGCDataFn?;
|
|
29
|
-
private wipSerializedUsedRoutes;
|
|
30
|
-
private referenceUsedRoutes;
|
|
31
|
-
private readonly baseGCDetailsP;
|
|
32
|
-
private baseGCDetailsLoaded;
|
|
33
|
-
private gcData;
|
|
34
|
-
private usedRoutes;
|
|
35
|
-
private readonly gcDisabled;
|
|
36
|
-
/**
|
|
37
|
-
* Do not call constructor directly.
|
|
38
|
-
* Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.
|
|
39
|
-
*/
|
|
40
|
-
constructor(logger: ITelemetryLogger, summarizeFn: (fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext) => Promise<ISummarizeInternalResult>, config: ISummarizerNodeConfigWithGC, changeSequenceNumber: number,
|
|
41
|
-
/** Undefined means created without summary */
|
|
42
|
-
latestSummary?: SummaryNode, initialSummary?: IInitialSummary, wipSummaryLogger?: ITelemetryLogger, getGCDataFn?: ((fullGC?: boolean | undefined) => Promise<IGarbageCollectionData>) | undefined, getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>);
|
|
43
|
-
/**
|
|
44
|
-
* Loads state from this node's initial GC summary details. This contains the following data from the last summary
|
|
45
|
-
* seen by the server for this client:
|
|
46
|
-
* - usedRoutes: This is used to figure out if the used state of this node changed since last summary.
|
|
47
|
-
* - gcData: The garbage collection data of this node that is required for running GC.
|
|
48
|
-
*/
|
|
49
|
-
private loadBaseGCDetails;
|
|
50
|
-
summarize(fullTree: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): Promise<ISummarizeResult>;
|
|
51
|
-
/**
|
|
52
|
-
* Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from
|
|
53
|
-
* the previous summary. Else, it gets new GC data from the underlying Fluid object.
|
|
54
|
-
* @param fullGC - true to bypass optimizations and force full generation of GC data.
|
|
55
|
-
*/
|
|
56
|
-
getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
|
|
57
|
-
/**
|
|
58
|
-
* Called during the start of a summary. Updates the work-in-progress used routes.
|
|
59
|
-
*/
|
|
60
|
-
startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger): void;
|
|
61
|
-
/**
|
|
62
|
-
* Called after summary has been uploaded to the server. Add the work-in-progress state to the pending
|
|
63
|
-
* summary queue. We track this until we get an ack from the server for this summary.
|
|
64
|
-
*/
|
|
65
|
-
protected completeSummaryCore(proposalHandle: string, parentPath: EscapedPath | undefined, parentSkipRecursion: boolean): void;
|
|
66
|
-
/**
|
|
67
|
-
* Clears the work-in-progress state.
|
|
68
|
-
*/
|
|
69
|
-
clearSummary(): void;
|
|
70
|
-
/**
|
|
71
|
-
* Called when we get an ack from the server for a summary we sent. Update the reference state of this node
|
|
72
|
-
* from the state in the pending summary queue.
|
|
73
|
-
*/
|
|
74
|
-
protected refreshLatestSummaryFromPending(proposalHandle: string, referenceSequenceNumber: number): void;
|
|
75
|
-
/**
|
|
76
|
-
* Called when we need to upload the reference state from the given summary.
|
|
77
|
-
*/
|
|
78
|
-
protected refreshLatestSummaryFromSnapshot(referenceSequenceNumber: number, snapshotTree: ISnapshotTree, basePath: EscapedPath | undefined, localPath: EscapedPath, correlatedSummaryLogger: ITelemetryLogger, readAndParseBlob: ReadAndParseBlob): Promise<void>;
|
|
79
|
-
/**
|
|
80
|
-
* Updates GC state from the given snapshot if GC is enabled and the snapshot is newer than the one this node
|
|
81
|
-
* is tracking.
|
|
82
|
-
*/
|
|
83
|
-
private refreshGCStateFromSnapshot;
|
|
84
|
-
/**
|
|
85
|
-
* Override the createChild method to return an instance of SummarizerNodeWithGC.
|
|
86
|
-
*/
|
|
87
|
-
createChild(
|
|
88
|
-
/** Summarize function */
|
|
89
|
-
summarizeInternalFn: SummarizeInternalFn,
|
|
90
|
-
/** Initial id or path part of this node */
|
|
91
|
-
id: string,
|
|
92
|
-
/**
|
|
93
|
-
* Information needed to create the node.
|
|
94
|
-
* If it is from a base summary, it will assert that a summary has been seen.
|
|
95
|
-
* Attach information if it is created from an attach op.
|
|
96
|
-
*/
|
|
97
|
-
createParam: CreateChildSummarizerNodeParam, config?: ISummarizerNodeConfigWithGC, getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>, getBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>): ISummarizerNodeWithGC;
|
|
98
|
-
/**
|
|
99
|
-
* Deletes the child node with the given id.
|
|
100
|
-
*/
|
|
101
|
-
deleteChild(id: string): void;
|
|
102
|
-
/**
|
|
103
|
-
* Override the getChild method to return an instance of SummarizerNodeWithGC.
|
|
104
|
-
*/
|
|
105
|
-
getChild(id: string): ISummarizerNodeWithGC | undefined;
|
|
106
|
-
isReferenced(): boolean;
|
|
107
|
-
updateUsedRoutes(usedRoutes: string[]): void;
|
|
108
|
-
/**
|
|
109
|
-
* Override the hasChanged method. If this node data or its used state changed, the node is considered changed.
|
|
110
|
-
*/
|
|
111
|
-
protected hasChanged(): boolean;
|
|
112
|
-
/**
|
|
113
|
-
* This tells whether the data in this node has changed or not.
|
|
114
|
-
*/
|
|
115
|
-
private hasDataChanged;
|
|
116
|
-
/**
|
|
117
|
-
* This tells whether the used state of this node has changed since last successful summary. If the used routes
|
|
118
|
-
* of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes
|
|
119
|
-
* was previously used and became unused (or vice versa), its used state has changed.
|
|
120
|
-
*/
|
|
121
|
-
private hasUsedStateChanged;
|
|
12
|
+
export interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {
|
|
122
13
|
}
|
|
123
14
|
/**
|
|
124
15
|
* Creates a root summarizer node with GC functionality built-in.
|
|
@@ -130,6 +21,9 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
130
21
|
* @param config - Configure behavior of summarizer node
|
|
131
22
|
* @param getGCDataFn - Function to get the GC data of this node
|
|
132
23
|
* @param baseGCDetailsP - Function to get the initial GC details of this node
|
|
24
|
+
*
|
|
25
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
26
|
+
* upcoming release.
|
|
133
27
|
*/
|
|
134
28
|
export declare const createRootSummarizerNodeWithGC: (logger: ITelemetryLogger, summarizeInternalFn: SummarizeInternalFn, changeSequenceNumber: number, referenceSequenceNumber: number | undefined, config?: ISummarizerNodeConfigWithGC, getGCDataFn?: ((fullGC?: boolean | undefined) => Promise<IGarbageCollectionData>) | undefined, getBaseGCDetailsFn?: (() => Promise<IGarbageCollectionDetailsBase>) | undefined) => IRootSummarizerNodeWithGC;
|
|
135
29
|
//# sourceMappingURL=summarizerNodeWithGc.d.ts.map
|
|
@@ -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;
|
|
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;AAStE,OAAO,EAGN,sBAAsB,EACtB,6BAA6B,EAG7B,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EAEnB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAIN,2BAA2B,EAG3B,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,WAAW,yBAChB,SAAQ,qBAAqB,EAC5B,2BAA2B;CAAG;AAmfhC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,8BAA8B,WAClC,gBAAgB,uBACH,mBAAmB,wBAClB,MAAM,2BACH,MAAM,GAAG,SAAS,WACnC,2BAA2B,mDACC,QAAQ,sBAAsB,CAAC,2CACxC,QAAQ,6BAA6B,CAAC,kBAC/D,yBAcD,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.createRootSummarizerNodeWithGC =
|
|
7
|
+
exports.createRootSummarizerNodeWithGC = void 0;
|
|
8
8
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
9
9
|
const garbage_collector_1 = require("@fluidframework/garbage-collector");
|
|
10
10
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
@@ -37,8 +37,10 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
37
37
|
*/
|
|
38
38
|
constructor(logger, summarizeFn, config, changeSequenceNumber,
|
|
39
39
|
/** Undefined means created without summary */
|
|
40
|
-
latestSummary, initialSummary, wipSummaryLogger, getGCDataFn, getBaseGCDetailsFn
|
|
41
|
-
|
|
40
|
+
latestSummary, initialSummary, wipSummaryLogger, getGCDataFn, getBaseGCDetailsFn,
|
|
41
|
+
/** A unique id of this node to be logged when sending telemetry. */
|
|
42
|
+
telemetryId) {
|
|
43
|
+
super(logger, async (fullTree, _trackState, telemetryContext) => summarizeFn(fullTree, true /* trackState */, telemetryContext), config, changeSequenceNumber, latestSummary, initialSummary, wipSummaryLogger, telemetryId);
|
|
42
44
|
this.summarizeFn = summarizeFn;
|
|
43
45
|
this.getGCDataFn = getGCDataFn;
|
|
44
46
|
// Keeps track of whether we have loaded the base details to ensure that we on;y do it once.
|
|
@@ -82,9 +84,9 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
async summarize(fullTree, trackState = true, telemetryContext) {
|
|
85
|
-
// If GC is not disabled and
|
|
87
|
+
// If GC is not disabled and a summary is in progress, GC should have run and updated the used routes for this
|
|
86
88
|
// summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.
|
|
87
|
-
if (!this.gcDisabled && this.
|
|
89
|
+
if (!this.gcDisabled && this.isSummaryInProgress()) {
|
|
88
90
|
(0, common_utils_1.assert)(this.wipSerializedUsedRoutes !== undefined, 0x1b1 /* "wip used routes should be set if tracking a summary" */);
|
|
89
91
|
}
|
|
90
92
|
// If trackState is true, get summary from base summarizer node which tracks summary state.
|
|
@@ -134,7 +136,21 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
134
136
|
// If GC is disabled, don't set wip used routes.
|
|
135
137
|
if (!this.gcDisabled) {
|
|
136
138
|
wipSerializedUsedRoutes = this.wipSerializedUsedRoutes;
|
|
137
|
-
|
|
139
|
+
/**
|
|
140
|
+
* The absence of wip used routes indicates that GC was not run on this node. This can happen if:
|
|
141
|
+
* 1. A child node was created after GC was already run on the parent. For example, a data store
|
|
142
|
+
* is realized (loaded) after GC was run on it creating summarizer nodes for its DDSes. In this
|
|
143
|
+
* case, the used routes of the parent should be passed on the child nodes and it should be fine.
|
|
144
|
+
* 2. A new node was created but GC was never run on it. This can mean that the GC data generated
|
|
145
|
+
* during summarize is complete . We should not continue, log and throw an error. This will help us
|
|
146
|
+
* identify these cases and take appropriate action.
|
|
147
|
+
*/
|
|
148
|
+
if (wipSerializedUsedRoutes === undefined) {
|
|
149
|
+
this.throwUnexpectedError({
|
|
150
|
+
eventName: "NodeDidNotRunGC",
|
|
151
|
+
proposalHandle,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
138
154
|
}
|
|
139
155
|
super.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);
|
|
140
156
|
// If GC is disabled, skip setting pending summary with GC state.
|
|
@@ -282,9 +298,9 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
282
298
|
return (_a = childBaseGCDetails.get(id)) !== null && _a !== void 0 ? _a : {};
|
|
283
299
|
});
|
|
284
300
|
const createDetails = this.getCreateDetailsForChild(id, createParam);
|
|
285
|
-
const child = new SummarizerNodeWithGC(this.
|
|
301
|
+
const child = new SummarizerNodeWithGC(this.logger, summarizeInternalFn, Object.assign(Object.assign({}, config), {
|
|
286
302
|
// Propagate our gcDisabled state to the child if its not explicity specified in child's config.
|
|
287
|
-
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled }), createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger, getGCDataFn, async () => getChildBaseGCDetailsP);
|
|
303
|
+
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled }), createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger, getGCDataFn, async () => getChildBaseGCDetailsP, createDetails.telemetryNodeId);
|
|
288
304
|
// There may be additional state that has to be updated in this child. For example, if a summary is being
|
|
289
305
|
// tracked, the child's summary tracking state needs to be updated too.
|
|
290
306
|
this.maybeUpdateChildState(child);
|
|
@@ -310,9 +326,9 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
310
326
|
// Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()
|
|
311
327
|
// are in the same order.
|
|
312
328
|
this.usedRoutes = usedRoutes.sort();
|
|
313
|
-
// If GC is not disabled and
|
|
329
|
+
// If GC is not disabled and a summary is in progress, update the work-in-progress used routes so that it can
|
|
314
330
|
// be tracked for this summary.
|
|
315
|
-
if (!this.gcDisabled && this.
|
|
331
|
+
if (!this.gcDisabled && this.isSummaryInProgress()) {
|
|
316
332
|
this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);
|
|
317
333
|
}
|
|
318
334
|
}
|
|
@@ -342,7 +358,6 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
342
358
|
JSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes));
|
|
343
359
|
}
|
|
344
360
|
}
|
|
345
|
-
exports.SummarizerNodeWithGC = SummarizerNodeWithGC;
|
|
346
361
|
/**
|
|
347
362
|
* Creates a root summarizer node with GC functionality built-in.
|
|
348
363
|
* @param logger - Logger to use within SummarizerNode
|
|
@@ -353,9 +368,12 @@ exports.SummarizerNodeWithGC = SummarizerNodeWithGC;
|
|
|
353
368
|
* @param config - Configure behavior of summarizer node
|
|
354
369
|
* @param getGCDataFn - Function to get the GC data of this node
|
|
355
370
|
* @param baseGCDetailsP - Function to get the initial GC details of this node
|
|
371
|
+
*
|
|
372
|
+
* @deprecated Internal implementation detail and will no longer be exported in an
|
|
373
|
+
* upcoming release.
|
|
356
374
|
*/
|
|
357
375
|
const createRootSummarizerNodeWithGC = (logger, summarizeInternalFn, changeSequenceNumber, referenceSequenceNumber, config = {}, getGCDataFn, getBaseGCDetailsFn) => new SummarizerNodeWithGC(logger, summarizeInternalFn, config, changeSequenceNumber, referenceSequenceNumber === undefined
|
|
358
376
|
? undefined
|
|
359
|
-
: summarizerNodeUtils_1.SummaryNode.createForRoot(referenceSequenceNumber), undefined /* initialSummary */, undefined /* wipSummaryLogger */, getGCDataFn, getBaseGCDetailsFn);
|
|
377
|
+
: summarizerNodeUtils_1.SummaryNode.createForRoot(referenceSequenceNumber), undefined /* initialSummary */, undefined /* wipSummaryLogger */, getGCDataFn, getBaseGCDetailsFn, "" /* telemetryId */);
|
|
360
378
|
exports.createRootSummarizerNodeWithGC = createRootSummarizerNodeWithGC;
|
|
361
379
|
//# sourceMappingURL=summarizerNodeWithGc.js.map
|
|
@@ -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 {\n\tcloneGCData,\n\tgetGCDataFromSnapshot,\n\trunGarbageCollection,\n\tunpackChildNodesGCDetails,\n} from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tCreateChildSummarizerNodeParam,\n\tgcTreeKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n\tISummarizeInternalResult,\n\tISummarizeResult,\n\tISummarizerNodeConfigWithGC,\n\tISummarizerNodeWithGC,\n\tSummarizeInternalFn,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n\tEscapedPath,\n\tICreateChildDetails,\n\tIInitialSummary,\n\tISummarizerNodeRootContract,\n\tparseSummaryForSubtrees,\n\tSummaryNode,\n} from \"./summarizerNodeUtils\";\n\nexport interface IRootSummarizerNodeWithGC\n\textends ISummarizerNodeWithGC,\n\t\tISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n\tconstructor(\n\t\tpublic readonly serializedUsedRoutes: string,\n\t\tsummary: {\n\t\t\treadonly referenceSequenceNumber: number;\n\t\t\treadonly basePath: EscapedPath | undefined;\n\t\t\treadonly localPath: EscapedPath;\n\t\t\tadditionalPath?: EscapedPath;\n\t\t},\n\t) {\n\t\tsuper(summary);\n\t}\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n *\n * - Adds a new API `getGCData` to return GC data of this node.\n *\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n *\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 *\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\t// Tracks the work-in-progress used routes during summary.\n\tprivate wipSerializedUsedRoutes: string | undefined;\n\n\t// This is the last known used routes of this node as seen by the server as part of a summary.\n\tprivate referenceUsedRoutes: string[] | undefined;\n\n\t// The base GC details of this node used to initialize the GC state.\n\tprivate readonly baseGCDetailsP: LazyPromise<IGarbageCollectionDetailsBase>;\n\n\t// Keeps track of whether we have loaded the base details to ensure that we on;y do it once.\n\tprivate baseGCDetailsLoaded: boolean = false;\n\n\tprivate gcData: IGarbageCollectionData | undefined;\n\n\t// Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n\t// that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n\t// removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n\tprivate usedRoutes: string[] = [\"\"];\n\n\t// True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n\tprivate readonly gcDisabled: boolean;\n\n\t/**\n\t * Do not call constructor directly.\n\t * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n\t */\n\tpublic constructor(\n\t\tlogger: ITelemetryLogger,\n\t\tprivate readonly summarizeFn: (\n\t\t\tfullTree: boolean,\n\t\t\ttrackState: boolean,\n\t\t\ttelemetryContext?: ITelemetryContext,\n\t\t) => Promise<ISummarizeInternalResult>,\n\t\tconfig: ISummarizerNodeConfigWithGC,\n\t\tchangeSequenceNumber: number,\n\t\t/** Undefined means created without summary */\n\t\tlatestSummary?: SummaryNode,\n\t\tinitialSummary?: IInitialSummary,\n\t\twipSummaryLogger?: ITelemetryLogger,\n\t\tprivate readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\t\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n\t) {\n\t\tsuper(\n\t\t\tlogger,\n\t\t\tasync (fullTree: boolean, _trackState: boolean, telemetryContext?: ITelemetryContext) =>\n\t\t\t\tsummarizeFn(fullTree, true /* trackState */, telemetryContext),\n\t\t\tconfig,\n\t\t\tchangeSequenceNumber,\n\t\t\tlatestSummary,\n\t\t\tinitialSummary,\n\t\t\twipSummaryLogger,\n\t\t);\n\n\t\tthis.gcDisabled = config.gcDisabled === true;\n\n\t\tthis.baseGCDetailsP = new LazyPromise(async () => {\n\t\t\treturn (await getBaseGCDetailsFn?.()) ?? { usedRoutes: [] };\n\t\t});\n\t}\n\n\t/**\n\t * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n\t * seen by the server for this client:\n\t * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n\t * - gcData: The garbage collection data of this node that is required for running GC.\n\t */\n\tprivate async loadBaseGCDetails() {\n\t\tif (this.baseGCDetailsLoaded) {\n\t\t\treturn;\n\t\t}\n\t\tconst baseGCDetails = await this.baseGCDetailsP;\n\n\t\t// Possible race - If there were parallel calls to loadBaseGCDetails, we want to make sure that we update\n\t\t// the state from the base details only once.\n\t\tif (this.baseGCDetailsLoaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.baseGCDetailsLoaded = true;\n\n\t\t// Update GC data, used routes and reference used routes. The used routes are sorted because they are compared\n\t\t// across GC runs to check if they changed. Sorting ensures that the elements are in the same order.\n\t\t// If the GC details has GC data, initialize our GC data from it.\n\t\tif (baseGCDetails.gcData !== undefined) {\n\t\t\tthis.gcData = cloneGCData(baseGCDetails.gcData);\n\t\t}\n\t\tif (baseGCDetails.usedRoutes !== undefined) {\n\t\t\tthis.usedRoutes = Array.from(baseGCDetails.usedRoutes).sort();\n\t\t\tthis.referenceUsedRoutes = Array.from(baseGCDetails.usedRoutes).sort();\n\t\t}\n\t}\n\n\tpublic async summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean = true,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<ISummarizeResult> {\n\t\t// If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this\n\t\t// summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n\t\tif (!this.gcDisabled && this.isTrackingInProgress()) {\n\t\t\tassert(\n\t\t\t\tthis.wipSerializedUsedRoutes !== undefined,\n\t\t\t\t0x1b1 /* \"wip used routes should be set if tracking a summary\" */,\n\t\t\t);\n\t\t}\n\n\t\t// If trackState is true, get summary from base summarizer node which tracks summary state.\n\t\t// If trackState is false, get summary from summarizeInternal.\n\t\treturn trackState\n\t\t\t? super.summarize(fullTree, true /* trackState */, telemetryContext)\n\t\t\t: this.summarizeFn(fullTree, trackState, telemetryContext);\n\t}\n\n\t/**\n\t * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n\t * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n\t * @param fullGC - true to bypass optimizations and force full generation of GC data.\n\t */\n\tpublic async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n\t\tassert(\n\t\t\t!this.gcDisabled,\n\t\t\t0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */,\n\t\t);\n\t\tassert(\n\t\t\tthis.getGCDataFn !== undefined,\n\t\t\t0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */,\n\t\t);\n\n\t\t// Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n\t\t// called and the node's data has not changed since last summary, the GC data in initial details is returned.\n\t\tawait this.loadBaseGCDetails();\n\n\t\t// If there is no new data since last summary and we have GC data from the previous run, return it. The previous\n\t\t// GC data may not be available if loaded from a snapshot with either GC disabled or before GC was added.\n\t\t// Note - canReuseHandle is checked to be consistent with summarize - generate GC data for nodes for which\n\t\t// summary must be generated.\n\t\tif (this.canReuseHandle && !fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n\t\t\treturn cloneGCData(this.gcData);\n\t\t}\n\n\t\tconst gcData = await this.getGCDataFn(fullGC);\n\t\tthis.gcData = cloneGCData(gcData);\n\t\treturn gcData;\n\t}\n\n\t/**\n\t * Called during the start of a summary. Updates the work-in-progress used routes.\n\t */\n\tpublic startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n\t\t// If GC is disabled, skip setting wip used routes since we should not track GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tassert(\n\t\t\t\tthis.wipSerializedUsedRoutes === undefined,\n\t\t\t\t0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */,\n\t\t\t);\n\t\t}\n\t\tsuper.startSummary(referenceSequenceNumber, summaryLogger);\n\t}\n\n\t/**\n\t * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n\t * summary queue. We track this until we get an ack from the server for this summary.\n\t */\n\tprotected completeSummaryCore(\n\t\tproposalHandle: string,\n\t\tparentPath: EscapedPath | undefined,\n\t\tparentSkipRecursion: boolean,\n\t) {\n\t\tlet wipSerializedUsedRoutes: string | undefined;\n\t\t// If GC is disabled, don't set wip used routes.\n\t\tif (!this.gcDisabled) {\n\t\t\twipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n\t\t\tassert(\n\t\t\t\twipSerializedUsedRoutes !== undefined,\n\t\t\t\t0x1b5 /* \"We should have been tracking used routes\" */,\n\t\t\t);\n\t\t}\n\n\t\tsuper.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n\t\t// If GC is disabled, skip setting pending summary with GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tconst summaryNode = this.pendingSummaries.get(proposalHandle);\n\t\t\tif (summaryNode !== undefined) {\n\t\t\t\tconst summaryNodeWithGC = new SummaryNodeWithGC(\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\twipSerializedUsedRoutes!,\n\t\t\t\t\tsummaryNode,\n\t\t\t\t);\n\t\t\t\tthis.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clears the work-in-progress state.\n\t */\n\tpublic clearSummary() {\n\t\tthis.wipSerializedUsedRoutes = undefined;\n\t\tsuper.clearSummary();\n\t}\n\n\t/**\n\t * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n\t * from the state in the pending summary queue.\n\t */\n\tprotected refreshLatestSummaryFromPending(\n\t\tproposalHandle: string,\n\t\treferenceSequenceNumber: number,\n\t): void {\n\t\t// If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tconst summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n\t\t\tif (summaryNode?.serializedUsedRoutes !== undefined) {\n\t\t\t\tthis.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n\t\t\t}\n\t\t}\n\n\t\treturn super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n\t}\n\n\t/**\n\t * Called when we need to upload the reference state from the given summary.\n\t */\n\tprotected async refreshLatestSummaryFromSnapshot(\n\t\treferenceSequenceNumber: number,\n\t\tsnapshotTree: ISnapshotTree,\n\t\tbasePath: EscapedPath | undefined,\n\t\tlocalPath: EscapedPath,\n\t\tcorrelatedSummaryLogger: ITelemetryLogger,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<void> {\n\t\tawait this.refreshGCStateFromSnapshot(\n\t\t\treferenceSequenceNumber,\n\t\t\tsnapshotTree,\n\t\t\treadAndParseBlob,\n\t\t);\n\t\treturn super.refreshLatestSummaryFromSnapshot(\n\t\t\treferenceSequenceNumber,\n\t\t\tsnapshotTree,\n\t\t\tbasePath,\n\t\t\tlocalPath,\n\t\t\tcorrelatedSummaryLogger,\n\t\t\treadAndParseBlob,\n\t\t);\n\t}\n\n\t/**\n\t * Updates GC state from the given snapshot if GC is enabled and the snapshot is newer than the one this node\n\t * is tracking.\n\t */\n\tprivate async refreshGCStateFromSnapshot(\n\t\treferenceSequenceNumber: number,\n\t\tsnapshotTree: ISnapshotTree,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<void> {\n\t\t// If GC is disabled or we have seen a newer summary, skip updating GC state.\n\t\tif (this.gcDisabled || this.referenceSequenceNumber >= referenceSequenceNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Load the base GC details before proceeding because if that happens later it can overwrite the GC details\n\t\t// written by the following code.\n\t\tawait this.loadBaseGCDetails();\n\n\t\t// Possible re-entrancy. We may already have processed this while loading base GC details.\n\t\tif (this.referenceSequenceNumber >= referenceSequenceNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\t/**\n\t\t * GC data is written at root of the snapshot tree under \"gc\" sub-tree. This data needs to be propagated to\n\t\t * all the nodes in the container.\n\t\t * The root summarizer node reads the GC data from the \"gc\" sub-tree, runs GC on it to get used routes in\n\t\t * the container and updates its GC data and referenced used routes. It then gets the GC data and used\n\t\t * routes of all its children and adds it to their snapshot tree.\n\t\t * All the other nodes gets the GC data and used routes from their snapshot tree and updates their state.\n\t\t * They get the GC data and used routes of their children and add it to their snapshot tree and so on.\n\t\t *\n\t\t * Note that if the snapshot does not have GC tree, GC data will be set to undefined and used routes will be\n\t\t * set to self-route (meaning referenced) for all nodes. This is important because the GC data needs to be\n\t\t * regenerated in the next summary.\n\t\t */\n\t\tlet gcDetails: IGarbageCollectionDetailsBase | undefined;\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\tif (gcSnapshotTree !== undefined) {\n\t\t\t// If there is a GC tree in the snapshot, this is the root summarizer node. Read GC data from the tree\n\t\t\t// process it as explained above.\n\t\t\tconst gcSnapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\t\tfor (const [nodeId, nodeData] of Object.entries(gcSnapshotData.gcState.gcNodes)) {\n\t\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t\t}\n\t\t\t// Run GC on the nodes in the snapshot to get the used routes for each node in the container.\n\t\t\tconst usedRoutes = runGarbageCollection(gcNodes, [\"/\"]).referencedNodeIds;\n\t\t\tgcDetails = { gcData: { gcNodes }, usedRoutes };\n\t\t} else {\n\t\t\t// If there is a GC blob in the snapshot, it's a non-root summarizer nodes - The root summarizer node\n\t\t\t// writes GC blob in the snapshot of child nodes. Get GC data and used routes from the blob.\n\t\t\tconst gcDetailsBlob = snapshotTree.blobs[gcTreeKey];\n\t\t\tif (gcDetailsBlob !== undefined) {\n\t\t\t\tgcDetails = JSON.parse(gcDetailsBlob) as IGarbageCollectionDetailsBase;\n\t\t\t}\n\t\t}\n\n\t\t// Update this node to the same GC state it was when the ack corresponding to this summary was processed.\n\t\tthis.gcData = gcDetails?.gcData !== undefined ? cloneGCData(gcDetails.gcData) : undefined;\n\t\tthis.referenceUsedRoutes =\n\t\t\tgcDetails?.usedRoutes !== undefined ? Array.from(gcDetails.usedRoutes) : undefined;\n\t\t// If there are no used routes in the GC details, set it to have self route which will make the node\n\t\t// referenced. This scenario can only happen if the snapshot is from a client where GC was not run or\n\t\t// disabled. In both the cases, the node should be referenced.\n\t\tthis.usedRoutes =\n\t\t\tgcDetails?.usedRoutes !== undefined ? Array.from(gcDetails.usedRoutes) : [\"\"];\n\n\t\tif (gcDetails === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the GC data and used routes of children GC nodes and add it to their snapshot tree.\n\t\tconst gcDetailsMap = unpackChildNodesGCDetails(gcDetails);\n\t\tconst { childrenTree } = parseSummaryForSubtrees(snapshotTree);\n\t\tgcDetailsMap.forEach((childGCDetails: IGarbageCollectionDetailsBase, childId: string) => {\n\t\t\tif (childrenTree.trees[childId] !== undefined) {\n\t\t\t\tchildrenTree.trees[childId].blobs[gcTreeKey] = JSON.stringify(childGCDetails);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Override the createChild method to return an instance of SummarizerNodeWithGC.\n\t */\n\tpublic createChild(\n\t\t/** Summarize function */\n\t\tsummarizeInternalFn: SummarizeInternalFn,\n\t\t/** Initial id or path part of this node */\n\t\tid: string,\n\t\t/**\n\t\t * Information needed to create the node.\n\t\t * If it is from a base summary, it will assert that a summary has been seen.\n\t\t * Attach information if it is created from an attach op.\n\t\t */\n\t\tcreateParam: CreateChildSummarizerNodeParam,\n\t\tconfig: ISummarizerNodeConfigWithGC = {},\n\t\tgetGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\t\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n\t): ISummarizerNodeWithGC {\n\t\tassert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n\t\t/**\n\t\t * Update the child node's base GC details from this node's current GC details instead of updating from the base\n\t\t * GC details of this node. This will handle scenarios where the GC details was updated during refresh from\n\t\t * snapshot and the child node wasn't created then. If a child is created after that, its GC details should be\n\t\t * the one from the downloaded snapshot and not the base GC details.\n\t\t */\n\t\tconst getChildBaseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {\n\t\t\t// Ensure that the base GC details is loaded because a child can be created before GC runs which is when\n\t\t\t// base GC details is usually loaded.\n\t\t\tawait this.loadBaseGCDetails();\n\t\t\tconst childBaseGCDetails = unpackChildNodesGCDetails({\n\t\t\t\tgcData: this.gcData,\n\t\t\t\tusedRoutes: this.usedRoutes,\n\t\t\t});\n\t\t\treturn childBaseGCDetails.get(id) ?? {};\n\t\t});\n\n\t\tconst createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n\t\tconst child = new SummarizerNodeWithGC(\n\t\t\tthis.defaultLogger,\n\t\t\tsummarizeInternalFn,\n\t\t\t{\n\t\t\t\t...config,\n\t\t\t\t// Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n\t\t\t\tgcDisabled: config.gcDisabled ?? this.gcDisabled,\n\t\t\t},\n\t\t\tcreateDetails.changeSequenceNumber,\n\t\t\tcreateDetails.latestSummary,\n\t\t\tcreateDetails.initialSummary,\n\t\t\tthis.wipSummaryLogger,\n\t\t\tgetGCDataFn,\n\t\t\tasync () => getChildBaseGCDetailsP,\n\t\t);\n\n\t\t// There may be additional state that has to be updated in this child. For example, if a summary is being\n\t\t// tracked, the child's summary tracking state needs to be updated too.\n\t\tthis.maybeUpdateChildState(child);\n\n\t\tthis.children.set(id, child);\n\t\treturn child;\n\t}\n\n\t/**\n\t * Deletes the child node with the given id.\n\t */\n\tpublic deleteChild(id: string): void {\n\t\tthis.children.delete(id);\n\t}\n\n\t/**\n\t * Override the getChild method to return an instance of SummarizerNodeWithGC.\n\t */\n\tpublic getChild(id: string): ISummarizerNodeWithGC | undefined {\n\t\treturn this.children.get(id) as SummarizerNodeWithGC;\n\t}\n\n\tpublic isReferenced(): boolean {\n\t\treturn this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n\t}\n\n\tpublic updateUsedRoutes(usedRoutes: string[]) {\n\t\t// Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n\t\t// are in the same order.\n\t\tthis.usedRoutes = usedRoutes.sort();\n\n\t\t// If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can\n\t\t// be tracked for this summary.\n\t\tif (!this.gcDisabled && this.isTrackingInProgress()) {\n\t\t\tthis.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n\t\t}\n\t}\n\n\t/**\n\t * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n\t */\n\tprotected hasChanged(): boolean {\n\t\treturn this.hasDataChanged() || this.hasUsedStateChanged();\n\t}\n\n\t/**\n\t * This tells whether the data in this node has changed or not.\n\t */\n\tprivate hasDataChanged(): boolean {\n\t\treturn super.hasChanged();\n\t}\n\n\t/**\n\t * This tells whether the used state of this node has changed since last successful summary. If the used routes\n\t * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n\t * was previously used and became unused (or vice versa), its used state has changed.\n\t */\n\tprivate hasUsedStateChanged(): boolean {\n\t\t// If GC is disabled, we are not tracking used state, return false.\n\t\tif (this.gcDisabled) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (\n\t\t\tthis.referenceUsedRoutes === undefined ||\n\t\t\tJSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes)\n\t\t);\n\t}\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 baseGCDetailsP - Function to get the initial GC details of this node\n */\nexport const createRootSummarizerNodeWithGC = (\n\tlogger: ITelemetryLogger,\n\tsummarizeInternalFn: SummarizeInternalFn,\n\tchangeSequenceNumber: number,\n\treferenceSequenceNumber: number | undefined,\n\tconfig: ISummarizerNodeConfigWithGC = {},\n\tgetGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n): IRootSummarizerNodeWithGC =>\n\tnew SummarizerNodeWithGC(\n\t\tlogger,\n\t\tsummarizeInternalFn,\n\t\tconfig,\n\t\tchangeSequenceNumber,\n\t\treferenceSequenceNumber === undefined\n\t\t\t? undefined\n\t\t\t: SummaryNode.createForRoot(referenceSequenceNumber),\n\t\tundefined /* initialSummary */,\n\t\tundefined /* wipSummaryLogger */,\n\t\tgetGCDataFn,\n\t\tgetBaseGCDetailsFn,\n\t);\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 } from \"@fluidframework/common-utils\";\nimport {\n\tcloneGCData,\n\tgetGCDataFromSnapshot,\n\trunGarbageCollection,\n\tunpackChildNodesGCDetails,\n} from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n\tCreateChildSummarizerNodeParam,\n\tgcTreeKey,\n\tIGarbageCollectionData,\n\tIGarbageCollectionDetailsBase,\n\tISummarizeInternalResult,\n\tISummarizeResult,\n\tISummarizerNodeConfigWithGC,\n\tISummarizerNodeWithGC,\n\tSummarizeInternalFn,\n\tITelemetryContext,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n\tEscapedPath,\n\tICreateChildDetails,\n\tIInitialSummary,\n\tISummarizerNodeRootContract,\n\tparseSummaryForSubtrees,\n\tSummaryNode,\n} from \"./summarizerNodeUtils\";\n\n/**\n * @deprecated Internal implementation detail and will no longer be exported in an\n * upcoming release.\n */\nexport interface IRootSummarizerNodeWithGC\n\textends ISummarizerNodeWithGC,\n\t\tISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n\tconstructor(\n\t\tpublic readonly serializedUsedRoutes: string,\n\t\tsummary: {\n\t\t\treadonly referenceSequenceNumber: number;\n\t\t\treadonly basePath: EscapedPath | undefined;\n\t\t\treadonly localPath: EscapedPath;\n\t\t\tadditionalPath?: EscapedPath;\n\t\t},\n\t) {\n\t\tsuper(summary);\n\t}\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n *\n * - Adds a new API `getGCData` to return GC data of this node.\n *\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n *\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 *\n * - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls\n * directly into summarizeInternal method.\n */\nclass SummarizerNodeWithGC extends SummarizerNode implements IRootSummarizerNodeWithGC {\n\t// Tracks the work-in-progress used routes during summary.\n\tprivate wipSerializedUsedRoutes: string | undefined;\n\n\t// This is the last known used routes of this node as seen by the server as part of a summary.\n\tprivate referenceUsedRoutes: string[] | undefined;\n\n\t// The base GC details of this node used to initialize the GC state.\n\tprivate readonly baseGCDetailsP: LazyPromise<IGarbageCollectionDetailsBase>;\n\n\t// Keeps track of whether we have loaded the base details to ensure that we on;y do it once.\n\tprivate baseGCDetailsLoaded: boolean = false;\n\n\tprivate gcData: IGarbageCollectionData | undefined;\n\n\t// Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n\t// that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n\t// removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n\tprivate usedRoutes: string[] = [\"\"];\n\n\t// True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n\tprivate readonly gcDisabled: boolean;\n\n\t/**\n\t * Do not call constructor directly.\n\t * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n\t */\n\tpublic constructor(\n\t\tlogger: ITelemetryLogger,\n\t\tprivate readonly summarizeFn: (\n\t\t\tfullTree: boolean,\n\t\t\ttrackState: boolean,\n\t\t\ttelemetryContext?: ITelemetryContext,\n\t\t) => Promise<ISummarizeInternalResult>,\n\t\tconfig: ISummarizerNodeConfigWithGC,\n\t\tchangeSequenceNumber: number,\n\t\t/** Undefined means created without summary */\n\t\tlatestSummary?: SummaryNode,\n\t\tinitialSummary?: IInitialSummary,\n\t\twipSummaryLogger?: ITelemetryLogger,\n\t\tprivate readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\t\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n\t\t/** A unique id of this node to be logged when sending telemetry. */\n\t\ttelemetryId?: string,\n\t) {\n\t\tsuper(\n\t\t\tlogger,\n\t\t\tasync (fullTree: boolean, _trackState: boolean, telemetryContext?: ITelemetryContext) =>\n\t\t\t\tsummarizeFn(fullTree, true /* trackState */, telemetryContext),\n\t\t\tconfig,\n\t\t\tchangeSequenceNumber,\n\t\t\tlatestSummary,\n\t\t\tinitialSummary,\n\t\t\twipSummaryLogger,\n\t\t\ttelemetryId,\n\t\t);\n\n\t\tthis.gcDisabled = config.gcDisabled === true;\n\n\t\tthis.baseGCDetailsP = new LazyPromise(async () => {\n\t\t\treturn (await getBaseGCDetailsFn?.()) ?? { usedRoutes: [] };\n\t\t});\n\t}\n\n\t/**\n\t * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n\t * seen by the server for this client:\n\t * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n\t * - gcData: The garbage collection data of this node that is required for running GC.\n\t */\n\tprivate async loadBaseGCDetails() {\n\t\tif (this.baseGCDetailsLoaded) {\n\t\t\treturn;\n\t\t}\n\t\tconst baseGCDetails = await this.baseGCDetailsP;\n\n\t\t// Possible race - If there were parallel calls to loadBaseGCDetails, we want to make sure that we update\n\t\t// the state from the base details only once.\n\t\tif (this.baseGCDetailsLoaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.baseGCDetailsLoaded = true;\n\n\t\t// Update GC data, used routes and reference used routes. The used routes are sorted because they are compared\n\t\t// across GC runs to check if they changed. Sorting ensures that the elements are in the same order.\n\t\t// If the GC details has GC data, initialize our GC data from it.\n\t\tif (baseGCDetails.gcData !== undefined) {\n\t\t\tthis.gcData = cloneGCData(baseGCDetails.gcData);\n\t\t}\n\t\tif (baseGCDetails.usedRoutes !== undefined) {\n\t\t\tthis.usedRoutes = Array.from(baseGCDetails.usedRoutes).sort();\n\t\t\tthis.referenceUsedRoutes = Array.from(baseGCDetails.usedRoutes).sort();\n\t\t}\n\t}\n\n\tpublic async summarize(\n\t\tfullTree: boolean,\n\t\ttrackState: boolean = true,\n\t\ttelemetryContext?: ITelemetryContext,\n\t): Promise<ISummarizeResult> {\n\t\t// If GC is not disabled and a summary is in progress, GC should have run and updated the used routes for this\n\t\t// summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n\t\tif (!this.gcDisabled && this.isSummaryInProgress()) {\n\t\t\tassert(\n\t\t\t\tthis.wipSerializedUsedRoutes !== undefined,\n\t\t\t\t0x1b1 /* \"wip used routes should be set if tracking a summary\" */,\n\t\t\t);\n\t\t}\n\n\t\t// If trackState is true, get summary from base summarizer node which tracks summary state.\n\t\t// If trackState is false, get summary from summarizeInternal.\n\t\treturn trackState\n\t\t\t? super.summarize(fullTree, true /* trackState */, telemetryContext)\n\t\t\t: this.summarizeFn(fullTree, trackState, telemetryContext);\n\t}\n\n\t/**\n\t * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n\t * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n\t * @param fullGC - true to bypass optimizations and force full generation of GC data.\n\t */\n\tpublic async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n\t\tassert(\n\t\t\t!this.gcDisabled,\n\t\t\t0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */,\n\t\t);\n\t\tassert(\n\t\t\tthis.getGCDataFn !== undefined,\n\t\t\t0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */,\n\t\t);\n\n\t\t// Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n\t\t// called and the node's data has not changed since last summary, the GC data in initial details is returned.\n\t\tawait this.loadBaseGCDetails();\n\n\t\t// If there is no new data since last summary and we have GC data from the previous run, return it. The previous\n\t\t// GC data may not be available if loaded from a snapshot with either GC disabled or before GC was added.\n\t\t// Note - canReuseHandle is checked to be consistent with summarize - generate GC data for nodes for which\n\t\t// summary must be generated.\n\t\tif (this.canReuseHandle && !fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n\t\t\treturn cloneGCData(this.gcData);\n\t\t}\n\n\t\tconst gcData = await this.getGCDataFn(fullGC);\n\t\tthis.gcData = cloneGCData(gcData);\n\t\treturn gcData;\n\t}\n\n\t/**\n\t * Called during the start of a summary. Updates the work-in-progress used routes.\n\t */\n\tpublic startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n\t\t// If GC is disabled, skip setting wip used routes since we should not track GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tassert(\n\t\t\t\tthis.wipSerializedUsedRoutes === undefined,\n\t\t\t\t0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */,\n\t\t\t);\n\t\t}\n\t\tsuper.startSummary(referenceSequenceNumber, summaryLogger);\n\t}\n\n\t/**\n\t * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n\t * summary queue. We track this until we get an ack from the server for this summary.\n\t */\n\tprotected completeSummaryCore(\n\t\tproposalHandle: string,\n\t\tparentPath: EscapedPath | undefined,\n\t\tparentSkipRecursion: boolean,\n\t) {\n\t\tlet wipSerializedUsedRoutes: string | undefined;\n\t\t// If GC is disabled, don't set wip used routes.\n\t\tif (!this.gcDisabled) {\n\t\t\twipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n\t\t\t/**\n\t\t\t * The absence of wip used routes indicates that GC was not run on this node. This can happen if:\n\t\t\t * 1. A child node was created after GC was already run on the parent. For example, a data store\n\t\t\t * is realized (loaded) after GC was run on it creating summarizer nodes for its DDSes. In this\n\t\t\t * case, the used routes of the parent should be passed on the child nodes and it should be fine.\n\t\t\t * 2. A new node was created but GC was never run on it. This can mean that the GC data generated\n\t\t\t * during summarize is complete . We should not continue, log and throw an error. This will help us\n\t\t\t * identify these cases and take appropriate action.\n\t\t\t */\n\t\t\tif (wipSerializedUsedRoutes === undefined) {\n\t\t\t\tthis.throwUnexpectedError({\n\t\t\t\t\teventName: \"NodeDidNotRunGC\",\n\t\t\t\t\tproposalHandle,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tsuper.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n\t\t// If GC is disabled, skip setting pending summary with GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tconst summaryNode = this.pendingSummaries.get(proposalHandle);\n\t\t\tif (summaryNode !== undefined) {\n\t\t\t\tconst summaryNodeWithGC = new SummaryNodeWithGC(\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\twipSerializedUsedRoutes!,\n\t\t\t\t\tsummaryNode,\n\t\t\t\t);\n\t\t\t\tthis.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clears the work-in-progress state.\n\t */\n\tpublic clearSummary() {\n\t\tthis.wipSerializedUsedRoutes = undefined;\n\t\tsuper.clearSummary();\n\t}\n\n\t/**\n\t * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n\t * from the state in the pending summary queue.\n\t */\n\tprotected refreshLatestSummaryFromPending(\n\t\tproposalHandle: string,\n\t\treferenceSequenceNumber: number,\n\t): void {\n\t\t// If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n\t\tif (!this.gcDisabled) {\n\t\t\tconst summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n\t\t\tif (summaryNode?.serializedUsedRoutes !== undefined) {\n\t\t\t\tthis.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n\t\t\t}\n\t\t}\n\n\t\treturn super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n\t}\n\n\t/**\n\t * Called when we need to upload the reference state from the given summary.\n\t */\n\tprotected async refreshLatestSummaryFromSnapshot(\n\t\treferenceSequenceNumber: number,\n\t\tsnapshotTree: ISnapshotTree,\n\t\tbasePath: EscapedPath | undefined,\n\t\tlocalPath: EscapedPath,\n\t\tcorrelatedSummaryLogger: ITelemetryLogger,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<void> {\n\t\tawait this.refreshGCStateFromSnapshot(\n\t\t\treferenceSequenceNumber,\n\t\t\tsnapshotTree,\n\t\t\treadAndParseBlob,\n\t\t);\n\t\treturn super.refreshLatestSummaryFromSnapshot(\n\t\t\treferenceSequenceNumber,\n\t\t\tsnapshotTree,\n\t\t\tbasePath,\n\t\t\tlocalPath,\n\t\t\tcorrelatedSummaryLogger,\n\t\t\treadAndParseBlob,\n\t\t);\n\t}\n\n\t/**\n\t * Updates GC state from the given snapshot if GC is enabled and the snapshot is newer than the one this node\n\t * is tracking.\n\t */\n\tprivate async refreshGCStateFromSnapshot(\n\t\treferenceSequenceNumber: number,\n\t\tsnapshotTree: ISnapshotTree,\n\t\treadAndParseBlob: ReadAndParseBlob,\n\t): Promise<void> {\n\t\t// If GC is disabled or we have seen a newer summary, skip updating GC state.\n\t\tif (this.gcDisabled || this.referenceSequenceNumber >= referenceSequenceNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Load the base GC details before proceeding because if that happens later it can overwrite the GC details\n\t\t// written by the following code.\n\t\tawait this.loadBaseGCDetails();\n\n\t\t// Possible re-entrancy. We may already have processed this while loading base GC details.\n\t\tif (this.referenceSequenceNumber >= referenceSequenceNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\t/**\n\t\t * GC data is written at root of the snapshot tree under \"gc\" sub-tree. This data needs to be propagated to\n\t\t * all the nodes in the container.\n\t\t * The root summarizer node reads the GC data from the \"gc\" sub-tree, runs GC on it to get used routes in\n\t\t * the container and updates its GC data and referenced used routes. It then gets the GC data and used\n\t\t * routes of all its children and adds it to their snapshot tree.\n\t\t * All the other nodes gets the GC data and used routes from their snapshot tree and updates their state.\n\t\t * They get the GC data and used routes of their children and add it to their snapshot tree and so on.\n\t\t *\n\t\t * Note that if the snapshot does not have GC tree, GC data will be set to undefined and used routes will be\n\t\t * set to self-route (meaning referenced) for all nodes. This is important because the GC data needs to be\n\t\t * regenerated in the next summary.\n\t\t */\n\t\tlet gcDetails: IGarbageCollectionDetailsBase | undefined;\n\t\tconst gcSnapshotTree = snapshotTree.trees[gcTreeKey];\n\t\tif (gcSnapshotTree !== undefined) {\n\t\t\t// If there is a GC tree in the snapshot, this is the root summarizer node. Read GC data from the tree\n\t\t\t// process it as explained above.\n\t\t\tconst gcSnapshotData = await getGCDataFromSnapshot(gcSnapshotTree, readAndParseBlob);\n\n\t\t\tconst gcNodes: { [id: string]: string[] } = {};\n\t\t\tfor (const [nodeId, nodeData] of Object.entries(gcSnapshotData.gcState.gcNodes)) {\n\t\t\t\tgcNodes[nodeId] = Array.from(nodeData.outboundRoutes);\n\t\t\t}\n\t\t\t// Run GC on the nodes in the snapshot to get the used routes for each node in the container.\n\t\t\tconst usedRoutes = runGarbageCollection(gcNodes, [\"/\"]).referencedNodeIds;\n\t\t\tgcDetails = { gcData: { gcNodes }, usedRoutes };\n\t\t} else {\n\t\t\t// If there is a GC blob in the snapshot, it's a non-root summarizer nodes - The root summarizer node\n\t\t\t// writes GC blob in the snapshot of child nodes. Get GC data and used routes from the blob.\n\t\t\tconst gcDetailsBlob = snapshotTree.blobs[gcTreeKey];\n\t\t\tif (gcDetailsBlob !== undefined) {\n\t\t\t\tgcDetails = JSON.parse(gcDetailsBlob) as IGarbageCollectionDetailsBase;\n\t\t\t}\n\t\t}\n\n\t\t// Update this node to the same GC state it was when the ack corresponding to this summary was processed.\n\t\tthis.gcData = gcDetails?.gcData !== undefined ? cloneGCData(gcDetails.gcData) : undefined;\n\t\tthis.referenceUsedRoutes =\n\t\t\tgcDetails?.usedRoutes !== undefined ? Array.from(gcDetails.usedRoutes) : undefined;\n\t\t// If there are no used routes in the GC details, set it to have self route which will make the node\n\t\t// referenced. This scenario can only happen if the snapshot is from a client where GC was not run or\n\t\t// disabled. In both the cases, the node should be referenced.\n\t\tthis.usedRoutes =\n\t\t\tgcDetails?.usedRoutes !== undefined ? Array.from(gcDetails.usedRoutes) : [\"\"];\n\n\t\tif (gcDetails === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Generate the GC data and used routes of children GC nodes and add it to their snapshot tree.\n\t\tconst gcDetailsMap = unpackChildNodesGCDetails(gcDetails);\n\t\tconst { childrenTree } = parseSummaryForSubtrees(snapshotTree);\n\t\tgcDetailsMap.forEach((childGCDetails: IGarbageCollectionDetailsBase, childId: string) => {\n\t\t\tif (childrenTree.trees[childId] !== undefined) {\n\t\t\t\tchildrenTree.trees[childId].blobs[gcTreeKey] = JSON.stringify(childGCDetails);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Override the createChild method to return an instance of SummarizerNodeWithGC.\n\t */\n\tpublic createChild(\n\t\t/** Summarize function */\n\t\tsummarizeInternalFn: SummarizeInternalFn,\n\t\t/** Initial id or path part of this node */\n\t\tid: string,\n\t\t/**\n\t\t * Information needed to create the node.\n\t\t * If it is from a base summary, it will assert that a summary has been seen.\n\t\t * Attach information if it is created from an attach op.\n\t\t */\n\t\tcreateParam: CreateChildSummarizerNodeParam,\n\t\tconfig: ISummarizerNodeConfigWithGC = {},\n\t\tgetGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\t\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n\t): ISummarizerNodeWithGC {\n\t\tassert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n\t\t/**\n\t\t * Update the child node's base GC details from this node's current GC details instead of updating from the base\n\t\t * GC details of this node. This will handle scenarios where the GC details was updated during refresh from\n\t\t * snapshot and the child node wasn't created then. If a child is created after that, its GC details should be\n\t\t * the one from the downloaded snapshot and not the base GC details.\n\t\t */\n\t\tconst getChildBaseGCDetailsP = new LazyPromise<IGarbageCollectionDetailsBase>(async () => {\n\t\t\t// Ensure that the base GC details is loaded because a child can be created before GC runs which is when\n\t\t\t// base GC details is usually loaded.\n\t\t\tawait this.loadBaseGCDetails();\n\t\t\tconst childBaseGCDetails = unpackChildNodesGCDetails({\n\t\t\t\tgcData: this.gcData,\n\t\t\t\tusedRoutes: this.usedRoutes,\n\t\t\t});\n\t\t\treturn childBaseGCDetails.get(id) ?? {};\n\t\t});\n\n\t\tconst createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n\t\tconst child = new SummarizerNodeWithGC(\n\t\t\tthis.logger,\n\t\t\tsummarizeInternalFn,\n\t\t\t{\n\t\t\t\t...config,\n\t\t\t\t// Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n\t\t\t\tgcDisabled: config.gcDisabled ?? this.gcDisabled,\n\t\t\t},\n\t\t\tcreateDetails.changeSequenceNumber,\n\t\t\tcreateDetails.latestSummary,\n\t\t\tcreateDetails.initialSummary,\n\t\t\tthis.wipSummaryLogger,\n\t\t\tgetGCDataFn,\n\t\t\tasync () => getChildBaseGCDetailsP,\n\t\t\tcreateDetails.telemetryNodeId,\n\t\t);\n\n\t\t// There may be additional state that has to be updated in this child. For example, if a summary is being\n\t\t// tracked, the child's summary tracking state needs to be updated too.\n\t\tthis.maybeUpdateChildState(child);\n\n\t\tthis.children.set(id, child);\n\t\treturn child;\n\t}\n\n\t/**\n\t * Deletes the child node with the given id.\n\t */\n\tpublic deleteChild(id: string): void {\n\t\tthis.children.delete(id);\n\t}\n\n\t/**\n\t * Override the getChild method to return an instance of SummarizerNodeWithGC.\n\t */\n\tpublic getChild(id: string): ISummarizerNodeWithGC | undefined {\n\t\treturn this.children.get(id) as SummarizerNodeWithGC;\n\t}\n\n\tpublic isReferenced(): boolean {\n\t\treturn this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n\t}\n\n\tpublic updateUsedRoutes(usedRoutes: string[]) {\n\t\t// Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n\t\t// are in the same order.\n\t\tthis.usedRoutes = usedRoutes.sort();\n\n\t\t// If GC is not disabled and a summary is in progress, update the work-in-progress used routes so that it can\n\t\t// be tracked for this summary.\n\t\tif (!this.gcDisabled && this.isSummaryInProgress()) {\n\t\t\tthis.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n\t\t}\n\t}\n\n\t/**\n\t * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n\t */\n\tprotected hasChanged(): boolean {\n\t\treturn this.hasDataChanged() || this.hasUsedStateChanged();\n\t}\n\n\t/**\n\t * This tells whether the data in this node has changed or not.\n\t */\n\tprivate hasDataChanged(): boolean {\n\t\treturn super.hasChanged();\n\t}\n\n\t/**\n\t * This tells whether the used state of this node has changed since last successful summary. If the used routes\n\t * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n\t * was previously used and became unused (or vice versa), its used state has changed.\n\t */\n\tprivate hasUsedStateChanged(): boolean {\n\t\t// If GC is disabled, we are not tracking used state, return false.\n\t\tif (this.gcDisabled) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (\n\t\t\tthis.referenceUsedRoutes === undefined ||\n\t\t\tJSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes)\n\t\t);\n\t}\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 baseGCDetailsP - Function to get the initial GC details of this node\n *\n * @deprecated Internal implementation detail and will no longer be exported in an\n * upcoming release.\n */\nexport const createRootSummarizerNodeWithGC = (\n\tlogger: ITelemetryLogger,\n\tsummarizeInternalFn: SummarizeInternalFn,\n\tchangeSequenceNumber: number,\n\treferenceSequenceNumber: number | undefined,\n\tconfig: ISummarizerNodeConfigWithGC = {},\n\tgetGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n\tgetBaseGCDetailsFn?: () => Promise<IGarbageCollectionDetailsBase>,\n): IRootSummarizerNodeWithGC =>\n\tnew SummarizerNodeWithGC(\n\t\tlogger,\n\t\tsummarizeInternalFn,\n\t\tconfig,\n\t\tchangeSequenceNumber,\n\t\treferenceSequenceNumber === undefined\n\t\t\t? undefined\n\t\t\t: SummaryNode.createForRoot(referenceSequenceNumber),\n\t\tundefined /* initialSummary */,\n\t\tundefined /* wipSummaryLogger */,\n\t\tgetGCDataFn,\n\t\tgetBaseGCDetailsFn,\n\t\t\"\" /* telemetryId */,\n\t);\n"]}
|
package/dist/summaryUtils.d.ts
CHANGED
|
@@ -59,6 +59,10 @@ export declare class TelemetryContext implements ITelemetryContext {
|
|
|
59
59
|
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.set}
|
|
60
60
|
*/
|
|
61
61
|
set(prefix: string, property: string, value: TelemetryEventPropertyType): void;
|
|
62
|
+
/**
|
|
63
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.setMultiple}
|
|
64
|
+
*/
|
|
65
|
+
setMultiple(prefix: string, property: string, values: Record<string, TelemetryEventPropertyType>): void;
|
|
62
66
|
/**
|
|
63
67
|
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.get}
|
|
64
68
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summaryUtils.d.ts","sourceRoot":"","sources":["../src/summaryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAShF,OAAO,EACN,KAAK,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,YAAY,EAGZ,aAAa,EACb,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACN,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,MAAM,qCAAqC,CAAC;AAE7C;;;;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,CAEpE;AAyBD,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAIpE;AAED,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,qBAAqB,EAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GAAG,UAAU,GAC1B,IAAI,CAQN;AAED,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,qBAAqB,EAC9B,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,gBAAgB,GAC/B,IAAI,CAGN;AAED,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,qBAAqB,EAC9B,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,gBAAgB,GAC/B,IAAI,CAGN;AAED,qBAAa,kBAAmB,YAAW,qBAAqB;IAC/D,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;IAexD,SAAS,CACf,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,UAAU,EACxE,MAAM,EAAE,MAAM,GACZ,IAAI;IASA,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,gBAAgB,GAAG,IAAI;IAKlE,aAAa,CAAC,EAAE,EAAE,MAAM;IAIxB,cAAc,IAAI,qBAAqB;CAG9C;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,QAAQ,EAAE,KAAK,EACf,QAAQ,GAAE,OAAe,GACvB,qBAAqB,CAoCvB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAE,OAAe,GAAG,gBAAgB,CAgBjG;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,aAAa,GAAG,qBAAqB,CA2B/F;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAuC1E;AAED,qBAAa,gBAAiB,YAAW,iBAAiB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiD;IAE3E;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,0BAA0B,GAAG,IAAI;IAI9E;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,0BAA0B;IAIjE;;OAEG;IACH,SAAS,IAAI,MAAM;CAOnB"}
|
|
1
|
+
{"version":3,"file":"summaryUtils.d.ts","sourceRoot":"","sources":["../src/summaryUtils.ts"],"names":[],"mappings":"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"}
|
package/dist/summaryUtils.js
CHANGED
|
@@ -292,6 +292,15 @@ class TelemetryContext {
|
|
|
292
292
|
set(prefix, property, value) {
|
|
293
293
|
this.telemetry.set(`${prefix}${property}`, value);
|
|
294
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.setMultiple}
|
|
297
|
+
*/
|
|
298
|
+
setMultiple(prefix, property, values) {
|
|
299
|
+
// Set the values individually so that they are logged as a flat list along with other properties.
|
|
300
|
+
for (const key of Object.keys(values)) {
|
|
301
|
+
this.set(prefix, `${property}_${key}`, values[key]);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
295
304
|
/**
|
|
296
305
|
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.get}
|
|
297
306
|
*/
|