(trunk libT) #4048 "use bitsets instead of bitfield in tr_completion" -- done.

Excuse the sprawl. Much of this didn't fit into self-contained commits.
This commit is contained in:
Jordan Lee 2011-02-23 03:54:04 +00:00
parent 6754258823
commit 2b9db3c242
19 changed files with 813 additions and 655 deletions

View File

@ -475,6 +475,19 @@ tr_bencGetStr( const tr_benc * val, const char ** setme )
return success;
}
tr_bool
tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len )
{
const tr_bool success = tr_bencIsString( val );
if( success ) {
*setme_raw = (uint8_t*) getStr(val);
*setme_len = val->val.s.len;
}
return success;
}
tr_bool
tr_bencGetBool( const tr_benc * val, tr_bool * setme )
{
@ -563,20 +576,9 @@ tr_bencDictFindDict( tr_benc * dict, const char * key, tr_benc ** setme )
}
tr_bool
tr_bencDictFindRaw( tr_benc * dict,
const char * key,
const uint8_t ** setme_raw,
size_t * setme_len )
tr_bencDictFindRaw( tr_benc * dict, const char * key, const uint8_t ** setme_raw, size_t * setme_len )
{
tr_benc * child;
const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
if( found ) {
*setme_raw = (uint8_t*) getStr(child);
*setme_len = child->val.s.len;
}
return found;
return tr_bencGetRaw( tr_bencDictFind( dict, key ), setme_raw, setme_len );
}
/***
@ -1704,7 +1706,7 @@ tr_bencToFile( const tr_benc * top, tr_fmt_mode mode, const char * filename )
}
else
{
tr_fsync( fd );
//tr_fsync( fd );
tr_close_file( fd );
#ifdef WIN32

View File

@ -214,6 +214,10 @@ tr_bool tr_bencGetInt( const tr_benc * val, int64_t * setme );
@return TRUE if successful, or FALSE if the variant could not be represented as a string */
tr_bool tr_bencGetStr( const tr_benc * val, const char ** setme );
/** @brief Get a raw byte array from a variant object
@return TRUE if successful, or FALSE if the variant could not be represented as a raw byte array */
tr_bool tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len );
/** @brief Get a boolean from a variant object
@return TRUE if successful, or FALSE if the variant could not be represented as a boolean */
tr_bool tr_bencGetBool( const tr_benc * val, tr_bool * setme );

View File

