@fluidframework/runtime-utils 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.224419
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/.eslintrc.js +5 -7
- package/.mocharc.js +12 -0
- package/CHANGELOG.md +191 -0
- package/README.md +68 -1
- package/api-extractor-lint.json +4 -0
- package/api-extractor.json +2 -2
- package/api-report/runtime-utils.api.md +201 -0
- package/dist/{dataStoreHandleContextUtils.js → dataStoreHandleContextUtils.cjs} +5 -2
- package/dist/dataStoreHandleContextUtils.cjs.map +1 -0
- package/dist/dataStoreHandleContextUtils.d.ts +1 -0
- package/dist/dataStoreHandleContextUtils.d.ts.map +1 -1
- package/dist/{dataStoreHelpers.js → dataStoreHelpers.cjs} +44 -25
- package/dist/dataStoreHelpers.cjs.map +1 -0
- package/dist/dataStoreHelpers.d.ts +23 -4
- package/dist/dataStoreHelpers.d.ts.map +1 -1
- package/dist/index.cjs +44 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/{objectstoragepartition.js → objectstoragepartition.cjs} +4 -3
- package/dist/objectstoragepartition.cjs.map +1 -0
- package/dist/objectstoragepartition.d.ts +1 -0
- package/dist/objectstoragepartition.d.ts.map +1 -1
- package/dist/{objectstorageutils.js → objectstorageutils.cjs} +11 -15
- package/dist/objectstorageutils.cjs.map +1 -0
- package/dist/objectstorageutils.d.ts +6 -0
- package/dist/objectstorageutils.d.ts.map +1 -1
- package/dist/{requestParser.js → requestParser.cjs} +7 -11
- package/dist/requestParser.cjs.map +1 -0
- package/dist/requestParser.d.ts +1 -0
- package/dist/requestParser.d.ts.map +1 -1
- package/dist/runtime-utils-alpha.d.ts +155 -0
- package/dist/runtime-utils-beta.d.ts +103 -0
- package/dist/runtime-utils-public.d.ts +103 -0
- package/dist/runtime-utils-untrimmed.d.ts +306 -0
- package/dist/{runtimeFactoryHelper.js → runtimeFactoryHelper.cjs} +11 -12
- package/dist/runtimeFactoryHelper.cjs.map +1 -0
- package/dist/runtimeFactoryHelper.d.ts +4 -1
- package/dist/runtimeFactoryHelper.d.ts.map +1 -1
- package/dist/{summaryUtils.js → summaryUtils.cjs} +138 -34
- package/dist/summaryUtils.cjs.map +1 -0
- package/dist/summaryUtils.d.ts +66 -4
- package/dist/summaryUtils.d.ts.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/unpackUsedRoutes.cjs +34 -0
- package/dist/unpackUsedRoutes.cjs.map +1 -0
- package/dist/unpackUsedRoutes.d.ts +12 -0
- package/dist/unpackUsedRoutes.d.ts.map +1 -0
- package/dist/{utils.js → utils.cjs} +2 -1
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.ts +7 -2
- package/dist/utils.d.ts.map +1 -1
- package/lib/{dataStoreHandleContextUtils.d.ts → dataStoreHandleContextUtils.d.mts} +1 -0
- package/lib/dataStoreHandleContextUtils.d.mts.map +1 -0
- package/lib/{dataStoreHandleContextUtils.js → dataStoreHandleContextUtils.mjs} +5 -2
- package/lib/dataStoreHandleContextUtils.mjs.map +1 -0
- package/lib/{dataStoreHelpers.d.ts → dataStoreHelpers.d.mts} +23 -4
- package/lib/dataStoreHelpers.d.mts.map +1 -0
- package/lib/{dataStoreHelpers.js → dataStoreHelpers.mjs} +42 -22
- package/lib/dataStoreHelpers.mjs.map +1 -0
- package/lib/index.d.mts +14 -0
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +14 -0
- package/lib/index.mjs.map +1 -0
- package/lib/{objectstoragepartition.d.ts → objectstoragepartition.d.mts} +1 -0
- package/lib/objectstoragepartition.d.mts.map +1 -0
- package/lib/{objectstoragepartition.js → objectstoragepartition.mjs} +3 -2
- package/lib/objectstoragepartition.mjs.map +1 -0
- package/lib/{objectstorageutils.d.ts → objectstorageutils.d.mts} +6 -0
- package/lib/objectstorageutils.d.mts.map +1 -0
- package/lib/{objectstorageutils.js → objectstorageutils.mjs} +11 -15
- package/lib/objectstorageutils.mjs.map +1 -0
- package/lib/{requestParser.d.ts → requestParser.d.mts} +1 -4
- package/lib/requestParser.d.mts.map +1 -0
- package/lib/{requestParser.js → requestParser.mjs} +7 -11
- package/lib/requestParser.mjs.map +1 -0
- package/lib/runtime-utils-alpha.d.mts +155 -0
- package/lib/runtime-utils-beta.d.mts +103 -0
- package/lib/runtime-utils-public.d.mts +103 -0
- package/lib/runtime-utils-untrimmed.d.mts +306 -0
- package/lib/{runtimeFactoryHelper.d.ts → runtimeFactoryHelper.d.mts} +4 -1
- package/lib/runtimeFactoryHelper.d.mts.map +1 -0
- package/lib/runtimeFactoryHelper.mjs +24 -0
- package/lib/runtimeFactoryHelper.mjs.map +1 -0
- package/lib/{summaryUtils.d.ts → summaryUtils.d.mts} +66 -4
- package/lib/summaryUtils.d.mts.map +1 -0
- package/lib/{summaryUtils.js → summaryUtils.mjs} +129 -26
- package/lib/summaryUtils.mjs.map +1 -0
- package/lib/unpackUsedRoutes.d.mts +12 -0
- package/lib/unpackUsedRoutes.d.mts.map +1 -0
- package/lib/unpackUsedRoutes.mjs +30 -0
- package/lib/unpackUsedRoutes.mjs.map +1 -0
- package/lib/{utils.d.ts → utils.d.mts} +7 -2
- package/lib/utils.d.mts.map +1 -0
- package/lib/{utils.js → utils.mjs} +2 -1
- package/lib/utils.mjs.map +1 -0
- package/package.json +102 -66
- package/prettier.config.cjs +8 -0
- package/src/dataStoreHandleContextUtils.ts +24 -16
- package/src/dataStoreHelpers.ts +106 -83
- package/src/index.ts +31 -9
- package/src/objectstoragepartition.ts +18 -14
- package/src/objectstorageutils.ts +37 -36
- package/src/requestParser.ts +81 -86
- package/src/runtimeFactoryHelper.ts +27 -26
- package/src/summaryUtils.ts +425 -299
- package/src/unpackUsedRoutes.ts +31 -0
- package/src/utils.ts +12 -7
- package/tsc-multi.test.json +4 -0
- package/tsconfig.json +10 -12
- package/dist/dataStoreHandleContextUtils.js.map +0 -1
- package/dist/dataStoreHelpers.js.map +0 -1
- package/dist/index.js +0 -26
- package/dist/index.js.map +0 -1
- package/dist/objectstoragepartition.js.map +0 -1
- package/dist/objectstorageutils.js.map +0 -1
- package/dist/packageVersion.d.ts +0 -9
- package/dist/packageVersion.d.ts.map +0 -1
- package/dist/packageVersion.js +0 -12
- package/dist/packageVersion.js.map +0 -1
- package/dist/requestParser.js.map +0 -1
- package/dist/runtimeFactoryHelper.js.map +0 -1
- package/dist/summarizerNode/index.d.ts +0 -8
- package/dist/summarizerNode/index.d.ts.map +0 -1
- package/dist/summarizerNode/index.js +0 -12
- package/dist/summarizerNode/index.js.map +0 -1
- package/dist/summarizerNode/summarizerNode.d.ts +0 -139
- package/dist/summarizerNode/summarizerNode.d.ts.map +0 -1
- package/dist/summarizerNode/summarizerNode.js +0 -480
- package/dist/summarizerNode/summarizerNode.js.map +0 -1
- package/dist/summarizerNode/summarizerNodeUtils.d.ts +0 -161
- package/dist/summarizerNode/summarizerNodeUtils.d.ts.map +0 -1
- package/dist/summarizerNode/summarizerNodeUtils.js +0 -225
- package/dist/summarizerNode/summarizerNodeUtils.js.map +0 -1
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts +0 -133
- package/dist/summarizerNode/summarizerNodeWithGc.d.ts.map +0 -1
- package/dist/summarizerNode/summarizerNodeWithGc.js +0 -294
- package/dist/summarizerNode/summarizerNodeWithGc.js.map +0 -1
- package/dist/summaryUtils.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/lib/dataStoreHandleContextUtils.d.ts.map +0 -1
- package/lib/dataStoreHandleContextUtils.js.map +0 -1
- package/lib/dataStoreHelpers.d.ts.map +0 -1
- package/lib/dataStoreHelpers.js.map +0 -1
- package/lib/index.d.ts +0 -14
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -14
- package/lib/index.js.map +0 -1
- package/lib/objectstoragepartition.d.ts.map +0 -1
- package/lib/objectstoragepartition.js.map +0 -1
- package/lib/objectstorageutils.d.ts.map +0 -1
- package/lib/objectstorageutils.js.map +0 -1
- package/lib/packageVersion.d.ts +0 -9
- package/lib/packageVersion.d.ts.map +0 -1
- package/lib/packageVersion.js +0 -9
- package/lib/packageVersion.js.map +0 -1
- package/lib/requestParser.d.ts.map +0 -1
- package/lib/requestParser.js.map +0 -1
- package/lib/runtimeFactoryHelper.d.ts.map +0 -1
- package/lib/runtimeFactoryHelper.js +0 -25
- package/lib/runtimeFactoryHelper.js.map +0 -1
- package/lib/summarizerNode/index.d.ts +0 -8
- package/lib/summarizerNode/index.d.ts.map +0 -1
- package/lib/summarizerNode/index.js +0 -7
- package/lib/summarizerNode/index.js.map +0 -1
- package/lib/summarizerNode/summarizerNode.d.ts +0 -139
- package/lib/summarizerNode/summarizerNode.d.ts.map +0 -1
- package/lib/summarizerNode/summarizerNode.js +0 -475
- package/lib/summarizerNode/summarizerNode.js.map +0 -1
- package/lib/summarizerNode/summarizerNodeUtils.d.ts +0 -161
- package/lib/summarizerNode/summarizerNodeUtils.d.ts.map +0 -1
- package/lib/summarizerNode/summarizerNodeUtils.js +0 -216
- package/lib/summarizerNode/summarizerNodeUtils.js.map +0 -1
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts +0 -133
- package/lib/summarizerNode/summarizerNodeWithGc.d.ts.map +0 -1
- package/lib/summarizerNode/summarizerNodeWithGc.js +0 -289
- package/lib/summarizerNode/summarizerNodeWithGc.js.map +0 -1
- package/lib/summaryUtils.d.ts.map +0 -1
- package/lib/summaryUtils.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
- package/src/packageVersion.ts +0 -9
- package/src/summarizerNode/index.ts +0 -8
- package/src/summarizerNode/summarizerNode.ts +0 -662
- package/src/summarizerNode/summarizerNodeUtils.ts +0 -339
- package/src/summarizerNode/summarizerNodeWithGc.ts +0 -459
- package/tsconfig.esnext.json +0 -7
package/src/summaryUtils.ts
CHANGED
|
@@ -3,373 +3,499 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { TelemetryEventPropertyType } from "@fluidframework/
|
|
6
|
+
import { TelemetryEventPropertyType } from "@fluidframework/core-interfaces";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "@fluidframework/
|
|
14
|
-
import { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from "@fluidframework/
|
|
8
|
+
bufferToString,
|
|
9
|
+
fromBase64ToUtf8,
|
|
10
|
+
IsoBuffer,
|
|
11
|
+
Uint8ArrayToString,
|
|
12
|
+
} from "@fluid-internal/client-utils";
|
|
13
|
+
import { unreachableCase } from "@fluidframework/core-utils";
|
|
14
|
+
import { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from "@fluidframework/driver-utils";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ISnapshotTree,
|
|
16
|
+
ITree,
|
|
17
|
+
SummaryType,
|
|
18
|
+
ISummaryTree,
|
|
19
|
+
SummaryObject,
|
|
20
|
+
ISummaryBlob,
|
|
21
|
+
TreeEntry,
|
|
22
|
+
ITreeEntry,
|
|
24
23
|
} from "@fluidframework/protocol-definitions";
|
|
25
24
|
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
ISummaryStats,
|
|
26
|
+
ISummarizeResult,
|
|
27
|
+
ISummaryTreeWithStats,
|
|
28
|
+
ITelemetryContext,
|
|
29
|
+
IGarbageCollectionData,
|
|
30
30
|
} from "@fluidframework/runtime-definitions";
|
|
31
|
+
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Combines summary stats by adding their totals together.
|
|
34
35
|
* Returns empty stats if called without args.
|
|
35
36
|
* @param stats - stats to merge
|
|
37
|
+
* @internal
|
|
36
38
|
*/
|
|
37
39
|
export function mergeStats(...stats: ISummaryStats[]): ISummaryStats {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
const results = {
|
|
41
|
+
treeNodeCount: 0,
|
|
42
|
+
blobNodeCount: 0,
|
|
43
|
+
handleNodeCount: 0,
|
|
44
|
+
totalBlobSize: 0,
|
|
45
|
+
unreferencedBlobSize: 0,
|
|
46
|
+
};
|
|
47
|
+
for (const stat of stats) {
|
|
48
|
+
results.treeNodeCount += stat.treeNodeCount;
|
|
49
|
+
results.blobNodeCount += stat.blobNodeCount;
|
|
50
|
+
results.handleNodeCount += stat.handleNodeCount;
|
|
51
|
+
results.totalBlobSize += stat.totalBlobSize;
|
|
52
|
+
results.unreferencedBlobSize += stat.unreferencedBlobSize;
|
|
53
|
+
}
|
|
54
|
+
return results;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
55
60
|
export function utf8ByteLength(str: string): number {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
// returns the byte length of an utf8 string
|
|
62
|
+
let s = str.length;
|
|
63
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
64
|
+
const code = str.charCodeAt(i);
|
|
65
|
+
if (code > 0x7f && code <= 0x7ff) {
|
|
66
|
+
s++;
|
|
67
|
+
} else if (code > 0x7ff && code <= 0xffff) {
|
|
68
|
+
s += 2;
|
|
69
|
+
}
|
|
70
|
+
if (code >= 0xdc00 && code <= 0xdfff) {
|
|
71
|
+
i--; // trail surrogate
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return s;
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
/**
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
72
80
|
export function getBlobSize(content: ISummaryBlob["content"]): number {
|
|
73
|
-
|
|
74
|
-
return utf8ByteLength(content);
|
|
75
|
-
} else {
|
|
76
|
-
return content.byteLength;
|
|
77
|
-
}
|
|
81
|
+
return typeof content === "string" ? utf8ByteLength(content) : content.byteLength;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
function calculateStatsCore(summaryObject: SummaryObject, stats: ISummaryStats): void {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
85
|
+
switch (summaryObject.type) {
|
|
86
|
+
case SummaryType.Tree: {
|
|
87
|
+
stats.treeNodeCount++;
|
|
88
|
+
for (const value of Object.values(summaryObject.tree)) {
|
|
89
|
+
calculateStatsCore(value, stats);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
case SummaryType.Handle: {
|
|
94
|
+
stats.handleNodeCount++;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
case SummaryType.Blob: {
|
|
98
|
+
stats.blobNodeCount++;
|
|
99
|
+
stats.totalBlobSize += getBlobSize(summaryObject.content);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
default:
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
100
105
|
}
|
|
101
106
|
|
|
107
|
+
/**
|
|
108
|
+
* @internal
|
|
109
|
+
*/
|
|
102
110
|
export function calculateStats(summary: SummaryObject): ISummaryStats {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
const stats = mergeStats();
|
|
112
|
+
calculateStatsCore(summary, stats);
|
|
113
|
+
return stats;
|
|
106
114
|
}
|
|
107
115
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
/**
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
export function addBlobToSummary(
|
|
120
|
+
summary: ISummaryTreeWithStats,
|
|
121
|
+
key: string,
|
|
122
|
+
content: string | Uint8Array,
|
|
123
|
+
): void {
|
|
124
|
+
const blob: ISummaryBlob = {
|
|
125
|
+
type: SummaryType.Blob,
|
|
126
|
+
content,
|
|
127
|
+
};
|
|
128
|
+
summary.summary.tree[key] = blob;
|
|
129
|
+
summary.stats.blobNodeCount++;
|
|
130
|
+
summary.stats.totalBlobSize += getBlobSize(content);
|
|
116
131
|
}
|
|
117
132
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
/**
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
export function addTreeToSummary(
|
|
137
|
+
summary: ISummaryTreeWithStats,
|
|
138
|
+
key: string,
|
|
139
|
+
summarizeResult: ISummarizeResult,
|
|
140
|
+
): void {
|
|
141
|
+
summary.summary.tree[key] = summarizeResult.summary;
|
|
142
|
+
summary.stats = mergeStats(summary.stats, summarizeResult.stats);
|
|
121
143
|
}
|
|
122
144
|
|
|
145
|
+
/**
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
123
148
|
export function addSummarizeResultToSummary(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
149
|
+
summary: ISummaryTreeWithStats,
|
|
150
|
+
key: string,
|
|
151
|
+
summarizeResult: ISummarizeResult,
|
|
127
152
|
): void {
|
|
128
|
-
|
|
129
|
-
|
|
153
|
+
summary.summary.tree[key] = summarizeResult.summary;
|
|
154
|
+
summary.stats = mergeStats(summary.stats, summarizeResult.stats);
|
|
130
155
|
}
|
|
131
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @alpha
|
|
159
|
+
*/
|
|
132
160
|
export class SummaryTreeBuilder implements ISummaryTreeWithStats {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
161
|
+
private attachmentCounter: number = 0;
|
|
162
|
+
|
|
163
|
+
public get summary(): ISummaryTree {
|
|
164
|
+
return {
|
|
165
|
+
type: SummaryType.Tree,
|
|
166
|
+
tree: { ...this.summaryTree },
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public get stats(): Readonly<ISummaryStats> {
|
|
171
|
+
return { ...this.summaryStats };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
constructor() {
|
|
175
|
+
this.summaryStats = mergeStats();
|
|
176
|
+
this.summaryStats.treeNodeCount++;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private readonly summaryTree: { [path: string]: SummaryObject } = {};
|
|
180
|
+
private summaryStats: ISummaryStats;
|
|
181
|
+
|
|
182
|
+
public addBlob(key: string, content: string | Uint8Array): void {
|
|
183
|
+
// Prevent cloning by directly referencing underlying private properties
|
|
184
|
+
addBlobToSummary(
|
|
185
|
+
{
|
|
186
|
+
summary: {
|
|
187
|
+
type: SummaryType.Tree,
|
|
188
|
+
tree: this.summaryTree,
|
|
189
|
+
},
|
|
190
|
+
stats: this.summaryStats,
|
|
191
|
+
},
|
|
192
|
+
key,
|
|
193
|
+
content,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public addHandle(
|
|
198
|
+
key: string,
|
|
199
|
+
handleType: SummaryType.Tree | SummaryType.Blob | SummaryType.Attachment,
|
|
200
|
+
handle: string,
|
|
201
|
+
): void {
|
|
202
|
+
this.summaryTree[key] = {
|
|
203
|
+
type: SummaryType.Handle,
|
|
204
|
+
handleType,
|
|
205
|
+
handle,
|
|
206
|
+
};
|
|
207
|
+
this.summaryStats.handleNodeCount++;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public addWithStats(key: string, summarizeResult: ISummarizeResult): void {
|
|
211
|
+
this.summaryTree[key] = summarizeResult.summary;
|
|
212
|
+
this.summaryStats = mergeStats(this.summaryStats, summarizeResult.stats);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public addAttachment(id: string) {
|
|
216
|
+
this.summaryTree[this.attachmentCounter++] = { id, type: SummaryType.Attachment };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public getSummaryTree(): ISummaryTreeWithStats {
|
|
220
|
+
return { summary: this.summary, stats: this.stats };
|
|
221
|
+
}
|
|
189
222
|
}
|
|
190
223
|
|
|
191
224
|
/**
|
|
192
225
|
* Converts snapshot ITree to ISummaryTree format and tracks stats.
|
|
193
226
|
* @param snapshot - snapshot in ITree format
|
|
194
227
|
* @param fullTree - true to never use handles, even if id is specified
|
|
228
|
+
* @alpha
|
|
195
229
|
*/
|
|
196
230
|
export function convertToSummaryTreeWithStats(
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
snapshot: ITree,
|
|
232
|
+
fullTree: boolean = false,
|
|
199
233
|
): ISummaryTreeWithStats {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const summaryTree = builder.getSummaryTree();
|
|
237
|
-
summaryTree.summary.unreferenced = snapshot.unreferenced;
|
|
238
|
-
return summaryTree;
|
|
234
|
+
const builder = new SummaryTreeBuilder();
|
|
235
|
+
for (const entry of snapshot.entries) {
|
|
236
|
+
switch (entry.type) {
|
|
237
|
+
case TreeEntry.Blob: {
|
|
238
|
+
const blob = entry.value;
|
|
239
|
+
const content =
|
|
240
|
+
blob.encoding === "base64"
|
|
241
|
+
? IsoBuffer.from(blob.contents, "base64")
|
|
242
|
+
: blob.contents;
|
|
243
|
+
builder.addBlob(entry.path, content);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case TreeEntry.Tree: {
|
|
248
|
+
const subtree = convertToSummaryTree(entry.value, fullTree);
|
|
249
|
+
builder.addWithStats(entry.path, subtree);
|
|
250
|
+
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case TreeEntry.Attachment: {
|
|
255
|
+
const id = entry.value.id;
|
|
256
|
+
builder.addAttachment(id);
|
|
257
|
+
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
default:
|
|
262
|
+
throw new Error("Unexpected TreeEntry type");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const summaryTree = builder.getSummaryTree();
|
|
267
|
+
summaryTree.summary.unreferenced = snapshot.unreferenced;
|
|
268
|
+
return summaryTree;
|
|
239
269
|
}
|
|
240
270
|
|
|
241
271
|
/**
|
|
242
272
|
* Converts snapshot ITree to ISummaryTree format and tracks stats.
|
|
243
273
|
* @param snapshot - snapshot in ITree format
|
|
244
274
|
* @param fullTree - true to never use handles, even if id is specified
|
|
275
|
+
* @internal
|
|
245
276
|
*/
|
|
246
|
-
export function convertToSummaryTree(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
} else {
|
|
263
|
-
return convertToSummaryTreeWithStats(snapshot, fullTree);
|
|
264
|
-
}
|
|
277
|
+
export function convertToSummaryTree(snapshot: ITree, fullTree: boolean = false): ISummarizeResult {
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
279
|
+
if (snapshot.id && !fullTree) {
|
|
280
|
+
const stats = mergeStats();
|
|
281
|
+
stats.handleNodeCount++;
|
|
282
|
+
return {
|
|
283
|
+
summary: {
|
|
284
|
+
handle: snapshot.id,
|
|
285
|
+
handleType: SummaryType.Tree,
|
|
286
|
+
type: SummaryType.Handle,
|
|
287
|
+
},
|
|
288
|
+
stats,
|
|
289
|
+
};
|
|
290
|
+
} else {
|
|
291
|
+
return convertToSummaryTreeWithStats(snapshot, fullTree);
|
|
292
|
+
}
|
|
265
293
|
}
|
|
266
294
|
|
|
267
295
|
/**
|
|
268
296
|
* Converts ISnapshotTree to ISummaryTree format and tracks stats. This snapshot tree was
|
|
269
297
|
* was taken by serialize api in detached container.
|
|
270
298
|
* @param snapshot - snapshot in ISnapshotTree format
|
|
299
|
+
* @internal
|
|
271
300
|
*/
|
|
272
301
|
export function convertSnapshotTreeToSummaryTree(
|
|
273
|
-
|
|
302
|
+
snapshot: ISnapshotTreeWithBlobContents,
|
|
274
303
|
): ISummaryTreeWithStats {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
304
|
+
const builder = new SummaryTreeBuilder();
|
|
305
|
+
for (const [path, id] of Object.entries(snapshot.blobs)) {
|
|
306
|
+
let decoded: string | undefined;
|
|
307
|
+
if (snapshot.blobsContents !== undefined) {
|
|
308
|
+
const content: ArrayBufferLike = snapshot.blobsContents[id];
|
|
309
|
+
if (content !== undefined) {
|
|
310
|
+
decoded = bufferToString(content, "utf-8");
|
|
311
|
+
}
|
|
312
|
+
// 0.44 back-compat We still put contents in same blob for back-compat so need to add blob
|
|
313
|
+
// only for blobPath -> blobId mapping and not for blobId -> blob value contents.
|
|
314
|
+
} else if (snapshot.blobs[id] !== undefined) {
|
|
315
|
+
decoded = fromBase64ToUtf8(snapshot.blobs[id]);
|
|
316
|
+
}
|
|
317
|
+
if (decoded !== undefined) {
|
|
318
|
+
builder.addBlob(path, decoded);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const [key, tree] of Object.entries(snapshot.trees)) {
|
|
323
|
+
const subtree = convertSnapshotTreeToSummaryTree(tree);
|
|
324
|
+
builder.addWithStats(key, subtree);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const summaryTree = builder.getSummaryTree();
|
|
328
|
+
summaryTree.summary.unreferenced = snapshot.unreferenced;
|
|
329
|
+
return summaryTree;
|
|
301
330
|
}
|
|
302
331
|
|
|
303
332
|
/**
|
|
304
333
|
* Converts ISummaryTree to ITree format. This is needed for back-compat while we get rid of snapshot.
|
|
305
334
|
* @param summaryTree - summary tree in ISummaryTree format
|
|
335
|
+
* @internal
|
|
306
336
|
*/
|
|
307
337
|
export function convertSummaryTreeToITree(summaryTree: ISummaryTree): ITree {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
338
|
+
const entries: ITreeEntry[] = [];
|
|
339
|
+
for (const [key, value] of Object.entries(summaryTree.tree)) {
|
|
340
|
+
switch (value.type) {
|
|
341
|
+
case SummaryType.Blob: {
|
|
342
|
+
let parsedContent: string;
|
|
343
|
+
let encoding: "utf-8" | "base64" = "utf-8";
|
|
344
|
+
if (typeof value.content === "string") {
|
|
345
|
+
parsedContent = value.content;
|
|
346
|
+
} else {
|
|
347
|
+
parsedContent = Uint8ArrayToString(value.content, "base64");
|
|
348
|
+
encoding = "base64";
|
|
349
|
+
}
|
|
350
|
+
entries.push(new BlobTreeEntry(key, parsedContent, encoding));
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
case SummaryType.Tree: {
|
|
355
|
+
entries.push(new TreeTreeEntry(key, convertSummaryTreeToITree(value)));
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
case SummaryType.Attachment: {
|
|
360
|
+
entries.push(new AttachmentTreeEntry(key, value.id));
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
case SummaryType.Handle: {
|
|
365
|
+
throw new Error("Should not have Handle type in summary tree");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
default:
|
|
369
|
+
unreachableCase(value, "Unexpected summary tree type");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
entries,
|
|
374
|
+
unreferenced: summaryTree.unreferenced,
|
|
375
|
+
};
|
|
346
376
|
}
|
|
347
377
|
|
|
378
|
+
/**
|
|
379
|
+
* @internal
|
|
380
|
+
*/
|
|
348
381
|
export class TelemetryContext implements ITelemetryContext {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
382
|
+
private readonly telemetry = new Map<string, TelemetryEventPropertyType>();
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.set}
|
|
386
|
+
*/
|
|
387
|
+
set(prefix: string, property: string, value: TelemetryEventPropertyType): void {
|
|
388
|
+
this.telemetry.set(`${prefix}${property}`, value);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.setMultiple}
|
|
393
|
+
*/
|
|
394
|
+
setMultiple(
|
|
395
|
+
prefix: string,
|
|
396
|
+
property: string,
|
|
397
|
+
values: Record<string, TelemetryEventPropertyType>,
|
|
398
|
+
): void {
|
|
399
|
+
// Set the values individually so that they are logged as a flat list along with other properties.
|
|
400
|
+
for (const key of Object.keys(values)) {
|
|
401
|
+
this.set(prefix, `${property}_${key}`, values[key]);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.get}
|
|
407
|
+
*/
|
|
408
|
+
get(prefix: string, property: string): TelemetryEventPropertyType {
|
|
409
|
+
return this.telemetry.get(`${prefix}${property}`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* {@inheritDoc @fluidframework/runtime-definitions#ITelemetryContext.serialize}
|
|
414
|
+
*/
|
|
415
|
+
serialize(): string {
|
|
416
|
+
const jsonObject = {};
|
|
417
|
+
this.telemetry.forEach((value, key) => {
|
|
418
|
+
jsonObject[key] = value;
|
|
419
|
+
});
|
|
420
|
+
return JSON.stringify(jsonObject);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Trims the leading slashes from the given string.
|
|
426
|
+
* @param str - A string that may contain leading slashes.
|
|
427
|
+
* @returns A new string without leading slashes.
|
|
428
|
+
*/
|
|
429
|
+
function trimLeadingSlashes(str: string) {
|
|
430
|
+
return str.replace(/^\/+/g, "");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Trims the trailing slashes from the given string.
|
|
435
|
+
* @param str - A string that may contain trailing slashes.
|
|
436
|
+
* @returns A new string without trailing slashes.
|
|
437
|
+
*/
|
|
438
|
+
function trimTrailingSlashes(str: string) {
|
|
439
|
+
return str.replace(/\/+$/g, "");
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Helper class to build the garbage collection data of a node by combining the data from multiple nodes.
|
|
444
|
+
* @internal
|
|
445
|
+
*/
|
|
446
|
+
export class GCDataBuilder implements IGarbageCollectionData {
|
|
447
|
+
private readonly gcNodesSet: { [id: string]: Set<string> } = {};
|
|
448
|
+
public get gcNodes(): { [id: string]: string[] } {
|
|
449
|
+
const gcNodes = {};
|
|
450
|
+
for (const [nodeId, outboundRoutes] of Object.entries(this.gcNodesSet)) {
|
|
451
|
+
gcNodes[nodeId] = [...outboundRoutes];
|
|
452
|
+
}
|
|
453
|
+
return gcNodes;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
public addNode(id: string, outboundRoutes: string[]) {
|
|
457
|
+
this.gcNodesSet[id] = new Set(outboundRoutes);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Adds the given GC nodes. It does the following:
|
|
462
|
+
* - Normalizes the ids of the given nodes.
|
|
463
|
+
* - Prefixes the given `prefixId` to the given nodes' ids.
|
|
464
|
+
* - Adds the outbound routes of the nodes against the normalized and prefixed id.
|
|
465
|
+
*/
|
|
466
|
+
public prefixAndAddNodes(prefixId: string, gcNodes: { [id: string]: string[] }) {
|
|
467
|
+
for (const [id, outboundRoutes] of Object.entries(gcNodes)) {
|
|
468
|
+
// Remove any leading slashes from the id.
|
|
469
|
+
let normalizedId = trimLeadingSlashes(id);
|
|
470
|
+
// Prefix the given id to the normalized id.
|
|
471
|
+
normalizedId = `/${prefixId}/${normalizedId}`;
|
|
472
|
+
// Remove any trailing slashes from the normalized id. Note that the trailing slashes are removed after
|
|
473
|
+
// adding the prefix for handling the special case where id is "/".
|
|
474
|
+
normalizedId = trimTrailingSlashes(normalizedId);
|
|
475
|
+
|
|
476
|
+
// Add the outbound routes against the normalized and prefixed id without duplicates.
|
|
477
|
+
this.gcNodesSet[normalizedId] = new Set(outboundRoutes);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
public addNodes(gcNodes: { [id: string]: string[] }) {
|
|
482
|
+
for (const [id, outboundRoutes] of Object.entries(gcNodes)) {
|
|
483
|
+
this.gcNodesSet[id] = new Set(outboundRoutes);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Adds the given outbound route to the outbound routes of all GC nodes.
|
|
489
|
+
*/
|
|
490
|
+
public addRouteToAllNodes(outboundRoute: string) {
|
|
491
|
+
for (const outboundRoutes of Object.values(this.gcNodesSet)) {
|
|
492
|
+
outboundRoutes.add(outboundRoute);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
public getGCData(): IGarbageCollectionData {
|
|
497
|
+
return {
|
|
498
|
+
gcNodes: this.gcNodes,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
375
501
|
}
|