diff --git a/lib/replicator.js b/lib/replicator.js index 369a6f08..c42c7e0c 100644 --- a/lib/replicator.js +++ b/lib/replicator.js @@ -585,7 +585,10 @@ class Peer { } get remoteContiguousLength() { - return this.remoteBitfield.findFirst(false, this._remoteContiguousLength) + const length = this.remoteBitfield.findFirst(false, this._remoteContiguousLength) + // Cache the verified extent so repeated reads do not rescan the same bitfield run. + if (length > this._remoteContiguousLength) this._remoteContiguousLength = length + return length } getMaxInflight() { @@ -1411,12 +1414,13 @@ class Peer { if (start === 0 && drop === false) { if (length > this._remoteContiguousLength) { this._remoteContiguousLength = length - if ( - this.remoteFork === this.core.state.fork && - length > this.core.header.hints.remoteContiguousLength - ) { - this.core.updateRemoteContiguousLength(length) - } + } + + if ( + this.remoteFork === this.core.state.fork && + length > this.core.header.hints.remoteContiguousLength + ) { + this.core.updateRemoteContiguousLength(length) } } else if (length === 1) { const bitfield = this.core.skipBitfield === null ? this.core.bitfield : this.core.skipBitfield diff --git a/test/remote-bitfield.js b/test/remote-bitfield.js index f1d84fd8..ea1c3091 100644 --- a/test/remote-bitfield.js +++ b/test/remote-bitfield.js @@ -1,7 +1,7 @@ const test = require('brittle') const b4a = require('b4a') const RemoteBitfield = require('../lib/remote-bitfield') -const { create, replicate } = require('./helpers') +const { create, replicate, eventFlush } = require('./helpers') test('remote bitfield - findFirst', function (t) { const b = new RemoteBitfield() @@ -66,6 +66,43 @@ test('remote congituous length consistency (remote-bitfield findFirst edge case) ) }) +test('remote contiguous length caches verified bitfield extent', async function (t) { + const a = await create(t) + const b = await create(t, a.key) + + replicate(a, b, t) + await eventFlush() + + const peer = getPeer(b, a) + + peer.remoteBitfield.setRange(0, 1024, true) + peer._remoteContiguousLength = 0 + + t.is(peer.remoteContiguousLength, 1024) + t.is(peer._remoteContiguousLength, 1024) +}) + +test('range updates core remote contiguous length after getter advances peer cache', async function (t) { + const a = await create(t) + const b = await create(t, a.key) + + replicate(a, b, t) + await eventFlush() + + const peer = getPeer(b, a) + + peer.remoteFork = b.core.state.fork + peer.remoteBitfield.setRange(0, 1024, true) + peer._remoteContiguousLength = 0 + + t.is(peer.remoteContiguousLength, 1024) + t.is(b.core.header.hints.remoteContiguousLength, 0) + + await peer.onrange({ start: 0, length: 1024, drop: false }) + + t.is(b.core.header.hints.remoteContiguousLength, 1024) +}) + test('bitfield messages sent on cache miss', async function (t) { const original = await create(t) const sparse = await create(t, original.key)