hypercore 11.35.0 → 11.35.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.
Files changed (2) hide show
  1. package/lib/replicator.js +108 -36
  2. package/package.json +1 -1
package/lib/replicator.js CHANGED
@@ -285,6 +285,10 @@ class RangeRequest extends Attachable {
285
285
  this.ranges[rangeIndex] = h
286
286
  }
287
287
 
288
+ if (!this.resolved && this.replicator._updatesRunning) {
289
+ this.replicator._updatesQueued = true
290
+ }
291
+
288
292
  if (this.end === -1) {
289
293
  this.replicator._alwaysLatestBlock--
290
294
  }
@@ -1541,8 +1545,8 @@ class Peer {
1541
1545
  }
1542
1546
 
1543
1547
  _requestSeek(s) {
1544
- // if replicator is updating the seeks etc, bail and wait for it to drain
1545
- if (this.replicator._updatesPending > 0) return false
1548
+ // if replicator is updating the seeks, bail and wait for it to drain
1549
+ if (this.replicator._updatingSeeks) return false
1546
1550
  if (this.replicator.pushOnly) return false
1547
1551
 
1548
1552
  const { length, fork } = this.core.state
@@ -2028,7 +2032,9 @@ module.exports = class Replicator {
2028
2032
  this._hadPeers = false
2029
2033
  this._active = 0
2030
2034
  this._ifAvailable = 0
2031
- this._updatesPending = 0
2035
+ this._updatingSeeks = false
2036
+ this._updatesRunning = false
2037
+ this._updatesQueued = false
2032
2038
  this._applyingReorg = null
2033
2039
  this._manifestPeer = null
2034
2040
  this._notDownloadingLinger = notDownloadingLinger
@@ -2614,55 +2620,117 @@ module.exports = class Replicator {
2614
2620
  }
2615
2621
  }
2616
2622
 
2623
+ _updateRanges(index, limit) {
2624
+ index = Math.min(index, this._ranges.length - 1)
2625
+
2626
+ let checked = 0
2627
+ let resolved = 0
2628
+ let updateAll = false
2629
+ let remaining = Math.min(limit, this._ranges.length)
2630
+
2631
+ while (remaining-- > 0 && this._ranges.length > 0) {
2632
+ if (index >= this._ranges.length) index = 0
2633
+
2634
+ const r = this._ranges[index]
2635
+
2636
+ clampRange(this.core, r)
2637
+ checked++
2638
+
2639
+ if (r.end !== -1 && r.start >= r.end) {
2640
+ this._resolveRangeRequest(r)
2641
+ resolved++
2642
+ // Crossing into the capped window exposes another range to peer scheduling.
2643
+ if (this._ranges.length === MAX_RANGES) updateAll = true
2644
+ } else {
2645
+ index++
2646
+ }
2647
+ }
2648
+
2649
+ index = this._ranges.length === 0 ? 0 : index % this._ranges.length
2650
+
2651
+ return { checked, resolved, index, updateAll }
2652
+ }
2653
+
2617
2654
  // "slow" updates here - async but not allowed to ever throw
2618
2655
  async _updateNonPrimary(updateAll) {
2619
- // Check if running, if so skip it and the running one will issue another update for us (debounce)
2620
- while (++this._updatesPending === 1) {
2621
- let len = Math.min(MAX_RANGES, this._ranges.length)
2656
+ this._updatesQueued = true
2657
+ if (this._updatesRunning) {
2658
+ if (this._inflight.idle || updateAll) this.queueUpdateAll()
2659
+ return
2660
+ }
2622
2661
 
2623
- for (let i = 0; i < len; i++) {
2624
- const r = this._ranges[i]
2662
+ this._updatesRunning = true
2625
2663
 
2626
- clampRange(this.core, r)
2664
+ while (this._updatesQueued) {
2665
+ this._updatesQueued = false
2627
2666
 
2628
- if (r.end !== -1 && r.start >= r.end) {
2629
- this._resolveRangeRequest(r)
2630
- i--
2631
- if (len > this._ranges.length) len--
2632
- if (this._ranges.length === MAX_RANGES) updateAll = true
2633
- }
2634
- }
2667
+ let checkedSinceResolve = 0
2668
+ let rangeIndex = 0
2669
+ const drain = this._inflight.idle || updateAll
2670
+ const checkedSeeks = new Set()
2635
2671
 
2636
- for (let i = 0; i < this._seeks.length; i++) {
2637
- const s = this._seeks[i]
2672
+ while (true) {
2673
+ const limit = Math.min(MAX_RANGES, this._ranges.length - checkedSinceResolve)
2674
+ const {
2675
+ checked,
2676
+ resolved,
2677
+ index,
2678
+ updateAll: resultUpdateAll
2679
+ } = this._updateRanges(rangeIndex, limit)
2680
+ rangeIndex = index
2638
2681
 
2639
- let err = null
2640
- let res = null
2682
+ if (resultUpdateAll) updateAll = true
2641
2683
 
2642
- try {
2643
- res = await s.seeker.update()
2644
- } catch (error) {
2645
- err = error
2646
- }
2684
+ if (resolved > 0) checkedSinceResolve = 0
2685
+ else checkedSinceResolve += checked
2686
+
2687
+ const continueRanges = checked > 0 && checkedSinceResolve < this._ranges.length && drain
2688
+
2689
+ this._updatingSeeks = true
2690
+
2691
+ let checkedSeek = false
2692
+ for (const s of this._seeks.slice()) {
2693
+ if (checkedSeeks.has(s) || !this._seeks.includes(s)) continue
2694
+ checkedSeeks.add(s)
2695
+ checkedSeek = true
2696
+
2697
+ let err = null
2698
+ let res = null
2699
+
2700
+ try {
2701
+ res = await s.seeker.update()
2702
+ } catch (error) {
2703
+ err = error
2704
+ }
2647
2705
 
2648
- if (!res && !err) continue
2706
+ const seekIndex = this._seeks.indexOf(s)
2707
+ if (seekIndex === -1 || (!res && !err)) continue
2649
2708
 
2650
- if (i < this._seeks.length - 1) this._seeks[i] = this._seeks.pop()
2651
- else this._seeks.pop()
2709
+ const h = this._seeks.pop()
2710
+ if (h !== s) this._seeks[seekIndex] = h
2652
2711
 
2653
- i--
2712
+ if (err) s.reject(err)
2713
+ else s.resolve(res)
2714
+ }
2715
+
2716
+ this._updatingSeeks = false
2717
+
2718
+ if (
2719
+ (!continueRanges || (checkedSeek && this._seeks.length > 0)) &&
2720
+ (this._inflight.idle || updateAll)
2721
+ ) {
2722
+ this.queueUpdateAll()
2723
+ }
2724
+ if (!continueRanges) break
2654
2725
 
2655
- if (err) s.reject(err)
2656
- else s.resolve(res)
2726
+ await yieldToLoop()
2727
+ if (this.destroyed) break
2657
2728
  }
2658
2729
 
2659
- // No additional updates scheduled - break
2660
- if (--this._updatesPending === 0) break
2661
- // Debounce the additional updates - continue
2662
- this._updatesPending = 0
2730
+ if (this.destroyed) break
2663
2731
  }
2664
2732
 
2665
- if (this._inflight.idle || updateAll) this.queueUpdateAll()
2733
+ this._updatesRunning = false
2666
2734
  }
2667
2735
 
2668
2736
  _clearRequest(peer, req) {
@@ -3398,6 +3466,10 @@ function incrementRx(stats1, stats2) {
3398
3466
 
3399
3467
  function noop() {}
3400
3468
 
3469
+ function yieldToLoop() {
3470
+ return new Promise((resolve) => setImmediate(resolve))
3471
+ }
3472
+
3401
3473
  function backoff(times) {
3402
3474
  const sleep = times < 2 ? 200 : times < 5 ? 500 : times < 40 ? 1000 : 5000
3403
3475
  return new Promise((resolve) => setTimeout(resolve, sleep))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.35.0",
3
+ "version": "11.35.1",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {