@andersbakken/fisk 3.5.6 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,306 +0,0 @@
1
- const EventEmitter = require("events");
2
-
3
- function prettysize(bytes)
4
- {
5
- const prettysize = require("prettysize");
6
- return prettysize(bytes, bytes >= 1024); // don't want 0Bytes
7
- }
8
-
9
- class NodeData
10
- {
11
- constructor(size, maxSize, sha1s)
12
- {
13
- this.sha1s = sha1s;
14
- this.size = size;
15
- this.maxSize = maxSize;
16
- }
17
- };
18
-
19
- class SHA1Data
20
- {
21
- constructor(fileSize, node)
22
- {
23
- this.fileSize = fileSize;
24
- this.nodes = [ node ];
25
- }
26
- };
27
-
28
- function addToSHA1Map(bySHA1, sha1, fileSize, node)
29
- {
30
- let data = bySHA1.get(sha1);
31
- if (data) {
32
- data.nodes.push(node);
33
- return data.nodes.length;
34
- } else {
35
- bySHA1.set(sha1, new SHA1Data(fileSize, node));
36
- return 1;
37
- }
38
- }
39
-
40
- function removeFromSHA1Map(bySHA1, sha1, node)
41
- {
42
- let data = bySHA1.get(sha1);
43
- if (data) {
44
- let idx = data.nodes.indexOf(node);
45
- if (idx != -1) {
46
- data.nodes.splice(idx, 1);
47
- if (data.nodes.length == 0) {
48
- bySHA1.delete(sha1);
49
- }
50
- } else {
51
- console.error("We don't have", node.ip + ":" + node.port, "for", sha1);
52
- }
53
- } else {
54
- console.error("We don't have", sha1);
55
- }
56
- }
57
-
58
- class ObjectCacheManager extends EventEmitter
59
- {
60
- constructor(option)
61
- {
62
- super();
63
- this.hits = 0;
64
- this.bySHA1 = new Map();
65
- this.byNode = new Map();
66
- this.redundancy = option.int("object-cache-redundancy", 1);
67
- if (this.redundancy <= 0)
68
- this.redundancy = 1;
69
- this.distributeOnInsertion = option("distribute-object-cache-on-insertion") || false;
70
- this.distributeOnCacheHit = option("distribute-object-cache-on-cache-hit") || false;
71
- }
72
-
73
- clear()
74
- {
75
- this.hits = 0;
76
- this.emit("cleared");
77
- }
78
-
79
- hit(sha1)
80
- {
81
- ++this.hits;
82
- if (this.distributeOnCacheHit) {
83
- this.distribute({ sha1: sha1, redundancy: this.redundancy });
84
- }
85
- }
86
-
87
- get(sha1)
88
- {
89
- // console.log("looking for", sha1, [ this.bySHA1.keys() ]);
90
- return this.bySHA1.get(sha1);
91
- }
92
-
93
- insert(msg, node)
94
- {
95
- let nodeData = this.byNode.get(node);
96
- console.log("adding", msg.sourceFile, msg.sha1, "for", node.ip + ":" + node.port, nodeData ? nodeData.sha1s.length : -1);
97
- if (nodeData) {
98
- nodeData.sha1s.push(msg.sha1);
99
- nodeData.size = msg.cacheSize;
100
- const count = addToSHA1Map(this.bySHA1, msg.sha1, msg.fileSize, node);
101
- if (this.distributeOnInsertion && count - 1 < this.redundancy) {
102
- this.distribute({ sha1: msg.sha1, redundancy: this.redundancy });
103
- }
104
- } else {
105
- console.error("insert: We don't seem to have this node", node.ip + ":" + node.port);
106
- }
107
- }
108
-
109
- remove(msg, node)
110
- {
111
- let nodeData = this.byNode.get(node);
112
- console.log("removing", msg.sourceFile, msg.sha1, "for", node.ip + ":" + node.port, nodeData ? nodeData.sha1s.length : -1);
113
- if (nodeData) {
114
- let idx = nodeData.sha1s.indexOf(msg.sha1);
115
- if (idx != -1) {
116
- nodeData.sha1s.splice(idx, 1);
117
- } else {
118
- console.error("We don't have", msg.sha1, "on", node.ip + ":" + node.port);
119
- }
120
- removeFromSHA1Map(this.bySHA1, msg.sha1, node);
121
- nodeData.size = msg.cacheSize;
122
- } else {
123
- console.error("remove: We don't seem to have this node", node.ip + ":" + node.port);
124
- }
125
- }
126
-
127
- addNode(node, data)
128
- {
129
- console.log("adding object cache node",
130
- node.ip + ":" + node.port,
131
- node.name, node.hostname,
132
- "maxSize", prettysize(data.maxSize),
133
- "cacheSize", prettysize(data.cacheSize),
134
- "sha1s", data.sha1s.length);
135
- if (this.byNode.get(node)) {
136
- console.log("We already have", node.ip + ":" + node.port);
137
- return;
138
- }
139
- let sha1s = data.sha1s.map(item => item.sha1);
140
- this.byNode.set(node, new NodeData(data.cacheSize, data.maxSize, sha1s));
141
- data.sha1s.forEach(item => {
142
- addToSHA1Map(this.bySHA1, item.sha1, item.fileSize, node);
143
- });
144
- }
145
-
146
- removeNode(node)
147
- {
148
- console.log("removing node", node.ip + ":" + node.port);
149
- let nodeData = this.byNode.get(node);
150
- if (!nodeData) {
151
- console.error("We don't have", node.ip + ":" + node.port);
152
- return;
153
- }
154
- this.byNode.delete(node);
155
- nodeData.sha1s.forEach(sha1 => removeFromSHA1Map(this.bySHA1, sha1, node));
156
- }
157
-
158
- dump(query)
159
- {
160
- if ("clear" in query) {
161
- this.clear();
162
- }
163
- let ret = {
164
- hits: this.hits,
165
- };
166
-
167
- if ("nodes" in query) {
168
- ret.nodes = {};
169
- const verbose = "verbose" in query;
170
- this.byNode.forEach((value, key) => {
171
- let data = {
172
- sha1s: verbose ? value.sha1s : value.sha1s.length,
173
- maxSize: prettysize(value.maxSize),
174
- size: prettysize(value.size)
175
- };
176
- if (key.name)
177
- data.name = key.name;
178
- if (key.hostname)
179
- data.name = key.hostname;
180
- ret.nodes[key.ip + ":" + key.port] = data;
181
- });
182
- }
183
-
184
- if ("objects" in query) {
185
- ret.sha1 = {};
186
- this.bySHA1.forEach((value, key) => {
187
- // console.log(key, value);
188
- ret.sha1[key] = { fileSize: prettysize(value.fileSize), nodes: value.nodes.map(node => node.ip + ":" + node.port) };
189
- });
190
- }
191
-
192
- return ret;
193
- }
194
-
195
- distribute(query, res)
196
- {
197
- const dry = "dry" in query;
198
- let redundancy = parseInt(query.redundancy);
199
- if (isNaN(redundancy) || redundancy <= 0)
200
- redundancy = 1;
201
- let max = parseInt(query.max);
202
- if (isNaN(max) || max <= 0)
203
- max = undefined;
204
- const sha1 = query.sha1;
205
-
206
- let ret;
207
- if (res) {
208
- ret = { type: "fetch_cache_objects", "dry": dry, commands: {} };
209
- console.log("distribute called with redundancy of", redundancy, "and max of", max, "dry", dry, "sha1", sha1);
210
- }
211
-
212
- let that = this;
213
- let nodes = Array.from(this.byNode.keys());
214
- let nodeIdx = 0;
215
- let commands = new Map();
216
- if (!sha1) {
217
- this.byNode.forEach((value, key) => {
218
- commands.set(key, { objects: [], available: value.maxSize - value.size });
219
- });
220
- }
221
- let nodeRestriction = query.node;
222
- let count = 0;
223
- // console.log(commands);
224
- if (this.byNode.size >= 2) {
225
- // let max = 1;
226
- let roundRobinIndex = 0;
227
- function processObject(sha1, value)
228
- {
229
- if (max != undefined && max <= 0)
230
- return;
231
- let needed = Math.min(redundancy + 1 - value.nodes.length, that.byNode.size - 1);
232
- if (needed > 0) {
233
- let needed = redundancy + 1 - value.nodes.length;
234
- // console.log("should distribute", key, "to", needed, "nodes");
235
-
236
- let firstIdx;
237
- let found = 0;
238
- while (found < needed) {
239
- if (++nodeIdx == nodes.length)
240
- nodeIdx = 0;
241
- if (firstIdx === undefined) {
242
- firstIdx = nodeIdx;
243
- } else if (firstIdx === nodeIdx) {
244
- break;
245
- }
246
- let node = nodes[nodeIdx];
247
- if (value.nodes.indexOf(node) != -1) {
248
- continue;
249
- }
250
- let data = commands.get(node);
251
- let available;
252
- if (data) {
253
- available = data.available;
254
- } else {
255
- let nodeData = this.byNode[node];
256
- available = nodeData.maxSize - nodeData.size;
257
- }
258
- if (available < value.fileSize) {
259
- continue;
260
- }
261
- if (!data) {
262
- data = { objects: [], available: available };
263
- commands.set(node, data);
264
- }
265
- ++found;
266
- data.available -= value.fileSize;
267
- const src = value.nodes[roundRobinIndex++ % value.nodes.length];
268
- data.objects.push({ source: src.ip + ":" + src.port, sha1: sha1 });
269
- if (max != undefined && !--max)
270
- break;
271
- }
272
- // console.log("found candidates", candidates.map(node => node.ip + ":" + node.port));
273
- }
274
- }
275
- if (sha1) {
276
- let val = this.bySHA1.get(sha1);
277
- if (val) {
278
- processObject(sha1, val);
279
- } else {
280
- console.error("Couldn't find sha1", sha1);
281
- }
282
- } else {
283
- this.bySHA1.forEach((value, key) => processObject(key, value));
284
- }
285
- }
286
- commands.forEach((value, key) => {
287
- // console.log(key.ip + ": " + key.port, "will receive", value.objects);
288
- if (value.objects.length && (!nodeRestriction || (key.ip + ":" + key.port) == nodeRestriction)) {
289
- console.log(`sending ${value.objects.length}/${this.bySHA1.size} fetch_cache_objects to ${key.ip}:${key.port}`);
290
- if (ret)
291
- ret[`${key.ip}:${key.port}`] = value.objects;
292
- count += value.objects.length;
293
- if (!dry)
294
- key.send({ type: "fetch_cache_objects", objects: value.objects });
295
- }
296
- });
297
- if (ret) {
298
- ret["count"] = count;
299
- res.send(JSON.stringify(ret, null, 4));
300
- } else if (res) {
301
-
302
- }
303
- }
304
- };
305
-
306
- module.exports = ObjectCacheManager;
package/scheduler/peak.js DELETED
@@ -1,112 +0,0 @@
1
- class Peak {
2
- constructor(interval, name)
3
- {
4
- this.interval = interval;
5
- this.name = name;
6
- this.peakActiveJobs = 0;
7
- this.peakActiveJobsTime = Date.now();
8
- this.peakUtilization = 0;
9
- this.peakUtilizationTime = Date.now();
10
- if (interval) {
11
- this.actives = [];
12
- this.utilizations = [];
13
- }
14
- }
15
-
16
- record(now, activeJobs, utilization)
17
- {
18
- let ret = false;
19
- if (!this.interval) {
20
- if (activeJobs > this.peakActiveJobs) {
21
- this.peakActiveJobs = activeJobs;
22
- this.peakActiveJobsTime = now;
23
- ret = true;
24
- }
25
- if (utilization > this.peakUtilization) {
26
- this.peakUtilization = utilization;
27
- this.peakUtilizationTime = now;
28
- ret = true;
29
- }
30
- } else {
31
- const cutoff = now - this.interval;
32
- {
33
- let idx = 0;
34
- while (idx < this.actives.length) {
35
- if (this.actives[idx][0] > cutoff && this.actives[idx][1] > activeJobs) {
36
- break;
37
- }
38
- ++idx;
39
- }
40
- if (idx == this.actives.length) {
41
- ret = true;
42
- this.peakActiveJobs = activeJobs;
43
- this.peakActiveJobsTime = now;
44
- this.actives = [];
45
- } else if (idx) {
46
- this.actives.splice(0, idx);
47
- }
48
- this.actives.push([now, activeJobs]);
49
- }
50
- {
51
- let idx = 0;
52
- while (idx < this.utilizations.length) {
53
- if (this.utilizations[idx][0] > cutoff && this.utilizations[idx][1] > utilization) {
54
- break;
55
- }
56
- ++idx;
57
- }
58
- if (idx == this.utilizations.length) {
59
- ret = true;
60
- this.peakUtilization = utilization;
61
- this.peakUtilizationTime = now;
62
- this.utilization = [];
63
- } else if (idx) {
64
- this.utilizations.splice(0, idx);
65
- }
66
- this.utilizations.push([now, utilization]);
67
- }
68
- }
69
- return ret;
70
- }
71
-
72
- toObject()
73
- {
74
- if (this.interval) {
75
- const cutoff = Date.now() - this.interval;
76
- let peakActiveJobs = 0;
77
- {
78
- let splice = 0;
79
- for (let idx=0; idx<this.actives.length; ++idx) {
80
- if (this.actives[idx][0] < cutoff) {
81
- splice = idx + 1;
82
- } else {
83
- peakActiveJobs = Math.max(peakActiveJobs, this.actives[idx][1]);
84
- }
85
- }
86
- if (splice)
87
- this.actives.splice(0, splice);
88
- }
89
- let peakUtilization = 0;
90
- {
91
- let splice = 0;
92
- for (let idx=0; idx<this.utilizations.length; ++idx) {
93
- if (this.utilizations[idx][0] < cutoff) {
94
- splice = idx + 1;
95
- } else {
96
- peakUtilization = Math.max(peakUtilization, this.utilizations[idx][1]);
97
- }
98
- }
99
- if (splice)
100
- this.utilizations.splice(0, splice);
101
- }
102
- return { activeJobs: peakActiveJobs, utilizations: peakUtilization };
103
- }
104
-
105
- return {
106
- activeJobs: this.peakActiveJobs,
107
- utilization: this.peakUtilization
108
- };
109
- }
110
- };
111
-
112
- module.exports = Peak;
@@ -1,37 +0,0 @@
1
- <html>
2
- <head>
3
- <title>Fisk!</title>
4
- <script language="javascript">
5
- function doshit() {
6
- var div = document.getElementById("output");
7
- div.style = "overflow:auto; height:100%";
8
- var connection = new WebSocket("ws://" +
9
- window.location.origin.substr(7) + "/monitor");
10
-
11
- connection.onerror = function (error) {
12
- console.log('WebSocket Error ' + error);
13
- };
14
- connection.onmessage = function (e) {
15
- console.log('Server: ' + e.data);
16
- var text;
17
- try {
18
- var msg = JSON.parse(e.data);
19
- text = (new Date().toLocaleTimeString()) + ": " + msg.builder.name + ": " + msg.builder.port + " (" + msg.builder.ip + ") compiled " + msg.sourceFile + " for " + msg.client.name + " (" + msg.client.ip + ") in " + msg.compileDuration + "ms";
20
- } catch (err) {
21
- text = e.data;
22
- }
23
- var atBottom = div.scrollTop + 20 >= div.scrollHeight - div.clientHeight;
24
- div.appendChild(document.createTextNode(text));
25
- div.appendChild(document.createElement("br"));
26
- if (atBottom) {
27
- div.scrollTop = div.scrollHeight - div.clientHeight;
28
- }
29
- };
30
- }
31
- window.onload = doshit;
32
- </script>
33
- </head>
34
- <body>
35
- <div id="output"></div>
36
- </body>
37
- </html>