(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:
parent
6754258823
commit
2b9db3c242
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 ) ) )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ) )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue