Changeset 12012


Ignore:
Timestamp:
Feb 23, 2011, 3:54:04 AM (11 years ago)
Author:
jordan
Message:

(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.

Location:
trunk/libtransmission
Files:
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/bencode.c

    r11838 r12012  
    477477
    478478tr_bool
     479tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len )
     480{
     481    const tr_bool success = tr_bencIsString( val );
     482
     483    if( success ) {
     484        *setme_raw = (uint8_t*) getStr(val);
     485        *setme_len = val->val.s.len;
     486    }
     487
     488    return success;
     489}
     490
     491tr_bool
    479492tr_bencGetBool( const tr_benc * val, tr_bool * setme )
    480493{
     
    564577
    565578tr_bool
    566 tr_bencDictFindRaw( tr_benc         * dict,
    567                     const char      * key,
    568                     const uint8_t  ** setme_raw,
    569                     size_t          * setme_len )
    570 {
    571     tr_benc * child;
    572     const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
    573 
    574     if( found ) {
    575         *setme_raw = (uint8_t*) getStr(child);
    576         *setme_len = child->val.s.len;
    577     }
    578 
    579     return found;
     579tr_bencDictFindRaw( tr_benc * dict, const char * key, const uint8_t  ** setme_raw, size_t * setme_len )
     580{
     581    return tr_bencGetRaw( tr_bencDictFind( dict, key ), setme_raw, setme_len );
    580582}
    581583
     
    17051707        else
    17061708        {
    1707             tr_fsync( fd );
     1709            //tr_fsync( fd );
    17081710            tr_close_file( fd );
    17091711
  • trunk/libtransmission/bencode.h

    r11709 r12012  
    215215tr_bool   tr_bencGetStr( const tr_benc * val, const char ** setme );
    216216
     217/** @brief Get a raw byte array from a variant object
     218    @return TRUE if successful, or FALSE if the variant could not be represented as a raw byte array */
     219tr_bool   tr_bencGetRaw( const tr_benc * val, const uint8_t  ** setme_raw, size_t * setme_len );
     220
    217221/** @brief Get a boolean from a variant object
    218222    @return TRUE if successful, or FALSE if the variant could not be represented as a boolean  */
  • trunk/libtransmission/bitfield.c

    r12007 r12012  
    1717#include "bitfield.h"
    1818#include "bitset.h"
     19#include "utils.h" /* tr_new0() */
     20
     21const tr_bitfield TR_BITFIELD_INIT = { NULL, 0, 0 };
    1922
    2023tr_bitfield*
     
    3639
    3740tr_bitfield*
    38 tr_bitfieldDup( const tr_bitfield * in )
    39 {
    40     tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
    41 
    42     ret->bitCount = in->bitCount;
    43     ret->byteCount = in->byteCount;
    44     ret->bits = tr_memdup( in->bits, in->byteCount );
    45     return ret;
     41tr_bitfieldNew( size_t bitCount )
     42{
     43    return tr_bitfieldConstruct( tr_new( tr_bitfield, 1 ), bitCount );
     44}
     45
     46void
     47tr_bitfieldFree( tr_bitfield * b )
     48{
     49    tr_free( tr_bitfieldDestruct( b ) );
    4650}
    4751
     
    162166}
    163167
     168static const int trueBitCount[256] =
     169{
     170    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
     171    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     172    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     173    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     174    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     175    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     176    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     177    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     178    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
     179    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     180    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     181    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     182    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
     183    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     184    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
     185    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
     186};
     187
    164188size_t
    165189tr_bitfieldCountTrueBits( const tr_bitfield* b )
     
    167191    size_t           ret = 0;
    168192    const uint8_t *  it, *end;
    169     static const int trueBitCount[256] = {
    170         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,
    171         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,
    172         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,
    173         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,
    174         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,
    175         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,
    176         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,
    177         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
    178     };
    179193
    180194    if( !b )
     
    186200    return ret;
    187201}
     202
     203size_t
     204tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end )
     205{
     206    size_t ret = 0;
     207    const int first_byte = begin >> 3u;
     208    const int last_byte = ( end - 1 ) >> 3u;
     209
     210    assert( begin < end );
     211
     212    if( first_byte == last_byte )
     213    {
     214        int i;
     215        uint8_t val = b->bits[first_byte];
     216
     217        i = begin - (first_byte * 8);
     218        val <<= i;
     219        val >>= i;
     220        i = (last_byte+1)*8 - end;
     221        val >>= i;
     222        val <<= i;
     223
     224        ret += trueBitCount[val];
     225    }
     226    else
     227    {
     228        int i;
     229        uint8_t val;
     230
     231        /* first byte */
     232        i = begin - (first_byte * 8);
     233        val = b->bits[first_byte];
     234        val <<= i;
     235        val >>= i;
     236        ret += trueBitCount[val];
     237
     238        /* middle bytes */
     239        for( i=first_byte+1; i<last_byte; ++i )
     240            ret += trueBitCount[b->bits[i]];
     241
     242        /* last byte */
     243        i = (last_byte+1)*8 - end;
     244        val = b->bits[last_byte];
     245        val >>= i;
     246        val <<= i;
     247        ret += trueBitCount[val];
     248    }
     249
     250    assert( ret <= ( begin - end ) );
     251    return ret;
     252}
  • trunk/libtransmission/bitfield.h

    r12007 r12012  
    1919
    2020#include "transmission.h"
    21 #include "utils.h" /* tr_new0 */
    2221
    2322/** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
     
    3029tr_bitfield;
    3130
    32 tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitcount );
     31extern const tr_bitfield TR_BITFIELD_INIT;
     32
     33tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitCount );
    3334
    3435tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
    3536
    36 static inline tr_bitfield* tr_bitfieldNew( size_t bitcount )
    37 {
    38     return tr_bitfieldConstruct( tr_new0( tr_bitfield, 1 ), bitcount );
    39 }
     37tr_bitfield* tr_bitfieldNew( size_t bitCount );
    4038
    41 static inline void tr_bitfieldFree( tr_bitfield * b )
    42 {
    43     tr_free( tr_bitfieldDestruct( b ) );
    44 }
    45 
    46 tr_bitfield* tr_bitfieldDup( const tr_bitfield* ) TR_GNUC_MALLOC;
     39void tr_bitfieldFree( tr_bitfield * b );
    4740
    4841void         tr_bitfieldClear( tr_bitfield* );
     
    5750
    5851size_t       tr_bitfieldCountTrueBits( const tr_bitfield* );
     52
     53size_t       tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end );
     54
    5955
    6056tr_bitfield* tr_bitfieldOr( tr_bitfield*, const tr_bitfield* );
  • trunk/libtransmission/bitset.c

    r12006 r12012  
    1212
    1313#include "transmission.h"
     14#include "bencode.h"
    1415#include "bitset.h"
    15 
    16 void
    17 tr_bitsetConstructor( tr_bitset * b, size_t size )
    18 {
    19     tr_bitfieldConstruct( &b->bitfield, size );
    20 }
    21 
    22 void
    23 tr_bitsetDestructor( tr_bitset * b )
    24 {
    25     tr_bitfieldDestruct( &b->bitfield );
    26 }
    27 
    28 void
    29 tr_bitsetReserve( tr_bitset * b, size_t size )
    30 {
    31     if( b->bitfield.bitCount < size )
    32     {
    33         tr_bitfield * tmp = tr_bitfieldDup( &b->bitfield );
    34 
    35         tr_bitfieldDestruct( &b->bitfield );
    36         tr_bitfieldConstruct( &b->bitfield, size );
    37 
    38         if( ( tmp->bits != NULL ) && ( tmp->byteCount > 0 ) )
    39             memcpy( b->bitfield.bits, tmp->bits, tmp->byteCount );
    40 
    41         tr_bitfieldFree( tmp );
    42     }
    43 }
     16#include "utils.h"
     17
     18const tr_bitset TR_BITSET_INIT = { FALSE, FALSE, { NULL, 0, 0 } };
     19
     20void
     21tr_bitsetConstruct( tr_bitset * b, size_t bitCount )
     22{
     23    *b = TR_BITSET_INIT;
     24    b->bitfield.bitCount = bitCount;
     25}
     26
     27void
     28tr_bitsetDestruct( tr_bitset * b )
     29{
     30    tr_free( b->bitfield.bits );
     31    *b = TR_BITSET_INIT;
     32}
     33
     34static void
     35tr_bitsetClear( tr_bitset * b )
     36{
     37    tr_free( b->bitfield.bits );
     38    b->bitfield.bits = NULL;
     39    b->haveAll = FALSE;
     40    b->haveNone = FALSE;
     41}
     42
     43void
     44tr_bitsetSetHaveAll( tr_bitset * b )
     45{
     46    tr_bitsetClear( b );
     47    b->haveAll = TRUE;
     48}
     49
     50void
     51tr_bitsetSetHaveNone( tr_bitset * b )
     52{
     53    tr_bitsetClear( b );
     54    b->haveNone = TRUE;
     55}
     56
     57void
     58tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield )
     59{
     60    const size_t n = tr_bitfieldCountTrueBits( bitfield );
     61
     62    if( n == 0 )
     63    {
     64        tr_bitsetSetHaveNone( b );
     65    }
     66    else if( n == bitfield->bitCount )
     67    {
     68        tr_bitsetSetHaveAll( b );
     69    }
     70    else
     71    {
     72        tr_bitsetDestruct( b );
     73        b->bitfield.bits = tr_memdup( bitfield->bits, bitfield->byteCount );
     74        b->bitfield.bitCount = bitfield->bitCount;
     75        b->bitfield.byteCount = bitfield->byteCount;
     76    }
     77}
     78
     79/***
     80****
     81***/
     82
     83void
     84tr_bitsetAdd( tr_bitset * b, size_t i )
     85{
     86    tr_bitfield * bf = &b->bitfield;
     87
     88    if( b->haveAll )
     89        return;
     90
     91    b->haveNone = FALSE;
     92
     93    /* do we need to resize the bitfield to accomodate this bit? */
     94    if( !bf->bits || ( bf->bitCount < i+1 ) )
     95    {
     96        const size_t oldByteCount = bf->byteCount;
     97        if( bf->bitCount < i + 1 )
     98            bf->bitCount = i + 1;
     99        bf->byteCount = ( bf->bitCount + 7u ) / 8u;
     100        bf->bits = tr_renew( uint8_t, bf->bits, bf->byteCount );
     101        if( bf->byteCount > oldByteCount )
     102            memset( bf->bits + oldByteCount, 0, bf->byteCount - oldByteCount );
     103    }
     104
     105    tr_bitfieldAdd( bf, i );
     106}
     107
     108void
     109tr_bitsetRem( tr_bitset * b, size_t i )
     110{
     111    if( b->haveNone )
     112        return;
     113
     114    b->haveAll = FALSE;
     115
     116    if( !b->bitfield.bits )
     117    {
     118        tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
     119        tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
     120    }
     121
     122    tr_bitfieldRem( &b->bitfield, i );
     123}
     124
     125void
     126tr_bitsetRemRange( tr_bitset * b, size_t begin, size_t end )
     127{
     128    if( b->haveNone )
     129        return;
     130
     131    b->haveAll = FALSE;
     132    if( !b->bitfield.bits )
     133    {
     134        tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
     135        tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
     136    }
     137
     138    tr_bitfieldRemRange( &b->bitfield, begin, end );
     139}
     140
     141/***
     142****
     143***/
    44144
    45145tr_bool
     
    52152}
    53153
     154size_t
     155tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end )
     156{
     157    if( b->haveAll ) return end - begin;
     158    if( b->haveNone ) return 0;
     159    return tr_bitfieldCountRange( &b->bitfield, begin, end );
     160}
     161
     162double
     163tr_bitsetPercent( const tr_bitset * b )
     164{
     165    if( b->haveAll ) return 1.0;
     166    if( b->haveNone ) return 0.0;
     167    if( b->bitfield.bitCount == 0 ) return 0.0;
     168    return tr_bitfieldCountTrueBits( &b->bitfield ) / (double)b->bitfield.bitCount;
     169}
     170
    54171void
    55172tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
     
    61178}
    62179
    63 double
    64 tr_bitsetPercent( const tr_bitset * b )
    65 {
    66     if( b->haveAll ) return 1.0;
    67     if( b->haveNone ) return 0.0;
    68     if( b->bitfield.bitCount == 0 ) return 0.0;
    69     return tr_bitfieldCountTrueBits( &b->bitfield ) / (double)b->bitfield.bitCount;
    70 }
    71 
    72 void
    73 tr_bitsetSetHaveAll( tr_bitset * b )
    74 {
    75     b->haveAll = 1;
    76     b->haveNone = 0;
    77 }
    78 
    79 void
    80 tr_bitsetSetHaveNone( tr_bitset * b )
    81 {
    82     b->haveAll = 0;
    83     b->haveNone = 1;
    84 }
    85 
    86 int
    87 tr_bitsetAdd( tr_bitset * b, size_t i )
    88 {
    89     int ret = 0;
    90     if( !b->haveAll ) {
    91         b->haveNone = 0;
    92         tr_bitsetReserve( b, i+1 );
    93         ret = tr_bitfieldAdd( &b->bitfield, i );
    94     }
    95     return ret;
    96 }
     180/***
     181****
     182***/
     183
     184tr_bool
     185tr_bitsetFromBenc( tr_bitset * bitset, tr_benc * benc )
     186{
     187    size_t buflen;
     188    const uint8_t * buf;
     189    tr_bool handled = FALSE;
     190
     191    if( tr_bencGetRaw( benc, &buf, &buflen ) )
     192    {
     193        if( ( buflen == 3 ) && !memcmp( buf, "all", 3 ) )
     194        {
     195            tr_bitsetSetHaveAll( bitset );
     196            handled = TRUE;
     197        }
     198        else if( ( buflen == 4 ) && !memcmp( buf, "none", 4 ) )
     199        {
     200            tr_bitsetSetHaveNone( bitset );
     201            handled = TRUE;
     202        }
     203        else
     204        {
     205            bitset->haveAll = FALSE;
     206            bitset->haveNone = FALSE;
     207            tr_free( bitset->bitfield.bits );
     208            bitset->bitfield.bits = tr_memdup( buf, buflen );
     209            bitset->bitfield.byteCount = buflen;
     210            bitset->bitfield.bitCount = buflen * 8;
     211            handled = TRUE;
     212        }
     213    }
     214
     215    return handled;
     216}
     217
     218void
     219tr_bitsetToBenc( const tr_bitset * bitset, tr_benc * benc )
     220{
     221    if( bitset->haveAll )
     222    {
     223        tr_bencInitStr( benc, "all", 3 );
     224    }
     225    else if( bitset->haveNone )
     226    {
     227        tr_bencInitStr( benc, "none", 4 );
     228    }
     229    else
     230    {
     231        const tr_bitfield * bf = &bitset->bitfield;
     232        const size_t n = tr_bitfieldCountTrueBits( bf );
     233
     234        if( n == bf->bitCount )
     235        {
     236            tr_bencInitStr( benc, "all", 3 );
     237        }
     238        else if( n == 0 )
     239        {
     240            tr_bencInitStr( benc, "none", 4 );
     241        }
     242        else
     243        {
     244            tr_bencInitRaw( benc, bf->bits, bf->byteCount );
     245        }
     246    }
     247}
  • trunk/libtransmission/bitset.h

    r12006 r12012  
    3030tr_bitset;
    3131
    32 void tr_bitsetReserve( tr_bitset * b, size_t size );
    33 void tr_bitsetConstructor( tr_bitset * b, size_t size );
    34 void tr_bitsetDestructor( tr_bitset * b );
     32extern const tr_bitset TR_BITSET_INIT;
     33
     34void tr_bitsetConstruct( tr_bitset * b, size_t bitCount );
     35void tr_bitsetDestruct( tr_bitset * b );
    3536
    3637void tr_bitsetSetHaveAll( tr_bitset * b );
    3738void tr_bitsetSetHaveNone( tr_bitset * b );
    3839
    39 int  tr_bitsetAdd( tr_bitset * b, size_t i );
     40void tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield );
     41
     42void tr_bitsetAdd( tr_bitset * b, size_t i );
     43void tr_bitsetRem( tr_bitset * b, size_t i );
     44void tr_bitsetRemRange ( tr_bitset * b, size_t begin, size_t end );
     45
     46struct tr_benc;
     47tr_bool tr_bitsetFromBenc( tr_bitset * bitset, struct tr_benc * benc );
     48void tr_bitsetToBenc( const tr_bitset * bitset, struct tr_benc * benc );
    4049
    4150/***
     
    4655
    4756tr_bool tr_bitsetHas( const tr_bitset * b, const size_t nth );
     57size_t tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end );
    4858
    4959void tr_bitsetOr( tr_bitfield * a, const tr_bitset * b );
  • trunk/libtransmission/cache.c

    r11782 r12012  
    390390
    391391static int
    392 findPiece( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece )
     392findBlockPos( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t block )
    393393{
    394394    struct cache_block key;
    395395    key.tor = torrent;
    396     key.block = tr_torPieceFirstBlock( torrent, piece );
     396    key.block = block;
    397397    return tr_ptrArrayLowerBound( &cache->blocks, &key, cache_block_compare, NULL );
    398398}
     
    420420tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
    421421{
    422     int err = 0;
    423     const tr_file * file = &torrent->info.files[i];
    424     const tr_block_index_t begin = tr_torPieceFirstBlock( torrent, file->firstPiece );
    425     const tr_block_index_t end  = tr_torPieceFirstBlock( torrent, file->lastPiece ) + tr_torPieceCountBlocks( torrent, file->lastPiece );
    426     const int pos = findPiece( cache, torrent, file->firstPiece );
    427     dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu)", (int)i, (size_t)begin, (size_t)end );
     422    int pos;
     423    int err = 0;
     424    tr_block_index_t first;
     425    tr_block_index_t last;
     426    tr_torGetFileBlockRange( torrent, i, &first, &last );
     427    pos = findBlockPos( cache, torrent, first );
     428    dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu]", (int)i, (size_t)first, (size_t)last );
    428429
    429430    /* flush out all the blocks in that file */
     
    432433        const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
    433434        if( b->tor != torrent ) break;
    434         if( ( b->block < begin ) || ( b->block >= end ) ) break;
     435        if( ( b->block < first ) || ( b->block > last ) ) break;
    435436        err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
    436437    }
     
    443444{
    444445    int err = 0;
    445     const int pos = findPiece( cache, torrent, 0 );
     446    const int pos = findBlockPos( cache, torrent, 0 );
    446447
    447448    /* flush out all the blocks in that torrent */
  • trunk/libtransmission/completion.c

    r11892 r12012  
    1111 */
    1212
    13 #include <assert.h>
    14 #include <string.h>
    15 
    1613#include "transmission.h"
    1714#include "completion.h"
    1815#include "torrent.h"
    19 #include "torrent-magnet.h"
    2016#include "utils.h"
     17
     18/***
     19****
     20***/
    2121
    2222static void
    2323tr_cpReset( tr_completion * cp )
    2424{
    25     tr_bitfieldClear( &cp->pieceBitfield );
    26     tr_bitfieldClear( &cp->blockBitfield );
    27     memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
     25    tr_bitsetSetHaveNone( &cp->blockBitset );
     26    tr_free( cp->completeBlocks );
     27    cp->completeBlocks = NULL;
    2828    cp->sizeNow = 0;
    29     cp->sizeWhenDoneIsDirty = 1;
    30     cp->blocksWantedIsDirty = 1;
    31     cp->haveValidIsDirty = 1;
     29    cp->sizeWhenDoneIsDirty = TRUE;
     30    cp->blocksWantedIsDirty = TRUE;
     31    cp->haveValidIsDirty = TRUE;
    3232}
    3333
     
    3636{
    3737    cp->tor = tor;
    38     cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
    39     tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
    40     tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
     38    cp->completeBlocks = NULL;
     39    tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
    4140    tr_cpReset( cp );
    4241    return cp;
     
    4746{
    4847    tr_free( cp->completeBlocks );
    49     tr_bitfieldDestruct( &cp->pieceBitfield );
    50     tr_bitfieldDestruct( &cp->blockBitfield );
     48    tr_bitsetDestruct( &cp->blockBitset );
    5149    return cp;
    5250}
    5351
     52/***
     53****
     54***/
     55
     56static inline tr_bool
     57isSeed( const tr_completion * cp )
     58{
     59    return cp->blockBitset.haveAll;
     60}
     61
     62tr_completeness
     63tr_cpGetStatus( const tr_completion * cp )
     64{
     65    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
     66    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
     67    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
     68    return TR_LEECH;
     69}
     70
     71/* how many blocks are in this piece? */
     72static inline uint16_t
     73countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
     74{
     75    return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
     76                                             : tor->blockCountInPiece;
     77}
     78
     79static uint16_t *
     80getCompleteBlocks( const tr_completion * ccp )
     81{
     82    if( ccp->completeBlocks == NULL )
     83    {
     84        tr_completion * cp = (tr_completion*) ccp;
     85        cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
     86    }
     87
     88    return ccp->completeBlocks;
     89}
     90
    5491void
    5592tr_cpInvalidateDND( tr_completion * cp )
    5693{
    57     cp->sizeWhenDoneIsDirty = 1;
    58     cp->blocksWantedIsDirty = 1;
     94    cp->sizeWhenDoneIsDirty = TRUE;
     95    cp->blocksWantedIsDirty = TRUE;
    5996}
    6097
     
    6299tr_cpBlocksMissing( const tr_completion * ccp )
    63100{
     101    if( isSeed( ccp ) )
     102        return 0;
     103
    64104    if( ccp->blocksWantedIsDirty )
    65105    {
    66         tr_completion *    cp = (tr_completion *) ccp; /* mutable */
    67         const tr_torrent * tor = cp->tor;
    68         const tr_info *    info = &tor->info;
    69106        tr_piece_index_t   i;
    70107        tr_block_index_t   wanted = 0;
    71108        tr_block_index_t   complete = 0;
    72 
    73         for( i = 0; i < info->pieceCount; ++i )
    74         {
    75             if( info->pieces[i].dnd )
    76                 continue;
    77 
    78             wanted += tr_torPieceCountBlocks( tor, i );
    79             complete += cp->completeBlocks[i];
    80         }
    81 
    82         cp->blocksWantedLazy = wanted;
    83         cp->blocksWantedCompleteLazy = complete;
    84         cp->blocksWantedIsDirty = FALSE;
    85     }
    86 
    87     return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
    88 }
    89 
    90 uint64_t
    91 tr_cpSizeWhenDone( const tr_completion * ccp )
    92 {
    93     if( ccp->sizeWhenDoneIsDirty )
    94     {
    95         tr_completion *    cp = (tr_completion *) ccp; /* mutable */
    96         const tr_torrent * tor = cp->tor;
    97         const tr_info *    info = &tor->info;
    98         tr_piece_index_t   i;
    99         uint64_t           size = 0;
     109        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
     110        const uint16_t   * complete_blocks = getCompleteBlocks( cp );
     111        const tr_torrent * tor = ccp->tor;
     112        const tr_info    * info = &tor->info;
    100113
    101114        for( i = 0; i < info->pieceCount; ++i )
     
    103116            if( !info->pieces[i].dnd )
    104117            {
    105                 /* we want the piece... */
    106                 size += tr_torPieceCountBytes( tor, i );
    107             }
    108             else if( tr_cpPieceIsComplete( cp, i ) )
    109             {
    110                 /* we have the piece... */
    111                 size += tr_torPieceCountBytes( tor, i );
    112             }
    113             else if( cp->completeBlocks[i] )
    114             {
    115                 /* we have part of the piece... */
    116                 const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
    117                 const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
    118                 tr_block_index_t j;
    119                 for( j = b; j < e; ++j )
    120                     if( tr_cpBlockIsCompleteFast( cp, j ) )
    121                         size += tr_torBlockCountBytes( tor, j );
     118                wanted += countBlocksInPiece( tor, i );
     119                complete += complete_blocks[i];
    122120            }
    123121        }
    124122
    125         cp->sizeWhenDoneLazy = size;
    126         cp->sizeWhenDoneIsDirty = 0;
    127     }
    128 
    129     assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
    130     assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
    131     return ccp->sizeWhenDoneLazy;
    132 }
    133 
    134 void
    135 tr_cpPieceAdd( tr_completion *  cp,
    136                tr_piece_index_t piece )
    137 {
    138     const tr_torrent *     tor = cp->tor;
    139     const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
    140     const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
    141     tr_block_index_t       i;
    142 
    143     for( i = start; i < end; ++i )
     123        cp->blocksWantedLazy = wanted;
     124        cp->blocksWantedCompleteLazy = complete;
     125        cp->blocksWantedIsDirty = FALSE;
     126    }
     127
     128    return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
     129}
     130
     131void
     132tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
     133{
     134    tr_block_index_t i;
     135    tr_block_index_t first;
     136    tr_block_index_t last;
     137    const tr_torrent * tor = cp->tor;
     138    uint16_t * complete_blocks = getCompleteBlocks( cp );
     139
     140    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
     141    for( i=first; i<=last; ++i )
     142        if( tr_cpBlockIsComplete( cp, i ) )
     143            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
     144
     145    if( !tor->info.pieces[piece].dnd )
     146        cp->blocksWantedCompleteLazy -= complete_blocks[piece];
     147
     148    cp->sizeWhenDoneIsDirty = TRUE;
     149    cp->haveValidIsDirty = TRUE;
     150    complete_blocks[piece] = 0;
     151    tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
     152}
     153
     154void
     155tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
     156{
     157    tr_block_index_t i;
     158    tr_block_index_t first;
     159    tr_block_index_t last;
     160    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
     161
     162    for( i=first; i<=last; ++i )
    144163        tr_cpBlockAdd( cp, i );
    145164}
    146165
    147166void
    148 tr_cpPieceRem( tr_completion *  cp,
    149                tr_piece_index_t piece )
    150 {
    151     const tr_torrent *     tor = cp->tor;
    152     const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
    153     const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
    154     tr_block_index_t       block;
    155 
    156     assert( cp );
    157     assert( piece < tor->info.pieceCount );
    158     assert( start < tor->blockCount );
    159     assert( start <= end );
    160     assert( end <= tor->blockCount );
    161 
    162     for( block = start; block < end; ++block )
    163         if( tr_cpBlockIsCompleteFast( cp, block ) )
    164             cp->sizeNow -= tr_torBlockCountBytes( tor, block );
    165 
    166     if( !tor->info.pieces[piece].dnd )
    167         cp->blocksWantedCompleteLazy -= cp->completeBlocks[piece];
    168 
    169     cp->sizeWhenDoneIsDirty = 1;
    170     cp->haveValidIsDirty = 1;
    171     cp->completeBlocks[piece] = 0;
    172     tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
    173     tr_bitfieldRem( &cp->pieceBitfield, piece );
    174 }
    175 
    176 void
    177167tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
    178168{
     
    182172    {
    183173        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
    184         const int              blockSize = tr_torBlockCountBytes( tor,
    185                                                                   block );
    186 
    187         ++cp->completeBlocks[piece];
    188 
    189         if( tr_cpPieceIsComplete( cp, piece ) )
    190             tr_bitfieldAdd( &cp->pieceBitfield, piece );
    191 
    192         tr_bitfieldAdd( &cp->blockBitfield, block );
     174        const int blockSize = tr_torBlockCountBytes( tor, block );
     175
     176        getCompleteBlocks(cp)[piece]++;
     177
     178        tr_bitsetAdd( &cp->blockBitset, block );
    193179
    194180        cp->sizeNow += blockSize;
     
    196182            cp->blocksWantedCompleteLazy++;
    197183
    198         cp->haveValidIsDirty = 1;
    199         cp->sizeWhenDoneIsDirty = 1;
    200     }
    201 }
    202 
    203 
    204 void
    205 tr_cpSetHaveAll( tr_completion * cp )
    206 {
    207     tr_piece_index_t i;
     184        cp->sizeWhenDoneIsDirty = TRUE;
     185        cp->haveValidIsDirty = TRUE;
     186    }
     187}
     188
     189
     190tr_bool
     191tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
     192{
     193    tr_bool success = FALSE;
    208194    tr_torrent * tor = cp->tor;
    209195
     196    /* start cp with a state where it thinks we have nothing */
    210197    tr_cpReset( cp );
    211198
    212     cp->sizeNow = tor->info.totalSize;
    213     tr_bitfieldAddRange( &cp->blockBitfield, 0, tor->blockCount );
    214     tr_bitfieldAddRange( &cp->pieceBitfield, 0, tor->info.pieceCount );
    215     for( i=0; i<tor->info.pieceCount; ++i )
    216         cp->completeBlocks[i] = tr_torPieceCountBlocks( tor, i );
    217     cp->sizeWhenDoneIsDirty = 1;
    218     cp->blocksWantedIsDirty = 1;
    219     cp->haveValidIsDirty = 1;
    220 }
    221 
    222 /* Initialize a completion object from a bitfield indicating which blocks we have */
    223 tr_bool
    224 tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
    225 {
    226     tr_bool success = FALSE;
    227 
    228     assert( cp );
    229     assert( blockBitfield );
    230 
    231     /* The bitfield of block flags is typically loaded from a resume file.
    232        Test the bitfield's length in case the resume file somehow got corrupted */
    233     if(( success = blockBitfield->byteCount == cp->blockBitfield.byteCount ))
    234     {
    235         tr_block_index_t b = 0;
    236         tr_piece_index_t p = 0;
    237         uint32_t pieceBlock = 0;
    238         uint16_t completeBlocksInPiece = 0;
    239         tr_block_index_t completeBlocksInTorrent = 0;
    240         uint32_t blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
    241 
    242         /* start cp with a state where it thinks we have nothing */
    243         tr_cpReset( cp );
    244 
    245         /* init our block bitfield from the one passed in */
    246         memcpy( cp->blockBitfield.bits, blockBitfield->bits, blockBitfield->byteCount );
    247 
    248         /* invalidate the fields that are lazy-evaluated */
    249         cp->sizeWhenDoneIsDirty = TRUE;
    250         cp->blocksWantedIsDirty = TRUE;
    251         cp->haveValidIsDirty = TRUE;
    252 
    253         /* to set the remaining fields, we walk through every block... */
    254         while( b < cp->tor->blockCount )
     199    if( blocks->haveAll )
     200    {
     201        tr_bitsetSetHaveAll( &cp->blockBitset );
     202        cp->sizeNow = tor->info.totalSize;
     203
     204        success = TRUE;
     205    }
     206    else if( blocks->haveNone )
     207    {
     208        /* already reset... */
     209        success = TRUE;
     210    }
     211    else
     212    {
     213        const tr_bitfield * src = &blocks->bitfield;
     214        tr_bitfield * tgt = &cp->blockBitset.bitfield;
     215
     216        tr_bitfieldConstruct( tgt, tor->blockCount );
     217
     218        /* The bitfield of block flags is typically loaded from a resume file.
     219           Test the bitfield's length in case the resume file is corrupt */
     220        if(( success = src->byteCount == tgt->byteCount ))
    255221        {
    256             if( tr_bitfieldHasFast( blockBitfield, b ) )
    257                 ++completeBlocksInPiece;
    258 
    259             ++b;
    260             ++pieceBlock;
    261 
    262             /* by the time we reach the end of a piece, we have enough info
    263                to update that piece's slot in cp.completeBlocks and cp.pieceBitfield */
    264             if( pieceBlock == blocksInCurrentPiece )
    265             {
    266                 cp->completeBlocks[p] = completeBlocksInPiece;
    267                 completeBlocksInTorrent += completeBlocksInPiece;
    268                 if( completeBlocksInPiece == blocksInCurrentPiece )
    269                     tr_bitfieldAdd( &cp->pieceBitfield, p );
    270 
    271                 /* reset the per-piece counters because we're starting on a new piece now */
    272                 ++p;
    273                 completeBlocksInPiece = 0;
    274                 pieceBlock = 0;
    275                 blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
     222            size_t i = 0;
     223            uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
     224
     225            /* init our block bitfield from the one passed in */
     226            memcpy( tgt->bits, src->bits, src->byteCount );
     227
     228            /* update cp.sizeNow and the cp.blockBitset flags */
     229            i = tr_bitfieldCountTrueBits( tgt );
     230            if( i == tor->blockCount ) {
     231                tr_bitsetSetHaveAll( &cp->blockBitset );
     232                cp->sizeNow = cp->tor->info.totalSize;
     233            } else if( !i ) {
     234                tr_bitsetSetHaveNone( &cp->blockBitset );
     235                cp->sizeNow = 0;
     236            } else {
     237                cp->blockBitset.haveAll = cp->blockBitset.haveNone = FALSE;
     238                cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
     239                cp->sizeNow *= tor->blockSize;
     240                if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
     241                    cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
    276242            }
    277         }
    278 
    279         /* update sizeNow */
    280         cp->sizeNow = completeBlocksInTorrent;
    281         cp->sizeNow *= tr_torBlockCountBytes( cp->tor, 0 );
    282         if( tr_bitfieldHasFast( &cp->blockBitfield, cp->tor->blockCount-1 ) ) {
    283             /* the last block is usually smaller than the other blocks,
    284                so handle that special case or cp->sizeNow might be too large */
    285             cp->sizeNow -= tr_torBlockCountBytes( cp->tor, 0 );
    286             cp->sizeNow += tr_torBlockCountBytes( cp->tor, cp->tor->blockCount-1 );
     243
     244            /* update complete_blocks_in_piece */
     245            for( i=0; i<tor->info.pieceCount; ++i ) {
     246                 tr_block_index_t first, last;
     247                 tr_torGetPieceBlockRange( tor, i, &first, &last );
     248                 complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
     249            }
    287250        }
    288251    }
     
    295258***/
    296259
    297 tr_completeness
    298 tr_cpGetStatus( const tr_completion * cp )
    299 {
    300     if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
    301     if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
    302     if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
    303     return TR_LEECH;
    304 }
    305 
    306 static uint64_t
    307 calculateHaveValid( const tr_completion * ccp )
    308 {
    309     uint64_t                  b = 0;
    310     tr_piece_index_t          i;
    311     const tr_torrent        * tor            = ccp->tor;
    312     const uint64_t            pieceSize      = tor->info.pieceSize;
    313     const uint64_t            lastPieceSize  = tor->lastPieceSize;
    314     const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
    315 
    316     if( !tr_torrentHasMetadata( tor ) )
    317         return 0;
    318 
    319     for( i=0; i!=lastPiece; ++i )
    320         if( tr_cpPieceIsComplete( ccp, i ) )
    321             b += pieceSize;
    322 
    323     if( tr_cpPieceIsComplete( ccp, lastPiece ) )
    324         b += lastPieceSize;
    325 
    326     return b;
    327 }
    328 
    329260uint64_t
    330261tr_cpHaveValid( const tr_completion * ccp )
     
    332263    if( ccp->haveValidIsDirty )
    333264    {
    334         tr_completion * cp = (tr_completion *) ccp; /* mutable */
    335         cp->haveValidLazy = calculateHaveValid( ccp );
    336         cp->haveValidIsDirty = 0;
     265        tr_piece_index_t   i;
     266        uint64_t           size = 0;
     267        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
     268        const tr_torrent * tor = ccp->tor;
     269        const tr_info    * info = &tor->info;
     270
     271        for( i=0; i<info->pieceCount; ++i )
     272            if( tr_cpPieceIsComplete( ccp, i ) )
     273                size += tr_torPieceCountBytes( tor, i );
     274
     275        cp->haveValidIsDirty = FALSE;
     276        cp->haveValidLazy = size;
    337277    }
    338278
     
    340280}
    341281
    342 void
    343 tr_cpGetAmountDone( const tr_completion * cp,
    344                     float *               tab,
    345                     int                   tabCount )
    346 {
    347     int                i;
    348     const tr_torrent * tor = cp->tor;
    349     const float        interval = tor->info.pieceCount / (float)tabCount;
    350     const int          isSeed = tr_cpGetStatus( cp ) == TR_SEED;
    351 
    352     for( i = 0; i < tabCount; ++i )
    353     {
    354         const tr_piece_index_t piece = i * interval;
    355 
    356         if( tor == NULL )
    357             tab[i] = 0.0f;
    358         else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
    359             tab[i] = 1.0f;
    360         else
    361             tab[i] = (float)cp->completeBlocks[piece] /
    362                      tr_torPieceCountBlocks( tor, piece );
    363     }
     282uint64_t
     283tr_cpSizeWhenDone( const tr_completion * ccp )
     284{
     285    if( ccp->sizeWhenDoneIsDirty )
     286    {
     287        tr_piece_index_t   i;
     288        uint64_t           size = 0;
     289        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
     290        const tr_torrent * tor = ccp->tor;
     291        const tr_info    * info = &tor->info;
     292
     293        for( i=0; i<info->pieceCount; ++i )
     294            if( !info->pieces[i].dnd || tr_cpPieceIsComplete( cp, i ) )
     295                size += tr_torPieceCountBytes( tor, i );
     296
     297        cp->sizeWhenDoneIsDirty = FALSE;
     298        cp->sizeWhenDoneLazy = size;
     299    }
     300
     301    return ccp->sizeWhenDoneLazy;
     302}
     303
     304void
     305tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
     306{
     307    int i, b;
     308    const int span = cp->tor->blockCount / tabCount;
     309
     310    for( i=b=0; i<tabCount; ++i, b+=span )
     311        tab[i] = tr_bitsetCountRange(&cp->blockBitset,b,b+span) / (float)span;
    364312}
    365313
    366314int
    367 tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
    368 {
    369     return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
    370 }
    371 
     315tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
     316{
     317    if( isSeed( cp ) )
     318        return 0;
     319
     320    return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
     321}
    372322
    373323tr_bool
    374 tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
    375 {
    376     return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
    377 }
    378 
    379 tr_bool
    380 tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t fileIndex )
    381 {
    382     tr_block_index_t block;
    383 
    384     const tr_torrent * tor = cp->tor;
    385     const tr_file * file = &tor->info.files[fileIndex];
    386 
    387     if( file->firstPiece == file->lastPiece )
    388     {
    389         const tr_block_index_t firstBlock = file->offset / tor->blockSize;
    390         const tr_block_index_t lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
    391         for( block=firstBlock; block<=lastBlock; ++block )
    392             if( !tr_cpBlockIsCompleteFast( cp, block ) )
    393                 return FALSE;
    394     }
    395     else
    396     {
    397         tr_piece_index_t piece;
    398         tr_block_index_t firstBlock;
    399         tr_block_index_t firstBlockInLastPiece;
    400         tr_block_index_t lastBlock;
    401         tr_block_index_t lastBlockInFirstPiece;
    402         uint64_t lastByteInFirstPiece;
    403         uint64_t firstByteInLastPiece;
    404 
    405         /* go piece-by-piece in the middle pieces... it's faster than block-by-block */
    406         for( piece=file->firstPiece+1; piece<file->lastPiece; ++piece )
    407             if( !tr_cpPieceIsComplete( cp, piece ) )
    408                 return FALSE;
    409 
    410         /* go block-by-block in the first piece */
    411         firstBlock = file->offset / tor->blockSize;
    412         lastByteInFirstPiece = ( (uint64_t)(file->firstPiece+1) * tor->info.pieceSize ) - 1;
    413         lastBlockInFirstPiece = lastByteInFirstPiece / tor->blockSize;
    414         assert( lastBlockInFirstPiece >= firstBlock );
    415         assert( lastBlockInFirstPiece - firstBlock <= tr_torPieceCountBlocks( tor, file->firstPiece ) );
    416         for( block=firstBlock; block<=lastBlockInFirstPiece; ++block )
    417             if( !tr_cpBlockIsCompleteFast( cp, block ) )
    418                 return FALSE;
    419 
    420         /* go block-by-block in the last piece */
    421         lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
    422         firstByteInLastPiece = (uint64_t)file->lastPiece * tor->info.pieceSize;
    423         firstBlockInLastPiece = firstByteInLastPiece / tor->blockSize;
    424         assert( firstBlockInLastPiece <= lastBlock );
    425         assert( firstBlockInLastPiece >= firstBlock );
    426         assert( firstBlockInLastPiece >= lastBlockInFirstPiece );
    427         assert( lastBlock - firstBlockInLastPiece <= tr_torPieceCountBlocks( tor, file->lastPiece ) );
    428         for( block=firstBlockInLastPiece; block<=lastBlock; ++block )
    429             if( !tr_cpBlockIsCompleteFast( cp, block ) )
    430                 return FALSE;
    431     }
    432 
    433     return TRUE;
    434 
    435 }
     324tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
     325{
     326    tr_block_index_t f, l;
     327
     328    if( cp->tor->info.files[i].length == 0 )
     329        return TRUE;
     330
     331    tr_torGetFileBlockRange( cp->tor, i, &f, &l );
     332    return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
     333}
     334
     335tr_bitfield *
     336tr_cpCreatePieceBitfield( const tr_completion * cp )
     337{
     338    tr_piece_index_t i;
     339    const tr_piece_index_t n = cp->tor->info.pieceCount;
     340    tr_bitfield * bf = tr_bitfieldNew( n );
     341
     342    for( i=0; i<n; ++i )
     343        if( tr_cpPieceIsComplete( cp, i ) )
     344            tr_bitfieldAdd( bf, i );
     345
     346    return bf;
     347}
  • trunk/libtransmission/completion.h

    r11892 r12012  
    2121
    2222#include "transmission.h"
    23 #include "bitfield.h"
     23#include "bitset.h"
     24#include "utils.h" /* tr_getRatio() */
    2425
    2526typedef struct tr_completion
     
    3233
    3334    /* do we have this block? */
    34     tr_bitfield    blockBitfield;
    35 
    36     /* do we have this piece? */
    37     tr_bitfield    pieceBitfield;
     35    tr_bitset    blockBitset;
    3836
    3937    /* a block is complete if and only if we have it */
     
    7775**/
    7876
    79 tr_completeness            tr_cpGetStatus( const tr_completion * );
     77tr_completeness    tr_cpGetStatus( const tr_completion * );
    8078
    81 uint64_t                   tr_cpHaveValid( const tr_completion * );
     79uint64_t           tr_cpHaveValid( const tr_completion * );
    8280
    83 tr_block_index_t           tr_cpBlocksMissing( const tr_completion * );
     81tr_block_index_t   tr_cpBlocksMissing( const tr_completion * );
    8482
    85 uint64_t                   tr_cpSizeWhenDone( const tr_completion * );
     83uint64_t           tr_cpSizeWhenDone( const tr_completion * );
    8684
    87 void                       tr_cpInvalidateDND( tr_completion * );
     85void               tr_cpInvalidateDND( tr_completion * );
    8886
    89 void                       tr_cpGetAmountDone( const   tr_completion * completion,
    90                                                float                 * tab,
    91                                                int                     tabCount );
     87void               tr_cpGetAmountDone( const   tr_completion * completion,
     88                                       float                 * tab,
     89                                       int                     tabCount );
    9290
    9391static inline uint64_t tr_cpHaveTotal( const tr_completion * cp )
     
    128126**/
    129127
    130 int tr_cpMissingBlocksInPiece( const tr_completion  * cp,
    131                                tr_piece_index_t       piece );
     128int tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i );
    132129
    133 tr_bool  tr_cpPieceIsComplete( const tr_completion * cp,
    134                                tr_piece_index_t      piece );
     130static inline tr_bool
     131tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t i )
     132{
     133    return tr_cpMissingBlocksInPiece( cp, i ) == 0;
     134}
    135135
    136 void   tr_cpPieceAdd( tr_completion    * completion,
    137                       tr_piece_index_t   piece );
     136void   tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t i );
    138137
    139 void   tr_cpPieceRem( tr_completion     * completion,
    140                       tr_piece_index_t   piece );
     138void   tr_cpPieceRem( tr_completion * cp, tr_piece_index_t i );
    141139
    142140tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
     
    146144**/
    147145
    148 static inline tr_bool tr_cpBlockIsCompleteFast( const tr_completion * cp, tr_block_index_t block )
     146static inline tr_bool
     147tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t i )
    149148{
    150     return tr_bitfieldHasFast( &cp->blockBitfield, block );
     149    return tr_bitsetHas( &cp->blockBitset, i );
    151150}
    152151
    153 static inline tr_bool tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
    154 {
    155     return tr_bitfieldHas( &cp->blockBitfield, block );
    156 }
     152void tr_cpBlockAdd( tr_completion * cp, tr_block_index_t i );
    157153
    158 void      tr_cpBlockAdd( tr_completion * completion,
    159                          tr_block_index_t block );
    160 
    161 tr_bool   tr_cpBlockBitfieldSet( tr_completion      * completion,
    162                                  struct tr_bitfield * blocks );
    163 
    164 void      tr_cpSetHaveAll( tr_completion * completion );
     154tr_bool tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks );
    165155
    166156/***
     
    168158***/
    169159
    170 static inline const struct tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp ) {
    171     return &cp->pieceBitfield;
     160static inline const tr_bitset *
     161tr_cpBlockBitset( const tr_completion * cp )
     162{
     163    return &cp->blockBitset;
    172164}
    173165
    174 static inline const struct tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp ) {
    175     assert( cp );
    176     assert( cp->blockBitfield.bits );
    177     assert( cp->blockBitfield.bitCount );
    178     return &cp->blockBitfield;
    179 }
     166tr_bitfield * tr_cpCreatePieceBitfield( const tr_completion * cp );
    180167
    181168#endif
  • trunk/libtransmission/peer-mgr.c

    r12006 r12012  
    384384    tr_peer * peer = tr_new0( tr_peer, 1 );
    385385
    386     tr_bitsetConstructor( &peer->have, 0 );
     386    peer->have = TR_BITSET_INIT;
    387387
    388388    peer->atom = atom;
     
    435435    tr_historyFree( peer->cancelsSentToPeer   );
    436436
    437     tr_bitsetDestructor( &peer->have );
     437    tr_bitsetDestruct( &peer->have );
    438438    tr_bitfieldFree( peer->blame );
    439439    tr_free( peer->client );
     
    13361336        if( tr_bitsetHas( have, p->index ) )
    13371337        {
    1338             tr_block_index_t b = tr_torPieceFirstBlock( tor, p->index );
    1339             const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, p->index );
     1338            tr_block_index_t b;
     1339            tr_block_index_t first;
     1340            tr_block_index_t last;
    13401341            tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
    13411342
    1342             for( ; b!=e && got<numwant; ++b )
     1343            tr_torGetPieceBlockRange( tor, p->index, &first, &last );
     1344
     1345            for( b=first; b<=last && got<numwant; ++b )
    13431346            {
    13441347                int peerCount;
     
    13461349
    13471350                /* don't request blocks we've already got */
    1348                 if( tr_cpBlockIsCompleteFast( &tor->completion, b ) )
     1351                if( tr_cpBlockIsComplete( &tor->completion, b ) )
    13491352                    continue;
    13501353
     
    15471550    /* request the blocks that we don't have in this piece */
    15481551    {
    1549         tr_block_index_t block;
     1552        tr_block_index_t b;
     1553        tr_block_index_t first;
     1554        tr_block_index_t last;
    15501555        const tr_torrent * tor = t->tor;
    1551         const tr_block_index_t start = tr_torPieceFirstBlock( tor, pieceIndex );
    1552         const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, pieceIndex );
    1553 
    1554         for( block=start; block<end; ++block )
     1556
     1557        tr_torGetPieceBlockRange( t->tor, pieceIndex, &first, &last );
     1558
     1559        for( b=first; b<=last; ++b )
    15551560        {
    1556             if( !tr_cpBlockIsComplete( tor->completion, block ) )
     1561            if( !tr_cpBlockIsComplete( tor->completion, b ) )
    15571562            {
    1558                 const uint32_t offset = getBlockOffsetInPiece( tor, block );
    1559                 const uint32_t length = tr_torBlockCountBytes( tor, block );
     1563                const uint32_t offset = getBlockOffsetInPiece( tor, b );
     1564                const uint32_t length = tr_torBlockCountBytes( tor, b );
    15601565                tr_peerMsgsAddRequest( peer->msgs, pieceIndex, offset, length );
    15611566                incrementPieceRequests( t, pieceIndex );
  • trunk/libtransmission/peer-msgs.c

    r11953 r12012  
    8989    LOW_PRIORITY_INTERVAL_SECS = 10,
    9090
    91     /* number of pieces to remove from the bitfield when
    92      * lazy bitfields are turned on */
    93     LAZY_PIECE_COUNT = 26,
    94 
    9591    /* number of pieces we'll allow in our fast set */
    9692    MAX_FAST_SET_SIZE = 3,
     
    121117};
    122118
    123 static uint32_t
    124 getBlockOffsetInPiece( const tr_torrent * tor, uint64_t b )
    125 {
    126     const uint64_t piecePos = tor->info.pieceSize * tr_torBlockPiece( tor, b );
    127     const uint64_t blockPos = tor->blockSize * b;
    128     assert( blockPos >= piecePos );
    129     return (uint32_t)( blockPos - piecePos );
    130 }
    131 
    132119static void
    133120blockToReq( const tr_torrent     * tor,
     
    135122            struct peer_request  * setme )
    136123{
    137     assert( setme != NULL );
    138 
    139     setme->index = tr_torBlockPiece( tor, block );
    140     setme->offset = getBlockOffsetInPiece( tor, block );
    141     setme->length = tr_torBlockCountBytes( tor, block );
     124    tr_torrentGetBlockLocation( tor, block, &setme->index,
     125                                            &setme->offset,
     126                                            &setme->length );
    142127}
    143128
     
    14521437
    14531438            /* a peer can send the same HAVE message twice... */
    1454             if( !tr_bitsetHas( &msgs->peer->have, ui32 ) )
    1455                 if( !tr_bitsetAdd( &msgs->peer->have, ui32 ) )
    1456                     fireClientGotHave( msgs, ui32 );
     1439            if( !tr_bitsetHas( &msgs->peer->have, ui32 ) ) {
     1440                tr_bitsetAdd( &msgs->peer->have, ui32 );
     1441                fireClientGotHave( msgs, ui32 );
     1442            }
    14571443            updatePeerProgress( msgs );
    14581444            break;
    14591445
    14601446        case BT_BITFIELD: {
     1447            tr_bitfield tmp = TR_BITFIELD_INIT;
    14611448            const size_t bitCount = tr_torrentHasMetadata( msgs->torrent )
    14621449                                  ? msgs->torrent->info.pieceCount
    14631450                                  : msglen * 8;
     1451            tr_bitfieldConstruct( &tmp, bitCount );
    14641452            dbgmsg( msgs, "got a bitfield" );
    1465             tr_bitsetReserve( &msgs->peer->have, bitCount );
    1466             tr_peerIoReadBytes( msgs->peer->io, inbuf,
    1467                                 msgs->peer->have.bitfield.bits, msglen );
    1468             fireClientGotBitfield( msgs, &msgs->peer->have.bitfield );
     1453            tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp.bits, msglen );
     1454            tr_bitsetSetBitfield( &msgs->peer->have, &tmp );
     1455            fireClientGotBitfield( msgs, &tmp );
     1456            tr_bitfieldDestruct( &tmp );
    14691457            updatePeerProgress( msgs );
    14701458            break;
     
    20502038{
    20512039    struct evbuffer * out = msgs->outMessages;
    2052     tr_bitfield *     field;
    2053     tr_piece_index_t  lazyPieces[LAZY_PIECE_COUNT];
    2054     size_t            i;
    2055     size_t            lazyCount = 0;
    2056 
    2057     field = tr_bitfieldDup( tr_cpPieceBitfield( &msgs->torrent->completion ) );
    2058 
    2059     if( tr_sessionIsLazyBitfieldEnabled( getSession( msgs ) ) )
    2060     {
    2061         /** Lazy bitfields aren't a high priority or secure, so I'm opting for
    2062             speed over a truly random sample -- let's limit the pool size to
    2063             the first 1000 pieces so large torrents don't bog things down */
    2064         size_t poolSize;
    2065         const size_t maxPoolSize = MIN( msgs->torrent->info.pieceCount, 1000 );
    2066         tr_piece_index_t * pool = tr_new( tr_piece_index_t, maxPoolSize );
    2067 
    2068         /* build the pool */
    2069         for( i=poolSize=0; i<maxPoolSize; ++i )
    2070             if( tr_bitfieldHas( field, i ) )
    2071                 pool[poolSize++] = i;
    2072 
    2073         /* pull random piece indices from the pool */
    2074         while( ( poolSize > 0 ) && ( lazyCount < LAZY_PIECE_COUNT ) )
    2075         {
    2076             const int pos = tr_cryptoWeakRandInt( poolSize );
    2077             const tr_piece_index_t piece = pool[pos];
    2078             tr_bitfieldRem( field, piece );
    2079             lazyPieces[lazyCount++] = piece;
    2080             pool[pos] = pool[--poolSize];
    2081         }
    2082 
    2083         /* cleanup */
    2084         tr_free( pool );
    2085     }
    2086 
    2087     evbuffer_add_uint32( out, sizeof( uint8_t ) + field->byteCount );
     2040    tr_bitfield * bf = tr_cpCreatePieceBitfield( &msgs->torrent->completion );
     2041
     2042    evbuffer_add_uint32( out, sizeof( uint8_t ) + bf->byteCount );
    20882043    evbuffer_add_uint8 ( out, BT_BITFIELD );
    2089     evbuffer_add       ( out, field->bits, field->byteCount );
    2090     dbgmsg( msgs, "sending bitfield... outMessage size is now %zu",
    2091             evbuffer_get_length( out ) );
     2044    evbuffer_add       ( out, bf->bits, bf->byteCount );
     2045    dbgmsg( msgs, "sending bitfield... outMessage size is now %zu", evbuffer_get_length( out ) );
    20922046    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    20932047
    2094     for( i = 0; i < lazyCount; ++i )
    2095         protocolSendHave( msgs, lazyPieces[i] );
    2096 
    2097     tr_bitfieldFree( field );
     2048    tr_bitfieldFree( bf );
    20982049}
    20992050
     
    21032054    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
    21042055
    2105     if( fext && ( tr_cpGetStatus( &msgs->torrent->completion ) == TR_SEED ) )
     2056    if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveAll ) )
    21062057    {
    21072058        protocolSendHaveAll( msgs );
    21082059    }
    2109     else if( fext && ( tr_cpHaveValid( &msgs->torrent->completion ) == 0 ) )
     2060    else if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveNone ) )
    21102061    {
    21112062        protocolSendHaveNone( msgs );
  • trunk/libtransmission/resume.c

    r11974 r12012  
    1717#include "transmission.h"
    1818#include "bencode.h"
     19#include "bitset.h"
    1920#include "completion.h"
    2021#include "metainfo.h" /* tr_metainfoGetBasename() */
     
    6667#define KEY_PROGRESS_MTIMES    "mtimes"
    6768#define KEY_PROGRESS_BITFIELD  "bitfield"
     69#define KEY_PROGRESS_BLOCKS    "blocks"
    6870#define KEY_PROGRESS_HAVE      "have"
    6971
     
    408410
    409411static void
    410 saveProgress( tr_benc * dict, const tr_torrent * tor )
     412saveProgress( tr_benc * dict, tr_torrent * tor )
    411413{
    412414    tr_benc * l;
    413415    tr_benc * prog;
    414416    tr_file_index_t fi;
    415     const struct tr_bitfield * bitfield;
    416417    const tr_info * inf = tr_torrentInfo( tor );
    417418    const time_t now = tr_time( );
     
    468469        tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" );
    469470
    470     /* add the pieces bitfield */
    471     bitfield = tr_cpBlockBitfield( &tor->completion );
    472     tr_bencDictAddRaw( prog, KEY_PROGRESS_BITFIELD, bitfield->bits,
    473                                                     bitfield->byteCount );
     471    /* add the blocks bitfield */
     472    tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ),
     473                     tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) );
    474474}
    475475
     
    492492        size_t rawlen;
    493493        tr_benc * l;
     494        tr_benc * b;
     495        struct tr_bitset bitset = TR_BITSET_INIT;
    494496
    495497        if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
     
    566568
    567569        err = NULL;
    568         if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
     570
     571        if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
     572        {
     573            if( !tr_bitsetFromBenc( &bitset, b ) )
     574                err = "Invalid value for PIECES";
     575        }
     576        else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
    569577        {
    570578            if( !strcmp( str, "all" ) )
    571                 tr_cpSetHaveAll( &tor->completion );
     579                tr_bitsetSetHaveAll( &bitset );
    572580            else
    573581                err = "Invalid value for HAVE";
     
    575583        else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
    576584        {
    577             tr_bitfield tmp;
    578             tmp.byteCount = rawlen;
    579             tmp.bitCount = tmp.byteCount * 8;
    580             tmp.bits = (uint8_t*) raw;
    581             if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
    582                 err = "Error loading bitfield";
    583         }
    584         else err = "Couldn't find 'have' or 'bitfield'";
    585 
     585            bitset.bitfield.bits = (void*) raw;
     586            bitset.bitfield.byteCount = rawlen;
     587            bitset.bitfield.bitCount = rawlen * 8;
     588        }
     589        else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
     590
     591        if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) )
     592            err = "Error loading bitfield";
    586593        if( err != NULL )
    587594            tr_tordbg( tor, "Torrent needs to be verified - %s", err );
  • trunk/libtransmission/rpcimpl.c

    r11969 r12012  
    562562        tr_bencDictAddInt( d, key, st->peersSendingToUs );
    563563    else if( tr_streq( key, keylen, "pieces" ) ) {
    564         const tr_bitfield * pieces = tr_cpPieceBitfield( &tor->completion );
    565         char * str = tr_base64_encode( pieces->bits, pieces->byteCount, NULL );
     564        tr_bitfield * bf = tr_cpCreatePieceBitfield( &tor->completion );
     565        char * str = tr_base64_encode( bf->bits, bf->byteCount, NULL );
    566566        tr_bencDictAddStr( d, key, str!=NULL ? str : "" );
    567567        tr_free( str );
     568        tr_bitfieldFree( bf );
    568569    }
    569570    else if( tr_streq( key, keylen, "pieceCount" ) )
  • trunk/libtransmission/session.c

    r11960 r12012  
    326326    tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           tr_getDefaultDownloadDir( ) );
    327327    tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   FALSE );
    328     tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
    329328    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
    330329    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
     
    391390    tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           tr_sessionGetIncompleteDir( s ) );
    392391    tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   tr_sessionIsIncompleteDirEnabled( s ) );
    393     tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
    394392    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
    395393    tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          tr_fdGetFileLimit( s ) );
     
    759757    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
    760758        tr_sessionSetCacheLimit_MB( session, i );
    761     if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal ) )
    762         tr_sessionSetLazyBitfieldEnabled( session, boolVal );
    763759    if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
    764760        tr_sessionSetPeerLimitPerTorrent( session, i );
  • trunk/libtransmission/torrent.c

    r11987 r12012  
    13091309    if( f->length )
    13101310    {
    1311         const tr_block_index_t firstBlock = f->offset / tor->blockSize;
    1312         const uint64_t lastByte = f->offset + f->length - 1;
    1313         const tr_block_index_t lastBlock = lastByte / tor->blockSize;
    1314 
    1315         if( firstBlock == lastBlock )
     1311        tr_block_index_t first;
     1312        tr_block_index_t last;
     1313        tr_torGetFileBlockRange( tor, index, &first, &last );
     1314
     1315        if( first == last )
    13161316        {
    1317             if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
     1317            if( tr_cpBlockIsComplete( &tor->completion, first ) )
    13181318                total = f->length;
    13191319        }
    13201320        else
    13211321        {
    1322             tr_block_index_t i;
    1323 
    13241322            /* the first block */
    1325             if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
     1323            if( tr_cpBlockIsComplete( &tor->completion, first ) )
    13261324                total += tor->blockSize - ( f->offset % tor->blockSize );
    13271325
    13281326            /* the middle blocks */
    1329             if( f->firstPiece == f->lastPiece )
    1330             {
    1331                 for( i=firstBlock+1; i<lastBlock; ++i )
    1332                     if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
    1333                         total += tor->blockSize;
     1327            if( first + 1 < last ) {
     1328                uint64_t u = tr_bitsetCountRange( tr_cpBlockBitset( &tor->completion ), first+1, last );
     1329                u *= tor->blockSize;
     1330                total += u;
    13341331            }
    1335             else
    1336             {
    1337                 uint64_t b = 0;
    1338                 const tr_block_index_t firstBlockOfLastPiece
    1339                            = tr_torPieceFirstBlock( tor, f->lastPiece );
    1340                 const tr_block_index_t lastBlockOfFirstPiece
    1341                            = tr_torPieceFirstBlock( tor, f->firstPiece )
    1342                              + tr_torPieceCountBlocks( tor, f->firstPiece ) - 1;
    1343 
    1344                 /* the rest of the first piece */
    1345                 for( i=firstBlock+1; i<lastBlock && i<=lastBlockOfFirstPiece; ++i )
    1346                     if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
    1347                         ++b;
    1348 
    1349                 /* the middle pieces */
    1350                 if( f->firstPiece + 1 < f->lastPiece )
    1351                     for( i=f->firstPiece+1; i<f->lastPiece; ++i )
    1352                         b += tor->blockCountInPiece - tr_cpMissingBlocksInPiece( &tor->completion, i );
    1353 
    1354                 /* the rest of the last piece */
    1355                 for( i=firstBlockOfLastPiece; i<lastBlock; ++i )
    1356                     if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
    1357                         ++b;
    1358 
    1359                 b *= tor->blockSize;
    1360                 total += b;
    1361             }
    13621332
    13631333            /* the last block */
    1364             if( tr_cpBlockIsCompleteFast( &tor->completion, lastBlock ) )
    1365                 total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * lastBlock );
     1334            if( tr_cpBlockIsComplete( &tor->completion, last ) )
     1335                total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * last );
    13661336        }
    13671337    }
     
    22832253***/
    22842254
     2255void
     2256tr_torrentGetBlockLocation( const tr_torrent * tor,
     2257                            tr_block_index_t   block,
     2258                            tr_piece_index_t * piece,
     2259                            uint32_t         * offset,
     2260                            uint32_t         * length )
     2261{
     2262    uint64_t pos = block;
     2263    pos *= tor->blockSize;
     2264    *piece = pos / tor->info.pieceSize;
     2265    *offset = pos - ( *piece * tor->info.pieceSize );
     2266    *length = tr_torBlockCountBytes( tor, block );
     2267}
     2268
     2269
    22852270tr_block_index_t
    22862271_tr_block( const tr_torrent * tor,
     
    23442329    return ret;
    23452330}
     2331
     2332void
     2333tr_torGetFileBlockRange( const tr_torrent        * tor,
     2334                         const tr_file_index_t     file,
     2335                         tr_block_index_t        * first,
     2336                         tr_block_index_t        * last )
     2337{
     2338    const tr_file * f = &tor->info.files[file];
     2339    uint64_t offset = f->offset;
     2340    *first = offset / tor->blockSize;
     2341    if( !f->length )
     2342        *last = *first;
     2343    else {
     2344        offset += f->length - 1;
     2345        *last = offset / tor->blockSize;
     2346    }
     2347}
     2348
     2349void
     2350tr_torGetPieceBlockRange( const tr_torrent        * tor,
     2351                          const tr_piece_index_t    piece,
     2352                          tr_block_index_t        * first,
     2353                          tr_block_index_t        * last )
     2354{
     2355    uint64_t offset = tor->info.pieceSize;
     2356    offset *= piece;
     2357    *first = offset / tor->blockSize;
     2358    offset += ( tr_torPieceCountBytes( tor, piece ) - 1 );
     2359    *last = offset / tor->blockSize;
     2360}
     2361
    23462362
    23472363/***
  • trunk/libtransmission/torrent.h

    r11890 r12012  
    8383                                 uint32_t           length );
    8484
     85void             tr_torrentGetBlockLocation( const tr_torrent * tor,
     86                                             tr_block_index_t   block,
     87                                             tr_piece_index_t * piece,
     88                                             uint32_t         * offset,
     89                                             uint32_t         * length );
     90
     91void             tr_torGetFileBlockRange( const tr_torrent        * tor,
     92                                          const tr_file_index_t     file,
     93                                          tr_block_index_t        * first,
     94                                          tr_block_index_t        * last );
     95
     96void             tr_torGetPieceBlockRange( const tr_torrent        * tor,
     97                                           const tr_piece_index_t    piece,
     98                                           tr_block_index_t        * first,
     99                                           tr_block_index_t        * last );
     100
    85101void             tr_torrentInitFilePriority( tr_torrent       * tor,
    86102                                             tr_file_index_t    fileIndex,
     
    256272}
    257273
    258 /* get the index of this piece's first block */
    259 static inline tr_block_index_t
    260 tr_torPieceFirstBlock( const tr_torrent * tor, const tr_piece_index_t piece )
    261 {
    262     return piece * tor->blockCountInPiece;
    263 }
    264 
    265274/* what piece index is this block in? */
    266275static inline tr_piece_index_t
     
    268277{
    269278    return block / tor->blockCountInPiece;
    270 }
    271 
    272 /* how many blocks are in this piece? */
    273 static inline uint16_t
    274 tr_torPieceCountBlocks( const tr_torrent * tor, const tr_piece_index_t piece )
    275 {
    276     return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
    277                                              : tor->blockCountInPiece;
    278279}
    279280
  • trunk/libtransmission/transmission.h

    r11987 r12012  
    171171#define TR_PREFS_KEY_INCOMPLETE_DIR                "incomplete-dir"
    172172#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED        "incomplete-dir-enabled"
    173 #define TR_PREFS_KEY_LAZY_BITFIELD                 "lazy-bitfield-enabled"
    174173#define TR_PREFS_KEY_MSGLEVEL                      "message-level"
    175174#define TR_PREFS_KEY_OPEN_FILE_LIMIT               "open-file-limit"
  • trunk/libtransmission/utils-test.c

    r11798 r12012  
    4747
    4848static int
     49test_bitfield_count_range( void )
     50{
     51    int i;
     52    int n;
     53    int begin;
     54    int end;
     55    int count1;
     56    int count2;
     57    const int bitCount = 100 + tr_cryptoWeakRandInt( 1000 );
     58    tr_bitfield * bf;
     59
     60    /* generate a random bitfield */
     61    bf = tr_bitfieldNew( bitCount );
     62    for( i=0, n=tr_cryptoWeakRandInt(bitCount); i<n; ++i )
     63        tr_bitfieldAdd( bf, tr_cryptoWeakRandInt(bitCount) );
     64
     65    begin = tr_cryptoWeakRandInt( bitCount );
     66    do {
     67        end = tr_cryptoWeakRandInt( bitCount );
     68    } while( end == begin );
     69    if( end < begin ) {
     70        const int tmp = begin;
     71        begin = end;
     72        end = tmp;
     73    }
     74
     75    count1 = 0;
     76    for( i=begin; i<end; ++i )
     77        if( tr_bitfieldHas( bf, i ) )
     78            ++count1;
     79    count2 = tr_bitfieldCountRange( bf, begin, end );
     80    check( count1 == count2 );
     81
     82    tr_bitfieldFree( bf );
     83    return 0;
     84}
     85
     86static int
    4987test_bitfields( void )
    5088{
     
    407445}
    408446
     447struct blah
     448{
     449    uint8_t  hash[SHA_DIGEST_LENGTH];  /* pieces hash */
     450    int8_t   priority;                 /* TR_PRI_HIGH, _NORMAL, or _LOW */
     451    int8_t   dnd;                      /* "do not download" flag */
     452    time_t   timeChecked;              /* the last time we tested this piece */
     453};
     454
     455
    409456int
    410457main( void )
     
    414461    int   i;
    415462    int   l;
     463
     464fprintf( stderr, "sizeof time_t %zu\n", sizeof(time_t));
     465fprintf( stderr, "sizeof char[20] %zu\n", (size_t)20);
     466fprintf( stderr, "sizeof uint8_t %zu\n", sizeof(uint8_t));
     467fprintf( stderr, "sizeof blah %zu\n", sizeof(struct blah));
     468return 0;
    416469
    417470    /* base64 */
     
    466519            return i;
    467520
    468     return 0;
    469 }
    470 
     521    /* bitfield count range */
     522    for( l=0; l<1000000; ++l )
     523        if(( i = test_bitfield_count_range( )))
     524            return i;
     525
     526    return 0;
     527}
     528
  • trunk/libtransmission/webseed.c

    r11897 r12012  
    6565webseed_free( struct tr_webseed * w )
    6666{
    67     tr_bitsetDestructor( &w->parent.have );
     67    tr_bitsetDestruct( &w->parent.have );
    6868    tr_free( w->parent.client );
    6969
     
    9090    tr_peer_event e = TR_PEER_EVENT_INIT;
    9191    e.eventType = TR_PEER_CLIENT_GOT_REJ;
    92     e.pieceIndex = tr_torBlockPiece( tor, block );
    93     e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
    94     e.length = tr_torBlockCountBytes( tor, block );
     92    tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
    9593    publish( w, &e );
    9694}
     
    10199    tr_peer_event e = TR_PEER_EVENT_INIT;
    102100    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
    103     e.pieceIndex = tr_torBlockPiece( tor, block );
    104     e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
    105     e.length = tr_torBlockCountBytes( tor, block );
     101    tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
    106102    publish( w, &e );
    107103}
     
    335331    peer->peerIsChoked = TRUE;
    336332    peer->clientIsInterested = !tr_torrentIsSeed( tor );
    337     tr_bitsetConstructor( &peer->have, tor->info.pieceCount );
    338     tr_bitsetSetHaveAll( &peer->have );
    339333    peer->progress = 1.0;
    340334    peer->client = tr_strdup( "webseed" );
     335    peer->have = TR_BITSET_INIT;
     336    tr_bitsetSetHaveAll( &peer->have );
    341337
    342338    w->torrent_id = tr_torrentId( tor );
Note: See TracChangeset for help on using the changeset viewer.