@ -16,6 +16,9 @@
#include "transmission.h"
#include "bitfield.h"
#include "bitset.h"
#include "utils.h" /* tr_new0() */
const tr_bitfield TR_BITFIELD_INIT = { NULL, 0, 0 };
tr_bitfield*
tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
@ -35,14 +38,15 @@ tr_bitfieldDestruct( tr_bitfield * b )
}
tr_bitfield*
tr_bitfieldDup( const tr_bitfield * in )
tr_bitfieldNew( size_t bitCount )
{
tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
return tr_bitfieldConstruct( tr_new( tr_bitfield, 1 ), bitCount );
}
ret->bitCount = in->bitCount;
ret->byteCount = in->byteCount;
ret->bits = tr_memdup( in->bits, in->byteCount );
return ret;
void
tr_bitfieldFree( tr_bitfield * b )
{
tr_free( tr_bitfieldDestruct( b ) );
}
void
@ -161,21 +165,31 @@ tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
return a;
}
static const int trueBitCount[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
size_t
tr_bitfieldCountTrueBits( const tr_bitfield* b )
{
size_t ret = 0;
const uint8_t * it, *end;
static const int trueBitCount[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
if( !b )
return 0;
@ -185,3 +199,54 @@ tr_bitfieldCountTrueBits( const tr_bitfield* b )
return ret;
}
size_t
tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end )
{
size_t ret = 0;
const int first_byte = begin >> 3u;
const int last_byte = ( end - 1 ) >> 3u;
assert( begin < end );
if( first_byte == last_byte )
{
int i;
uint8_t val = b->bits[first_byte];
i = begin - (first_byte * 8);
val <<= i;
val >>= i;
i = (last_byte+1)*8 - end;
val >>= i;
val <<= i;
ret += trueBitCount[val];
}
else
{
int i;
uint8_t val;
/* first byte */
i = begin - (first_byte * 8);
val = b->bits[first_byte];
val <<= i;
val >>= i;
ret += trueBitCount[val];
/* middle bytes */
for( i=first_byte+1; i<last_byte; ++i )
ret += trueBitCount[b->bits[i]];
/* last byte */
i = (last_byte+1)*8 - end;
val = b->bits[last_byte];
val >>= i;
val <<= i;
ret += trueBitCount[val];
}
assert( ret <= ( begin - end ) );
return ret;
}

View File

@ -18,7 +18,6 @@
#define TR_BITFIELD_H 1
#include "transmission.h"
#include "utils.h" /* tr_new0 */
/** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
typedef struct tr_bitfield
@ -29,21 +28,15 @@ typedef struct tr_bitfield
}
tr_bitfield;
tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitcount );
extern const tr_bitfield TR_BITFIELD_INIT;
tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitCount );
tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
static inline tr_bitfield* tr_bitfieldNew( size_t bitcount )
{
return tr_bitfieldConstruct( tr_new0( tr_bitfield, 1 ), bitcount );
}
tr_bitfield* tr_bitfieldNew( size_t bitCount );
static inline void tr_bitfieldFree( tr_bitfield * b )
{
tr_free( tr_bitfieldDestruct( b ) );
}
tr_bitfield* tr_bitfieldDup( const tr_bitfield* ) TR_GNUC_MALLOC;
void tr_bitfieldFree( tr_bitfield * b );
void tr_bitfieldClear( tr_bitfield* );
@ -57,6 +50,9 @@ int tr_bitfieldRemRange( tr_bitfield*, size_t begin, size_t end );
size_t tr_bitfieldCountTrueBits( const tr_bitfield* );
size_t tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end );
tr_bitfield* tr_bitfieldOr( tr_bitfield*, const tr_bitfield* );
/** A stripped-down version of bitfieldHas to be used

View File

@ -11,37 +11,137 @@
*/
#include "transmission.h"
#include "bencode.h"
#include "bitset.h"
#include "utils.h"
const tr_bitset TR_BITSET_INIT = { FALSE, FALSE, { NULL, 0, 0 } };
void
tr_bitsetConstructor( tr_bitset * b, size_t size )
tr_bitsetConstruct( tr_bitset * b, size_t bitCount )
{
tr_bitfieldConstruct( &b->bitfield, size );
*b = TR_BITSET_INIT;
b->bitfield.bitCount = bitCount;
}
void
tr_bitsetDestructor( tr_bitset * b )
tr_bitsetDestruct( tr_bitset * b )
{
tr_bitfieldDestruct( &b->bitfield );
tr_free( b->bitfield.bits );
*b = TR_BITSET_INIT;
}
static void
tr_bitsetClear( tr_bitset * b )
{
tr_free( b->bitfield.bits );
b->bitfield.bits = NULL;
b->haveAll = FALSE;
b->haveNone = FALSE;
}
void
tr_bitsetReserve( tr_bitset * b, size_t size )
tr_bitsetSetHaveAll( tr_bitset * b )
{
if( b->bitfield.bitCount < size )
tr_bitsetClear( b );
b->haveAll = TRUE;
}
void
tr_bitsetSetHaveNone( tr_bitset * b )
{
tr_bitsetClear( b );
b->haveNone = TRUE;
}
void
tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield )
{
const size_t n = tr_bitfieldCountTrueBits( bitfield );
if( n == 0 )
{
tr_bitfield * tmp = tr_bitfieldDup( &b->bitfield );
tr_bitfieldDestruct( &b->bitfield );
tr_bitfieldConstruct( &b->bitfield, size );
if( ( tmp->bits != NULL ) && ( tmp->byteCount > 0 ) )
memcpy( b->bitfield.bits, tmp->bits, tmp->byteCount );
tr_bitfieldFree( tmp );
tr_bitsetSetHaveNone( b );
}
else if( n == bitfield->bitCount )
{
tr_bitsetSetHaveAll( b );
}
else
{
tr_bitsetDestruct( b );
b->bitfield.bits = tr_memdup( bitfield->bits, bitfield->byteCount );
b->bitfield.bitCount = bitfield->bitCount;
b->bitfield.byteCount = bitfield->byteCount;
}
}
/***
****
***/
void
tr_bitsetAdd( tr_bitset * b, size_t i )
{
tr_bitfield * bf = &b->bitfield;
if( b->haveAll )
return;
b->haveNone = FALSE;
/* do we need to resize the bitfield to accomodate this bit? */
if( !bf->bits || ( bf->bitCount < i+1 ) )
{
const size_t oldByteCount = bf->byteCount;
if( bf->bitCount < i + 1 )
bf->bitCount = i + 1;
bf->byteCount = ( bf->bitCount + 7u ) / 8u;
bf->bits = tr_renew( uint8_t, bf->bits, bf->byteCount );
if( bf->byteCount > oldByteCount )
memset( bf->bits + oldByteCount, 0, bf->byteCount - oldByteCount );
}
tr_bitfieldAdd( bf, i );
}
void
tr_bitsetRem( tr_bitset * b, size_t i )
{
if( b->haveNone )
return;
b->haveAll = FALSE;
if( !b->bitfield.bits )
{
tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
}
tr_bitfieldRem( &b->bitfield, i );
}
void
tr_bitsetRemRange( tr_bitset * b, size_t begin, size_t end )
{
if( b->haveNone )
return;
b->haveAll = FALSE;
if( !b->bitfield.bits )
{
tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
}
tr_bitfieldRemRange( &b->bitfield, begin, end );
}
/***
****
***/
tr_bool
tr_bitsetHas( const tr_bitset * b, const size_t nth )
{
@ -51,13 +151,12 @@ tr_bitsetHas( const tr_bitset * b, const size_t nth )
return tr_bitfieldHas( &b->bitfield, nth );
}
void
tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
size_t
tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end )
{
if( b->haveAll )
tr_bitfieldAddRange( a, 0, a->bitCount );
else if( !b->haveNone )
tr_bitfieldOr( a, &b->bitfield );
if( b->haveAll ) return end - begin;
if( b->haveNone ) return 0;
return tr_bitfieldCountRange( &b->bitfield, begin, end );
}
double
@ -70,27 +169,79 @@ tr_bitsetPercent( const tr_bitset * b )
}
void
tr_bitsetSetHaveAll( tr_bitset * b )
tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
{
b->haveAll = 1;
b->haveNone = 0;
if( b->haveAll )
tr_bitfieldAddRange( a, 0, a->bitCount );
else if( !b->haveNone )
tr_bitfieldOr( a, &b->bitfield );
}
/***
****
***/
tr_bool
tr_bitsetFromBenc( tr_bitset * bitset, tr_benc * benc )
{
size_t buflen;
const uint8_t * buf;
tr_bool handled = FALSE;
if( tr_bencGetRaw( benc, &buf, &buflen ) )
{
if( ( buflen == 3 ) && !memcmp( buf, "all", 3 ) )
{
tr_bitsetSetHaveAll( bitset );
handled = TRUE;
}
else if( ( buflen == 4 ) && !memcmp( buf, "none", 4 ) )
{
tr_bitsetSetHaveNone( bitset );
handled = TRUE;
}
else
{
bitset->haveAll = FALSE;
bitset->haveNone = FALSE;
tr_free( bitset->bitfield.bits );
bitset->bitfield.bits = tr_memdup( buf, buflen );
bitset->bitfield.byteCount = buflen;
bitset->bitfield.bitCount = buflen * 8;
handled = TRUE;
}
}
return handled;
}
void
tr_bitsetSetHaveNone( tr_bitset * b )
tr_bitsetToBenc( const tr_bitset * bitset, tr_benc * benc )
{
b->haveAll = 0;
b->haveNone = 1;
}
int
tr_bitsetAdd( tr_bitset * b, size_t i )
{
int ret = 0;
if( !b->haveAll ) {
b->haveNone = 0;
tr_bitsetReserve( b, i+1 );
ret = tr_bitfieldAdd( &b->bitfield, i );
if( bitset->haveAll )
{
tr_bencInitStr( benc, "all", 3 );
}
else if( bitset->haveNone )
{
tr_bencInitStr( benc, "none", 4 );
}
else
{
const tr_bitfield * bf = &bitset->bitfield;
const size_t n = tr_bitfieldCountTrueBits( bf );
if( n == bf->bitCount )
{
tr_bencInitStr( benc, "all", 3 );
}
else if( n == 0 )
{
tr_bencInitStr( benc, "none", 4 );
}
else
{
tr_bencInitRaw( benc, bf->bits, bf->byteCount );
}
}
return ret;
}

View File

@ -29,14 +29,23 @@ typedef struct tr_bitset
}
tr_bitset;
void tr_bitsetReserve( tr_bitset * b, size_t size );
void tr_bitsetConstructor( tr_bitset * b, size_t size );
void tr_bitsetDestructor( tr_bitset * b );
extern const tr_bitset TR_BITSET_INIT;
void tr_bitsetConstruct( tr_bitset * b, size_t bitCount );
void tr_bitsetDestruct( tr_bitset * b );
void tr_bitsetSetHaveAll( tr_bitset * b );
void tr_bitsetSetHaveNone( tr_bitset * b );
int tr_bitsetAdd( tr_bitset * b, size_t i );
void tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield );
void tr_bitsetAdd( tr_bitset * b, size_t i );
void tr_bitsetRem( tr_bitset * b, size_t i );
void tr_bitsetRemRange ( tr_bitset * b, size_t begin, size_t end );
struct tr_benc;
tr_bool tr_bitsetFromBenc( tr_bitset * bitset, struct tr_benc * benc );
void tr_bitsetToBenc( const tr_bitset * bitset, struct tr_benc * benc );
/***
****
@ -45,6 +54,7 @@ int tr_bitsetAdd( tr_bitset * b, size_t i );
double tr_bitsetPercent( const tr_bitset * b );
tr_bool tr_bitsetHas( const tr_bitset * b, const size_t nth );
size_t tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end );
void tr_bitsetOr( tr_bitfield * a, const tr_bitset * b );

View File

@ -389,11 +389,11 @@ tr_cachePrefetchBlock( tr_cache * cache,
***/
static int
findPiece( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece )
findBlockPos( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t block )
{
struct cache_block key;
key.tor = torrent;
key.block = tr_torPieceFirstBlock( torrent, piece );
key.block = block;
return tr_ptrArrayLowerBound( &cache->blocks, &key, cache_block_compare, NULL );
}
@ -419,19 +419,20 @@ int tr_cacheFlushDone( tr_cache * cache )
int
tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
{
int pos;
int err = 0;
const tr_file * file = &torrent->info.files[i];
const tr_block_index_t begin = tr_torPieceFirstBlock( torrent, file->firstPiece );
const tr_block_index_t end = tr_torPieceFirstBlock( torrent, file->lastPiece ) + tr_torPieceCountBlocks( torrent, file->lastPiece );
const int pos = findPiece( cache, torrent, file->firstPiece );
dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu)", (int)i, (size_t)begin, (size_t)end );
tr_block_index_t first;
tr_block_index_t last;
tr_torGetFileBlockRange( torrent, i, &first, &last );
pos = findBlockPos( cache, torrent, first );
dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu]", (int)i, (size_t)first, (size_t)last );
/* flush out all the blocks in that file */
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
{
const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
if( b->tor != torrent ) break;
if( ( b->block < begin ) || ( b->block >= end ) ) break;
if( ( b->block < first ) || ( b->block > last ) ) break;
err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
}
@ -442,7 +443,7 @@ int
tr_cacheFlushTorrent( tr_cache * cache, tr_torrent * torrent )
{
int err = 0;
const int pos = findPiece( cache, torrent, 0 );
const int pos = findBlockPos( cache, torrent, 0 );
/* flush out all the blocks in that torrent */
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )

