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