a nice patch that makes the three most CPU-hogging functions (as reported by Shark) essentially free and reduces memory overhead by 8 bytes per piece per torrent. Lots of asserts for extra testing fun.
This commit is contained in:
parent
157d20cee1
commit
79a0081092
|
@ -40,6 +40,11 @@ struct tr_completion_s
|
|||
|
||||
/* a block is complete if and only if we have it */
|
||||
uint16_t * completeBlocks;
|
||||
|
||||
uint8_t doneDirty;
|
||||
uint64_t doneHave;
|
||||
uint64_t doneTotal;
|
||||
uint64_t completeHave;
|
||||
};
|
||||
|
||||
tr_completion_t * tr_cpInit( tr_torrent_t * tor )
|
||||
|
@ -75,6 +80,60 @@ void tr_cpReset( tr_completion_t * cp )
|
|||
memset( cp->blockDownloaders, 0, tor->blockCount );
|
||||
tr_bitfieldClear( cp->pieceBitfield );
|
||||
memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
|
||||
|
||||
cp->doneDirty = TRUE;
|
||||
cp->doneHave = 0;
|
||||
cp->doneTotal = 0;
|
||||
cp->completeHave = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
tr_cpEnsureDoneValid( const tr_completion_t * ccp )
|
||||
{
|
||||
const tr_torrent_t * tor = ccp->tor;
|
||||
const tr_info_t * info = &tor->info;
|
||||
uint64_t have=0, total=0;
|
||||
int i;
|
||||
tr_completion_t * cp ;
|
||||
|
||||
if( !ccp->doneDirty )
|
||||
return;
|
||||
|
||||
/* too bad C doesn't have 'mutable' */
|
||||
cp = (tr_completion_t*) ccp;
|
||||
cp->doneDirty = FALSE;
|
||||
|
||||
for( i=0; i<info->pieceCount; ++i ) {
|
||||
if( !info->pieces[i].dnd ) {
|
||||
total += info->pieceSize;
|
||||
have += cp->completeBlocks[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
have *= tor->blockSize;
|
||||
|
||||
/* the last piece/block is probably smaller than the others */
|
||||
if( !info->pieces[info->pieceCount-1].dnd ) {
|
||||
total -= ( info->pieceSize - ( info->totalSize % info->pieceSize ) );
|
||||
if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
|
||||
have -= ( tor->blockSize - ( info->totalSize % tor->blockSize ) );
|
||||
}
|
||||
|
||||
assert( have <= total );
|
||||
assert( total <= info->totalSize );
|
||||
|
||||
cp->doneHave = have;
|
||||
cp->doneTotal = total;
|
||||
}
|
||||
|
||||
void
|
||||
tr_cpInvalidateDND ( tr_completion_t * cp )
|
||||
{
|
||||
cp->doneDirty = TRUE;
|
||||
}
|
||||
|
||||
int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
|
||||
|
@ -84,7 +143,7 @@ int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
|
|||
|
||||
int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
|
||||
{
|
||||
return cp->completeBlocks[piece] >= TR_BLOCKS_IN_PIECE(cp->tor,piece);
|
||||
return cp->completeBlocks[piece] >= tr_torPieceCountBlocks(cp->tor,piece);
|
||||
}
|
||||
|
||||
const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
|
||||
|
@ -95,32 +154,40 @@ const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
|
|||
void tr_cpPieceAdd( tr_completion_t * cp, int piece )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
|
||||
const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
|
||||
const int endBlock = startBlock + n_blocks;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
int i;
|
||||
|
||||
cp->completeBlocks[piece] = n_blocks;
|
||||
tr_bitfieldAddRange( cp->blockBitfield, startBlock, endBlock );
|
||||
tr_bitfieldAdd( cp->pieceBitfield, piece );
|
||||
for( i=start; i<end; ++i )
|
||||
tr_cpBlockAdd( cp, i );
|
||||
}
|
||||
|
||||
void tr_cpPieceRem( tr_completion_t * cp, int piece )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
|
||||
const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
|
||||
const int endBlock = startBlock + n_blocks;
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
int block;
|
||||
|
||||
assert( cp != NULL );
|
||||
assert( 0 <= piece );
|
||||
assert( piece < tor->info.pieceCount );
|
||||
assert( 0 <= startBlock );
|
||||
assert( startBlock < tor->blockCount );
|
||||
assert( startBlock <= endBlock );
|
||||
assert( endBlock <= tor->blockCount );
|
||||
assert( 0 <= start );
|
||||
assert( start < tor->blockCount );
|
||||
assert( start <= end );
|
||||
assert( end <= tor->blockCount );
|
||||
|
||||
for( block=start; block<end; ++block ) {
|
||||
if( tr_cpBlockIsComplete( cp, block ) ) {
|
||||
const int blockSize = tr_torBlockCountBytes( tor, block );
|
||||
cp->completeHave -= blockSize;
|
||||
if( !tor->info.pieces[piece].dnd )
|
||||
cp->doneHave -= blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
cp->completeBlocks[piece] = 0;
|
||||
tr_bitfieldRemRange ( cp->blockBitfield, startBlock, endBlock );
|
||||
tr_bitfieldRemRange ( cp->blockBitfield, start, end );
|
||||
tr_bitfieldRem( cp->pieceBitfield, piece );
|
||||
}
|
||||
|
||||
|
@ -140,20 +207,27 @@ int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
|
|||
return tr_bitfieldHas( cp->blockBitfield, block );
|
||||
}
|
||||
|
||||
void tr_cpBlockAdd( tr_completion_t * cp, int block )
|
||||
void
|
||||
tr_cpBlockAdd( tr_completion_t * cp, int block )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
|
||||
if( !tr_cpBlockIsComplete( cp, block ) )
|
||||
{
|
||||
const int piece = TOR_BLOCK_PIECE(tor, block);
|
||||
const int piece = tr_torBlockPiece( tor, block );
|
||||
const int blockSize = tr_torBlockCountBytes( tor, block );
|
||||
|
||||
++cp->completeBlocks[piece];
|
||||
|
||||
if( cp->completeBlocks[piece] == TR_BLOCKS_IN_PIECE(tor,piece) )
|
||||
if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
|
||||
tr_bitfieldAdd( cp->pieceBitfield, piece );
|
||||
|
||||
tr_bitfieldAdd( cp->blockBitfield, block );
|
||||
|
||||
cp->completeHave += blockSize;
|
||||
|
||||
if( !tor->info.pieces[piece].dnd )
|
||||
cp->doneHave += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +257,7 @@ float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
|
|||
{
|
||||
assert( cp != NULL );
|
||||
|
||||
return cp->completeBlocks[piece] / (double)TR_BLOCKS_IN_PIECE(cp->tor,piece);
|
||||
return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -192,8 +266,8 @@ tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
|
|||
int i;
|
||||
int n;
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
|
||||
const int end = start + TR_BLOCKS_IN_PIECE(tor,piece);
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
|
||||
n = 0;
|
||||
for( i = start; i < end; ++i )
|
||||
|
@ -207,8 +281,8 @@ int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
|
|||
{
|
||||
int i;
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
|
||||
const int end = start + TR_BLOCKS_IN_PIECE(tor,piece);
|
||||
const int start = tr_torPieceFirstBlock(tor,piece);
|
||||
const int end = start + tr_torPieceCountBlocks(tor,piece);
|
||||
|
||||
for( i = start; i < end; ++i )
|
||||
if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
|
||||
|
@ -221,93 +295,46 @@ int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
|
|||
****
|
||||
***/
|
||||
|
||||
cp_status_t
|
||||
tr_cpGetStatus ( const tr_completion_t * cp )
|
||||
float
|
||||
tr_cpPercentComplete ( const tr_completion_t * cp )
|
||||
{
|
||||
int i;
|
||||
int ret = TR_CP_COMPLETE;
|
||||
const tr_info_t * info;
|
||||
|
||||
assert( cp != NULL );
|
||||
assert( cp->tor != NULL );
|
||||
|
||||
info = &cp->tor->info;
|
||||
for( i=0; i<info->pieceCount; ++i ) {
|
||||
if( tr_cpPieceIsComplete( cp, i ) )
|
||||
continue;
|
||||
if( !info->pieces[i].dnd )
|
||||
return TR_CP_INCOMPLETE;
|
||||
ret = TR_CP_DONE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return (double)cp->completeHave / cp->tor->info.totalSize;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tr_cpLeftUntilComplete ( const tr_completion_t * cp )
|
||||
{
|
||||
int i;
|
||||
uint64_t b=0;
|
||||
const tr_torrent_t * tor;
|
||||
const tr_info_t * info;
|
||||
|
||||
assert( cp != NULL );
|
||||
assert( cp->tor != NULL );
|
||||
|
||||
tor = cp->tor;
|
||||
info = &tor->info;
|
||||
for( i=0; i<info->pieceCount; ++i )
|
||||
if( !tr_cpPieceIsComplete( cp, i ) )
|
||||
b += ( TR_BLOCKS_IN_PIECE(tor,i) - cp->completeBlocks[ i ] );
|
||||
|
||||
b *= tor->blockSize;
|
||||
|
||||
if( tor->blockCount && !tr_cpBlockIsComplete( cp, tor->blockCount - 1 ) )
|
||||
b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void
|
||||
tr_cpDoneStats( const tr_completion_t * cp ,
|
||||
uint64_t * setmeHaveBytes,
|
||||
uint64_t * setmeTotalBytes )
|
||||
{
|
||||
const tr_torrent_t * tor = cp->tor;
|
||||
const tr_info_t * info = &tor->info;
|
||||
uint64_t have=0, total=0;
|
||||
int i;
|
||||
|
||||
for( i=0; i<info->pieceCount; ++i ) {
|
||||
if( !info->pieces[i].dnd ) {
|
||||
total += info->pieceSize;
|
||||
have += cp->completeBlocks[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
have *= tor->blockSize;
|
||||
|
||||
/* the last piece/block is probably smaller than the others */
|
||||
if( !info->pieces[info->pieceCount-1].dnd ) {
|
||||
total -= ( info->pieceSize - ( info->totalSize % info->pieceSize ) );
|
||||
if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
|
||||
have -= ( tor->blockSize - ( info->totalSize % tor->blockSize ) );
|
||||
}
|
||||
|
||||
assert( have <= total );
|
||||
assert( total <= info->totalSize );
|
||||
|
||||
*setmeHaveBytes = have;
|
||||
*setmeTotalBytes = total;
|
||||
return cp->tor->info.totalSize - cp->completeHave;
|
||||
}
|
||||
|
||||
float
|
||||
tr_cpPercentComplete ( const tr_completion_t * cp )
|
||||
tr_cpPercentDone( const tr_completion_t * cp )
|
||||
{
|
||||
const uint64_t tilComplete = tr_cpLeftUntilComplete( cp );
|
||||
const uint64_t total = cp->tor->info.totalSize;
|
||||
const float f = 1.0 - (double)tilComplete / total;
|
||||
return MAX(0.0, f);
|
||||
tr_cpEnsureDoneValid( cp );
|
||||
|
||||
return (double)cp->doneHave / cp->doneTotal;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tr_cpLeftUntilDone ( const tr_completion_t * cp )
|
||||
{
|
||||
tr_cpEnsureDoneValid( cp );
|
||||
|
||||
return cp->doneTotal - cp->doneHave;
|
||||
}
|
||||
|
||||
cp_status_t
|
||||
tr_cpGetStatus ( const tr_completion_t * cp )
|
||||
{
|
||||
if( cp->completeHave >= cp->tor->info.totalSize )
|
||||
return TR_CP_COMPLETE;
|
||||
|
||||
tr_cpEnsureDoneValid( cp );
|
||||
|
||||
if( cp->doneHave >= cp->doneTotal )
|
||||
return TR_CP_DONE;
|
||||
|
||||
return TR_CP_INCOMPLETE;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
|
|
@ -34,14 +34,12 @@ void tr_cpReset( tr_completion_t * );
|
|||
/* General */
|
||||
|
||||
cp_status_t tr_cpGetStatus ( const tr_completion_t * );
|
||||
|
||||
uint64_t tr_cpDownloadedValid( const tr_completion_t * );
|
||||
uint64_t tr_cpLeftUntilComplete( const tr_completion_t * );
|
||||
uint64_t tr_cpLeftUntilDone( const tr_completion_t * );
|
||||
float tr_cpPercentComplete( const tr_completion_t * );
|
||||
void tr_cpDoneStats( const tr_completion_t * cp,
|
||||
uint64_t * setmeHaveBytes,
|
||||
uint64_t * setmeTotalBytes );
|
||||
|
||||
float tr_cpPercentDone( const tr_completion_t * );
|
||||
void tr_cpInvalidateDND ( tr_completion_t * );
|
||||
|
||||
/* Pieces */
|
||||
int tr_cpPieceHasAllBlocks( const tr_completion_t *, int piece );
|
||||
|
|
|
@ -81,7 +81,7 @@ findFileLocation ( const tr_torrent_t * tor,
|
|||
|
||||
assert ( 0<=pieceIndex && pieceIndex < info->pieceCount );
|
||||
assert ( 0<=tor->info.pieceSize );
|
||||
assert ( pieceOffset < tr_pieceSize(pieceIndex) );
|
||||
assert ( pieceOffset < tr_torPieceCountBytes( tor, pieceIndex ) );
|
||||
assert ( piecePos < info->totalSize );
|
||||
|
||||
for ( i=0; info->files[i].length<=piecePos; ++i )
|
||||
|
@ -139,7 +139,7 @@ readOrWritePiece ( tr_torrent_t * tor,
|
|||
const tr_info_t * info = &tor->info;
|
||||
|
||||
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
||||
assert( buflen <= (size_t) tr_pieceSize( pieceIndex ) );
|
||||
assert( buflen <= (size_t) tr_torPieceCountBytes( tor, pieceIndex ) );
|
||||
|
||||
findFileLocation ( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset );
|
||||
|
||||
|
@ -194,7 +194,7 @@ tr_ioRecalculateHash ( tr_torrent_t * tor,
|
|||
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
||||
|
||||
info = &tor->info;
|
||||
n = tr_pieceSize( pieceIndex );
|
||||
n = tr_torPieceCountBytes( tor, pieceIndex );
|
||||
|
||||
buf = malloc( n );
|
||||
ret = readOrWritePiece ( tor, TR_IO_READ, pieceIndex, 0, buf, n );
|
||||
|
|
|
@ -121,21 +121,23 @@ void tr_torrentReaderUnlock ( const tr_torrent_t * );
|
|||
void tr_torrentWriterLock ( tr_torrent_t * );
|
||||
void tr_torrentWriterUnlock ( tr_torrent_t * );
|
||||
|
||||
/* get the index of this piece's first block */
|
||||
#define tr_torPieceFirstBlock(tor,piece) ( (piece) * (tor)->blockCountInPiece )
|
||||
|
||||
#define TOR_BLOCK_PIECE(tor,block) \
|
||||
( (block) / ( (tor)->info.pieceSize / (tor)->blockSize ) )
|
||||
/* what piece index is this block in? */
|
||||
#define tr_torBlockPiece(tor,block) ( (block) / (tor)->blockCountInPiece )
|
||||
|
||||
#define TOR_PIECE_FIRST_BLOCK(tor,piece) \
|
||||
( (tor)->info.pieces[(piece)].firstBlock )
|
||||
/* how many blocks are in this piece? */
|
||||
#define tr_torPieceCountBlocks(tor,piece) \
|
||||
( ((piece)==((tor)->info.pieceCount-1)) ? (tor)->blockCountInLastPiece : (tor)->blockCountInPiece )
|
||||
|
||||
#define TR_BLOCKS_IN_PIECE(tor,piece) \
|
||||
( (tor)->info.pieces[(piece)].blockCount )
|
||||
/* how many bytes are in this piece? */
|
||||
#define tr_torPieceCountBytes(tor,piece) \
|
||||
( ((piece)==((tor)->info.pieceCount-1)) ? (tor)->lastPieceSize : (tor)->info.pieceSize )
|
||||
|
||||
#define tr_blockSize(a) _tr_blockSize(tor,a)
|
||||
int _tr_blockSize( const tr_torrent_t * tor, int block );
|
||||
|
||||
#define tr_pieceSize(a) _tr_pieceSize(tor,a)
|
||||
int _tr_pieceSize( const tr_torrent_t * tor, int piece );
|
||||
/* how many bytes are in this block? */
|
||||
#define tr_torBlockCountBytes(tor,block) \
|
||||
( ((block)==((tor)->blockCount-1)) ? (tor)->lastBlockSize : (tor)->blockSize )
|
||||
|
||||
#define tr_block(a,b) _tr_block(tor,a,b)
|
||||
int _tr_block( const tr_torrent_t * tor, int index, int begin );
|
||||
|
@ -184,6 +186,12 @@ struct tr_torrent_s
|
|||
/* How many bytes we ask for per request */
|
||||
int blockSize;
|
||||
int blockCount;
|
||||
|
||||
int lastBlockSize;
|
||||
int lastPieceSize;
|
||||
|
||||
int blockCountInPiece;
|
||||
int blockCountInLastPiece;
|
||||
|
||||
tr_completion_t * completion;
|
||||
|
||||
|
|
|
@ -689,8 +689,8 @@ writeEnd:
|
|||
for( ; openSlots>0 && piecesLeft>0; --piecesLeft, p=(p+1)%poolSize )
|
||||
{
|
||||
const int piece = pool[p];
|
||||
const int firstBlock = TOR_PIECE_FIRST_BLOCK( tor, piece );
|
||||
const int n = TR_BLOCKS_IN_PIECE( tor, piece );
|
||||
const int firstBlock = tr_torPieceFirstBlock( tor, piece );
|
||||
const int n = tr_torPieceCountBlocks( tor, piece );
|
||||
const int end = firstBlock + n;
|
||||
int block;
|
||||
for( block=firstBlock; openSlots>0 && block<end; ++block )
|
||||
|
|
|
@ -304,7 +304,7 @@ static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
|
|||
r->index = block / ( inf->pieceSize / tor->blockSize );
|
||||
r->begin = ( block % ( inf->pieceSize / tor->blockSize ) ) *
|
||||
tor->blockSize;
|
||||
r->length = tr_blockSize( block );
|
||||
r->length = tr_torBlockCountBytes( tor, block );
|
||||
(peer->inRequestCount)++;
|
||||
|
||||
/* Build the "ask" message */
|
||||
|
|
|
@ -223,7 +223,7 @@ static int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
peer_dbg( "GET request, invalid index" );
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
if( tr_pieceSize( index ) < begin + length )
|
||||
if( tr_torPieceCountBytes( tor, index ) < begin + length )
|
||||
{
|
||||
peer_dbg( "GET request, invalid begin/length" );
|
||||
return TR_ERROR_ASSERT;
|
||||
|
@ -301,7 +301,7 @@ static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
peer_dbg( "GET piece, invalid index" );
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
if( tr_pieceSize( index ) < begin + len - 8 )
|
||||
if( tr_torPieceCountBytes( tor, index ) < begin + len - 8 )
|
||||
{
|
||||
peer_dbg( "GET piece, invalid begin/length" );
|
||||
return TR_ERROR_ASSERT;
|
||||
|
@ -315,9 +315,9 @@ static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
updateRequests( peer, index, begin );
|
||||
|
||||
/* Sanity checks */
|
||||
if( len - 8 != tr_blockSize( block ) )
|
||||
if( len - 8 != tr_torBlockCountBytes( tor, block ) )
|
||||
{
|
||||
peer_dbg( "wrong size (expecting %d)", tr_blockSize( block ) );
|
||||
peer_dbg( "wrong size (expecting %d)", tr_torBlockCountBytes( tor, block ) );
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
if( tr_cpBlockIsComplete( tor->completion, block ) )
|
||||
|
@ -405,7 +405,7 @@ static int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
peer_dbg( "GET cancel, invalid index" );
|
||||
return TR_ERROR_ASSERT;
|
||||
}
|
||||
if( tr_pieceSize( index ) < begin + length )
|
||||
if( tr_torPieceCountBytes( tor, index ) < begin + length )
|
||||
{
|
||||
peer_dbg( "GET cancel, invalid begin/length" );
|
||||
return TR_ERROR_ASSERT;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -168,28 +169,7 @@ tr_torrentInitFilePieces( tr_torrent_t * tor )
|
|||
}
|
||||
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
{
|
||||
tr_piece_t * piece = tor->info.pieces + i;
|
||||
uint64_t lastByte;
|
||||
int lastBlock;
|
||||
if( i == (tor->info.pieceCount-1))
|
||||
lastByte = tor->info.totalSize - 1;
|
||||
else {
|
||||
lastByte = i + 1;
|
||||
lastByte *= tor->info.pieceSize;
|
||||
--lastByte;
|
||||
}
|
||||
lastBlock = lastByte / tor->blockSize;
|
||||
|
||||
piece->priority = calculatePiecePriority( tor, i );
|
||||
piece->firstBlock = i * (tor->info.pieceSize / tor->blockSize);
|
||||
piece->blockCount = lastBlock + 1 - piece->firstBlock;
|
||||
|
||||
assert( 0 <= piece->firstBlock );
|
||||
assert( piece->firstBlock <= lastBlock );
|
||||
assert( lastBlock < tor->blockCount );
|
||||
assert( piece->firstBlock + piece->blockCount <= tor->blockCount );
|
||||
}
|
||||
tor->info.pieces[i].priority = calculatePiecePriority( tor, i );
|
||||
}
|
||||
|
||||
static void torrentThreadLoop( void * );
|
||||
|
@ -202,8 +182,10 @@ torrentRealInit( tr_handle_t * h,
|
|||
{
|
||||
int i;
|
||||
uint64_t loaded;
|
||||
uint64_t t;
|
||||
char name[512];
|
||||
tr_bitfield_t * uncheckedPieces;
|
||||
tr_info_t * info = &tor->info;
|
||||
|
||||
tor->info.flags |= flags;
|
||||
|
||||
|
@ -226,10 +208,43 @@ torrentRealInit( tr_handle_t * h,
|
|||
|
||||
tor->pexDisabled = 0;
|
||||
|
||||
/* Block size: usually 16 kib, or less if we have to */
|
||||
tor->blockSize = MIN( tor->info.pieceSize, 1 << 14 );
|
||||
tor->blockCount = ( tor->info.totalSize + tor->blockSize - 1 ) /
|
||||
tor->blockSize;
|
||||
/**
|
||||
* Decide on a block size. constraints:
|
||||
* (1) most clients decline requests over 16 KiB
|
||||
* (2) pieceSize must be a multiple of block size
|
||||
*/
|
||||
tor->blockSize = info->pieceSize;
|
||||
while( tor->blockSize > (1024*16) )
|
||||
tor->blockSize /= 2;
|
||||
|
||||
tor->lastPieceSize = info->totalSize % info->pieceSize;
|
||||
|
||||
tor->lastBlockSize = info->totalSize % tor->blockSize;
|
||||
|
||||
tor->blockCount =
|
||||
( info->totalSize + tor->blockSize - 1 ) / tor->blockSize;
|
||||
|
||||
tor->blockCountInPiece =
|
||||
info->pieceSize / tor->blockSize;
|
||||
|
||||
tor->blockCountInLastPiece =
|
||||
( tor->lastPieceSize + tor->blockSize - 1 ) / tor->blockSize;
|
||||
|
||||
/* check our work */
|
||||
assert( ( info->pieceSize % tor->blockSize ) == 0 );
|
||||
t = info->pieceCount - 1;
|
||||
t *= info->pieceSize;
|
||||
t += tor->lastPieceSize;
|
||||
assert( t == info->totalSize );
|
||||
t = tor->blockCount - 1;
|
||||
t *= tor->blockSize;
|
||||
t += tor->lastBlockSize;
|
||||
assert( t == info->totalSize );
|
||||
t = info->pieceCount - 1;
|
||||
t *= tor->blockCountInPiece;
|
||||
t += tor->blockCountInLastPiece;
|
||||
assert( t == (uint64_t)tor->blockCount );
|
||||
|
||||
tor->completion = tr_cpInit( tor );
|
||||
|
||||
tr_torrentInitFilePieces( tor );
|
||||
|
@ -596,7 +611,6 @@ tr_torrentStat( tr_torrent_t * tor )
|
|||
tr_stat_t * s;
|
||||
tr_tracker_t * tc;
|
||||
int i;
|
||||
uint64_t doneHave, doneTotal;
|
||||
|
||||
tr_torrentReaderLock( tor );
|
||||
|
||||
|
@ -639,9 +653,8 @@ tr_torrentStat( tr_torrent_t * tor )
|
|||
|
||||
s->percentComplete = tr_cpPercentComplete ( tor->completion );
|
||||
|
||||
tr_cpDoneStats( tor->completion, &doneHave, &doneTotal );
|
||||
s->percentDone = (float)doneHave / (float)doneTotal;
|
||||
s->left = doneTotal - doneHave;
|
||||
s->percentDone = tr_cpPercentDone( tor->completion );
|
||||
s->left = tr_cpLeftUntilDone( tor->completion );
|
||||
|
||||
if( tor->uncheckedPieces )
|
||||
s->status = tor->runStatus==TR_RUN_CHECKING
|
||||
|
@ -721,8 +734,8 @@ fileBytesCompleted ( const tr_torrent_t * tor, int fileIndex )
|
|||
assert( (int)firstBlock < tor->blockCount );
|
||||
assert( (int)lastBlock < tor->blockCount );
|
||||
assert( firstBlock <= lastBlock );
|
||||
assert( (int)TOR_BLOCK_PIECE( tor, firstBlock ) == file->firstPiece );
|
||||
assert( (int)TOR_BLOCK_PIECE( tor, lastBlock ) == file->lastPiece );
|
||||
assert( (int)tr_torBlockPiece( tor, firstBlock ) == file->firstPiece );
|
||||
assert( (int)tr_torBlockPiece( tor, lastBlock ) == file->lastPiece );
|
||||
|
||||
if( firstBlock == lastBlock )
|
||||
{
|
||||
|
@ -1383,6 +1396,8 @@ tr_torrentSetFileDL( tr_torrent_t * tor,
|
|||
tor->info.pieces[i].dnd = dnd;
|
||||
}
|
||||
|
||||
tr_cpInvalidateDND ( tor->completion );
|
||||
|
||||
tor->fastResumeDirty = TRUE;
|
||||
|
||||
tr_torrentWriterUnlock( tor );
|
||||
|
@ -1403,31 +1418,6 @@ tr_torrentSetFileDLs ( tr_torrent_t * tor,
|
|||
****
|
||||
***/
|
||||
|
||||
int _tr_blockSize( const tr_torrent_t * tor, int block )
|
||||
{
|
||||
const tr_info_t * inf = &tor->info;
|
||||
int dummy;
|
||||
|
||||
if( block != tor->blockCount - 1 ||
|
||||
!( dummy = inf->totalSize % tor->blockSize ) )
|
||||
{
|
||||
return tor->blockSize;
|
||||
}
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
int _tr_pieceSize( const tr_torrent_t * tor, int piece )
|
||||
{
|
||||
const tr_info_t * inf = &tor->info;
|
||||
if( piece < inf->pieceCount - 1 ||
|
||||
!( inf->totalSize % inf->pieceSize ) )
|
||||
{
|
||||
return inf->pieceSize;
|
||||
}
|
||||
return inf->totalSize % inf->pieceSize;
|
||||
}
|
||||
|
||||
int _tr_block( const tr_torrent_t * tor, int index, int begin )
|
||||
{
|
||||
const tr_info_t * inf = &tor->info;
|
||||
|
|
|
@ -515,8 +515,6 @@ typedef struct tr_piece_s
|
|||
uint8_t hash[SHA_DIGEST_LENGTH]; /* pieces hash */
|
||||
int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
|
||||
int8_t dnd; /* nonzero if the piece shouldn't be downloaded */
|
||||
int firstBlock; /* this piece's first byte is in this block */
|
||||
int blockCount; /* number of blocks this piece is in */
|
||||
}
|
||||
tr_piece_t;
|
||||
|
||||
|
|
Loading…
Reference in New Issue