View File

@ -10,34 +10,33 @@
* $Id$
*/
#include <assert.h>
#include <string.h>
#include "transmission.h"
#include "completion.h"
#include "torrent.h"
#include "torrent-magnet.h"
#include "utils.h"
/***
****
***/
static void
tr_cpReset( tr_completion * cp )
{
tr_bitfieldClear( &cp->pieceBitfield );
tr_bitfieldClear( &cp->blockBitfield );
memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
tr_bitsetSetHaveNone( &cp->blockBitset );
tr_free( cp->completeBlocks );
cp->completeBlocks = NULL;
cp->sizeNow = 0;
cp->sizeWhenDoneIsDirty = 1;
cp->blocksWantedIsDirty = 1;
cp->haveValidIsDirty = 1;
cp->sizeWhenDoneIsDirty = TRUE;
cp->blocksWantedIsDirty = TRUE;
cp->haveValidIsDirty = TRUE;
}
tr_completion *
tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
{
cp->tor = tor;
cp->completeBlocks = tr_new( uint16_t, tor->info.pieceCount );
tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
cp->completeBlocks = NULL;
tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
tr_cpReset( cp );
return cp;
}
@ -46,254 +45,20 @@ tr_completion*
tr_cpDestruct( tr_completion * cp )
{
tr_free( cp->completeBlocks );
tr_bitfieldDestruct( &cp->pieceBitfield );
tr_bitfieldDestruct( &cp->blockBitfield );
tr_bitsetDestruct( &cp->blockBitset );
return cp;
}
void
tr_cpInvalidateDND( tr_completion * cp )
{
cp->sizeWhenDoneIsDirty = 1;
cp->blocksWantedIsDirty = 1;
}
tr_block_index_t
tr_cpBlocksMissing( const tr_completion * ccp )
{
if( ccp->blocksWantedIsDirty )
{
tr_completion * cp = (tr_completion *) ccp; /* mutable */
const tr_torrent * tor = cp->tor;
const tr_info * info = &tor->info;
tr_piece_index_t i;
tr_block_index_t wanted = 0;
tr_block_index_t complete = 0;
for( i = 0; i < info->pieceCount; ++i )
{
if( info->pieces[i].dnd )
continue;
wanted += tr_torPieceCountBlocks( tor, i );
complete += cp->completeBlocks[i];
}
cp->blocksWantedLazy = wanted;
cp->blocksWantedCompleteLazy = complete;
cp->blocksWantedIsDirty = FALSE;
}
return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
}
uint64_t
tr_cpSizeWhenDone( const tr_completion * ccp )
{
if( ccp->sizeWhenDoneIsDirty )
{
tr_completion * cp = (tr_completion *) ccp; /* mutable */
const tr_torrent * tor = cp->tor;
const tr_info * info = &tor->info;
tr_piece_index_t i;
uint64_t size = 0;
for( i = 0; i < info->pieceCount; ++i )
{
if( !info->pieces[i].dnd )
{
/* we want the piece... */
size += tr_torPieceCountBytes( tor, i );
}
else if( tr_cpPieceIsComplete( cp, i ) )
{
/* we have the piece... */
size += tr_torPieceCountBytes( tor, i );
}
else if( cp->completeBlocks[i] )
{
/* we have part of the piece... */
const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
tr_block_index_t j;
for( j = b; j < e; ++j )
if( tr_cpBlockIsCompleteFast( cp, j ) )
size += tr_torBlockCountBytes( tor, j );
}
}
cp->sizeWhenDoneLazy = size;
cp->sizeWhenDoneIsDirty = 0;
}
assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
return ccp->sizeWhenDoneLazy;
}
void
tr_cpPieceAdd( tr_completion * cp,
tr_piece_index_t piece )
{
const tr_torrent * tor = cp->tor;
const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
tr_block_index_t i;
for( i = start; i < end; ++i )
tr_cpBlockAdd( cp, i );
}
void
tr_cpPieceRem( tr_completion * cp,
tr_piece_index_t piece )
{
const tr_torrent * tor = cp->tor;
const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
tr_block_index_t block;
assert( cp );
assert( piece < tor->info.pieceCount );
assert( start < tor->blockCount );
assert( start <= end );
assert( end <= tor->blockCount );
for( block = start; block < end; ++block )
if( tr_cpBlockIsCompleteFast( cp, block ) )
cp->sizeNow -= tr_torBlockCountBytes( tor, block );
if( !tor->info.pieces[piece].dnd )
cp->blocksWantedCompleteLazy -= cp->completeBlocks[piece];
cp->sizeWhenDoneIsDirty = 1;
cp->haveValidIsDirty = 1;
cp->completeBlocks[piece] = 0;
tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
tr_bitfieldRem( &cp->pieceBitfield, piece );
}
void
tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
{
const tr_torrent * tor = cp->tor;
if( !tr_cpBlockIsComplete( cp, block ) )
{
const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
const int blockSize = tr_torBlockCountBytes( tor,
block );
++cp->completeBlocks[piece];
if( tr_cpPieceIsComplete( cp, piece ) )
tr_bitfieldAdd( &cp->pieceBitfield, piece );
tr_bitfieldAdd( &cp->blockBitfield, block );
cp->sizeNow += blockSize;
if( !tor->info.pieces[piece].dnd )
cp->blocksWantedCompleteLazy++;
cp->haveValidIsDirty = 1;
cp->sizeWhenDoneIsDirty = 1;
}
}
void
tr_cpSetHaveAll( tr_completion * cp )
{
tr_piece_index_t i;
tr_torrent * tor = cp->tor;
tr_cpReset( cp );
cp->sizeNow = tor->info.totalSize;
tr_bitfieldAddRange( &cp->blockBitfield, 0, tor->blockCount );
tr_bitfieldAddRange( &cp->pieceBitfield, 0, tor->info.pieceCount );
for( i=0; i<tor->info.pieceCount; ++i )
cp->completeBlocks[i] = tr_torPieceCountBlocks( tor, i );
cp->sizeWhenDoneIsDirty = 1;
cp->blocksWantedIsDirty = 1;
cp->haveValidIsDirty = 1;
}
/* Initialize a completion object from a bitfield indicating which blocks we have */
tr_bool
tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
{
tr_bool success = FALSE;
assert( cp );
assert( blockBitfield );
/* The bitfield of block flags is typically loaded from a resume file.
Test the bitfield's length in case the resume file somehow got corrupted */
if(( success = blockBitfield->byteCount == cp->blockBitfield.byteCount ))
{
tr_block_index_t b = 0;
tr_piece_index_t p = 0;
uint32_t pieceBlock = 0;
uint16_t completeBlocksInPiece = 0;
tr_block_index_t completeBlocksInTorrent = 0;
uint32_t blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
/* start cp with a state where it thinks we have nothing */
tr_cpReset( cp );
/* init our block bitfield from the one passed in */
memcpy( cp->blockBitfield.bits, blockBitfield->bits, blockBitfield->byteCount );
/* invalidate the fields that are lazy-evaluated */
cp->sizeWhenDoneIsDirty = TRUE;
cp->blocksWantedIsDirty = TRUE;
cp->haveValidIsDirty = TRUE;
/* to set the remaining fields, we walk through every block... */
while( b < cp->tor->blockCount )
{
if( tr_bitfieldHasFast( blockBitfield, b ) )
++completeBlocksInPiece;
++b;
++pieceBlock;
/* by the time we reach the end of a piece, we have enough info
to update that piece's slot in cp.completeBlocks and cp.pieceBitfield */
if( pieceBlock == blocksInCurrentPiece )
{
cp->completeBlocks[p] = completeBlocksInPiece;
completeBlocksInTorrent += completeBlocksInPiece;
if( completeBlocksInPiece == blocksInCurrentPiece )
tr_bitfieldAdd( &cp->pieceBitfield, p );
/* reset the per-piece counters because we're starting on a new piece now */
++p;
completeBlocksInPiece = 0;
pieceBlock = 0;
blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
}
}
/* update sizeNow */
cp->sizeNow = completeBlocksInTorrent;
cp->sizeNow *= tr_torBlockCountBytes( cp->tor, 0 );
if( tr_bitfieldHasFast( &cp->blockBitfield, cp->tor->blockCount-1 ) ) {
/* the last block is usually smaller than the other blocks,
so handle that special case or cp->sizeNow might be too large */
cp->sizeNow -= tr_torBlockCountBytes( cp->tor, 0 );
cp->sizeNow += tr_torBlockCountBytes( cp->tor, cp->tor->blockCount-1 );
}
}
return success;
}
/***
****
***/
static inline tr_bool
isSeed( const tr_completion * cp )
{
return cp->blockBitset.haveAll;
}
tr_completeness
tr_cpGetStatus( const tr_completion * cp )
{
@ -303,133 +68,280 @@ tr_cpGetStatus( const tr_completion * cp )
return TR_LEECH;
}
static uint64_t
calculateHaveValid( const tr_completion * ccp )
/* how many blocks are in this piece? */
static inline uint16_t
countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
{
uint64_t b = 0;
tr_piece_index_t i;
const tr_torrent * tor = ccp->tor;
const uint64_t pieceSize = tor->info.pieceSize;
const uint64_t lastPieceSize = tor->lastPieceSize;
const tr_piece_index_t lastPiece = tor->info.pieceCount - 1;
return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
: tor->blockCountInPiece;
}
if( !tr_torrentHasMetadata( tor ) )
static uint16_t *
getCompleteBlocks( const tr_completion * ccp )
{
if( ccp->completeBlocks == NULL )
{
tr_completion * cp = (tr_completion*) ccp;
cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
}
return ccp->completeBlocks;
}
void
tr_cpInvalidateDND( tr_completion * cp )
{
cp->sizeWhenDoneIsDirty = TRUE;
cp->blocksWantedIsDirty = TRUE;
}
tr_block_index_t
tr_cpBlocksMissing( const tr_completion * ccp )
{
if( isSeed( ccp ) )
return 0;
for( i=0; i!=lastPiece; ++i )
if( tr_cpPieceIsComplete( ccp, i ) )
b += pieceSize;
if( ccp->blocksWantedIsDirty )
{
tr_piece_index_t i;
tr_block_index_t wanted = 0;
tr_block_index_t complete = 0;
tr_completion * cp = (tr_completion *) ccp; /* mutable */
const uint16_t * complete_blocks = getCompleteBlocks( cp );
const tr_torrent * tor = ccp->tor;
const tr_info * info = &tor->info;
if( tr_cpPieceIsComplete( ccp, lastPiece ) )
b += lastPieceSize;
for( i = 0; i < info->pieceCount; ++i )
{
if( !info->pieces[i].dnd )
{
wanted += countBlocksInPiece( tor, i );
complete += complete_blocks[i];
}
}
return b;
cp->blocksWantedLazy = wanted;
cp->blocksWantedCompleteLazy = complete;
cp->blocksWantedIsDirty = FALSE;
}
return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
}
void
tr_cpPieceRem( tr_completion * cp, tr_piece_index_t piece )
{
tr_block_index_t i;
tr_block_index_t first;
tr_block_index_t last;
const tr_torrent * tor = cp->tor;
uint16_t * complete_blocks = getCompleteBlocks( cp );
tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
for( i=first; i<=last; ++i )
if( tr_cpBlockIsComplete( cp, i ) )
cp->sizeNow -= tr_torBlockCountBytes( tor, i );
if( !tor->info.pieces[piece].dnd )
cp->blocksWantedCompleteLazy -= complete_blocks[piece];
cp->sizeWhenDoneIsDirty = TRUE;
cp->haveValidIsDirty = TRUE;
complete_blocks[piece] = 0;
tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
}
void
tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
{
tr_block_index_t i;
tr_block_index_t first;
tr_block_index_t last;
tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
for( i=first; i<=last; ++i )
tr_cpBlockAdd( cp, i );
}
void
tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
{
const tr_torrent * tor = cp->tor;
if( !tr_cpBlockIsComplete( cp, block ) )
{
const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
const int blockSize = tr_torBlockCountBytes( tor, block );
getCompleteBlocks(cp)[piece]++;
tr_bitsetAdd( &cp->blockBitset, block );
cp->sizeNow += blockSize;
if( !tor->info.pieces[piece].dnd )
cp->blocksWantedCompleteLazy++;
cp->sizeWhenDoneIsDirty = TRUE;
cp->haveValidIsDirty = TRUE;
}
}
tr_bool
tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
{
tr_bool success = FALSE;
tr_torrent * tor = cp->tor;
/* start cp with a state where it thinks we have nothing */
tr_cpReset( cp );
if( blocks->haveAll )
{
tr_bitsetSetHaveAll( &cp->blockBitset );
cp->sizeNow = tor->info.totalSize;
success = TRUE;
}
else if( blocks->haveNone )
{
/* already reset... */
success = TRUE;
}
else
{
const tr_bitfield * src = &blocks->bitfield;
tr_bitfield * tgt = &cp->blockBitset.bitfield;
tr_bitfieldConstruct( tgt, tor->blockCount );
/* The bitfield of block flags is typically loaded from a resume file.
Test the bitfield's length in case the resume file is corrupt */
if(( success = src->byteCount == tgt->byteCount ))
{
size_t i = 0;
uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
/* init our block bitfield from the one passed in */
memcpy( tgt->bits, src->bits, src->byteCount );
/* update cp.sizeNow and the cp.blockBitset flags */
i = tr_bitfieldCountTrueBits( tgt );
if( i == tor->blockCount ) {
tr_bitsetSetHaveAll( &cp->blockBitset );
cp->sizeNow = cp->tor->info.totalSize;
} else if( !i ) {
tr_bitsetSetHaveNone( &cp->blockBitset );
cp->sizeNow = 0;
} else {
cp->blockBitset.haveAll = cp->blockBitset.haveNone = FALSE;
cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
cp->sizeNow *= tor->blockSize;
if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
}
/* update complete_blocks_in_piece */
for( i=0; i<tor->info.pieceCount; ++i ) {
tr_block_index_t first, last;
tr_torGetPieceBlockRange( tor, i, &first, &last );
complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
}
}
}
return success;
}
/***
****
***/
uint64_t
tr_cpHaveValid( const tr_completion * ccp )
{
if( ccp->haveValidIsDirty )
{
tr_completion * cp = (tr_completion *) ccp; /* mutable */
cp->haveValidLazy = calculateHaveValid( ccp );
cp->haveValidIsDirty = 0;
tr_piece_index_t i;
uint64_t size = 0;
tr_completion * cp = (tr_completion *) ccp; /* mutable */
const tr_torrent * tor = ccp->tor;
const tr_info * info = &tor->info;
for( i=0; i<info->pieceCount; ++i )
if( tr_cpPieceIsComplete( ccp, i ) )
size += tr_torPieceCountBytes( tor, i );
cp->haveValidIsDirty = FALSE;
cp->haveValidLazy = size;
}
return ccp->haveValidLazy;
}
void
tr_cpGetAmountDone( const tr_completion * cp,
float * tab,
int tabCount )
uint64_t
tr_cpSizeWhenDone( const tr_completion * ccp )
{
int i;
const tr_torrent * tor = cp->tor;
const float interval = tor->info.pieceCount / (float)tabCount;
const int isSeed = tr_cpGetStatus( cp ) == TR_SEED;
for( i = 0; i < tabCount; ++i )
if( ccp->sizeWhenDoneIsDirty )
{
const tr_piece_index_t piece = i * interval;
tr_piece_index_t i;
uint64_t size = 0;
tr_completion * cp = (tr_completion *) ccp; /* mutable */
const tr_torrent * tor = ccp->tor;
const tr_info * info = &tor->info;
if( tor == NULL )
tab[i] = 0.0f;
else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
tab[i] = 1.0f;
else
tab[i] = (float)cp->completeBlocks[piece] /
tr_torPieceCountBlocks( tor, piece );
for( i=0; i<info->pieceCount; ++i )
if( !info->pieces[i].dnd || tr_cpPieceIsComplete( cp, i ) )
size += tr_torPieceCountBytes( tor, i );
cp->sizeWhenDoneIsDirty = FALSE;
cp->sizeWhenDoneLazy = size;
}
return ccp->sizeWhenDoneLazy;
}
void
tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
{
int i, b;
const int span = cp->tor->blockCount / tabCount;
for( i=b=0; i<tabCount; ++i, b+=span )
tab[i] = tr_bitsetCountRange(&cp->blockBitset,b,b+span) / (float)span;
}
int
tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
{
return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
}
if( isSeed( cp ) )
return 0;
tr_bool
tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
{
return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
}
tr_bool
tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t fileIndex )
tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
{
tr_block_index_t block;
tr_block_index_t f, l;
const tr_torrent * tor = cp->tor;
const tr_file * file = &tor->info.files[fileIndex];
if( file->firstPiece == file->lastPiece )
{
const tr_block_index_t firstBlock = file->offset / tor->blockSize;
const tr_block_index_t lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
for( block=firstBlock; block<=lastBlock; ++block )
if( !tr_cpBlockIsCompleteFast( cp, block ) )
return FALSE;
}
else
{
tr_piece_index_t piece;
tr_block_index_t firstBlock;
tr_block_index_t firstBlockInLastPiece;
tr_block_index_t lastBlock;
tr_block_index_t lastBlockInFirstPiece;
uint64_t lastByteInFirstPiece;
uint64_t firstByteInLastPiece;
/* go piece-by-piece in the middle pieces... it's faster than block-by-block */
for( piece=file->firstPiece+1; piece<file->lastPiece; ++piece )
if( !tr_cpPieceIsComplete( cp, piece ) )
return FALSE;
/* go block-by-block in the first piece */
firstBlock = file->offset / tor->blockSize;
lastByteInFirstPiece = ( (uint64_t)(file->firstPiece+1) * tor->info.pieceSize ) - 1;
lastBlockInFirstPiece = lastByteInFirstPiece / tor->blockSize;
assert( lastBlockInFirstPiece >= firstBlock );
assert( lastBlockInFirstPiece - firstBlock <= tr_torPieceCountBlocks( tor, file->firstPiece ) );
for( block=firstBlock; block<=lastBlockInFirstPiece; ++block )
if( !tr_cpBlockIsCompleteFast( cp, block ) )
return FALSE;
/* go block-by-block in the last piece */
lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
firstByteInLastPiece = (uint64_t)file->lastPiece * tor->info.pieceSize;
firstBlockInLastPiece = firstByteInLastPiece / tor->blockSize;
assert( firstBlockInLastPiece <= lastBlock );
assert( firstBlockInLastPiece >= firstBlock );
assert( firstBlockInLastPiece >= lastBlockInFirstPiece );
assert( lastBlock - firstBlockInLastPiece <= tr_torPieceCountBlocks( tor, file->lastPiece ) );
for( block=firstBlockInLastPiece; block<=lastBlock; ++block )
if( !tr_cpBlockIsCompleteFast( cp, block ) )
return FALSE;
}
return TRUE;
if( cp->tor->info.files[i].length == 0 )
return TRUE;
tr_torGetFileBlockRange( cp->tor, i, &f, &l );
return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
}
tr_bitfield *
tr_cpCreatePieceBitfield( const tr_completion * cp )
{
tr_piece_index_t i;
const tr_piece_index_t n = cp->tor->info.pieceCount;
tr_bitfield * bf = tr_bitfieldNew( n );
for( i=0; i<n; ++i )
if( tr_cpPieceIsComplete( cp, i ) )
tr_bitfieldAdd( bf, i );
return bf;
}

View File

@ -20,7 +20,8 @@
#include <assert.h>
#include "transmission.h"
#include "bitfield.h"
#include "bitset.h"
#include "utils.h" /* tr_getRatio() */
typedef struct tr_completion
{
@ -31,10 +32,7 @@ typedef struct tr_completion
tr_torrent * tor;
/* do we have this block? */
tr_bitfield blockBitfield;
/* do we have this piece? */
tr_bitfield pieceBitfield;
tr_bitset blockBitset;
/* a block is complete if and only if we have it */
uint16_t * completeBlocks;
@ -76,19 +74,19 @@ tr_completion * tr_cpDestruct( tr_completion * );
*** General
**/
tr_completeness tr_cpGetStatus( const tr_completion * );
tr_completeness tr_cpGetStatus( const tr_completion * );
uint64_t tr_cpHaveValid( const tr_completion * );
uint64_t tr_cpHaveValid( const tr_completion * );
tr_block_index_t tr_cpBlocksMissing( const tr_completion * );
tr_block_index_t tr_cpBlocksMissing( const tr_completion * );
uint64_t tr_cpSizeWhenDone( const tr_completion * );
uint64_t tr_cpSizeWhenDone( const tr_completion * );
void tr_cpInvalidateDND( tr_completion * );
void tr_cpInvalidateDND( tr_completion * );
void tr_cpGetAmountDone( const tr_completion * completion,
float * tab,
int tabCount );
void tr_cpGetAmountDone( const tr_completion * completion,
float * tab,
int tabCount );
static inline uint64_t tr_cpHaveTotal( const tr_completion * cp )
{
@ -127,17 +125,17 @@ static inline double tr_cpPercentDone( const tr_completion * cp )
*** Pieces
**/
int tr_cpMissingBlocksInPiece( const tr_completion * cp,
tr_piece_index_t piece );
int tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i );
tr_bool tr_cpPieceIsComplete( const tr_completion * cp,
tr_piece_index_t piece );
static inline tr_bool
tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t i )
{
return tr_cpMissingBlocksInPiece( cp, i ) == 0;
}
void tr_cpPieceAdd( tr_completion * completion,
tr_piece_index_t piece );
void tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t i );
void tr_cpPieceRem( tr_completion * completion,
tr_piece_index_t piece );
void tr_cpPieceRem( tr_completion * cp, tr_piece_index_t i );
tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
@ -145,37 +143,26 @@ tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
*** Blocks
**/
static inline tr_bool tr_cpBlockIsCompleteFast( const tr_completion * cp, tr_block_index_t block )
static inline tr_bool
tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t i )
{
return tr_bitfieldHasFast( &cp->blockBitfield, block );
return tr_bitsetHas( &cp->blockBitset, i );
}
static inline tr_bool tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
{
return tr_bitfieldHas( &cp->blockBitfield, block );
}
void tr_cpBlockAdd( tr_completion * cp, tr_block_index_t i );
void tr_cpBlockAdd( tr_completion * completion,
tr_block_index_t block );
tr_bool tr_cpBlockBitfieldSet( tr_completion * completion,
struct tr_bitfield * blocks );
void tr_cpSetHaveAll( tr_completion * completion );
tr_bool tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks );
/***
****
***/
static inline const struct tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp ) {
return &cp->pieceBitfield;
static inline const tr_bitset *
tr_cpBlockBitset( const tr_completion * cp )
{
return &cp->blockBitset;
}
static inline const struct tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp ) {
assert( cp );
assert( cp->blockBitfield.bits );
assert( cp->blockBitfield.bitCount );
return &cp->blockBitfield;
}
tr_bitfield * tr_cpCreatePieceBitfield( const tr_completion * cp );
#endif

