add per-priority-level endgame mode
This commit is contained in:
parent
1f3084179e
commit
71efb5c74b
|
@ -700,48 +700,86 @@ getPreferredPieces( Torrent * t,
|
||||||
static uint64_t*
|
static uint64_t*
|
||||||
getPreferredBlocks( Torrent * t, uint64_t * setmeCount )
|
getPreferredBlocks( Torrent * t, uint64_t * setmeCount )
|
||||||
{
|
{
|
||||||
|
int s;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t pieceCount;
|
uint32_t pieceCount;
|
||||||
|
uint32_t blockCount;
|
||||||
|
uint32_t unreqCount[3], reqCount[3];
|
||||||
uint32_t * pieces;
|
uint32_t * pieces;
|
||||||
uint64_t *req, *unreq, *ret, *walk;
|
uint64_t * ret, * walk;
|
||||||
int reqCount, unreqCount;
|
uint64_t * unreq[3], *req[3];
|
||||||
const tr_torrent * tor = t->tor;
|
const tr_torrent * tor = t->tor;
|
||||||
|
|
||||||
assert( torrentIsLocked( t ) );
|
assert( torrentIsLocked( t ) );
|
||||||
|
|
||||||
pieces = getPreferredPieces( t, &pieceCount );
|
pieces = getPreferredPieces( t, &pieceCount );
|
||||||
|
|
||||||
req = tr_new( uint64_t, pieceCount * tor->blockCountInPiece );
|
/**
|
||||||
reqCount = 0;
|
* Now we walk through those preferred pieces to find all the blocks
|
||||||
unreq = tr_new( uint64_t, pieceCount * tor->blockCountInPiece );
|
* are still missing from them. We put unrequested blocks first,
|
||||||
unreqCount = 0;
|
* of course, but by including requested blocks afterwards, endgame
|
||||||
|
* handling happens naturally.
|
||||||
|
*
|
||||||
|
* By doing this once per priority we also effectively get an endgame
|
||||||
|
* mode for each priority level. The helps keep high priority files
|
||||||
|
* from getting stuck at 99% due of unresponsive peers.
|
||||||
|
*/
|
||||||
|
|
||||||
for( i=0; i<pieceCount; ++i ) {
|
/* make temporary bins for the four tiers of blocks */
|
||||||
|
for( i=0; i<3; ++i ) {
|
||||||
|
req[i] = tr_new( uint64_t, pieceCount * tor->blockCountInPiece );
|
||||||
|
reqCount[i] = 0;
|
||||||
|
unreq[i] = tr_new( uint64_t, pieceCount * tor->blockCountInPiece );
|
||||||
|
unreqCount[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort the blocks into our temp bins */
|
||||||
|
for( i=blockCount=0; i<pieceCount; ++i )
|
||||||
|
{
|
||||||
const uint32_t index = pieces[i];
|
const uint32_t index = pieces[i];
|
||||||
|
const int priorityIndex = tor->info.pieces[index].priority + 1;
|
||||||
const int begin = tr_torPieceFirstBlock( tor, index );
|
const int begin = tr_torPieceFirstBlock( tor, index );
|
||||||
const int end = begin + tr_torPieceCountBlocks( tor, (int)index );
|
const int end = begin + tr_torPieceCountBlocks( tor, (int)index );
|
||||||
int block;
|
int block;
|
||||||
|
|
||||||
for( block=begin; block<end; ++block )
|
for( block=begin; block<end; ++block )
|
||||||
|
{
|
||||||
if( tr_cpBlockIsComplete( tor->completion, block ) )
|
if( tr_cpBlockIsComplete( tor->completion, block ) )
|
||||||
continue;
|
continue;
|
||||||
else if( tr_bitfieldHas( t->requested, block ) )
|
|
||||||
req[reqCount++] = block;
|
++blockCount;
|
||||||
|
|
||||||
|
if( tr_bitfieldHas( t->requested, block ) )
|
||||||
|
{
|
||||||
|
const uint32_t n = reqCount[priorityIndex]++;
|
||||||
|
req[priorityIndex][n] = block;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
unreq[unreqCount++] = block;
|
{
|
||||||
|
const uint32_t n = unreqCount[priorityIndex]++;
|
||||||
|
unreq[priorityIndex][n] = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = walk = tr_new( uint64_t, unreqCount + reqCount );
|
/* join the bins together, going from highest priority to lowest so
|
||||||
memcpy( walk, unreq, sizeof(uint64_t) * unreqCount );
|
* the the blocks we want to request first will be first in the list */
|
||||||
walk += unreqCount;
|
ret = walk = tr_new( uint64_t, blockCount );
|
||||||
memcpy( walk, req, sizeof(uint64_t) * reqCount );
|
for( s=2; s>=0; --s ) {
|
||||||
walk += reqCount;
|
memcpy( walk, unreq[s], sizeof(uint64_t) * unreqCount[s] );
|
||||||
assert( ( walk - ret ) == ( unreqCount + reqCount ) );
|
walk += unreqCount[s];
|
||||||
*setmeCount = walk - ret;
|
memcpy( walk, req[s], sizeof(uint64_t) * reqCount[s] );
|
||||||
|
walk += reqCount[s];
|
||||||
|
}
|
||||||
|
assert( ( walk - ret ) == blockCount );
|
||||||
|
*setmeCount = blockCount;
|
||||||
|
|
||||||
tr_free( req );
|
/* cleanup */
|
||||||
tr_free( unreq );
|
|
||||||
tr_free( pieces );
|
tr_free( pieces );
|
||||||
|
for( i=0; i<3; ++i ) {
|
||||||
|
tr_free( unreq[i] );
|
||||||
|
tr_free( req[i] );
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue