source: trunk/libtransmission/completion.c @ 12918

Last change on this file since 12918 was 12918, checked in by jordan, 10 years ago

(trunk libT) add several more tr_completion assertions to smoke out the (sizeWhenDone() < sizeNow()) error reported in the forums

  • Property svn:keywords set to Date Rev Author Id
File size: 8.5 KB
RevLine 
[7632]1/*
[11709]2 * This file Copyright (C) Mnemosyne LLC
[3]3 *
[11599]4 * This file is licensed by the GPL version 2. Works owned by the
[7632]5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
[260]9 *
[7632]10 * $Id: completion.c 12918 2011-09-26 06:18:48Z jordan $
11 */
[3]12
[12531]13#include <assert.h>
14
[3]15#include "transmission.h"
[2149]16#include "completion.h"
[4324]17#include "torrent.h"
[2555]18#include "utils.h"
[3]19
[12012]20/***
21****
22***/
23
[3815]24static void
25tr_cpReset( tr_completion * cp )
26{
[5682]27    cp->sizeNow = 0;
[12204]28    cp->sizeWhenDoneIsDirty = true;
29    cp->haveValidIsDirty = true;
[12248]30    tr_bitfieldSetHasNone( &cp->blockBitfield );
[3815]31}
32
[12248]33void
[7578]34tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
[3]35{
[7578]36    cp->tor = tor;
[12248]37    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
[5]38    tr_cpReset( cp );
[3]39}
40
[12262]41void
[12248]42tr_cpBlockInit( tr_completion * cp, const tr_bitfield * b )
43{
44    tr_cpReset( cp );
45
46    /* set blockBitfield */
[12262]47    tr_bitfieldSetFromBitfield( &cp->blockBitfield, b );
[12248]48
49    /* set sizeNow */
50    cp->sizeNow = tr_bitfieldCountTrueBits( &cp->blockBitfield );
[12918]51    assert( cp->sizeNow <= cp->tor->blockCount );
[12248]52    cp->sizeNow *= cp->tor->blockSize;
53    if( tr_bitfieldHas( b, cp->tor->blockCount-1 ) )
54        cp->sizeNow -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
[12918]55    assert( cp->sizeNow <= cp->tor->info.totalSize );
[12248]56}
57
[12012]58/***
59****
60***/
61
62tr_completeness
63tr_cpGetStatus( const tr_completion * cp )
64{
[12251]65    if( tr_cpHasAll( cp ) ) return TR_SEED;
[12012]66    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
67    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
68    return TR_LEECH;
69}
70
[5682]71void
[12012]72tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
[2531]73{
[12248]74    tr_block_index_t i, f, l;
[12012]75    const tr_torrent * tor = cp->tor;
[2531]76
[12248]77    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
78
79    for( i=f; i<=l; ++i )
[12012]80        if( tr_cpBlockIsComplete( cp, i ) )
81            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
[2531]82
[12248]83    cp->haveValidIsDirty = true;
[12204]84    cp->sizeWhenDoneIsDirty = true;
[12248]85    tr_bitfieldRemRange( &cp->blockBitfield, f, l+1 );
[2531]86}
87
[4840]88void
[12012]89tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
[3]90{
[12248]91    tr_block_index_t i, f, l;
92    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
[3]93
[12248]94    for( i=f; i<=l; ++i )
[2531]95        tr_cpBlockAdd( cp, i );
[3]96}
97
[4840]98void
[7631]99tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
[3]100{
[3105]101    const tr_torrent * tor = cp->tor;
[2149]102
[3]103    if( !tr_cpBlockIsComplete( cp, block ) )
104    {
[12248]105        tr_bitfieldAdd( &cp->blockBitfield, block );
106        cp->sizeNow += tr_torBlockCountBytes( tor, block );
[2478]107
[12248]108        cp->haveValidIsDirty = true;
[12204]109        cp->sizeWhenDoneIsDirty = true;
[3]110    }
111}
112
[2149]113/***
114****
115***/
116
[12012]117uint64_t
118tr_cpHaveValid( const tr_completion * ccp )
[2149]119{
[12012]120    if( ccp->haveValidIsDirty )
121    {
[12248]122        tr_piece_index_t i;
123        uint64_t size = 0;
124        tr_completion * cp = (tr_completion *) ccp; /* mutable */
[12012]125        const tr_torrent * tor = ccp->tor;
[12248]126        const tr_info * info = &tor->info;
[2149]127
[12012]128        for( i=0; i<info->pieceCount; ++i )
129            if( tr_cpPieceIsComplete( ccp, i ) )
130                size += tr_torPieceCountBytes( tor, i );
[2149]131
[12248]132        cp->haveValidLazy = size;
[12204]133        cp->haveValidIsDirty = false;
[12012]134    }
[9550]135
[12012]136    return ccp->haveValidLazy;
[2149]137}
[3178]138
139uint64_t
[12012]140tr_cpSizeWhenDone( const tr_completion * ccp )
[7050]141{
[12012]142    if( ccp->sizeWhenDoneIsDirty )
[7050]143    {
[12248]144        uint64_t size = 0;
[12251]145        const tr_torrent * tor = ccp->tor;
[12918]146        const tr_info * inf = tr_torrentInfo( tor );
[12248]147        tr_completion * cp = (tr_completion *) ccp; /* mutable */
[12012]148
[12251]149        if( tr_cpHasAll( ccp ) )
150        {
[12918]151            size = inf->totalSize;
[12251]152        }
153        else
154        {
155            tr_piece_index_t p;
[12012]156
[12918]157            for( p=0; p<inf->pieceCount; ++p )
[12251]158            {
[12918]159                uint64_t n = 0;
160                const uint64_t pieceSize = tr_torPieceCountBytes( tor, p );
161
162                if( !inf->pieces[p].dnd )
[12251]163                {
[12918]164                    n = pieceSize;
[12251]165                }
166                else
167                {
[12918]168                    uint64_t o = 0;
[12251]169                    tr_block_index_t b, f, l;
170                    tr_torGetPieceBlockRange( cp->tor, p, &f, &l );
171                    for( b=f; b<=l; ++b )
172                        if( tr_cpBlockIsComplete( cp, b ) )
[12918]173                            n += tr_torBlockCountBytes( tor, b );
174
175                    o = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
176                    o *= cp->tor->blockSize;
177                    if( l == ( cp->tor->blockCount - 1 )  && tr_bitfieldHas( &cp->blockBitfield, l ) )
178                        o -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
179
180                    assert( n == o );
[12251]181                }
[12918]182
183                assert( n <= tr_torPieceCountBytes( tor, p ) );
184                size += n;
[12251]185            }
186        }
187
[12918]188        assert( size <= inf->totalSize );
189        assert( size >= cp->sizeNow );
190
[12248]191        cp->sizeWhenDoneLazy = size;
[12204]192        cp->sizeWhenDoneIsDirty = false;
[7050]193    }
194
[12012]195    return ccp->sizeWhenDoneLazy;
[7050]196}
197
[12918]198uint64_t
199tr_cpLeftUntilDone( const tr_completion * cp )
200{
201    const uint64_t sizeWhenDone = tr_cpSizeWhenDone( cp );
202
203    assert( sizeWhenDone >= cp->sizeNow );
204
205    return sizeWhenDone - cp->sizeNow;
206}
207
[5682]208void
[12012]209tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
[5682]210{
[12101]211    int i;
[12251]212    const bool seed = tr_cpHasAll( cp );
[12101]213    const float interval = cp->tor->info.pieceCount / (float)tabCount;
[6108]214
[12101]215    for( i=0; i<tabCount; ++i ) {
216        if( seed )
217            tab[i] = 1.0f;
218        else {
[12248]219            tr_block_index_t f, l;
[12101]220            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
[12248]221            tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
222            tab[i] = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 )
223                                                            / (float)(l+1-f);
[12101]224        }
225    }
[5682]226}
[7578]227
[12248]228size_t
229tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
[7578]230{
[12251]231    if( tr_cpHasAll( cp ) )
[12012]232        return 0;
[12248]233    else {
234        tr_block_index_t f, l;
235        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
236        return (l+1-f) - tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
237    }
238}
[7578]239
[12248]240size_t
241tr_cpMissingBytesInPiece( const tr_completion * cp, tr_piece_index_t piece )
242{
[12251]243    if( tr_cpHasAll( cp ) )
[12248]244        return 0;
245    else {
246        size_t haveBytes = 0;
247        tr_block_index_t f, l;
[12531]248        const size_t pieceByteSize = tr_torPieceCountBytes( cp->tor, piece );
[12248]249        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
[12531]250        if( f != l ) {
251            /* nb: we don't pass the usual l+1 here to tr_bitfieldCountRange().
252               It's faster to handle the last block separately because its size
253               needs to be checked separately. */
254            haveBytes = tr_bitfieldCountRange( &cp->blockBitfield, f, l );
255            haveBytes *= cp->tor->blockSize;
256        }
257        if( tr_bitfieldHas( &cp->blockBitfield, l ) ) /* handle the last block */
[12248]258            haveBytes += tr_torBlockCountBytes( cp->tor, l );
[12531]259        assert(  haveBytes <= pieceByteSize );
260        return pieceByteSize - haveBytes;
[12248]261    }
[7578]262}
[7692]263
[12204]264bool
[12012]265tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
[7692]266{
[12012]267    if( cp->tor->info.files[i].length == 0 )
[12204]268        return true;
[12248]269    else {
270        tr_block_index_t f, l;
271        tr_torGetFileBlockRange( cp->tor, i, &f, &l );
272        return tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 ) == (l+1-f);
273    }
[12012]274}
[7692]275
[12248]276void *
277tr_cpCreatePieceBitfield( const tr_completion * cp, size_t * byte_count )
[12012]278{
[12248]279    void * ret;
280    tr_bitfield pieces;
[12012]281    const tr_piece_index_t n = cp->tor->info.pieceCount;
[12248]282    tr_bitfieldConstruct( &pieces, n );
[7692]283
[12248]284    if( tr_cpHasAll( cp ) )
285        tr_bitfieldSetHasAll( &pieces );
286    else if( !tr_cpHasNone( cp ) ) {
287        tr_piece_index_t i;
[12902]288        bool * flags = tr_new( bool, n );
[12248]289        for( i=0; i<n; ++i )
[12902]290            flags[i] = tr_cpPieceIsComplete( cp, i );
291        tr_bitfieldSetFromFlags( &pieces, flags, n );
292        tr_free( flags );
[12248]293    }
[11797]294
[12248]295    ret = tr_bitfieldGetRaw( &pieces, byte_count );
296    tr_bitfieldDestruct( &pieces );
297    return ret;
[7692]298}
[12248]299
300double
301tr_cpPercentComplete( const tr_completion * cp )
302{
303    const double ratio = tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
304
305    if( (int)ratio == TR_RATIO_NA )
306        return 0.0;
307    else if( (int)ratio == TR_RATIO_INF )
308        return 1.0;
309    else
310        return ratio;
311}
312
313double
314tr_cpPercentDone( const tr_completion * cp )
315{
316    const double ratio = tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
317    const int iratio = (int)ratio;
318    return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
319}
Note: See TracBrowser for help on using the repository browser.