View File

@ -383,7 +383,7 @@ peerConstructor( struct peer_atom * atom )
{
tr_peer * peer = tr_new0( tr_peer, 1 );
tr_bitsetConstructor( &peer->have, 0 );
peer->have = TR_BITSET_INIT;
peer->atom = atom;
atom->peer = peer;
@ -434,7 +434,7 @@ peerDestructor( Torrent * t, tr_peer * peer )
tr_historyFree( peer->cancelsSentToClient );
tr_historyFree( peer->cancelsSentToPeer );
tr_bitsetDestructor( &peer->have );
tr_bitsetDestruct( &peer->have );
tr_bitfieldFree( peer->blame );
tr_free( peer->client );
peer->atom->peer = NULL;
@ -1335,17 +1335,20 @@ tr_peerMgrGetNextRequests( tr_torrent * tor,
/* if the peer has this piece that we want... */
if( tr_bitsetHas( have, p->index ) )
{
tr_block_index_t b = tr_torPieceFirstBlock( tor, p->index );
const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, p->index );
tr_block_index_t b;
tr_block_index_t first;
tr_block_index_t last;
tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
for( ; b!=e && got<numwant; ++b )
tr_torGetPieceBlockRange( tor, p->index, &first, &last );
for( b=first; b<=last && got<numwant; ++b )
{
int peerCount;
tr_peer ** peers;
/* don't request blocks we've already got */
if( tr_cpBlockIsCompleteFast( &tor->completion, b ) )
if( tr_cpBlockIsComplete( &tor->completion, b ) )
continue;
/* always add peer if this block has no peers yet */
@ -1546,17 +1549,19 @@ peerSuggestedPiece( Torrent * t UNUSED,
/* request the blocks that we don't have in this piece */
{
tr_block_index_t block;
tr_block_index_t b;
tr_block_index_t first;
tr_block_index_t last;
const tr_torrent * tor = t->tor;
const tr_block_index_t start = tr_torPieceFirstBlock( tor, pieceIndex );
const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, pieceIndex );
for( block=start; block<end; ++block )
tr_torGetPieceBlockRange( t->tor, pieceIndex, &first, &last );
for( b=first; b<=last; ++b )
{
if( !tr_cpBlockIsComplete( tor->completion, block ) )
if( !tr_cpBlockIsComplete( tor->completion, b ) )
{
const uint32_t offset = getBlockOffsetInPiece( tor, block );
const uint32_t length = tr_torBlockCountBytes( tor, block );
const uint32_t offset = getBlockOffsetInPiece( tor, b );
const uint32_t length = tr_torBlockCountBytes( tor, b );
tr_peerMsgsAddRequest( peer->msgs, pieceIndex, offset, length );
incrementPieceRequests( t, pieceIndex );
}

View File

@ -88,10 +88,6 @@ enum
HIGH_PRIORITY_INTERVAL_SECS = 2,
LOW_PRIORITY_INTERVAL_SECS = 10,
/* number of pieces to remove from the bitfield when
* lazy bitfields are turned on */
LAZY_PIECE_COUNT = 26,
/* number of pieces we'll allow in our fast set */
MAX_FAST_SET_SIZE = 3,
@ -120,25 +116,14 @@ struct peer_request
uint32_t length;
};
static uint32_t
getBlockOffsetInPiece( const tr_torrent * tor, uint64_t b )
{
const uint64_t piecePos = tor->info.pieceSize * tr_torBlockPiece( tor, b );
const uint64_t blockPos = tor->blockSize * b;
assert( blockPos >= piecePos );
return (uint32_t)( blockPos - piecePos );
}
static void
blockToReq( const tr_torrent * tor,
tr_block_index_t block,
struct peer_request * setme )
{
assert( setme != NULL );
setme->index = tr_torBlockPiece( tor, block );
setme->offset = getBlockOffsetInPiece( tor, block );
setme->length = tr_torBlockCountBytes( tor, block );
tr_torrentGetBlockLocation( tor, block, &setme->index,
&setme->offset,
&setme->length );
}
/**
@ -1451,21 +1436,24 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
}
/* a peer can send the same HAVE message twice... */
if( !tr_bitsetHas( &msgs->peer->have, ui32 ) )
if( !tr_bitsetAdd( &msgs->peer->have, ui32 ) )
fireClientGotHave( msgs, ui32 );
if( !tr_bitsetHas( &msgs->peer->have, ui32 ) ) {
tr_bitsetAdd( &msgs->peer->have, ui32 );
fireClientGotHave( msgs, ui32 );
}
updatePeerProgress( msgs );
break;
case BT_BITFIELD: {
tr_bitfield tmp = TR_BITFIELD_INIT;
const size_t bitCount = tr_torrentHasMetadata( msgs->torrent )
? msgs->torrent->info.pieceCount
: msglen * 8;
tr_bitfieldConstruct( &tmp, bitCount );
dbgmsg( msgs, "got a bitfield" );
tr_bitsetReserve( &msgs->peer->have, bitCount );
tr_peerIoReadBytes( msgs->peer->io, inbuf,
msgs->peer->have.bitfield.bits, msglen );
fireClientGotBitfield( msgs, &msgs->peer->have.bitfield );
tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp.bits, msglen );
tr_bitsetSetBitfield( &msgs->peer->have, &tmp );
fireClientGotBitfield( msgs, &tmp );
tr_bitfieldDestruct( &tmp );
updatePeerProgress( msgs );
break;
}
@ -2049,52 +2037,15 @@ static void
sendBitfield( tr_peermsgs * msgs )
{
struct evbuffer * out = msgs->outMessages;
tr_bitfield * field;
tr_piece_index_t lazyPieces[LAZY_PIECE_COUNT];
size_t i;
size_t lazyCount = 0;
tr_bitfield * bf = tr_cpCreatePieceBitfield( &msgs->torrent->completion );
field = tr_bitfieldDup( tr_cpPieceBitfield( &msgs->torrent->completion ) );
if( tr_sessionIsLazyBitfieldEnabled( getSession( msgs ) ) )
{
/** Lazy bitfields aren't a high priority or secure, so I'm opting for
speed over a truly random sample -- let's limit the pool size to
the first 1000 pieces so large torrents don't bog things down */
size_t poolSize;
const size_t maxPoolSize = MIN( msgs->torrent->info.pieceCount, 1000 );
tr_piece_index_t * pool = tr_new( tr_piece_index_t, maxPoolSize );
/* build the pool */
for( i=poolSize=0; i<maxPoolSize; ++i )
if( tr_bitfieldHas( field, i ) )
pool[poolSize++] = i;
/* pull random piece indices from the pool */
while( ( poolSize > 0 ) && ( lazyCount < LAZY_PIECE_COUNT ) )
{
const int pos = tr_cryptoWeakRandInt( poolSize );
const tr_piece_index_t piece = pool[pos];
tr_bitfieldRem( field, piece );
lazyPieces[lazyCount++] = piece;
pool[pos] = pool[--poolSize];
}
/* cleanup */
tr_free( pool );
}
evbuffer_add_uint32( out, sizeof( uint8_t ) + field->byteCount );
evbuffer_add_uint32( out, sizeof( uint8_t ) + bf->byteCount );
evbuffer_add_uint8 ( out, BT_BITFIELD );
evbuffer_add ( out, field->bits, field->byteCount );
dbgmsg( msgs, "sending bitfield... outMessage size is now %zu",
evbuffer_get_length( out ) );
evbuffer_add ( out, bf->bits, bf->byteCount );
dbgmsg( msgs, "sending bitfield... outMessage size is now %zu", evbuffer_get_length( out ) );
pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
for( i = 0; i < lazyCount; ++i )
protocolSendHave( msgs, lazyPieces[i] );
tr_bitfieldFree( field );
tr_bitfieldFree( bf );
}
static void
@ -2102,11 +2053,11 @@ tellPeerWhatWeHave( tr_peermsgs * msgs )
{
const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
if( fext && ( tr_cpGetStatus( &msgs->torrent->completion ) == TR_SEED ) )
if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveAll ) )
{
protocolSendHaveAll( msgs );
}
else if( fext && ( tr_cpHaveValid( &msgs->torrent->completion ) == 0 ) )
else if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveNone ) )
{
protocolSendHaveNone( msgs );
}

