@fluidframework/runtime-utils 0.51.3 → 0.53.0-46105
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/dataStoreHelpers.d.ts +2 -3
- package/dist/dataStoreHelpers.d.ts.map +1 -1
- package/dist/dataStoreHelpers.js +18 -31
- package/dist/dataStoreHelpers.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/remoteObjectHandle.d.ts +0 -4
- package/dist/remoteObjectHandle.d.ts.map +1 -1
- package/dist/remoteObjectHandle.js +2 -7
- package/dist/remoteObjectHandle.js.map +1 -1
- package/dist/summarizerNode/summarizerNode.js +5 -4
- package/dist/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeUtils.js +2 -1
- package/dist/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts +1 -13
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summarizerNode/summarizerNodeWithGc.js +3 -73
- package/dist/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summaryUtils.js +14 -14
- package/dist/summaryUtils.js.map +1 -1
- package/lib/dataStoreHelpers.d.ts +2 -3
- package/lib/dataStoreHelpers.d.ts.map +1 -1
- package/lib/dataStoreHelpers.js +17 -29
- package/lib/dataStoreHelpers.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/remoteObjectHandle.d.ts +0 -4
- package/lib/remoteObjectHandle.d.ts.map +1 -1
- package/lib/remoteObjectHandle.js +2 -7
- package/lib/remoteObjectHandle.js.map +1 -1
- package/lib/summarizerNode/summarizerNode.js +5 -4
- package/lib/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeUtils.js +2 -1
- package/lib/summarizerNode/summarizerNodeUtils.js.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts +1 -13
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summarizerNode/summarizerNodeWithGc.js +4 -74
- package/lib/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summaryUtils.js +15 -15
- package/lib/summaryUtils.js.map +1 -1
- package/package.json +12 -11
- package/src/dataStoreHelpers.ts +26 -30
- package/src/packageVersion.ts +1 -1
- package/src/remoteObjectHandle.ts +7 -12
- package/src/summarizerNode/summarizerNodeWithGc.ts +3 -92
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
|
-
import {
|
|
6
|
+
import { ISnapshotTree } from "@fluidframework/protocol-definitions";
|
|
7
7
|
import { CreateChildSummarizerNodeParam, IGarbageCollectionData, IGarbageCollectionSummaryDetails, ISummarizeInternalResult, ISummarizeResult, ISummarizerNodeConfigWithGC, ISummarizerNodeWithGC } from "@fluidframework/runtime-definitions";
|
|
8
8
|
import { ReadAndParseBlob } from "../utils";
|
|
9
9
|
import { SummarizerNode } from "./summarizerNode";
|
|
@@ -28,11 +28,7 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
28
28
|
private gcData;
|
|
29
29
|
private usedRoutes;
|
|
30
30
|
private unreferencedTimestampMs;
|
|
31
|
-
private readonly maxUnreferencedDurationMs;
|
|
32
|
-
private readonly unreferencedTimer;
|
|
33
|
-
private inactive;
|
|
34
31
|
private readonly gcDisabled;
|
|
35
|
-
private useAfterFreeErrorLogged;
|
|
36
32
|
/**
|
|
37
33
|
* Do not call constructor directly.
|
|
38
34
|
* Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.
|
|
@@ -102,14 +98,6 @@ export declare class SummarizerNodeWithGC extends SummarizerNode implements IRoo
|
|
|
102
98
|
getChild(id: string): ISummarizerNodeWithGC | undefined;
|
|
103
99
|
isReferenced(): boolean;
|
|
104
100
|
updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number): void;
|
|
105
|
-
recordChange(op: ISequencedDocumentMessage): void;
|
|
106
|
-
/**
|
|
107
|
-
* Logs an error event if the node is inactive. This is used to identify cases where an inactive object is used.
|
|
108
|
-
* @param eventName - The name of the event to log.
|
|
109
|
-
* @param currentTimestampMs - The current time stamp. Used to report how long the object has been inactive.
|
|
110
|
-
* @returns true if we logged an error, false otherwise.
|
|
111
|
-
*/
|
|
112
|
-
private logErrorIfInactive;
|
|
113
101
|
/**
|
|
114
102
|
* Override the hasChanged method. If this node data or its used state changed, the node is considered changed.
|
|
115
103
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeWithGc.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAGtE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"summarizerNodeWithGc.d.ts","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,6 @@ const garbage_collector_1 = require("@fluidframework/garbage-collector");
|
|
|
10
10
|
const runtime_definitions_1 = require("@fluidframework/runtime-definitions");
|
|
11
11
|
const summarizerNode_1 = require("./summarizerNode");
|
|
12
12
|
const summarizerNodeUtils_1 = require("./summarizerNodeUtils");
|
|
13
|
-
const defaultMaxUnreferencedDurationMs = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
14
13
|
// Extend SummaryNode to add used routes tracking to it.
|
|
15
14
|
class SummaryNodeWithGC extends summarizerNodeUtils_1.SummaryNode {
|
|
16
15
|
constructor(serializedUsedRoutes, summary) {
|
|
@@ -35,7 +34,6 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
35
34
|
constructor(logger, summarizeFn, config, changeSequenceNumber,
|
|
36
35
|
/** Undefined means created without summary */
|
|
37
36
|
latestSummary, initialSummary, wipSummaryLogger, getGCDataFn, getInitialGCSummaryDetailsFn) {
|
|
38
|
-
var _a;
|
|
39
37
|
super(logger, async (fullTree) => summarizeFn(fullTree, true /* trackState */), config, changeSequenceNumber, latestSummary, initialSummary, wipSummaryLogger);
|
|
40
38
|
this.summarizeFn = summarizeFn;
|
|
41
39
|
this.getGCDataFn = getGCDataFn;
|
|
@@ -43,20 +41,11 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
43
41
|
// that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is
|
|
44
42
|
// removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.
|
|
45
43
|
this.usedRoutes = [""];
|
|
46
|
-
// Tracks whether this node is inactive after being unreferenced for maxUnreferencedDurationMs.
|
|
47
|
-
this.inactive = false;
|
|
48
|
-
// Keeps track of whether we logged an use-after-free error. This is temporary since the error is too noisy.
|
|
49
|
-
// To be removed once this item is completed - https://github.com/microsoft/FluidFramework/issues/7895.
|
|
50
|
-
this.useAfterFreeErrorLogged = false;
|
|
51
44
|
this.gcDisabled = config.gcDisabled === true;
|
|
52
|
-
this.maxUnreferencedDurationMs = (_a = config.maxUnreferencedDurationMs) !== null && _a !== void 0 ? _a : defaultMaxUnreferencedDurationMs;
|
|
53
45
|
this.gcDetailsInInitialSummaryP = new common_utils_1.LazyPromise(async () => {
|
|
54
46
|
const gcSummaryDetails = await (getInitialGCSummaryDetailsFn === null || getInitialGCSummaryDetailsFn === void 0 ? void 0 : getInitialGCSummaryDetailsFn());
|
|
55
47
|
return gcSummaryDetails !== null && gcSummaryDetails !== void 0 ? gcSummaryDetails : { usedRoutes: [] };
|
|
56
48
|
});
|
|
57
|
-
this.unreferencedTimer = new common_utils_1.Timer(this.maxUnreferencedDurationMs, () => {
|
|
58
|
-
this.inactive = true;
|
|
59
|
-
});
|
|
60
49
|
}
|
|
61
50
|
// Returns the GC details that may be added to this node's summary.
|
|
62
51
|
getGCSummaryDetails() {
|
|
@@ -203,12 +192,12 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
203
192
|
* Attach information if it is created from an attach op.
|
|
204
193
|
*/
|
|
205
194
|
createParam, config = {}, getGCDataFn, getInitialGCSummaryDetailsFn) {
|
|
206
|
-
var _a
|
|
195
|
+
var _a;
|
|
207
196
|
common_utils_1.assert(!this.children.has(id), 0x1b6 /* "Create SummarizerNode child already exists" */);
|
|
208
197
|
const createDetails = this.getCreateDetailsForChild(id, createParam);
|
|
209
198
|
const child = new SummarizerNodeWithGC(this.defaultLogger, summarizeInternalFn, Object.assign(Object.assign({}, config), {
|
|
210
199
|
// Propagate our gcDisabled state to the child if its not explicity specified in child's config.
|
|
211
|
-
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled
|
|
200
|
+
gcDisabled: (_a = config.gcDisabled) !== null && _a !== void 0 ? _a : this.gcDisabled }), createDetails.changeSequenceNumber, createDetails.latestSummary, createDetails.initialSummary, this.wipSummaryLogger, getGCDataFn, getInitialGCSummaryDetailsFn);
|
|
212
201
|
// There may be additional state that has to be updated in this child. For example, if a summary is being
|
|
213
202
|
// tracked, the child's summary tracking state needs to be updated too.
|
|
214
203
|
this.maybeUpdateChildState(child);
|
|
@@ -240,72 +229,13 @@ class SummarizerNodeWithGC extends summarizerNode_1.SummarizerNode {
|
|
|
240
229
|
this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);
|
|
241
230
|
}
|
|
242
231
|
if (this.isReferenced()) {
|
|
243
|
-
// If this node has been unreferenced for longer than maxUnreferencedDurationMs and is being referenced,
|
|
244
|
-
// log an error as this may mean the maxUnreferencedDurationMs is not long enough.
|
|
245
|
-
this.logErrorIfInactive("inactiveObjectRevived", gcTimestamp);
|
|
246
|
-
// Clear unreferenced / inactive state, if any.
|
|
247
|
-
this.inactive = false;
|
|
248
232
|
this.unreferencedTimestampMs = undefined;
|
|
249
|
-
this.unreferencedTimer.clear();
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
// This node is unreferenced. We need to check if this node is inative or if we need to start the unreferenced
|
|
253
|
-
// timer which would mark the node as inactive.
|
|
254
|
-
// If there is no timestamp when GC was run, we don't have enough information to determine whether this content
|
|
255
|
-
// should become inactive.
|
|
256
|
-
if (gcTimestamp === undefined) {
|
|
257
233
|
return;
|
|
258
234
|
}
|
|
259
|
-
// If
|
|
260
|
-
// and start the unreferenced timer.
|
|
261
|
-
// Note that it's possible this node has been unreferenced before but the unreferencedTimestampMs was not added.
|
|
262
|
-
// For example, older versions where this concept did not exist or if gcTimestamp wasn't available. In such
|
|
263
|
-
// cases, we track them as if the content just became unreferenced.
|
|
235
|
+
// If this node just became unreferenced, update its unreferencedTimestampMs.
|
|
264
236
|
if (this.unreferencedTimestampMs === undefined) {
|
|
265
237
|
this.unreferencedTimestampMs = gcTimestamp;
|
|
266
|
-
this.unreferencedTimer.start();
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
// If we are here, this node was unreferenced earlier.
|
|
270
|
-
// If it is already inactive or has an unreferenced timer running, there is no more work to be done.
|
|
271
|
-
if (this.inactive || this.unreferencedTimer.hasTimer) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
// If it has been unreferenced longer than maxUnreferencedDurationMs, mark it as inactive. Otherwise, start the
|
|
275
|
-
// unreferenced timer for the duration left for it to reach maxUnreferencedDurationMs.
|
|
276
|
-
const currentUnreferencedDurationMs = gcTimestamp - this.unreferencedTimestampMs;
|
|
277
|
-
if (currentUnreferencedDurationMs >= this.maxUnreferencedDurationMs) {
|
|
278
|
-
this.inactive = true;
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
this.unreferencedTimer.start(this.maxUnreferencedDurationMs - currentUnreferencedDurationMs);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
recordChange(op) {
|
|
285
|
-
// If the node is changed after it is inactive, log an error as this may mean use-after-delete.
|
|
286
|
-
// Currently, we only log this error once per node per session as it's too noisy.
|
|
287
|
-
if (!this.useAfterFreeErrorLogged && this.logErrorIfInactive("inactiveObjectChanged")) {
|
|
288
|
-
this.useAfterFreeErrorLogged = true;
|
|
289
|
-
}
|
|
290
|
-
super.recordChange(op);
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Logs an error event if the node is inactive. This is used to identify cases where an inactive object is used.
|
|
294
|
-
* @param eventName - The name of the event to log.
|
|
295
|
-
* @param currentTimestampMs - The current time stamp. Used to report how long the object has been inactive.
|
|
296
|
-
* @returns true if we logged an error, false otherwise.
|
|
297
|
-
*/
|
|
298
|
-
logErrorIfInactive(eventName, currentTimestampMs) {
|
|
299
|
-
if (this.inactive) {
|
|
300
|
-
common_utils_1.assert(this.unreferencedTimestampMs !== undefined, 0x271 /* "Node should not become inactive without setting unreferencedTimestampMs first" */);
|
|
301
|
-
this.defaultLogger.sendErrorEvent({
|
|
302
|
-
eventName,
|
|
303
|
-
unreferencedDuratonMs: (currentTimestampMs !== null && currentTimestampMs !== void 0 ? currentTimestampMs : Date.now()) - this.unreferencedTimestampMs,
|
|
304
|
-
maxUnreferencedDurationMs: this.maxUnreferencedDurationMs,
|
|
305
|
-
});
|
|
306
|
-
return true;
|
|
307
238
|
}
|
|
308
|
-
return false;
|
|
309
239
|
}
|
|
310
240
|
/**
|
|
311
241
|
* Override the hasChanged method. If this node data or its used state changed, the node is considered changed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizerNodeWithGc.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, LazyPromise, Timer } from \"@fluidframework/common-utils\";\nimport { cloneGCData } from \"@fluidframework/garbage-collector\";\nimport { ISequencedDocumentMessage, ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n CreateChildSummarizerNodeParam,\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionSummaryDetails,\n ISummarizeInternalResult,\n ISummarizeResult,\n ISummarizerNodeConfigWithGC,\n ISummarizerNodeWithGC,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n EscapedPath,\n ICreateChildDetails,\n IInitialSummary,\n ISummarizerNodeRootContract,\n SummaryNode,\n} from \"./summarizerNodeUtils\";\n\nconst defaultMaxUnreferencedDurationMs = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n constructor(\n public readonly serializedUsedRoutes: string,\n summary: {\n readonly referenceSequenceNumber: number,\n readonly basePath: EscapedPath | undefined,\n readonly localPath: EscapedPath,\n additionalPath?: EscapedPath,\n },\n ) {\n super(summary);\n }\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n * - Adds a new API `getGCData` to return GC data of this node.\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n * - Manages the used routes of this node. These are used to identify if this node is referenced in the document\n * and to determine if the node's used state changed since last summary.\n * - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls\n * directly into summarizeInternal method.\n */\nexport class SummarizerNodeWithGC extends SummarizerNode implements IRootSummarizerNodeWithGC {\n // Tracks the work-in-progress used routes during summary.\n private wipSerializedUsedRoutes: string | undefined;\n\n // This is the last known used routes of this node as seen by the server as part of a summary.\n private referenceUsedRoutes: string[] | undefined;\n\n // The GC details of this node in the initial summary.\n private gcDetailsInInitialSummaryP: LazyPromise<IGarbageCollectionSummaryDetails> | undefined;\n\n private gcData: IGarbageCollectionData | undefined;\n\n // Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n // that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n // removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n private usedRoutes: string[] = [\"\"];\n\n // If this node is marked as unreferenced, the time when it marked as such.\n private unreferencedTimestampMs: number | undefined;\n\n // The max duration for which this node can be unreferenced before it is eligible for deletion.\n private readonly maxUnreferencedDurationMs: number;\n\n // The timer that runs when the node is marked unreferenced.\n private readonly unreferencedTimer: Timer;\n\n // Tracks whether this node is inactive after being unreferenced for maxUnreferencedDurationMs.\n private inactive: boolean = false;\n\n // True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n private readonly gcDisabled: boolean;\n\n // Keeps track of whether we logged an use-after-free error. This is temporary since the error is too noisy.\n // To be removed once this item is completed - https://github.com/microsoft/FluidFramework/issues/7895.\n private useAfterFreeErrorLogged: boolean = false;\n\n /**\n * Do not call constructor directly.\n * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n */\n public constructor(\n logger: ITelemetryLogger,\n private readonly summarizeFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n config: ISummarizerNodeConfigWithGC,\n changeSequenceNumber: number,\n /** Undefined means created without summary */\n latestSummary?: SummaryNode,\n initialSummary?: IInitialSummary,\n wipSummaryLogger?: ITelemetryLogger,\n private readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ) {\n super(\n logger,\n async (fullTree: boolean) => summarizeFn(fullTree, true /* trackState */),\n config,\n changeSequenceNumber,\n latestSummary,\n initialSummary,\n wipSummaryLogger,\n );\n\n this.gcDisabled = config.gcDisabled === true;\n this.maxUnreferencedDurationMs = config.maxUnreferencedDurationMs ?? defaultMaxUnreferencedDurationMs;\n\n this.gcDetailsInInitialSummaryP = new LazyPromise(async () => {\n const gcSummaryDetails = await getInitialGCSummaryDetailsFn?.();\n return gcSummaryDetails ?? { usedRoutes: [] };\n });\n\n this.unreferencedTimer = new Timer(this.maxUnreferencedDurationMs, () => {\n this.inactive = true;\n });\n }\n\n // Returns the GC details that may be added to this node's summary.\n public getGCSummaryDetails(): IGarbageCollectionSummaryDetails {\n return {\n gcData: this.gcData,\n usedRoutes: this.usedRoutes,\n unrefTimestamp: this.unreferencedTimestampMs,\n };\n }\n\n /**\n * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n * seen by the server for this client:\n * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n * - gcData: The garbage collection data of this node that is required for running GC.\n */\n private async loadInitialGCSummaryDetails() {\n if (this.gcDetailsInInitialSummaryP === undefined) {\n return;\n }\n\n const gcDetailsInInitialSummaryP = this.gcDetailsInInitialSummaryP;\n this.gcDetailsInInitialSummaryP = undefined;\n\n const gcDetailsInInitialSummary = await gcDetailsInInitialSummaryP;\n // If the GC details has GC data, initialize our GC data from it.\n if (gcDetailsInInitialSummary.gcData !== undefined) {\n this.gcData = cloneGCData(gcDetailsInInitialSummary.gcData);\n }\n this.referenceUsedRoutes = gcDetailsInInitialSummary.usedRoutes;\n this.unreferencedTimestampMs = gcDetailsInInitialSummary.unrefTimestamp;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean = true): Promise<ISummarizeResult> {\n // If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this\n // summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n assert(this.wipSerializedUsedRoutes !== undefined,\n 0x1b1 /* \"wip used routes should be set if tracking a summary\" */);\n }\n\n // If trackState is true, get summary from base summarizer node which tracks summary state.\n // If trackState is false, get summary from summarizeInternal.\n return trackState ? super.summarize(fullTree) : this.summarizeFn(fullTree, trackState);\n }\n\n /**\n * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n assert(!this.gcDisabled, 0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */);\n assert(this.getGCDataFn !== undefined, 0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */);\n\n // Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n // called and the node's data has not changed since last summary, the GC data in initial details is returned.\n await this.loadInitialGCSummaryDetails();\n\n // If there is no new data since last summary and we have GC data from the previous run, return it. We may not\n // have data from previous GC run for clients with older summary format before GC was added. They won't have\n // GC details in their initial summary.\n if (!fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n return cloneGCData(this.gcData);\n }\n\n const gcData = await this.getGCDataFn(fullGC);\n this.gcData = cloneGCData(gcData);\n return gcData;\n }\n\n /**\n * Called during the start of a summary. Updates the work-in-progress used routes.\n */\n public startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n // If GC is disabled, skip setting wip used routes since we should not track GC state.\n if (!this.gcDisabled) {\n assert(\n this.wipSerializedUsedRoutes === undefined,\n 0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */);\n }\n super.startSummary(referenceSequenceNumber, summaryLogger);\n }\n\n /**\n * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n * summary queue. We track this until we get an ack from the server for this summary.\n */\n protected completeSummaryCore(\n proposalHandle: string,\n parentPath: EscapedPath | undefined,\n parentSkipRecursion: boolean,\n ) {\n let wipSerializedUsedRoutes: string | undefined;\n // If GC is disabled, don't set wip used routes.\n if (!this.gcDisabled) {\n wipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n assert(wipSerializedUsedRoutes !== undefined, 0x1b5 /* \"We should have been tracking used routes\" */);\n }\n\n super.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n // If GC is disabled, skip setting pending summary with GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle);\n if (summaryNode !== undefined) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const summaryNodeWithGC = new SummaryNodeWithGC(wipSerializedUsedRoutes!, summaryNode);\n this.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n }\n }\n }\n\n /**\n * Clears the work-in-progress state.\n */\n public clearSummary() {\n this.wipSerializedUsedRoutes = undefined;\n super.clearSummary();\n }\n\n /**\n * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n * from the state in the pending summary queue.\n */\n protected refreshLatestSummaryFromPending(\n proposalHandle: string,\n referenceSequenceNumber: number,\n ): void {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n if (summaryNode !== undefined) {\n this.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n }\n }\n\n return super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n }\n\n /**\n * Called when we need to upload the reference state from the given summary. Read the GC blob and get the state\n * to upload from it.\n */\n protected async refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber: number,\n snapshotTree: ISnapshotTree,\n basePath: EscapedPath | undefined,\n localPath: EscapedPath,\n correlatedSummaryLogger: ITelemetryLogger,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const gcDetailsBlob = snapshotTree.blobs[gcBlobKey];\n if (gcDetailsBlob !== undefined) {\n const gcDetails = await readAndParseBlob<IGarbageCollectionSummaryDetails>(gcDetailsBlob);\n\n // Possible re-entrancy. If we have already seen a summary later than this one, ignore it.\n if (this.referenceSequenceNumber >= referenceSequenceNumber) {\n return;\n }\n\n this.referenceUsedRoutes = gcDetails.usedRoutes;\n }\n }\n\n return super.refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber,\n snapshotTree,\n basePath,\n localPath,\n correlatedSummaryLogger,\n readAndParseBlob,\n );\n }\n\n /**\n * Override the createChild method to return an instance of SummarizerNodeWithGC.\n */\n public createChild(\n /** Summarize function */\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n /** Initial id or path part of this node */\n id: string,\n /**\n * Information needed to create the node.\n * If it is from a base summary, it will assert that a summary has been seen.\n * Attach information if it is created from an attach op.\n */\n createParam: CreateChildSummarizerNodeParam,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ): ISummarizerNodeWithGC {\n assert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n const createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n const child = new SummarizerNodeWithGC(\n this.defaultLogger,\n summarizeInternalFn,\n {\n ...config,\n // Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n gcDisabled: config.gcDisabled ?? this.gcDisabled,\n maxUnreferencedDurationMs: config.maxUnreferencedDurationMs ?? this.maxUnreferencedDurationMs,\n },\n createDetails.changeSequenceNumber,\n createDetails.latestSummary,\n createDetails.initialSummary,\n this.wipSummaryLogger,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n );\n\n // There may be additional state that has to be updated in this child. For example, if a summary is being\n // tracked, the child's summary tracking state needs to be updated too.\n this.maybeUpdateChildState(child);\n\n this.children.set(id, child);\n return child;\n }\n\n /**\n * Deletes the child node with the given id.\n */\n public deleteChild(id: string): void {\n this.children.delete(id);\n }\n\n /**\n * Override the getChild method to return an instance of SummarizerNodeWithGC.\n */\n public getChild(id: string): ISummarizerNodeWithGC | undefined {\n return this.children.get(id) as SummarizerNodeWithGC;\n }\n\n public isReferenced(): boolean {\n return this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n }\n\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number) {\n // Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n // are in the same order.\n this.usedRoutes = usedRoutes.sort();\n\n // If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can\n // be tracked for this summary.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n\n if (this.isReferenced()) {\n // If this node has been unreferenced for longer than maxUnreferencedDurationMs and is being referenced,\n // log an error as this may mean the maxUnreferencedDurationMs is not long enough.\n this.logErrorIfInactive(\"inactiveObjectRevived\", gcTimestamp);\n\n // Clear unreferenced / inactive state, if any.\n this.inactive = false;\n this.unreferencedTimestampMs = undefined;\n this.unreferencedTimer.clear();\n return;\n }\n\n // This node is unreferenced. We need to check if this node is inative or if we need to start the unreferenced\n // timer which would mark the node as inactive.\n\n // If there is no timestamp when GC was run, we don't have enough information to determine whether this content\n // should become inactive.\n if (gcTimestamp === undefined) {\n return;\n }\n\n // If unreferencedTimestampMs is not present, this node just became unreferenced. Update unreferencedTimestampMs\n // and start the unreferenced timer.\n // Note that it's possible this node has been unreferenced before but the unreferencedTimestampMs was not added.\n // For example, older versions where this concept did not exist or if gcTimestamp wasn't available. In such\n // cases, we track them as if the content just became unreferenced.\n if (this.unreferencedTimestampMs === undefined) {\n this.unreferencedTimestampMs = gcTimestamp;\n this.unreferencedTimer.start();\n return;\n }\n\n // If we are here, this node was unreferenced earlier.\n\n // If it is already inactive or has an unreferenced timer running, there is no more work to be done.\n if (this.inactive || this.unreferencedTimer.hasTimer) {\n return;\n }\n\n // If it has been unreferenced longer than maxUnreferencedDurationMs, mark it as inactive. Otherwise, start the\n // unreferenced timer for the duration left for it to reach maxUnreferencedDurationMs.\n const currentUnreferencedDurationMs = gcTimestamp - this.unreferencedTimestampMs;\n if (currentUnreferencedDurationMs >= this.maxUnreferencedDurationMs) {\n this.inactive = true;\n } else {\n this.unreferencedTimer.start(this.maxUnreferencedDurationMs - currentUnreferencedDurationMs);\n }\n }\n\n public recordChange(op: ISequencedDocumentMessage): void {\n // If the node is changed after it is inactive, log an error as this may mean use-after-delete.\n // Currently, we only log this error once per node per session as it's too noisy.\n if (!this.useAfterFreeErrorLogged && this.logErrorIfInactive(\"inactiveObjectChanged\")) {\n this.useAfterFreeErrorLogged = true;\n }\n super.recordChange(op);\n }\n\n /**\n * Logs an error event if the node is inactive. This is used to identify cases where an inactive object is used.\n * @param eventName - The name of the event to log.\n * @param currentTimestampMs - The current time stamp. Used to report how long the object has been inactive.\n * @returns true if we logged an error, false otherwise.\n */\n private logErrorIfInactive(eventName: string, currentTimestampMs?: number): boolean {\n if (this.inactive) {\n assert(\n this.unreferencedTimestampMs !== undefined,\n 0x271 /* \"Node should not become inactive without setting unreferencedTimestampMs first\" */);\n this.defaultLogger.sendErrorEvent({\n eventName,\n unreferencedDuratonMs: (currentTimestampMs ?? Date.now()) - this.unreferencedTimestampMs,\n maxUnreferencedDurationMs: this.maxUnreferencedDurationMs,\n });\n return true;\n }\n return false;\n }\n\n /**\n * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n */\n protected hasChanged(): boolean {\n return this.hasDataChanged() || this.hasUsedStateChanged();\n }\n\n /**\n * This tells whether the data in this node has changed or not.\n */\n private hasDataChanged(): boolean {\n return super.hasChanged();\n }\n\n /**\n * This tells whether the used state of this node has changed since last successful summary. If the used routes\n * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n * was previously used and became unused (or vice versa), its used state has changed.\n */\n private hasUsedStateChanged(): boolean {\n // If GC is disabled, we are not tracking used state, return false.\n if (this.gcDisabled) {\n return false;\n }\n\n return this.referenceUsedRoutes === undefined ||\n JSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes);\n }\n}\n\n/**\n * Creates a root summarizer node with GC functionality built-in.\n * @param logger - Logger to use within SummarizerNode\n * @param summarizeInternalFn - Function to generate summary\n * @param changeSequenceNumber - Sequence number of latest change to new node/subtree\n * @param referenceSequenceNumber - Reference sequence number of last acked summary,\n * or undefined if not loaded from summary\n * @param config - Configure behavior of summarizer node\n * @param getGCDataFn - Function to get the GC data of this node\n * @param gcDetailsInInitialSummaryP - Function to get the initial GC details of this node\n */\nexport const createRootSummarizerNodeWithGC = (\n logger: ITelemetryLogger,\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n changeSequenceNumber: number,\n referenceSequenceNumber: number | undefined,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n): IRootSummarizerNodeWithGC => new SummarizerNodeWithGC(\n logger,\n summarizeInternalFn,\n config,\n changeSequenceNumber,\n referenceSequenceNumber === undefined ? undefined : SummaryNode.createForRoot(referenceSequenceNumber),\n undefined /* initialSummary */,\n undefined /* wipSummaryLogger */,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n);\n"]}
|
|
1
|
+
{"version":3,"file":"summarizerNodeWithGc.js","sourceRoot":"","sources":["../../src/summarizerNode/summarizerNodeWithGc.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, LazyPromise } from \"@fluidframework/common-utils\";\nimport { cloneGCData } from \"@fluidframework/garbage-collector\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport {\n CreateChildSummarizerNodeParam,\n gcBlobKey,\n IGarbageCollectionData,\n IGarbageCollectionSummaryDetails,\n ISummarizeInternalResult,\n ISummarizeResult,\n ISummarizerNodeConfigWithGC,\n ISummarizerNodeWithGC,\n} from \"@fluidframework/runtime-definitions\";\nimport { ReadAndParseBlob } from \"../utils\";\nimport { SummarizerNode } from \"./summarizerNode\";\nimport {\n EscapedPath,\n ICreateChildDetails,\n IInitialSummary,\n ISummarizerNodeRootContract,\n SummaryNode,\n} from \"./summarizerNodeUtils\";\n\nexport interface IRootSummarizerNodeWithGC extends ISummarizerNodeWithGC, ISummarizerNodeRootContract {}\n\n// Extend SummaryNode to add used routes tracking to it.\nclass SummaryNodeWithGC extends SummaryNode {\n constructor(\n public readonly serializedUsedRoutes: string,\n summary: {\n readonly referenceSequenceNumber: number,\n readonly basePath: EscapedPath | undefined,\n readonly localPath: EscapedPath,\n additionalPath?: EscapedPath,\n },\n ) {\n super(summary);\n }\n}\n\n/**\n * Extends the functionality of SummarizerNode to manage this node's garbage collection data:\n * - Adds a new API `getGCData` to return GC data of this node.\n * - Caches the result of `getGCData` to be used if nothing changes between summaries.\n * - Manages the used routes of this node. These are used to identify if this node is referenced in the document\n * and to determine if the node's used state changed since last summary.\n * - Adds trackState param to summarize. If trackState is false, it bypasses the SummarizerNode and calls\n * directly into summarizeInternal method.\n */\nexport class SummarizerNodeWithGC extends SummarizerNode implements IRootSummarizerNodeWithGC {\n // Tracks the work-in-progress used routes during summary.\n private wipSerializedUsedRoutes: string | undefined;\n\n // This is the last known used routes of this node as seen by the server as part of a summary.\n private referenceUsedRoutes: string[] | undefined;\n\n // The GC details of this node in the initial summary.\n private gcDetailsInInitialSummaryP: LazyPromise<IGarbageCollectionSummaryDetails> | undefined;\n\n private gcData: IGarbageCollectionData | undefined;\n\n // Set used routes to have self route by default. This makes the node referenced by default. This is done to ensure\n // that this node is not marked as collected when running GC has been disabled. Once, the option to disable GC is\n // removed (from runGC flag in IContainerRuntimeOptions), this should be changed to be have no routes by default.\n private usedRoutes: string[] = [\"\"];\n\n // If this node is marked as unreferenced, the time when it marked as such.\n private unreferencedTimestampMs: number | undefined;\n\n // True if GC is disabled for this node. If so, do not track GC specific state for a summary.\n private readonly gcDisabled: boolean;\n\n /**\n * Do not call constructor directly.\n * Use createRootSummarizerNodeWithGC to create root node, or createChild to create child nodes.\n */\n public constructor(\n logger: ITelemetryLogger,\n private readonly summarizeFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n config: ISummarizerNodeConfigWithGC,\n changeSequenceNumber: number,\n /** Undefined means created without summary */\n latestSummary?: SummaryNode,\n initialSummary?: IInitialSummary,\n wipSummaryLogger?: ITelemetryLogger,\n private readonly getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ) {\n super(\n logger,\n async (fullTree: boolean) => summarizeFn(fullTree, true /* trackState */),\n config,\n changeSequenceNumber,\n latestSummary,\n initialSummary,\n wipSummaryLogger,\n );\n\n this.gcDisabled = config.gcDisabled === true;\n\n this.gcDetailsInInitialSummaryP = new LazyPromise(async () => {\n const gcSummaryDetails = await getInitialGCSummaryDetailsFn?.();\n return gcSummaryDetails ?? { usedRoutes: [] };\n });\n }\n\n // Returns the GC details that may be added to this node's summary.\n public getGCSummaryDetails(): IGarbageCollectionSummaryDetails {\n return {\n gcData: this.gcData,\n usedRoutes: this.usedRoutes,\n unrefTimestamp: this.unreferencedTimestampMs,\n };\n }\n\n /**\n * Loads state from this node's initial GC summary details. This contains the following data from the last summary\n * seen by the server for this client:\n * - usedRoutes: This is used to figure out if the used state of this node changed since last summary.\n * - gcData: The garbage collection data of this node that is required for running GC.\n */\n private async loadInitialGCSummaryDetails() {\n if (this.gcDetailsInInitialSummaryP === undefined) {\n return;\n }\n\n const gcDetailsInInitialSummaryP = this.gcDetailsInInitialSummaryP;\n this.gcDetailsInInitialSummaryP = undefined;\n\n const gcDetailsInInitialSummary = await gcDetailsInInitialSummaryP;\n // If the GC details has GC data, initialize our GC data from it.\n if (gcDetailsInInitialSummary.gcData !== undefined) {\n this.gcData = cloneGCData(gcDetailsInInitialSummary.gcData);\n }\n this.referenceUsedRoutes = gcDetailsInInitialSummary.usedRoutes;\n this.unreferencedTimestampMs = gcDetailsInInitialSummary.unrefTimestamp;\n }\n\n public async summarize(fullTree: boolean, trackState: boolean = true): Promise<ISummarizeResult> {\n // If GC is not disabled and we are tracking a summary, GC should have run and updated the used routes for this\n // summary by calling updateUsedRoutes which sets wipSerializedUsedRoutes.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n assert(this.wipSerializedUsedRoutes !== undefined,\n 0x1b1 /* \"wip used routes should be set if tracking a summary\" */);\n }\n\n // If trackState is true, get summary from base summarizer node which tracks summary state.\n // If trackState is false, get summary from summarizeInternal.\n return trackState ? super.summarize(fullTree) : this.summarizeFn(fullTree, trackState);\n }\n\n /**\n * Returns the GC data of this node. If nothing has changed since last summary, it tries to reuse the data from\n * the previous summary. Else, it gets new GC data from the underlying Fluid object.\n * @param fullGC - true to bypass optimizations and force full generation of GC data.\n */\n public async getGCData(fullGC: boolean = false): Promise<IGarbageCollectionData> {\n assert(!this.gcDisabled, 0x1b2 /* \"Getting GC data should not be called when GC is disabled!\" */);\n assert(this.getGCDataFn !== undefined, 0x1b3 /* \"GC data cannot be retrieved without getGCDataFn\" */);\n\n // Load GC details from the initial summary, if not already loaded. If this is the first time this function is\n // called and the node's data has not changed since last summary, the GC data in initial details is returned.\n await this.loadInitialGCSummaryDetails();\n\n // If there is no new data since last summary and we have GC data from the previous run, return it. We may not\n // have data from previous GC run for clients with older summary format before GC was added. They won't have\n // GC details in their initial summary.\n if (!fullGC && !this.hasDataChanged() && this.gcData !== undefined) {\n return cloneGCData(this.gcData);\n }\n\n const gcData = await this.getGCDataFn(fullGC);\n this.gcData = cloneGCData(gcData);\n return gcData;\n }\n\n /**\n * Called during the start of a summary. Updates the work-in-progress used routes.\n */\n public startSummary(referenceSequenceNumber: number, summaryLogger: ITelemetryLogger) {\n // If GC is disabled, skip setting wip used routes since we should not track GC state.\n if (!this.gcDisabled) {\n assert(\n this.wipSerializedUsedRoutes === undefined,\n 0x1b4 /* \"We should not already be tracking used routes when to track a new summary\" */);\n }\n super.startSummary(referenceSequenceNumber, summaryLogger);\n }\n\n /**\n * Called after summary has been uploaded to the server. Add the work-in-progress state to the pending\n * summary queue. We track this until we get an ack from the server for this summary.\n */\n protected completeSummaryCore(\n proposalHandle: string,\n parentPath: EscapedPath | undefined,\n parentSkipRecursion: boolean,\n ) {\n let wipSerializedUsedRoutes: string | undefined;\n // If GC is disabled, don't set wip used routes.\n if (!this.gcDisabled) {\n wipSerializedUsedRoutes = this.wipSerializedUsedRoutes;\n assert(wipSerializedUsedRoutes !== undefined, 0x1b5 /* \"We should have been tracking used routes\" */);\n }\n\n super.completeSummaryCore(proposalHandle, parentPath, parentSkipRecursion);\n\n // If GC is disabled, skip setting pending summary with GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle);\n if (summaryNode !== undefined) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const summaryNodeWithGC = new SummaryNodeWithGC(wipSerializedUsedRoutes!, summaryNode);\n this.pendingSummaries.set(proposalHandle, summaryNodeWithGC);\n }\n }\n }\n\n /**\n * Clears the work-in-progress state.\n */\n public clearSummary() {\n this.wipSerializedUsedRoutes = undefined;\n super.clearSummary();\n }\n\n /**\n * Called when we get an ack from the server for a summary we sent. Update the reference state of this node\n * from the state in the pending summary queue.\n */\n protected refreshLatestSummaryFromPending(\n proposalHandle: string,\n referenceSequenceNumber: number,\n ): void {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const summaryNode = this.pendingSummaries.get(proposalHandle) as SummaryNodeWithGC;\n if (summaryNode !== undefined) {\n this.referenceUsedRoutes = JSON.parse(summaryNode.serializedUsedRoutes);\n }\n }\n\n return super.refreshLatestSummaryFromPending(proposalHandle, referenceSequenceNumber);\n }\n\n /**\n * Called when we need to upload the reference state from the given summary. Read the GC blob and get the state\n * to upload from it.\n */\n protected async refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber: number,\n snapshotTree: ISnapshotTree,\n basePath: EscapedPath | undefined,\n localPath: EscapedPath,\n correlatedSummaryLogger: ITelemetryLogger,\n readAndParseBlob: ReadAndParseBlob,\n ): Promise<void> {\n // If GC is disabled, skip setting referenced used routes since we are not tracking GC state.\n if (!this.gcDisabled) {\n const gcDetailsBlob = snapshotTree.blobs[gcBlobKey];\n if (gcDetailsBlob !== undefined) {\n const gcDetails = await readAndParseBlob<IGarbageCollectionSummaryDetails>(gcDetailsBlob);\n\n // Possible re-entrancy. If we have already seen a summary later than this one, ignore it.\n if (this.referenceSequenceNumber >= referenceSequenceNumber) {\n return;\n }\n\n this.referenceUsedRoutes = gcDetails.usedRoutes;\n }\n }\n\n return super.refreshLatestSummaryFromSnapshot(\n referenceSequenceNumber,\n snapshotTree,\n basePath,\n localPath,\n correlatedSummaryLogger,\n readAndParseBlob,\n );\n }\n\n /**\n * Override the createChild method to return an instance of SummarizerNodeWithGC.\n */\n public createChild(\n /** Summarize function */\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n /** Initial id or path part of this node */\n id: string,\n /**\n * Information needed to create the node.\n * If it is from a base summary, it will assert that a summary has been seen.\n * Attach information if it is created from an attach op.\n */\n createParam: CreateChildSummarizerNodeParam,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n ): ISummarizerNodeWithGC {\n assert(!this.children.has(id), 0x1b6 /* \"Create SummarizerNode child already exists\" */);\n\n const createDetails: ICreateChildDetails = this.getCreateDetailsForChild(id, createParam);\n const child = new SummarizerNodeWithGC(\n this.defaultLogger,\n summarizeInternalFn,\n {\n ...config,\n // Propagate our gcDisabled state to the child if its not explicity specified in child's config.\n gcDisabled: config.gcDisabled ?? this.gcDisabled,\n },\n createDetails.changeSequenceNumber,\n createDetails.latestSummary,\n createDetails.initialSummary,\n this.wipSummaryLogger,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n );\n\n // There may be additional state that has to be updated in this child. For example, if a summary is being\n // tracked, the child's summary tracking state needs to be updated too.\n this.maybeUpdateChildState(child);\n\n this.children.set(id, child);\n return child;\n }\n\n /**\n * Deletes the child node with the given id.\n */\n public deleteChild(id: string): void {\n this.children.delete(id);\n }\n\n /**\n * Override the getChild method to return an instance of SummarizerNodeWithGC.\n */\n public getChild(id: string): ISummarizerNodeWithGC | undefined {\n return this.children.get(id) as SummarizerNodeWithGC;\n }\n\n public isReferenced(): boolean {\n return this.usedRoutes.includes(\"\") || this.usedRoutes.includes(\"/\");\n }\n\n public updateUsedRoutes(usedRoutes: string[], gcTimestamp?: number) {\n // Sort the given routes before updating. This will ensure that the routes compared in hasUsedStateChanged()\n // are in the same order.\n this.usedRoutes = usedRoutes.sort();\n\n // If GC is not disabled and we are tracking a summary, update the work-in-progress used routes so that it can\n // be tracked for this summary.\n if (!this.gcDisabled && this.isTrackingInProgress()) {\n this.wipSerializedUsedRoutes = JSON.stringify(this.usedRoutes);\n }\n\n if (this.isReferenced()) {\n this.unreferencedTimestampMs = undefined;\n return;\n }\n\n // If this node just became unreferenced, update its unreferencedTimestampMs.\n if (this.unreferencedTimestampMs === undefined) {\n this.unreferencedTimestampMs = gcTimestamp;\n }\n }\n\n /**\n * Override the hasChanged method. If this node data or its used state changed, the node is considered changed.\n */\n protected hasChanged(): boolean {\n return this.hasDataChanged() || this.hasUsedStateChanged();\n }\n\n /**\n * This tells whether the data in this node has changed or not.\n */\n private hasDataChanged(): boolean {\n return super.hasChanged();\n }\n\n /**\n * This tells whether the used state of this node has changed since last successful summary. If the used routes\n * of this node changed, its used state is considered changed. Basically, if this node or any of its child nodes\n * was previously used and became unused (or vice versa), its used state has changed.\n */\n private hasUsedStateChanged(): boolean {\n // If GC is disabled, we are not tracking used state, return false.\n if (this.gcDisabled) {\n return false;\n }\n\n return this.referenceUsedRoutes === undefined ||\n JSON.stringify(this.usedRoutes) !== JSON.stringify(this.referenceUsedRoutes);\n }\n}\n\n/**\n * Creates a root summarizer node with GC functionality built-in.\n * @param logger - Logger to use within SummarizerNode\n * @param summarizeInternalFn - Function to generate summary\n * @param changeSequenceNumber - Sequence number of latest change to new node/subtree\n * @param referenceSequenceNumber - Reference sequence number of last acked summary,\n * or undefined if not loaded from summary\n * @param config - Configure behavior of summarizer node\n * @param getGCDataFn - Function to get the GC data of this node\n * @param gcDetailsInInitialSummaryP - Function to get the initial GC details of this node\n */\nexport const createRootSummarizerNodeWithGC = (\n logger: ITelemetryLogger,\n summarizeInternalFn: (fullTree: boolean, trackState: boolean) => Promise<ISummarizeInternalResult>,\n changeSequenceNumber: number,\n referenceSequenceNumber: number | undefined,\n config: ISummarizerNodeConfigWithGC = {},\n getGCDataFn?: (fullGC?: boolean) => Promise<IGarbageCollectionData>,\n getInitialGCSummaryDetailsFn?: () => Promise<IGarbageCollectionSummaryDetails>,\n): IRootSummarizerNodeWithGC => new SummarizerNodeWithGC(\n logger,\n summarizeInternalFn,\n config,\n changeSequenceNumber,\n referenceSequenceNumber === undefined ? undefined : SummaryNode.createForRoot(referenceSequenceNumber),\n undefined /* initialSummary */,\n undefined /* wipSummaryLogger */,\n getGCDataFn,\n getInitialGCSummaryDetailsFn,\n);\n"]}
|
package/dist/summaryUtils.js
CHANGED
|
@@ -60,18 +60,18 @@ function getBlobSize(content) {
|
|
|
60
60
|
exports.getBlobSize = getBlobSize;
|
|
61
61
|
function calculateStatsCore(summaryObject, stats) {
|
|
62
62
|
switch (summaryObject.type) {
|
|
63
|
-
case
|
|
63
|
+
case protocol_definitions_1.SummaryType.Tree: {
|
|
64
64
|
stats.treeNodeCount++;
|
|
65
65
|
for (const value of Object.values(summaryObject.tree)) {
|
|
66
66
|
calculateStatsCore(value, stats);
|
|
67
67
|
}
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
case
|
|
70
|
+
case protocol_definitions_1.SummaryType.Handle: {
|
|
71
71
|
stats.handleNodeCount++;
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
-
case
|
|
74
|
+
case protocol_definitions_1.SummaryType.Blob: {
|
|
75
75
|
stats.blobNodeCount++;
|
|
76
76
|
stats.totalBlobSize += getBlobSize(summaryObject.content);
|
|
77
77
|
return;
|
|
@@ -87,7 +87,7 @@ function calculateStats(summary) {
|
|
|
87
87
|
exports.calculateStats = calculateStats;
|
|
88
88
|
function addBlobToSummary(summary, key, content) {
|
|
89
89
|
const blob = {
|
|
90
|
-
type:
|
|
90
|
+
type: protocol_definitions_1.SummaryType.Blob,
|
|
91
91
|
content,
|
|
92
92
|
};
|
|
93
93
|
summary.summary.tree[key] = blob;
|
|
@@ -109,7 +109,7 @@ class SummaryTreeBuilder {
|
|
|
109
109
|
}
|
|
110
110
|
get summary() {
|
|
111
111
|
return {
|
|
112
|
-
type:
|
|
112
|
+
type: protocol_definitions_1.SummaryType.Tree,
|
|
113
113
|
tree: Object.assign({}, this.summaryTree),
|
|
114
114
|
};
|
|
115
115
|
}
|
|
@@ -120,7 +120,7 @@ class SummaryTreeBuilder {
|
|
|
120
120
|
// Prevent cloning by directly referencing underlying private properties
|
|
121
121
|
addBlobToSummary({
|
|
122
122
|
summary: {
|
|
123
|
-
type:
|
|
123
|
+
type: protocol_definitions_1.SummaryType.Tree,
|
|
124
124
|
tree: this.summaryTree,
|
|
125
125
|
},
|
|
126
126
|
stats: this.summaryStats,
|
|
@@ -128,7 +128,7 @@ class SummaryTreeBuilder {
|
|
|
128
128
|
}
|
|
129
129
|
addHandle(key, handleType, handle) {
|
|
130
130
|
this.summaryTree[key] = {
|
|
131
|
-
type:
|
|
131
|
+
type: protocol_definitions_1.SummaryType.Handle,
|
|
132
132
|
handleType,
|
|
133
133
|
handle,
|
|
134
134
|
};
|
|
@@ -139,7 +139,7 @@ class SummaryTreeBuilder {
|
|
|
139
139
|
this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);
|
|
140
140
|
}
|
|
141
141
|
addAttachment(id) {
|
|
142
|
-
this.summaryTree[this.attachmentCounter++] = { id, type:
|
|
142
|
+
this.summaryTree[this.attachmentCounter++] = { id, type: protocol_definitions_1.SummaryType.Attachment };
|
|
143
143
|
}
|
|
144
144
|
getSummaryTree() {
|
|
145
145
|
return { summary: this.summary, stats: this.stats };
|
|
@@ -199,8 +199,8 @@ function convertToSummaryTree(snapshot, fullTree = false) {
|
|
|
199
199
|
return {
|
|
200
200
|
summary: {
|
|
201
201
|
handle: snapshot.id,
|
|
202
|
-
handleType:
|
|
203
|
-
type:
|
|
202
|
+
handleType: protocol_definitions_1.SummaryType.Tree,
|
|
203
|
+
type: protocol_definitions_1.SummaryType.Handle,
|
|
204
204
|
},
|
|
205
205
|
stats,
|
|
206
206
|
};
|
|
@@ -252,7 +252,7 @@ function convertSummaryTreeToITree(summaryTree) {
|
|
|
252
252
|
const entries = [];
|
|
253
253
|
for (const [key, value] of Object.entries(summaryTree.tree)) {
|
|
254
254
|
switch (value.type) {
|
|
255
|
-
case
|
|
255
|
+
case protocol_definitions_1.SummaryType.Blob: {
|
|
256
256
|
let parsedContent;
|
|
257
257
|
let encoding = "utf-8";
|
|
258
258
|
if (typeof value.content === "string") {
|
|
@@ -265,15 +265,15 @@ function convertSummaryTreeToITree(summaryTree) {
|
|
|
265
265
|
entries.push(new protocol_base_1.BlobTreeEntry(key, parsedContent, encoding));
|
|
266
266
|
break;
|
|
267
267
|
}
|
|
268
|
-
case
|
|
268
|
+
case protocol_definitions_1.SummaryType.Tree: {
|
|
269
269
|
entries.push(new protocol_base_1.TreeTreeEntry(key, convertSummaryTreeToITree(value)));
|
|
270
270
|
break;
|
|
271
271
|
}
|
|
272
|
-
case
|
|
272
|
+
case protocol_definitions_1.SummaryType.Attachment: {
|
|
273
273
|
entries.push(new protocol_base_1.AttachmentTreeEntry(key, value.id));
|
|
274
274
|
break;
|
|
275
275
|
}
|
|
276
|
-
case
|
|
276
|
+
case protocol_definitions_1.SummaryType.Handle: {
|
|
277
277
|
throw new Error("Should not have Handle type in summary tree");
|
|
278
278
|
}
|
|
279
279
|
default:
|
package/dist/summaryUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summaryUtils.js","sourceRoot":"","sources":["../src/summaryUtils.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 {\n assert,\n bufferToString,\n fromBase64ToUtf8,\n IsoBuffer,\n Uint8ArrayToString,\n unreachableCase,\n} from \"@fluidframework/common-utils\";\nimport { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n SummaryType,\n ISummaryTree,\n SummaryObject,\n ISummaryBlob,\n TreeEntry,\n ITreeEntry,\n ISnapshotTree,\n} from \"@fluidframework/protocol-definitions\";\nimport { ISummaryStats, ISummarizeResult, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\n\n/**\n * Combines summary stats by adding their totals together.\n * Returns empty stats if called without args.\n * @param stats - stats to merge\n */\nexport function mergeStats(...stats: ISummaryStats[]): ISummaryStats {\n const results = {\n treeNodeCount: 0,\n blobNodeCount: 0,\n handleNodeCount: 0,\n totalBlobSize: 0,\n unreferencedBlobSize: 0,\n };\n for (const stat of stats) {\n results.treeNodeCount += stat.treeNodeCount;\n results.blobNodeCount += stat.blobNodeCount;\n results.handleNodeCount += stat.handleNodeCount;\n results.totalBlobSize += stat.totalBlobSize;\n results.unreferencedBlobSize += stat.unreferencedBlobSize;\n }\n return results;\n}\n\nexport function utf8ByteLength(str: string): number {\n // returns the byte length of an utf8 string\n let s = str.length;\n for (let i = str.length - 1; i >= 0; i--) {\n const code = str.charCodeAt(i);\n if (code > 0x7f && code <= 0x7ff) {\n s++;\n } else if (code > 0x7ff && code <= 0xffff) {\n s += 2;\n }\n if (code >= 0xDC00 && code <= 0xDFFF) {\n i--; // trail surrogate\n }\n }\n return s;\n}\n\nexport function getBlobSize(content: ISummaryBlob[\"content\"]): number {\n if (typeof content === \"string\") {\n return utf8ByteLength(content);\n } else {\n return content.byteLength;\n }\n}\n\nfunction calculateStatsCore(summaryObject: SummaryObject, stats: ISummaryStats): void {\n switch (summaryObject.type) {\n case SummaryType.Tree: {\n stats.treeNodeCount++;\n for (const value of Object.values(summaryObject.tree)) {\n calculateStatsCore(value, stats);\n }\n return;\n }\n case SummaryType.Handle: {\n stats.handleNodeCount++;\n return;\n }\n case SummaryType.Blob: {\n stats.blobNodeCount++;\n stats.totalBlobSize += getBlobSize(summaryObject.content);\n return;\n }\n default: return;\n }\n}\n\nexport function calculateStats(summary: ISummaryTree): ISummaryStats {\n const stats = mergeStats();\n calculateStatsCore(summary, stats);\n return stats;\n}\n\nexport function addBlobToSummary(summary: ISummaryTreeWithStats, key: string, content: string | Uint8Array): void {\n const blob: ISummaryBlob = {\n type: SummaryType.Blob,\n content,\n };\n summary.summary.tree[key] = blob;\n summary.stats.blobNodeCount++;\n summary.stats.totalBlobSize += getBlobSize(content);\n}\n\nexport function addTreeToSummary(summary: ISummaryTreeWithStats, key: string, summarizeResult: ISummarizeResult): void {\n summary.summary.tree[key] = summarizeResult.summary;\n summary.stats = mergeStats(summary.stats, summarizeResult.stats);\n}\n\nexport class SummaryTreeBuilder implements ISummaryTreeWithStats {\n private attachmentCounter: number = 0;\n\n public get summary(): ISummaryTree {\n return {\n type: SummaryType.Tree,\n tree: { ...this.summaryTree },\n };\n }\n\n public get stats(): Readonly<ISummaryStats> {\n return { ...this.summaryStats };\n }\n\n constructor() {\n this.summaryStats = mergeStats();\n this.summaryStats.treeNodeCount++;\n }\n\n private readonly summaryTree: { [path: string]: SummaryObject } = {};\n private summaryStats: ISummaryStats;\n\n public addBlob(key: string, content: string | Uint8Array): void {\n // Prevent cloning by directly referencing underlying private properties\n addBlobToSummary({\n summary: {\n type: SummaryType.Tree,\n tree: this.summaryTree,\n },\n stats: this.summaryStats,\n }, key, content);\n }\n\n public addHandle(\n key: string,\n handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,\n handle: string): void\n {\n this.summaryTree[key] = {\n type: SummaryType.Handle,\n handleType,\n handle,\n };\n this.summaryStats.handleNodeCount++;\n }\n\n public addWithStats(key: string, summarizeResult: ISummarizeResult): void {\n this.summaryTree[key] = summarizeResult.summary;\n this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);\n }\n\n public addAttachment(id: string) {\n this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };\n }\n\n public getSummaryTree(): ISummaryTreeWithStats {\n return { summary: this.summary, stats: this.stats };\n }\n}\n\n/**\n * Converts snapshot ITree to ISummaryTree format and tracks stats.\n * @param snapshot - snapshot in ITree format\n * @param fullTree - true to never use handles, even if id is specified\n */\nexport function convertToSummaryTreeWithStats(\n snapshot: ITree,\n fullTree: boolean = false,\n): ISummaryTreeWithStats {\n const builder = new SummaryTreeBuilder();\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n const blob = entry.value;\n let content: string | Uint8Array;\n if (blob.encoding === \"base64\") {\n content = IsoBuffer.from(blob.contents, \"base64\");\n } else {\n content = blob.contents;\n }\n builder.addBlob(entry.path, content);\n break;\n }\n\n case TreeEntry.Tree: {\n const subtree = convertToSummaryTree(\n entry.value,\n fullTree);\n builder.addWithStats(entry.path, subtree);\n\n break;\n }\n\n case TreeEntry.Attachment: {\n const id = entry.value.id;\n builder.addAttachment(id);\n\n break;\n }\n\n default:\n throw new Error(\"Unexpected TreeEntry type\");\n }\n }\n\n const summaryTree = builder.getSummaryTree();\n summaryTree.summary.unreferenced = snapshot.unreferenced;\n return summaryTree;\n}\n\n/**\n * Converts snapshot ITree to ISummaryTree format and tracks stats.\n * @param snapshot - snapshot in ITree format\n * @param fullTree - true to never use handles, even if id is specified\n */\nexport function convertToSummaryTree(\n snapshot: ITree,\n fullTree: boolean = false,\n): ISummarizeResult {\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (snapshot.id && !fullTree) {\n const stats = mergeStats();\n stats.handleNodeCount++;\n return {\n summary: {\n handle: snapshot.id,\n handleType: SummaryType.Tree,\n type: SummaryType.Handle,\n },\n stats,\n };\n } else {\n return convertToSummaryTreeWithStats(snapshot, fullTree);\n }\n}\n\n/**\n * Converts ISnapshotTree to ISummaryTree format and tracks stats. This snapshot tree was\n * was taken by serialize api in detached container.\n * @param snapshot - snapshot in ISnapshotTree format\n */\nexport function convertSnapshotTreeToSummaryTree(\n snapshot: ISnapshotTree,\n): ISummaryTreeWithStats {\n assert(Object.keys(snapshot.commits).length === 0,\n 0x19e /* \"There should not be commit tree entries in snapshot\" */);\n\n const builder = new SummaryTreeBuilder();\n for (const [path, id] of Object.entries(snapshot.blobs)) {\n let decoded: string | undefined;\n if ((snapshot as any).blobsContents !== undefined) {\n const content: ArrayBufferLike = (snapshot as any).blobsContents[id];\n if (content !== undefined) {\n decoded = bufferToString(content, \"utf-8\");\n }\n // 0.44 back-compat We still put contents in same blob for back-compat so need to add blob\n // only for blobPath -> blobId mapping and not for blobId -> blob value contents.\n } else if (snapshot.blobs[id] !== undefined) {\n decoded = fromBase64ToUtf8(snapshot.blobs[id]);\n }\n if (decoded !== undefined) {\n builder.addBlob(path, decoded);\n }\n }\n\n for (const [key, tree] of Object.entries(snapshot.trees)) {\n const subtree = convertSnapshotTreeToSummaryTree(tree);\n builder.addWithStats(key, subtree);\n }\n\n const summaryTree = builder.getSummaryTree();\n summaryTree.summary.unreferenced = snapshot.unreferenced;\n return summaryTree;\n}\n\n/**\n * Converts ISummaryTree to ITree format. This is needed for back-compat while we get rid of snapshot.\n * @param summaryTree - summary tree in ISummaryTree format\n */\nexport function convertSummaryTreeToITree(summaryTree: ISummaryTree): ITree {\n const entries: ITreeEntry[] = [];\n for (const [key, value] of Object.entries(summaryTree.tree)) {\n switch (value.type) {\n case SummaryType.Blob: {\n let parsedContent: string;\n let encoding: \"utf-8\" | \"base64\" = \"utf-8\";\n if (typeof value.content === \"string\") {\n parsedContent = value.content;\n } else {\n parsedContent = Uint8ArrayToString(value.content, \"base64\");\n encoding = \"base64\";\n }\n entries.push(new BlobTreeEntry(key, parsedContent, encoding));\n break;\n }\n\n case SummaryType.Tree: {\n entries.push(new TreeTreeEntry(key, convertSummaryTreeToITree(value)));\n break;\n }\n\n case SummaryType.Attachment: {\n entries.push(new AttachmentTreeEntry(key, value.id));\n break;\n }\n\n case SummaryType.Handle: {\n throw new Error(\"Should not have Handle type in summary tree\");\n }\n\n default:\n unreachableCase(value, \"Unexpected summary tree type\");\n }\n }\n return {\n entries,\n unreferenced: summaryTree.unreferenced,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"summaryUtils.js","sourceRoot":"","sources":["../src/summaryUtils.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 {\n assert,\n bufferToString,\n fromBase64ToUtf8,\n IsoBuffer,\n Uint8ArrayToString,\n unreachableCase,\n} from \"@fluidframework/common-utils\";\nimport { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n SummaryType,\n ISummaryTree,\n SummaryObject,\n ISummaryBlob,\n TreeEntry,\n ITreeEntry,\n ISnapshotTree,\n} from \"@fluidframework/protocol-definitions\";\nimport { ISummaryStats, ISummarizeResult, ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\n\n/**\n * Combines summary stats by adding their totals together.\n * Returns empty stats if called without args.\n * @param stats - stats to merge\n */\nexport function mergeStats(...stats: ISummaryStats[]): ISummaryStats {\n const results = {\n treeNodeCount: 0,\n blobNodeCount: 0,\n handleNodeCount: 0,\n totalBlobSize: 0,\n unreferencedBlobSize: 0,\n };\n for (const stat of stats) {\n results.treeNodeCount += stat.treeNodeCount;\n results.blobNodeCount += stat.blobNodeCount;\n results.handleNodeCount += stat.handleNodeCount;\n results.totalBlobSize += stat.totalBlobSize;\n results.unreferencedBlobSize += stat.unreferencedBlobSize;\n }\n return results;\n}\n\nexport function utf8ByteLength(str: string): number {\n // returns the byte length of an utf8 string\n let s = str.length;\n for (let i = str.length - 1; i >= 0; i--) {\n const code = str.charCodeAt(i);\n if (code > 0x7f && code <= 0x7ff) {\n s++;\n } else if (code > 0x7ff && code <= 0xffff) {\n s += 2;\n }\n if (code >= 0xDC00 && code <= 0xDFFF) {\n i--; // trail surrogate\n }\n }\n return s;\n}\n\nexport function getBlobSize(content: ISummaryBlob[\"content\"]): number {\n if (typeof content === \"string\") {\n return utf8ByteLength(content);\n } else {\n return content.byteLength;\n }\n}\n\nfunction calculateStatsCore(summaryObject: SummaryObject, stats: ISummaryStats): void {\n switch (summaryObject.type) {\n case SummaryType.Tree: {\n stats.treeNodeCount++;\n for (const value of Object.values(summaryObject.tree)) {\n calculateStatsCore(value, stats);\n }\n return;\n }\n case SummaryType.Handle: {\n stats.handleNodeCount++;\n return;\n }\n case SummaryType.Blob: {\n stats.blobNodeCount++;\n stats.totalBlobSize += getBlobSize(summaryObject.content);\n return;\n }\n default: return;\n }\n}\n\nexport function calculateStats(summary: ISummaryTree): ISummaryStats {\n const stats = mergeStats();\n calculateStatsCore(summary, stats);\n return stats;\n}\n\nexport function addBlobToSummary(summary: ISummaryTreeWithStats, key: string, content: string | Uint8Array): void {\n const blob: ISummaryBlob = {\n type: SummaryType.Blob,\n content,\n };\n summary.summary.tree[key] = blob;\n summary.stats.blobNodeCount++;\n summary.stats.totalBlobSize += getBlobSize(content);\n}\n\nexport function addTreeToSummary(summary: ISummaryTreeWithStats, key: string, summarizeResult: ISummarizeResult): void {\n summary.summary.tree[key] = summarizeResult.summary;\n summary.stats = mergeStats(summary.stats, summarizeResult.stats);\n}\n\nexport class SummaryTreeBuilder implements ISummaryTreeWithStats {\n private attachmentCounter: number = 0;\n\n public get summary(): ISummaryTree {\n return {\n type: SummaryType.Tree,\n tree: { ...this.summaryTree },\n };\n }\n\n public get stats(): Readonly<ISummaryStats> {\n return { ...this.summaryStats };\n }\n\n constructor() {\n this.summaryStats = mergeStats();\n this.summaryStats.treeNodeCount++;\n }\n\n private readonly summaryTree: { [path: string]: SummaryObject } = {};\n private summaryStats: ISummaryStats;\n\n public addBlob(key: string, content: string | Uint8Array): void {\n // Prevent cloning by directly referencing underlying private properties\n addBlobToSummary({\n summary: {\n type: SummaryType.Tree,\n tree: this.summaryTree,\n },\n stats: this.summaryStats,\n }, key, content);\n }\n\n public addHandle(\n key: string,\n handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,\n handle: string): void\n {\n this.summaryTree[key] = {\n type: SummaryType.Handle,\n handleType,\n handle,\n };\n this.summaryStats.handleNodeCount++;\n }\n\n public addWithStats(key: string, summarizeResult: ISummarizeResult): void {\n this.summaryTree[key] = summarizeResult.summary;\n this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);\n }\n\n public addAttachment(id: string) {\n this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };\n }\n\n public getSummaryTree(): ISummaryTreeWithStats {\n return { summary: this.summary, stats: this.stats };\n }\n}\n\n/**\n * Converts snapshot ITree to ISummaryTree format and tracks stats.\n * @param snapshot - snapshot in ITree format\n * @param fullTree - true to never use handles, even if id is specified\n */\nexport function convertToSummaryTreeWithStats(\n snapshot: ITree,\n fullTree: boolean = false,\n): ISummaryTreeWithStats {\n const builder = new SummaryTreeBuilder();\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n const blob = entry.value;\n let content: string | Uint8Array;\n if (blob.encoding === \"base64\") {\n content = IsoBuffer.from(blob.contents, \"base64\");\n } else {\n content = blob.contents;\n }\n builder.addBlob(entry.path, content);\n break;\n }\n\n case TreeEntry.Tree: {\n const subtree = convertToSummaryTree(\n entry.value,\n fullTree);\n builder.addWithStats(entry.path, subtree);\n\n break;\n }\n\n case TreeEntry.Attachment: {\n const id = entry.value.id;\n builder.addAttachment(id);\n\n break;\n }\n\n default:\n throw new Error(\"Unexpected TreeEntry type\");\n }\n }\n\n const summaryTree = builder.getSummaryTree();\n summaryTree.summary.unreferenced = snapshot.unreferenced;\n return summaryTree;\n}\n\n/**\n * Converts snapshot ITree to ISummaryTree format and tracks stats.\n * @param snapshot - snapshot in ITree format\n * @param fullTree - true to never use handles, even if id is specified\n */\nexport function convertToSummaryTree(\n snapshot: ITree,\n fullTree: boolean = false,\n): ISummarizeResult {\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (snapshot.id && !fullTree) {\n const stats = mergeStats();\n stats.handleNodeCount++;\n return {\n summary: {\n handle: snapshot.id,\n handleType: SummaryType.Tree,\n type: SummaryType.Handle,\n },\n stats,\n };\n } else {\n return convertToSummaryTreeWithStats(snapshot, fullTree);\n }\n}\n\n/**\n * Converts ISnapshotTree to ISummaryTree format and tracks stats. This snapshot tree was\n * was taken by serialize api in detached container.\n * @param snapshot - snapshot in ISnapshotTree format\n */\nexport function convertSnapshotTreeToSummaryTree(\n snapshot: ISnapshotTree,\n): ISummaryTreeWithStats {\n assert(Object.keys(snapshot.commits).length === 0,\n 0x19e /* \"There should not be commit tree entries in snapshot\" */);\n\n const builder = new SummaryTreeBuilder();\n for (const [path, id] of Object.entries(snapshot.blobs)) {\n let decoded: string | undefined;\n if ((snapshot as any).blobsContents !== undefined) {\n const content: ArrayBufferLike = (snapshot as any).blobsContents[id];\n if (content !== undefined) {\n decoded = bufferToString(content, \"utf-8\");\n }\n // 0.44 back-compat We still put contents in same blob for back-compat so need to add blob\n // only for blobPath -> blobId mapping and not for blobId -> blob value contents.\n } else if (snapshot.blobs[id] !== undefined) {\n decoded = fromBase64ToUtf8(snapshot.blobs[id]);\n }\n if (decoded !== undefined) {\n builder.addBlob(path, decoded);\n }\n }\n\n for (const [key, tree] of Object.entries(snapshot.trees)) {\n const subtree = convertSnapshotTreeToSummaryTree(tree);\n builder.addWithStats(key, subtree);\n }\n\n const summaryTree = builder.getSummaryTree();\n summaryTree.summary.unreferenced = snapshot.unreferenced;\n return summaryTree;\n}\n\n/**\n * Converts ISummaryTree to ITree format. This is needed for back-compat while we get rid of snapshot.\n * @param summaryTree - summary tree in ISummaryTree format\n */\nexport function convertSummaryTreeToITree(summaryTree: ISummaryTree): ITree {\n const entries: ITreeEntry[] = [];\n for (const [key, value] of Object.entries(summaryTree.tree)) {\n switch (value.type) {\n case SummaryType.Blob: {\n let parsedContent: string;\n let encoding: \"utf-8\" | \"base64\" = \"utf-8\";\n if (typeof value.content === \"string\") {\n parsedContent = value.content;\n } else {\n parsedContent = Uint8ArrayToString(value.content, \"base64\");\n encoding = \"base64\";\n }\n entries.push(new BlobTreeEntry(key, parsedContent, encoding));\n break;\n }\n\n case SummaryType.Tree: {\n entries.push(new TreeTreeEntry(key, convertSummaryTreeToITree(value)));\n break;\n }\n\n case SummaryType.Attachment: {\n entries.push(new AttachmentTreeEntry(key, value.id));\n break;\n }\n\n case SummaryType.Handle: {\n throw new Error(\"Should not have Handle type in summary tree\");\n }\n\n default:\n unreachableCase(value, \"Unexpected summary tree type\");\n }\n }\n return {\n entries,\n unreferenced: summaryTree.unreferenced,\n };\n}\n"]}
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { IFluidObject, IFluidRouter, IRequest, IResponse } from "@fluidframework/core-interfaces";
|
|
5
|
+
import { FluidObject, IFluidObject, IFluidRouter, IRequest, IResponse } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { IFluidDataStoreFactory, IFluidDataStoreRegistry, IProvideFluidDataStoreRegistry } from "@fluidframework/runtime-definitions";
|
|
7
|
-
export declare function getStack(): string | undefined;
|
|
8
7
|
export declare function exceptionToResponse(err: any): IResponse;
|
|
9
8
|
export declare function responseToException(response: IResponse, request: IRequest): Error;
|
|
10
|
-
export declare function requestFluidObject<T = IFluidObject>(router: IFluidRouter, url: string | IRequest): Promise<T>;
|
|
9
|
+
export declare function requestFluidObject<T = IFluidObject & FluidObject>(router: IFluidRouter, url: string | IRequest): Promise<T>;
|
|
11
10
|
export declare const create404Response: (request: IRequest) => IResponse;
|
|
12
11
|
export declare function createResponseError(status: number, value: string, request: IRequest): IResponse;
|
|
13
12
|
export declare type Factory = IFluidDataStoreFactory & Partial<IProvideFluidDataStoreRegistry>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataStoreHelpers.d.ts","sourceRoot":"","sources":["../src/dataStoreHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,SAAS,EACZ,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,EACjC,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"dataStoreHelpers.d.ts","sourceRoot":"","sources":["../src/dataStoreHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,SAAS,EACZ,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,EACjC,MAAM,qCAAqC,CAAC;AAU7C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,CAsBvD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,GAAG,KAAK,CAYjF;AAED,wBAAsB,kBAAkB,CAAC,CAAC,GAAG,YAAY,GAAG,WAAW,EACnE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAU5D;AAED,eAAO,MAAM,iBAAiB,YAAa,QAAQ,cAAmD,CAAC;AAEvG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,SAAS,CAc/F;AAED,oBAAY,OAAO,GAAG,sBAAsB,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;AAGvF,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAChC,sBAAsB,GAAG,uBAAuB,CAStD"}
|
package/lib/dataStoreHelpers.js
CHANGED
|
@@ -3,20 +3,8 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { assert } from "@fluidframework/common-utils";
|
|
6
|
-
|
|
7
|
-
const err = new Error();
|
|
8
|
-
if (err.stack !== undefined) {
|
|
9
|
-
return err.stack;
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
throw err;
|
|
13
|
-
}
|
|
14
|
-
catch (err2) {
|
|
15
|
-
return err2.stack;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
6
|
+
import { generateErrorWithStack } from "@fluidframework/telemetry-utils";
|
|
18
7
|
export function exceptionToResponse(err) {
|
|
19
|
-
var _a;
|
|
20
8
|
const status = 500;
|
|
21
9
|
// eslint-disable-next-line no-null/no-null
|
|
22
10
|
if (err !== null && typeof err === "object" && err.errorFromRequestFluidObject === true) {
|
|
@@ -25,31 +13,29 @@ export function exceptionToResponse(err) {
|
|
|
25
13
|
mimeType: "text/plain",
|
|
26
14
|
status: responseErr.code,
|
|
27
15
|
value: responseErr.message,
|
|
28
|
-
stack
|
|
16
|
+
get stack() { return responseErr.stack; },
|
|
29
17
|
};
|
|
30
18
|
}
|
|
19
|
+
// Capture error objects, not stack itself, as stack retrieval is very expensive operation, so we delay it
|
|
20
|
+
const errWithStack = generateErrorWithStack();
|
|
31
21
|
return {
|
|
32
22
|
mimeType: "text/plain",
|
|
33
23
|
status,
|
|
34
24
|
value: `${err}`,
|
|
35
|
-
stack:
|
|
25
|
+
get stack() { var _a; return (_a = (err === null || err === void 0 ? void 0 : err.stack)) !== null && _a !== void 0 ? _a : errWithStack.stack; },
|
|
36
26
|
};
|
|
37
27
|
}
|
|
38
28
|
export function responseToException(response, request) {
|
|
39
29
|
const message = response.value;
|
|
40
|
-
const
|
|
41
|
-
const responseErr =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
catch (err2) { }
|
|
51
|
-
}
|
|
52
|
-
return err;
|
|
30
|
+
const errWithStack = generateErrorWithStack();
|
|
31
|
+
const responseErr = {
|
|
32
|
+
errorFromRequestFluidObject: true,
|
|
33
|
+
message,
|
|
34
|
+
name: "Error",
|
|
35
|
+
code: response.status,
|
|
36
|
+
get stack() { var _a; return (_a = response.stack) !== null && _a !== void 0 ? _a : errWithStack.stack; },
|
|
37
|
+
};
|
|
38
|
+
return responseErr;
|
|
53
39
|
}
|
|
54
40
|
export async function requestFluidObject(router, url) {
|
|
55
41
|
const request = typeof url === "string" ? { url } : url;
|
|
@@ -66,11 +52,13 @@ export function createResponseError(status, value, request) {
|
|
|
66
52
|
assert(status !== 200, 0x19b /* "Cannot not create response error on 200 status" */);
|
|
67
53
|
// Omit query string which could contain personal data (aka "PII")
|
|
68
54
|
const urlNoQuery = (_a = request.url) === null || _a === void 0 ? void 0 : _a.split("?")[0];
|
|
55
|
+
// Capture error objects, not stack itself, as stack retrieval is very expensive operation, so we delay it
|
|
56
|
+
const errWithStack = generateErrorWithStack();
|
|
69
57
|
return {
|
|
70
58
|
mimeType: "text/plain",
|
|
71
59
|
status,
|
|
72
60
|
value: urlNoQuery === undefined ? value : `${value}: ${urlNoQuery}`,
|
|
73
|
-
stack
|
|
61
|
+
get stack() { return errWithStack.stack; },
|
|
74
62
|
};
|
|
75
63
|
}
|
|
76
64
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|