Skip to content
This repository was archived by the owner on Dec 28, 2022. It is now read-only.

Commit c6afe24

Browse files
authored
Only emit append in non-sparse mode when contiguous length updates (#108)
* Only emit `append` in non-sparse mode when contiguous length updates * Skip `append` in non-sparse mode * Add `oncontigupdate` hook * Test non-sparse appends * Assert final `contiguousLength` * Emit append on all sessions
1 parent 6e2f340 commit c6afe24

File tree

3 files changed

+48
-9
lines changed

3 files changed

+48
-9
lines changed

index.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ module.exports = class Hypercore extends EventEmitter {
297297
crypto: this.crypto,
298298
legacy: opts.legacy,
299299
auth: opts.auth,
300-
onupdate: this._oncoreupdate.bind(this)
300+
onupdate: this._oncoreupdate.bind(this),
301+
oncontigupdate: this._oncorecontigupdate.bind(this)
301302
})
302303

303304
if (opts.userData) {
@@ -484,9 +485,10 @@ module.exports = class Hypercore extends EventEmitter {
484485
if (s._snapshot && bitfield.start < s._snapshot.compatLength) s._snapshot.compatLength = bitfield.start
485486
}
486487

487-
if (appended) {
488-
s.emit('append')
489-
}
488+
// For sparse sessions, immediately emit appends. Non-sparse sessions
489+
// are handled separately and only emit appends when their contiguous
490+
// length is updated.
491+
if (appended && s.sparse) s.emit('append')
490492
}
491493

492494
this.replicator.onupgrade()
@@ -505,6 +507,16 @@ module.exports = class Hypercore extends EventEmitter {
505507
}
506508
}
507509

510+
_oncorecontigupdate () {
511+
// For non-sparse sessions, emit appends only when the contiguous length is
512+
// updated.
513+
for (let i = 0; i < this.sessions.length; i++) {
514+
const s = this.sessions[i]
515+
516+
if (!s.sparse) s.emit('append')
517+
}
518+
}
519+
508520
_onpeerupdate (added, peer) {
509521
const name = added ? 'peer-add' : 'peer-remove'
510522

lib/core.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_SIGNATURE } = req
99
const m = require('./messages')
1010

1111
module.exports = class Core {
12-
constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate) {
12+
constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate, oncontigupdate) {
1313
this.onupdate = onupdate
14+
this.oncontigupdate = oncontigupdate
1415
this.header = header
1516
this.crypto = crypto
1617
this.oplog = oplog
@@ -164,7 +165,7 @@ module.exports = class Core {
164165
}
165166
}
166167

167-
return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop)
168+
return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop, opts.oncontigupdate || noop)
168169
}
169170

170171
_shouldFlush () {
@@ -202,6 +203,7 @@ module.exports = class Core {
202203
while (this.bitfield.get(i)) i++
203204

204205
this.header.contiguousLength = i
206+
this.oncontigupdate()
205207
}
206208
}
207209

@@ -285,6 +287,7 @@ module.exports = class Core {
285287
batch.commit()
286288

287289
this.header.contiguousLength = batch.length
290+
this.oncontigupdate()
288291
this.header.tree.length = batch.length
289292
this.header.tree.rootHash = hash
290293
this.header.tree.signature = batch.signature
@@ -472,6 +475,7 @@ module.exports = class Core {
472475
const appended = batch.length > batch.ancestors
473476

474477
this.header.contiguousLength = Math.min(batch.ancestors, this.header.contiguousLength)
478+
this.oncontigupdate()
475479
this.header.tree.fork = batch.fork
476480
this.header.tree.length = batch.length
477481
this.header.tree.rootHash = batch.hash()

test/replicate.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ test('one inflight request to a peer per block', async function (t) {
600600
})
601601

602602
test('non-sparse replication', async function (t) {
603-
t.plan(6)
603+
t.plan(2)
604604

605605
const a = await create()
606606
const b = await create(a.key, { sparse: false })
@@ -609,9 +609,32 @@ test('non-sparse replication', async function (t) {
609609

610610
replicate(a, b, t)
611611

612+
const download = t.test('download')
613+
614+
let contiguousLength = 0
615+
612616
b
613-
.once('download', () => t.is(b.core.tree.length, 5))
617+
// The tree length should be updated to the full length when the first block
618+
// is downloaded.
619+
.once('download', () => download.is(b.core.tree.length, 5))
620+
621+
// When blocks are downloaded, the reported length should always match the
622+
// contiguous length.
614623
.on('download', (i) => {
615-
t.is(b.length, b.contiguousLength, `block ${i}`)
624+
download.is(b.length, b.contiguousLength, `block ${i}`)
625+
})
626+
627+
// Appends should only be emitted when the contiguous length is updated and
628+
// never when it's zero.
629+
.on('append', () => {
630+
if (contiguousLength >= b.contiguousLength) {
631+
download.fail('append emitted before contiguous length updated')
632+
}
633+
634+
contiguousLength = b.contiguousLength
616635
})
636+
637+
await download
638+
639+
t.is(contiguousLength, b.length)
617640
})

0 commit comments

Comments
 (0)