View File

@ -16,6 +16,7 @@
#include "transmission.h"
#include "bencode.h"
#include "bitset.h"
#include "completion.h"
#include "metainfo.h" /* tr_metainfoGetBasename() */
#include "peer-mgr.h" /* pex */
@ -65,6 +66,7 @@
#define KEY_PROGRESS_CHECKTIME "time-checked"
#define KEY_PROGRESS_MTIMES "mtimes"
#define KEY_PROGRESS_BITFIELD "bitfield"
#define KEY_PROGRESS_BLOCKS "blocks"
#define KEY_PROGRESS_HAVE "have"
enum
@ -407,12 +409,11 @@ loadIdleLimits( tr_benc * dict,
***/
static void
saveProgress( tr_benc * dict, const tr_torrent * tor )
saveProgress( tr_benc * dict, tr_torrent * tor )
{
tr_benc * l;
tr_benc * prog;
tr_file_index_t fi;
const struct tr_bitfield * bitfield;
const tr_info * inf = tr_torrentInfo( tor );
const time_t now = tr_time( );
@ -467,10 +468,9 @@ saveProgress( tr_benc * dict, const tr_torrent * tor )
if( tor->completeness == TR_SEED )
tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" );
/* add the pieces bitfield */
bitfield = tr_cpBlockBitfield( &tor->completion );
tr_bencDictAddRaw( prog, KEY_PROGRESS_BITFIELD, bitfield->bits,
bitfield->byteCount );
/* add the blocks bitfield */
tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ),
tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) );
}
static uint64_t
@ -491,6 +491,8 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
const uint8_t * raw;
size_t rawlen;
tr_benc * l;
tr_benc * b;
struct tr_bitset bitset = TR_BITSET_INIT;
if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
{
@ -565,24 +567,29 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
}
err = NULL;
if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
{
if( !tr_bitsetFromBenc( &bitset, b ) )
err = "Invalid value for PIECES";
}
else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
{
if( !strcmp( str, "all" ) )
tr_cpSetHaveAll( &tor->completion );
tr_bitsetSetHaveAll( &bitset );
else
err = "Invalid value for HAVE";
}
else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
{
tr_bitfield tmp;
tmp.byteCount = rawlen;
tmp.bitCount = tmp.byteCount * 8;
tmp.bits = (uint8_t*) raw;
if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
err = "Error loading bitfield";
bitset.bitfield.bits = (void*) raw;
bitset.bitfield.byteCount = rawlen;
bitset.bitfield.bitCount = rawlen * 8;
}
else err = "Couldn't find 'have' or 'bitfield'";
else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) )
err = "Error loading bitfield";
if( err != NULL )
tr_tordbg( tor, "Torrent needs to be verified - %s", err );

