Skip to content

Commit 656ec5f

Browse files
authored
Bugfix: use backup logic for NOT_AVAILABLE replies (#786)
* Bugfix: use backup logic for NOT_AVAILABLE replies * Format * Fix stats test
1 parent 3f70c2e commit 656ec5f

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

lib/replicator.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,8 @@ class Peer {
526526
hotswaps: 0,
527527
invalidData: 0,
528528
invalidRequests: 0,
529-
backoffs: 0
529+
backoffs: 0,
530+
notAvailableBackoffs: 0
530531
}
531532

532533
this.receiverQueue = new ReceiverQueue()
@@ -1991,7 +1992,8 @@ module.exports = class Replicator {
19911992
hotswaps: 0,
19921993
invalidData: 0,
19931994
invalidRequests: 0,
1994-
backoffs: 0
1995+
backoffs: 0,
1996+
notAvailableBackoffs: 0
19951997
}
19961998

19971999
this._attached = new Set()
@@ -2684,6 +2686,15 @@ module.exports = class Replicator {
26842686
}
26852687

26862688
_onnodata(peer, req, reason) {
2689+
if (reason === NOT_AVAILABLE) {
2690+
peer.stats.notAvailableBackoffs++
2691+
this.stats.notAvailableBackoffs++
2692+
2693+
if (peer.stats.notAvailableBackoffs >= MAX_BACKOFFS) {
2694+
peer.paused = true
2695+
}
2696+
}
2697+
26872698
if (reason === INVALID_REQUEST) {
26882699
peer.stats.backoffs++
26892700
this.stats.backoffs++

test/replicate.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,11 @@ test('basic replication stats', async function (t) {
111111
t.is(aStats.hotswaps, 0, 'hotswaps init 0')
112112
t.is(aStats.invalidData, 0, 'invalid data init 0')
113113
t.is(aStats.invalidRequests, 0, 'invalid requests init 0')
114+
t.is(aStats.backoffs, 0, 'backoffs init 0')
115+
t.is(aStats.notAvailableBackoffs, 0, 'notAvailableBackoffs init 0')
114116

115117
const initStatsLength = [...Object.keys(aStats)].length
116-
t.is(initStatsLength, 13, 'Expected amount of stats')
118+
t.is(initStatsLength, 14, 'Expected amount of stats')
117119

118120
replicate(a, b, t)
119121

@@ -2910,6 +2912,36 @@ test('local recovering from remote', async function (t) {
29102912
t.is(b.length, a.length)
29112913
})
29122914

2915+
test('backoff respected for NOT_AVAILABLE in case of incorrectly false remote bitfield)', async function (t) {
2916+
const writer = await create(t)
2917+
2918+
await writer.append(['a', 'b', 'c', 'd', 'e'])
2919+
2920+
const badBitfielder = await create(t, writer.key)
2921+
const reader = await create(t, writer.key)
2922+
2923+
replicate(badBitfielder, writer, t)
2924+
await badBitfielder.get(0)
2925+
2926+
t.is(badBitfielder.core.bitfield.get(0), true, 'sanity check')
2927+
await badBitfielder.core.bitfield.set(0, false) // put incorrect bitfield
2928+
2929+
replicate(badBitfielder, reader, t)
2930+
2931+
await t.exception(
2932+
async () => reader.get(0, { timeout: 500 }),
2933+
/REQUEST_TIMEOUT/,
2934+
'cannot get the block due to bad bitfield'
2935+
)
2936+
2937+
t.is(reader.replicator.stats.notAvailableBackoffs, 32, 'paused after 32 attempts')
2938+
t.ok(
2939+
badBitfielder.replicator.stats.wireRequest.rx < 40,
2940+
'did not continue getting spammed (sanity check)'
2941+
)
2942+
t.ok(reader.replicator.stats.wireRequest.tx < 40, 'did not continue spamming (sanity check)')
2943+
})
2944+
29132945
async function createAndDownload(t, core) {
29142946
const b = await create(t, core.key)
29152947
replicate(core, b, t, { teardown: false })

0 commit comments

Comments
 (0)