hypercore 10.37.28 → 10.38.1

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 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
@@ -153,7 +153,7 @@ module.exports = class Verifier {
153
153
  }
154
154
  }
155
155
 
156
- throw new BAD_ARGUMENT('Public key is not a declared signer')
156
+ throw BAD_ARGUMENT('Public key is not a declared signer')
157
157
  }
158
158
 
159
159
  assemble (inputs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.37.28",
3
+ "version": "10.38.1",
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",