View File

@ -561,10 +561,11 @@ addField( const tr_torrent * tor, tr_benc * d, const char * key )
else if( tr_streq( key, keylen, "peersSendingToUs" ) )
tr_bencDictAddInt( d, key, st->peersSendingToUs );
else if( tr_streq( key, keylen, "pieces" ) ) {
const tr_bitfield * pieces = tr_cpPieceBitfield( &tor->completion );
char * str = tr_base64_encode( pieces->bits, pieces->byteCount, NULL );
tr_bitfield * bf = tr_cpCreatePieceBitfield( &tor->completion );
char * str = tr_base64_encode( bf->bits, bf->byteCount, NULL );
tr_bencDictAddStr( d, key, str!=NULL ? str : "" );
tr_free( str );
tr_bitfieldFree( bf );
}
else if( tr_streq( key, keylen, "pieceCount" ) )
tr_bencDictAddInt( d, key, inf->pieceCount );

View File

@ -325,7 +325,6 @@ tr_sessionGetDefaultSettings( const char * configDir UNUSED, tr_benc * d )
tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, FALSE );
tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_getDefaultDownloadDir( ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE );
tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD, TRUE );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF );
tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT, atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
@ -390,7 +389,6 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED, tr_sessionIsIdleLimited( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR, tr_sessionGetIncompleteDir( s ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, tr_sessionIsIncompleteDirEnabled( s ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD, s->useLazyBitfield );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL, tr_getMessageLevel( ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT, tr_fdGetFileLimit( s ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, tr_sessionGetPeerLimit( s ) );
@ -758,8 +756,6 @@ sessionSetImpl( void * vdata )
/* misc features */
if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
tr_sessionSetCacheLimit_MB( session, i );
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal ) )
tr_sessionSetLazyBitfieldEnabled( session, boolVal );
if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
tr_sessionSetPeerLimitPerTorrent( session, i );
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal ) )

View File

