Ignore:
Timestamp:
Mar 28, 2011, 4:31:05 PM (11 years ago)
Author:
jordan
Message:

(trunk libT) break the mac build and introduce new crashes.

This is partially to address #4145 "Downloads stuck at 100%" by refactoring the bitset, bitfield, and tr_completion; however, the ripple effect is larger than usual so things may get worse in the short term before getting better.

livings124: to fix the mac build, remove bitset.[ch] from xcode

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/completion.c

    r12204 r12248  
    1111 */
    1212
    13 #include <string.h> /* memcpy() */
    14 
    1513#include "transmission.h"
    1614#include "completion.h"
     
    2523tr_cpReset( tr_completion * cp )
    2624{
    27     tr_bitsetSetHaveNone( &cp->blockBitset );
    28     tr_free( cp->completeBlocks );
    29     cp->completeBlocks = NULL;
    3025    cp->sizeNow = 0;
    3126    cp->sizeWhenDoneIsDirty = true;
    32     cp->blocksWantedIsDirty = true;
    3327    cp->haveValidIsDirty = true;
    34 }
    35 
    36 tr_completion *
     28    tr_bitfieldSetHasNone( &cp->blockBitfield );
     29}
     30
     31void
    3732tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
    3833{
    3934    cp->tor = tor;
    40     cp->completeBlocks = NULL;
    41     tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
     35    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
    4236    tr_cpReset( cp );
    43     return cp;
    44 }
    45 
    46 tr_completion*
     37}
     38
     39void
    4740tr_cpDestruct( tr_completion * cp )
    4841{
    49     tr_free( cp->completeBlocks );
    50     tr_bitsetDestruct( &cp->blockBitset );
    51     return cp;
     42    tr_bitfieldDestruct( &cp->blockBitfield );
     43}
     44
     45bool
     46tr_cpBlockInit( tr_completion * cp, const tr_bitfield * b )
     47{
     48    bool success;
     49
     50    tr_cpReset( cp );
     51
     52    /* set blockBitfield */
     53    success = tr_bitfieldSetFromBitfield( &cp->blockBitfield, b );
     54
     55    /* set sizeNow */
     56    cp->sizeNow = tr_bitfieldCountTrueBits( &cp->blockBitfield );
     57    cp->sizeNow *= cp->tor->blockSize;
     58    if( tr_bitfieldHas( b, cp->tor->blockCount-1 ) )
     59        cp->sizeNow -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
     60
     61    return success;
    5262}
    5363
     
    5969isSeed( const tr_completion * cp )
    6070{
    61     return cp->blockBitset.haveAll;
     71    return tr_bitfieldHasAll( &cp->blockBitfield );
    6272}
    6373
     
    6575tr_cpGetStatus( const tr_completion * cp )
    6676{
     77    if( isSeed( cp ) ) return TR_SEED;
    6778    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
    68     if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
    6979    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
    7080    return TR_LEECH;
    7181}
    7282
    73 /* how many blocks are in this piece? */
    74 static inline uint16_t
    75 countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
    76 {
    77     return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
    78                                              : tor->blockCountInPiece;
    79 }
    80 
    81 static uint16_t *
    82 getCompleteBlocks( const tr_completion * ccp )
    83 {
    84     if( ccp->completeBlocks == NULL )
    85     {
    86         tr_completion * cp = (tr_completion*) ccp;
    87         cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
    88     }
    89 
    90     return ccp->completeBlocks;
    91 }
    92 
    9383void
    9484tr_cpInvalidateDND( tr_completion * cp )
    9585{
    9686    cp->sizeWhenDoneIsDirty = true;
    97     cp->blocksWantedIsDirty = true;
    98 }
    99 
    100 tr_block_index_t
    101 tr_cpBlocksMissing( const tr_completion * ccp )
    102 {
    103     if( isSeed( ccp ) )
    104         return 0;
    105 
    106     if( ccp->blocksWantedIsDirty )
    107     {
    108         tr_piece_index_t   i;
    109         tr_block_index_t   wanted = 0;
    110         tr_block_index_t   complete = 0;
    111         tr_completion    * cp = (tr_completion *) ccp; /* mutable */
    112         const uint16_t   * complete_blocks = getCompleteBlocks( cp );
    113         const tr_torrent * tor = ccp->tor;
    114         const tr_info    * info = &tor->info;
    115 
    116         for( i = 0; i < info->pieceCount; ++i )
    117         {
    118             if( !info->pieces[i].dnd )
    119             {
    120                 wanted += countBlocksInPiece( tor, i );
    121                 complete += complete_blocks[i];
    122             }
    123         }
    124 
    125         cp->blocksWantedLazy = wanted;
    126         cp->blocksWantedCompleteLazy = complete;
    127         cp->blocksWantedIsDirty = false;
    128     }
    129 
    130     return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
    13187}
    13288
     
    13490tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
    13591{
    136     tr_block_index_t i;
    137     tr_block_index_t first;
    138     tr_block_index_t last;
     92    tr_block_index_t i, f, l;
    13993    const tr_torrent * tor = cp->tor;
    140     uint16_t * complete_blocks = getCompleteBlocks( cp );
    141 
    142     tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
    143     for( i=first; i<=last; ++i )
     94
     95    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
     96
     97    for( i=f; i<=l; ++i )
    14498        if( tr_cpBlockIsComplete( cp, i ) )
    14599            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
    146100
    147     if( !tor->info.pieces[piece].dnd )
    148         cp->blocksWantedCompleteLazy -= complete_blocks[piece];
    149 
     101    cp->haveValidIsDirty = true;
    150102    cp->sizeWhenDoneIsDirty = true;
    151     cp->haveValidIsDirty = true;
    152     complete_blocks[piece] = 0;
    153     tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
     103    tr_bitfieldRemRange( &cp->blockBitfield, f, l+1 );
    154104}
    155105
     
    157107tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
    158108{
    159     tr_block_index_t i;
    160     tr_block_index_t first;
    161     tr_block_index_t last;
    162     tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
    163 
    164     for( i=first; i<=last; ++i )
     109    tr_block_index_t i, f, l;
     110    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
     111
     112    for( i=f; i<=l; ++i )
    165113        tr_cpBlockAdd( cp, i );
    166114}
     
    173121    if( !tr_cpBlockIsComplete( cp, block ) )
    174122    {
    175         const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
    176         const int blockSize = tr_torBlockCountBytes( tor, block );
    177 
    178         getCompleteBlocks(cp)[piece]++;
    179 
    180         tr_bitsetAdd( &cp->blockBitset, block );
    181 
    182         cp->sizeNow += blockSize;
    183         if( !tor->info.pieces[piece].dnd )
    184             cp->blocksWantedCompleteLazy++;
    185 
     123        tr_bitfieldAdd( &cp->blockBitfield, block );
     124        cp->sizeNow += tr_torBlockCountBytes( tor, block );
     125
     126        cp->haveValidIsDirty = true;
    186127        cp->sizeWhenDoneIsDirty = true;
    187         cp->haveValidIsDirty = true;
    188     }
    189 }
    190 
    191 
    192 bool
    193 tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
    194 {
    195     bool success = false;
    196     tr_torrent * tor = cp->tor;
    197 
    198     /* start cp with a state where it thinks we have nothing */
    199     tr_cpReset( cp );
    200 
    201     if( blocks->haveAll )
    202     {
    203         tr_bitsetSetHaveAll( &cp->blockBitset );
    204         cp->sizeNow = tor->info.totalSize;
    205 
    206         success = true;
    207     }
    208     else if( blocks->haveNone )
    209     {
    210         /* already reset... */
    211         success = true;
    212     }
    213     else
    214     {
    215         const tr_bitfield * src = &blocks->bitfield;
    216         tr_bitfield * tgt = &cp->blockBitset.bitfield;
    217 
    218         tr_bitfieldConstruct( tgt, tor->blockCount );
    219 
    220         /* The bitfield of block flags is typically loaded from a resume file.
    221            Test the bitfield's length in case the resume file is corrupt */
    222         if(( success = src->byteCount == tgt->byteCount ))
    223         {
    224             size_t i = 0;
    225             uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
    226 
    227             /* init our block bitfield from the one passed in */
    228             memcpy( tgt->bits, src->bits, src->byteCount );
    229 
    230             /* update cp.sizeNow and the cp.blockBitset flags */
    231             i = tr_bitfieldCountTrueBits( tgt );
    232             if( i == tor->blockCount ) {
    233                 tr_bitsetSetHaveAll( &cp->blockBitset );
    234                 cp->sizeNow = cp->tor->info.totalSize;
    235             } else if( !i ) {
    236                 tr_bitsetSetHaveNone( &cp->blockBitset );
    237                 cp->sizeNow = 0;
    238             } else {
    239                 cp->blockBitset.haveAll = cp->blockBitset.haveNone = false;
    240                 cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
    241                 cp->sizeNow *= tor->blockSize;
    242                 if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
    243                     cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
    244             }
    245 
    246             /* update complete_blocks_in_piece */
    247             for( i=0; i<tor->info.pieceCount; ++i ) {
    248                  tr_block_index_t first, last;
    249                  tr_torGetPieceBlockRange( tor, i, &first, &last );
    250                  complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
    251             }
    252         }
    253     }
    254 
    255     return success;
     128    }
    256129}
    257130
     
    265138    if( ccp->haveValidIsDirty )
    266139    {
    267         tr_piece_index_t   i;
    268         uint64_t           size = 0;
    269         tr_completion    * cp = (tr_completion *) ccp; /* mutable */
     140        tr_piece_index_t i;
     141        uint64_t size = 0;
     142        tr_completion * cp = (tr_completion *) ccp; /* mutable */
    270143        const tr_torrent * tor = ccp->tor;
    271         const tr_info    * info = &tor->info;
     144        const tr_info * info = &tor->info;
    272145
    273146        for( i=0; i<info->pieceCount; ++i )
     
    275148                size += tr_torPieceCountBytes( tor, i );
    276149
     150        cp->haveValidLazy = size;
    277151        cp->haveValidIsDirty = false;
    278         cp->haveValidLazy = size;
    279152    }
    280153
     
    287160    if( ccp->sizeWhenDoneIsDirty )
    288161    {
    289         tr_piece_index_t   i;
    290         uint64_t           size = 0;
    291         tr_completion    * cp = (tr_completion *) ccp; /* mutable */
     162        tr_piece_index_t i;
     163        uint64_t size = 0;
     164        tr_completion * cp = (tr_completion *) ccp; /* mutable */
    292165        const tr_torrent * tor = ccp->tor;
    293         const tr_info    * info = &tor->info;
     166        const tr_info * info = &tor->info;
    294167
    295168        for( i=0; i<info->pieceCount; ++i )
     
    297170                size += tr_torPieceCountBytes( tor, i );
    298171
     172        cp->sizeWhenDoneLazy = size;
    299173        cp->sizeWhenDoneIsDirty = false;
    300         cp->sizeWhenDoneLazy = size;
    301174    }
    302175
     
    304177}
    305178
     179uint64_t
     180tr_cpLeftUntilDone( const tr_completion * cp )
     181{
     182    return tr_cpSizeWhenDone( cp ) - cp->sizeNow;
     183}
     184
     185uint64_t
     186tr_cpLeftUntilComplete( const tr_completion * cp )
     187{
     188    return cp->tor->info.totalSize - cp->sizeNow;
     189}
     190
    306191void
    307192tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
    308193{
    309194    int i;
     195    const bool seed = isSeed( cp );
    310196    const float interval = cp->tor->info.pieceCount / (float)tabCount;
    311     const bool seed = isSeed( cp );
    312197
    313198    for( i=0; i<tabCount; ++i ) {
     
    315200            tab[i] = 1.0f;
    316201        else {
     202            tr_block_index_t f, l;
    317203            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
    318             tab[i] = getCompleteBlocks(cp)[piece] / (float)countBlocksInPiece( cp->tor, piece );
     204            tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
     205            tab[i] = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 )
     206                                                            / (float)(l+1-f);
    319207        }
    320208    }
    321209}
    322210
    323 int
    324 tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
     211size_t
     212tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
    325213{
    326214    if( isSeed( cp ) )
    327215        return 0;
    328 
    329     return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
     216    else {
     217        tr_block_index_t f, l;
     218        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
     219        return (l+1-f) - tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
     220    }
     221}
     222
     223size_t
     224tr_cpMissingBytesInPiece( const tr_completion * cp, tr_piece_index_t piece )
     225{
     226    if( isSeed( cp ) )
     227        return 0;
     228    else {
     229        size_t haveBytes = 0;
     230        tr_block_index_t f, l;
     231        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
     232        haveBytes = tr_bitfieldCountRange( &cp->blockBitfield, f, l );
     233        haveBytes *= cp->tor->blockSize;
     234        if( tr_bitfieldHas( &cp->blockBitfield, l ) )
     235            haveBytes += tr_torBlockCountBytes( cp->tor, l );
     236        return tr_torPieceCountBytes( cp->tor, piece ) - haveBytes;
     237    }
    330238}
    331239
     
    333241tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
    334242{
    335     tr_block_index_t f, l;
    336 
    337243    if( cp->tor->info.files[i].length == 0 )
    338244        return true;
    339 
    340     tr_torGetFileBlockRange( cp->tor, i, &f, &l );
    341     return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
    342 }
    343 
    344 tr_bitfield *
    345 tr_cpCreatePieceBitfield( const tr_completion * cp )
    346 {
    347     tr_piece_index_t i;
     245    else {
     246        tr_block_index_t f, l;
     247        tr_torGetFileBlockRange( cp->tor, i, &f, &l );
     248        return tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 ) == (l+1-f);
     249    }
     250}
     251
     252void *
     253tr_cpCreatePieceBitfield( const tr_completion * cp, size_t * byte_count )
     254{
     255    void * ret;
     256    tr_bitfield pieces;
    348257    const tr_piece_index_t n = cp->tor->info.pieceCount;
    349     tr_bitfield * bf = tr_bitfieldNew( n );
    350 
    351     for( i=0; i<n; ++i )
    352         if( tr_cpPieceIsComplete( cp, i ) )
    353             tr_bitfieldAdd( bf, i );
    354 
    355     return bf;
    356 }
     258    tr_bitfieldConstruct( &pieces, n );
     259
     260    if( tr_cpHasAll( cp ) )
     261        tr_bitfieldSetHasAll( &pieces );
     262    else if( !tr_cpHasNone( cp ) ) {
     263        tr_piece_index_t i;
     264        for( i=0; i<n; ++i )
     265            if( tr_cpPieceIsComplete( cp, i ) )
     266                tr_bitfieldAdd( &pieces, i );
     267    }
     268
     269    ret = tr_bitfieldGetRaw( &pieces, byte_count );
     270    tr_bitfieldDestruct( &pieces );
     271    return ret;
     272}
     273
     274double
     275tr_cpPercentComplete( const tr_completion * cp )
     276{
     277    const double ratio = tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
     278
     279    if( (int)ratio == TR_RATIO_NA )
     280        return 0.0;
     281    else if( (int)ratio == TR_RATIO_INF )
     282        return 1.0;
     283    else
     284        return ratio;
     285}
     286
     287double
     288tr_cpPercentDone( const tr_completion * cp )
     289{
     290    const double ratio = tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
     291    const int iratio = (int)ratio;
     292    return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
     293}
Note: See TracChangeset for help on using the changeset viewer.