hypercore 10.37.27 → 10.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +0 -1
- package/lib/hotswap-queue.js +60 -0
- package/lib/replicator.js +49 -2
- package/lib/verifier.js +1 -1
- package/package.json +2 -1
package/index.js
CHANGED
|
@@ -961,7 +961,6 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
961
961
|
if (this.opened === false) await this.opening
|
|
962
962
|
|
|
963
963
|
const activeRequests = (range && range.activeRequests) || this.activeRequests
|
|
964
|
-
|
|
965
964
|
return this.replicator.addRange(activeRequests, range)
|
|
966
965
|
}
|
|
967
966
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const TICKS = 16
|
|
2
|
+
|
|
3
|
+
module.exports = class HotswapQueue {
|
|
4
|
+
constructor () {
|
|
5
|
+
this.priorities = [[], [], []]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
* pick (peer) {
|
|
9
|
+
for (let i = 0; i < this.priorities.length; i++) {
|
|
10
|
+
// try first one more than second one etc etc
|
|
11
|
+
let ticks = (this.priorities.length - i) * TICKS
|
|
12
|
+
const queue = this.priorities[i]
|
|
13
|
+
|
|
14
|
+
for (let j = 0; j < queue.length; j++) {
|
|
15
|
+
const r = j + Math.floor(Math.random() * queue.length - j)
|
|
16
|
+
const a = queue[j]
|
|
17
|
+
const b = queue[r]
|
|
18
|
+
|
|
19
|
+
if (r !== j) {
|
|
20
|
+
queue[(b.hotswap.index = j)] = b
|
|
21
|
+
queue[(a.hotswap.index = r)] = a
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (hasInflight(b, peer)) continue
|
|
25
|
+
|
|
26
|
+
yield b
|
|
27
|
+
|
|
28
|
+
if (--ticks <= 0) break
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
add (block) {
|
|
34
|
+
if (block.hotswap !== null) this.remove(block)
|
|
35
|
+
if (block.inflight.length === 0 || block.inflight.length >= 3) return
|
|
36
|
+
|
|
37
|
+
// TODO: also use other stuff to determine queue prio
|
|
38
|
+
const queue = this.priorities[block.inflight.length - 1]
|
|
39
|
+
|
|
40
|
+
const index = queue.push(block) - 1
|
|
41
|
+
block.hotswap = { ref: this, queue, index }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
remove (block) {
|
|
45
|
+
const hotswap = block.hotswap
|
|
46
|
+
if (hotswap === null) return
|
|
47
|
+
|
|
48
|
+
block.hotswap = null
|
|
49
|
+
const head = hotswap.queue.pop()
|
|
50
|
+
if (head === block) return
|
|
51
|
+
hotswap.queue[(head.hotswap.index = hotswap.index)] = head
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function hasInflight (block, peer) {
|
|
56
|
+
for (let j = 0; j < block.inflight.length; j++) {
|
|
57
|
+
if (block.inflight[j].peer === peer) return true
|
|
58
|
+
}
|
|
59
|
+
return false
|
|
60
|
+
}
|
package/lib/replicator.js
CHANGED
|
@@ -27,6 +27,7 @@ const safetyCatch = require('safety-catch')
|
|
|
27
27
|
const RandomIterator = require('random-array-iterator')
|
|
28
28
|
const flatTree = require('flat-tree')
|
|
29
29
|
const ReceiverQueue = require('./receiver-queue')
|
|
30
|
+
const HotswapQueue = require('./hotswap-queue')
|
|
30
31
|
const RemoteBitfield = require('./remote-bitfield')
|
|
31
32
|
const { REQUEST_CANCELLED, REQUEST_TIMEOUT, INVALID_CAPABILITY, SNAPSHOT_NOT_AVAILABLE } = require('hypercore-errors')
|
|
32
33
|
const m = require('./messages')
|
|
@@ -139,6 +140,7 @@ class BlockRequest extends Attachable {
|
|
|
139
140
|
this.priority = priority
|
|
140
141
|
this.inflight = []
|
|
141
142
|
this.queued = false
|
|
143
|
+
this.hotswap = null
|
|
142
144
|
this.tracker = tracker
|
|
143
145
|
}
|
|
144
146
|
|
|
@@ -150,6 +152,7 @@ class BlockRequest extends Attachable {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
this.tracker.remove(this.index)
|
|
155
|
+
removeHotswap(this)
|
|
153
156
|
}
|
|
154
157
|
}
|
|
155
158
|
|
|
@@ -368,7 +371,8 @@ class Peer {
|
|
|
368
371
|
wireWant: { tx: 0, rx: 0 },
|
|
369
372
|
wireBitfield: { tx: 0, rx: 0 },
|
|
370
373
|
wireRange: { tx: 0, rx: 0 },
|
|
371
|
-
wireExtension: { tx: 0, rx: 0 }
|
|
374
|
+
wireExtension: { tx: 0, rx: 0 },
|
|
375
|
+
hotswaps: 0
|
|
372
376
|
}
|
|
373
377
|
|
|
374
378
|
this.receiverQueue = new ReceiverQueue()
|
|
@@ -428,6 +432,11 @@ class Peer {
|
|
|
428
432
|
return Math.max(this.inflightRange[0], Math.round(Math.min(this.inflightRange[1], this.inflightRange[0] * scale)))
|
|
429
433
|
}
|
|
430
434
|
|
|
435
|
+
getMaxHotswapInflight () {
|
|
436
|
+
const inf = this.getMaxInflight()
|
|
437
|
+
return Math.max(16, inf / 2)
|
|
438
|
+
}
|
|
439
|
+
|
|
431
440
|
signalUpgrade () {
|
|
432
441
|
if (this._shouldUpdateCanUpgrade() === true) this._updateCanUpgradeAndSync()
|
|
433
442
|
else this.sendSync()
|
|
@@ -1187,6 +1196,7 @@ class Peer {
|
|
|
1187
1196
|
this.replicator._markInflight(b.index)
|
|
1188
1197
|
|
|
1189
1198
|
b.inflight.push(req)
|
|
1199
|
+
this.replicator.hotswaps.add(b)
|
|
1190
1200
|
this._send(req)
|
|
1191
1201
|
}
|
|
1192
1202
|
|
|
@@ -1421,6 +1431,7 @@ module.exports = class Replicator {
|
|
|
1421
1431
|
this.downloading = false
|
|
1422
1432
|
this.activeSessions = 0
|
|
1423
1433
|
|
|
1434
|
+
this.hotswaps = new HotswapQueue()
|
|
1424
1435
|
this.inflightRange = inflightRange || DEFAULT_MAX_INFLIGHT
|
|
1425
1436
|
|
|
1426
1437
|
// Note: nodata and unwant not currently tracked
|
|
@@ -1433,7 +1444,8 @@ module.exports = class Replicator {
|
|
|
1433
1444
|
wireWant: { tx: 0, rx: 0 },
|
|
1434
1445
|
wireBitfield: { tx: 0, rx: 0 },
|
|
1435
1446
|
wireRange: { tx: 0, rx: 0 },
|
|
1436
|
-
wireExtension: { tx: 0, rx: 0 }
|
|
1447
|
+
wireExtension: { tx: 0, rx: 0 },
|
|
1448
|
+
hotswaps: 0
|
|
1437
1449
|
}
|
|
1438
1450
|
|
|
1439
1451
|
this._attached = new Set()
|
|
@@ -1826,6 +1838,7 @@ module.exports = class Replicator {
|
|
|
1826
1838
|
// sure to clear them afterwards.
|
|
1827
1839
|
for (const b of clear) {
|
|
1828
1840
|
this._blocks.remove(b.index)
|
|
1841
|
+
removeHotswap(b)
|
|
1829
1842
|
}
|
|
1830
1843
|
}
|
|
1831
1844
|
|
|
@@ -1834,10 +1847,18 @@ module.exports = class Replicator {
|
|
|
1834
1847
|
if (b === null) return false
|
|
1835
1848
|
|
|
1836
1849
|
removeInflight(b.inflight, req)
|
|
1850
|
+
removeHotswap(b)
|
|
1837
1851
|
b.queued = false
|
|
1838
1852
|
|
|
1839
1853
|
b.resolve(value)
|
|
1840
1854
|
|
|
1855
|
+
if (b.inflight.length > 0) { // if anything is still inflight, cancel it
|
|
1856
|
+
for (let i = b.inflight.length - 1; i >= 0; i--) {
|
|
1857
|
+
const req = b.inflight[i]
|
|
1858
|
+
req.peer._cancelRequest(req)
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1841
1862
|
return true
|
|
1842
1863
|
}
|
|
1843
1864
|
|
|
@@ -1868,6 +1889,10 @@ module.exports = class Replicator {
|
|
|
1868
1889
|
|
|
1869
1890
|
if (b === null || removeInflight(b.inflight, req) === false) return
|
|
1870
1891
|
|
|
1892
|
+
if (removeHotswap(b) === true && b.inflight.length > 0) {
|
|
1893
|
+
this.hotswaps.add(b)
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1871
1896
|
if (b.refs.length > 0 && isBlock === true) {
|
|
1872
1897
|
this._queueBlock(b)
|
|
1873
1898
|
return
|
|
@@ -2162,6 +2187,18 @@ module.exports = class Replicator {
|
|
|
2162
2187
|
return false
|
|
2163
2188
|
}
|
|
2164
2189
|
|
|
2190
|
+
_updateHotswap (peer) {
|
|
2191
|
+
const maxHotswaps = peer.getMaxHotswapInflight()
|
|
2192
|
+
if (!peer.isActive() || peer.inflight >= maxHotswaps) return
|
|
2193
|
+
|
|
2194
|
+
for (const b of this.hotswaps.pick(peer)) {
|
|
2195
|
+
if (peer._requestBlock(b) === false) continue
|
|
2196
|
+
peer.stats.hotswaps++
|
|
2197
|
+
peer.replicator.stats.hotswaps++
|
|
2198
|
+
if (peer.inflight >= maxHotswaps) break
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2165
2202
|
_updatePeer (peer) {
|
|
2166
2203
|
if (!peer.isActive() || peer.inflight >= peer.getMaxInflight()) {
|
|
2167
2204
|
return false
|
|
@@ -2231,6 +2268,10 @@ module.exports = class Replicator {
|
|
|
2231
2268
|
while (this._updatePeer(peer) === true);
|
|
2232
2269
|
while (this._updatePeerNonPrimary(peer) === true);
|
|
2233
2270
|
|
|
2271
|
+
if (this.peers.length > 1 && this._blocks.isEmpty() === false) {
|
|
2272
|
+
this._updateHotswap(peer)
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2234
2275
|
this._checkUpgradeIfAvailable()
|
|
2235
2276
|
this._maybeResolveIfAvailableRanges()
|
|
2236
2277
|
}
|
|
@@ -2407,6 +2448,12 @@ function matchingRequest (req, data) {
|
|
|
2407
2448
|
return req.fork === data.fork
|
|
2408
2449
|
}
|
|
2409
2450
|
|
|
2451
|
+
function removeHotswap (block) {
|
|
2452
|
+
if (block.hotswap === null) return false
|
|
2453
|
+
block.hotswap.ref.remove(block)
|
|
2454
|
+
return true
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2410
2457
|
function removeInflight (inf, req) {
|
|
2411
2458
|
const i = inf.indexOf(req)
|
|
2412
2459
|
if (i === -1) return false
|
package/lib/verifier.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.38.0",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"brittle": "^3.0.0",
|
|
69
|
+
"debugging-stream": "^3.1.0",
|
|
69
70
|
"hyperswarm": "^4.3.6",
|
|
70
71
|
"rache": "^1.0.0",
|
|
71
72
|
"random-access-memory": "^6.1.0",
|