@ -1308,61 +1308,31 @@ fileBytesCompleted( const tr_torrent * tor, tr_file_index_t index )
if( f->length )
{
const tr_block_index_t firstBlock = f->offset / tor->blockSize;
const uint64_t lastByte = f->offset + f->length - 1;
const tr_block_index_t lastBlock = lastByte / tor->blockSize;
tr_block_index_t first;
tr_block_index_t last;
tr_torGetFileBlockRange( tor, index, &first, &last );
if( firstBlock == lastBlock )
if( first == last )
{
if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
if( tr_cpBlockIsComplete( &tor->completion, first ) )
total = f->length;
}
else
{
tr_block_index_t i;
/* the first block */
if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
if( tr_cpBlockIsComplete( &tor->completion, first ) )
total += tor->blockSize - ( f->offset % tor->blockSize );
/* the middle blocks */
if( f->firstPiece == f->lastPiece )
{
for( i=firstBlock+1; i<lastBlock; ++i )
if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
total += tor->blockSize;
}
else
{
uint64_t b = 0;
const tr_block_index_t firstBlockOfLastPiece
= tr_torPieceFirstBlock( tor, f->lastPiece );
const tr_block_index_t lastBlockOfFirstPiece
= tr_torPieceFirstBlock( tor, f->firstPiece )
+ tr_torPieceCountBlocks( tor, f->firstPiece ) - 1;
/* the rest of the first piece */
for( i=firstBlock+1; i<lastBlock && i<=lastBlockOfFirstPiece; ++i )
if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
++b;
/* the middle pieces */
if( f->firstPiece + 1 < f->lastPiece )
for( i=f->firstPiece+1; i<f->lastPiece; ++i )
b += tor->blockCountInPiece - tr_cpMissingBlocksInPiece( &tor->completion, i );
/* the rest of the last piece */
for( i=firstBlockOfLastPiece; i<lastBlock; ++i )
if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
++b;
b *= tor->blockSize;
total += b;
if( first + 1 < last ) {
uint64_t u = tr_bitsetCountRange( tr_cpBlockBitset( &tor->completion ), first+1, last );
u *= tor->blockSize;
total += u;
}
/* the last block */
if( tr_cpBlockIsCompleteFast( &tor->completion, lastBlock ) )
total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * lastBlock );
if( tr_cpBlockIsComplete( &tor->completion, last ) )
total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * last );
}
}
@ -2282,6 +2252,21 @@ tr_torrentGetPeerLimit( const tr_torrent * tor )
****
***/
void
tr_torrentGetBlockLocation( const tr_torrent * tor,
tr_block_index_t block,
tr_piece_index_t * piece,
uint32_t * offset,
uint32_t * length )
{
uint64_t pos = block;
pos *= tor->blockSize;
*piece = pos / tor->info.pieceSize;
*offset = pos - ( *piece * tor->info.pieceSize );
*length = tr_torBlockCountBytes( tor, block );
}
tr_block_index_t
_tr_block( const tr_torrent * tor,
tr_piece_index_t index,
@ -2344,6 +2329,37 @@ tr_pieceOffset( const tr_torrent * tor,
return ret;
}
void
tr_torGetFileBlockRange( const tr_torrent * tor,
const tr_file_index_t file,
tr_block_index_t * first,
tr_block_index_t * last )
{
const tr_file * f = &tor->info.files[file];
uint64_t offset = f->offset;
*first = offset / tor->blockSize;
if( !f->length )
*last = *first;
else {
offset += f->length - 1;
*last = offset / tor->blockSize;
}
}
void
tr_torGetPieceBlockRange( const tr_torrent * tor,
const tr_piece_index_t piece,
tr_block_index_t * first,
tr_block_index_t * last )
{
uint64_t offset = tor->info.pieceSize;
offset *= piece;
*first = offset / tor->blockSize;
offset += ( tr_torPieceCountBytes( tor, piece ) - 1 );
*last = offset / tor->blockSize;
}
/***
****
***/

View File

@ -82,6 +82,22 @@ uint64_t tr_pieceOffset( const tr_torrent * tor,
uint32_t offset,
uint32_t length );
void tr_torrentGetBlockLocation( const tr_torrent * tor,
tr_block_index_t block,
tr_piece_index_t * piece,
uint32_t * offset,
uint32_t * length );
void tr_torGetFileBlockRange( const tr_torrent * tor,
const tr_file_index_t file,
tr_block_index_t * first,
tr_block_index_t * last );
void tr_torGetPieceBlockRange( const tr_torrent * tor,
const tr_piece_index_t piece,
tr_block_index_t * first,
tr_block_index_t * last );
void tr_torrentInitFilePriority( tr_torrent * tor,
tr_file_index_t fileIndex,
tr_priority_t priority );
@ -255,13 +271,6 @@ tr_torrentNext( tr_session * session, tr_torrent * current )
return current ? current->next : session->torrentList;
}
/* get the index of this piece's first block */
static inline tr_block_index_t
tr_torPieceFirstBlock( const tr_torrent * tor, const tr_piece_index_t piece )
{
return piece * tor->blockCountInPiece;
}
/* what piece index is this block in? */
static inline tr_piece_index_t
tr_torBlockPiece( const tr_torrent * tor, const tr_block_index_t block )
@ -269,14 +278,6 @@ tr_torBlockPiece( const tr_torrent * tor, const tr_block_index_t block )
return block / tor->blockCountInPiece;
}
/* how many blocks are in this piece? */
static inline uint16_t
tr_torPieceCountBlocks( const tr_torrent * tor, const tr_piece_index_t piece )
{
return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
: tor->blockCountInPiece;
}
/* how many bytes are in this piece? */
static inline uint32_t
tr_torPieceCountBytes( const tr_torrent * tor, const tr_piece_index_t piece )

View File

@ -170,7 +170,6 @@ const char* tr_getDefaultDownloadDir( void );
#define TR_PREFS_KEY_IDLE_LIMIT_ENABLED "idle-seeding-limit-enabled"
#define TR_PREFS_KEY_INCOMPLETE_DIR "incomplete-dir"
#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED "incomplete-dir-enabled"
#define TR_PREFS_KEY_LAZY_BITFIELD "lazy-bitfield-enabled"
#define TR_PREFS_KEY_MSGLEVEL "message-level"
#define TR_PREFS_KEY_OPEN_FILE_LIMIT "open-file-limit"
#define TR_PREFS_KEY_PEER_LIMIT_GLOBAL "peer-limit-global"

View File

@ -45,6 +45,44 @@ static int test = 0;
}
#endif
static int
test_bitfield_count_range( void )
{
int i;
int n;
int begin;
int end;
int count1;
int count2;
const int bitCount = 100 + tr_cryptoWeakRandInt( 1000 );
tr_bitfield * bf;
/* generate a random bitfield */
bf = tr_bitfieldNew( bitCount );
for( i=0, n=tr_cryptoWeakRandInt(bitCount); i<n; ++i )
tr_bitfieldAdd( bf, tr_cryptoWeakRandInt(bitCount) );
begin = tr_cryptoWeakRandInt( bitCount );
do {
end = tr_cryptoWeakRandInt( bitCount );
} while( end == begin );
if( end < begin ) {
const int tmp = begin;
begin = end;
end = tmp;
}
count1 = 0;
for( i=begin; i<end; ++i )
if( tr_bitfieldHas( bf, i ) )
++count1;
count2 = tr_bitfieldCountRange( bf, begin, end );
check( count1 == count2 );
tr_bitfieldFree( bf );
return 0;
}
static int
test_bitfields( void )
{
@ -406,6 +444,15 @@ test_truncd( void )
return 0;
}
struct blah
{
uint8_t hash[SHA_DIGEST_LENGTH]; /* pieces hash */
int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
int8_t dnd; /* "do not download" flag */
time_t timeChecked; /* the last time we tested this piece */
};
int
main( void )
{
@ -414,6 +461,12 @@ main( void )
int i;
int l;
fprintf( stderr, "sizeof time_t %zu\n", sizeof(time_t));
fprintf( stderr, "sizeof char[20] %zu\n", (size_t)20);
fprintf( stderr, "sizeof uint8_t %zu\n", sizeof(uint8_t));
fprintf( stderr, "sizeof blah %zu\n", sizeof(struct blah));
return 0;
/* base64 */
out = tr_base64_encode( "YOYO!", -1, &len );
check( out );
@ -465,6 +518,11 @@ main( void )
if( ( i = test_bitfields( ) ) )
return i;
/* bitfield count range */
for( l=0; l<1000000; ++l )
if(( i = test_bitfield_count_range( )))
return i;
return 0;
}

View File

@ -64,7 +64,7 @@ enum
static void
webseed_free( struct tr_webseed * w )
{
tr_bitsetDestructor( &w->parent.have );
tr_bitsetDestruct( &w->parent.have );
tr_free( w->parent.client );
event_free( w->timer );
@ -89,9 +89,7 @@ fire_client_got_rej( tr_torrent * tor, tr_webseed * w, tr_block_index_t block )
{
tr_peer_event e = TR_PEER_EVENT_INIT;
e.eventType = TR_PEER_CLIENT_GOT_REJ;
e.pieceIndex = tr_torBlockPiece( tor, block );
e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
e.length = tr_torBlockCountBytes( tor, block );
tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
publish( w, &e );
}
@ -100,9 +98,7 @@ fire_client_got_block( tr_torrent * tor, tr_webseed * w, tr_block_index_t block
{
tr_peer_event e = TR_PEER_EVENT_INIT;
e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
e.pieceIndex = tr_torBlockPiece( tor, block );
e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
e.length = tr_torBlockCountBytes( tor, block );
tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
publish( w, &e );
}
@ -334,10 +330,10 @@ tr_webseedNew( struct tr_torrent * tor,
peer->peerIsChoked = TRUE;
peer->clientIsInterested = !tr_torrentIsSeed( tor );
tr_bitsetConstructor( &peer->have, tor->info.pieceCount );
tr_bitsetSetHaveAll( &peer->have );
peer->progress = 1.0;
peer->client = tr_strdup( "webseed" );
peer->have = TR_BITSET_INIT;
tr_bitsetSetHaveAll( &peer->have );
w->torrent_id = tr_torrentId( tor );
w->session = tor->session;