@@ -2,7 +2,7 @@ const test = require('brittle')
22const b4a = require ( 'b4a' )
33const RAM = require ( 'random-access-memory' )
44const NoiseSecretStream = require ( '@hyperswarm/secret-stream' )
5- const { create, replicate, unreplicate, eventFlush } = require ( './helpers' )
5+ const { create, replicate, unreplicate, eventFlush, replicateDebugStream } = require ( './helpers' )
66const { makeStreamPair } = require ( './helpers/networking.js' )
77const Hypercore = require ( '../' )
88
@@ -51,9 +51,10 @@ test('basic replication stats', async function (t) {
5151 t . is ( aStats . wireExtension . tx , 0 , 'wireExtension init 0' )
5252 t . is ( aStats . wireCancel . rx , 0 , 'wireCancel init 0' )
5353 t . is ( aStats . wireCancel . tx , 0 , 'wireCancel init 0' )
54+ t . is ( aStats . hotswaps , 0 , 'hotswaps init 0' )
5455
5556 const initStatsLength = [ ...Object . keys ( aStats ) ] . length
56- t . is ( initStatsLength , 8 , 'Expected amount of stats' )
57+ t . is ( initStatsLength , 9 , 'Expected amount of stats' )
5758
5859 replicate ( a , b , t )
5960
@@ -1778,6 +1779,44 @@ test('replication count should never go negative', async function (t) {
17781779 }
17791780} )
17801781
1782+ test ( 'uses hotswaps to avoid long download tail' , async t => {
1783+ const core = await create ( )
1784+ const slowCore = await create ( core . key )
1785+
1786+ const batch = [ ]
1787+ while ( batch . length < 100 ) {
1788+ batch . push ( Buffer . allocUnsafe ( 60000 ) )
1789+ }
1790+ await core . append ( batch )
1791+
1792+ replicate ( core , slowCore , t )
1793+ await slowCore . download ( { start : 0 , end : core . length } ) . done ( )
1794+
1795+ t . is ( slowCore . contiguousLength , 100 , 'sanity check' )
1796+
1797+ const peerCore = await create ( core . key )
1798+ await peerCore . ready ( )
1799+ const [ fastStream ] = replicateDebugStream ( core , peerCore , t , { speed : 10_000_000 } )
1800+ const [ slowStream ] = replicateDebugStream ( slowCore , peerCore , t , { speed : 1_000_000 } )
1801+ const fastKey = fastStream . publicKey
1802+ const slowKey = slowStream . publicKey
1803+ const peerKey = fastStream . remotePublicKey
1804+ t . alike ( peerKey , slowStream . remotePublicKey , 'sanity check' )
1805+
1806+ await peerCore . download ( { start : 0 , end : core . length } ) . done ( )
1807+
1808+ const fastPeer = peerCore . replicator . peers . filter (
1809+ p => b4a . equals ( p . stream . remotePublicKey , fastKey ) ) [ 0 ]
1810+ const slowPeer = peerCore . replicator . peers . filter (
1811+ p => b4a . equals ( p . stream . remotePublicKey , slowKey ) ) [ 0 ]
1812+
1813+ t . ok ( fastPeer . stats . hotswaps > 0 , 'hotswaps happened for fast peer' )
1814+ t . ok ( fastPeer . stats . hotswaps > 0 , 'No hotswaps happened for slow peer' )
1815+ t . ok ( slowPeer . stats . wireCancel . tx > 0 , 'slow peer cancelled requests' )
1816+ t . ok ( fastPeer . stats . wireData . rx > slowPeer . stats . wireData . rx , 'sanity check: received more data from fast peer' )
1817+ t . ok ( slowPeer . stats . wireData . rx > 0 , 'sanity check: still received data from slow peer' )
1818+ } )
1819+
17811820async function waitForRequestBlock ( core ) {
17821821 while ( true ) {
17831822 const reqBlock = core . replicator . _inflight . _requests . find ( req => req && req . block )
0 commit comments