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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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}
Note: See TracChangeset for help on using the changeset viewer.