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
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
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.
9 *
10 * $Id: completion.c 12918 2011-09-26 06:18:48Z jordan $
11 */
12
13#include <assert.h>
14
15#include "transmission.h"
16#include "completion.h"
17#include "torrent.h"
18#include "utils.h"
19
20/***
21****
22***/
23
24static void
25tr_cpReset( tr_completion * cp )
26{
27    cp->sizeNow = 0;
28    cp->sizeWhenDoneIsDirty = true;
29    cp->haveValidIsDirty = true;
30    tr_bitfieldSetHasNone( &cp->blockBitfield );
31}
32
33void
34tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
35{
36    cp->tor = tor;
37    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
38    tr_cpReset( cp );
39}
40
41void
42tr_cpBlockInit( tr_completion * cp, const tr_bitfield * b )
43{
44    tr_cpReset( cp );
45
46    /* set blockBitfield */
47    tr_bitfieldSetFromBitfield( &cp->blockBitfield, b );
48
49    /* set sizeNow */
50    cp->sizeNow = tr_bitfieldCountTrueBits( &cp->blockBitfield );
51    assert( cp->sizeNow <= cp->tor->blockCount );
52    cp->sizeNow *= cp->tor->blockSize;
53    if( tr_bitfieldHas( b, cp->tor->blockCount-1 ) )
54        cp->sizeNow -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
55    assert( cp->sizeNow <= cp->tor->info.totalSize );
56}
57
58/***
59****
60***/
61
62tr_completeness
63tr_cpGetStatus( const tr_completion * cp )
64{
65    if( tr_cpHasAll( cp ) ) return TR_SEED;
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
71void
72tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
73{
74    tr_block_index_t i, f, l;
75    const tr_torrent * tor = cp->tor;
76
77    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
78
79    for( i=f; i<=l; ++i )
80        if( tr_cpBlockIsComplete( cp, i ) )
81            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
82
83    cp->haveValidIsDirty = true;
84    cp->sizeWhenDoneIsDirty = true;
85    tr_bitfieldRemRange( &cp->blockBitfield, f, l+1 );
86}
87
88void
89tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
90{
91    tr_block_index_t i, f, l;
92    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
93
94    for( i=f; i<=l; ++i )
95        tr_cpBlockAdd( cp, i );
96}
97
98void
99tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
100{
101    const tr_torrent * tor = cp->tor;
102
103    if( !tr_cpBlockIsComplete( cp, block ) )
104    {
105        tr_bitfieldAdd( &cp->blockBitfield, block );
106        cp->sizeNow += tr_torBlockCountBytes( tor, block );
107
108        cp->haveValidIsDirty = true;
109        cp->sizeWhenDoneIsDirty = true;
110    }
111}
112
113/***
114****
115***/
116
117uint64_t
118tr_cpHaveValid( const tr_completion * ccp )
119{
120    if( ccp->haveValidIsDirty )
121    {
122        tr_piece_index_t i;
123        uint64_t size = 0;
124        tr_completion * cp = (tr_completion *) ccp; /* mutable */
125        const tr_torrent * tor = ccp->tor;
126        const tr_info * info = &tor->info;
127
128        for( i=0; i<info->pieceCount; ++i )
129            if( tr_cpPieceIsComplete( ccp, i ) )
130                size += tr_torPieceCountBytes( tor, i );
131
132        cp->haveValidLazy = size;
133        cp->haveValidIsDirty = false;
134    }
135
136    return ccp->haveValidLazy;
137}
138
139uint64_t
140tr_cpSizeWhenDone( const tr_completion * ccp )
141{
142    if( ccp->sizeWhenDoneIsDirty )
143    {
144        uint64_t size = 0;
145        const tr_torrent * tor = ccp->tor;
146        const tr_info * inf = tr_torrentInfo( tor );
147        tr_completion * cp = (tr_completion *) ccp; /* mutable */
148
149        if( tr_cpHasAll( ccp ) )
150        {
151            size = inf->totalSize;
152        }
153        else
154        {
155            tr_piece_index_t p;
156
157            for( p=0; p<inf->pieceCount; ++p )
158            {
159                uint64_t n = 0;
160                const uint64_t pieceSize = tr_torPieceCountBytes( tor, p );
161
162                if( !inf->pieces[p].dnd )
163                {
164                    n = pieceSize;
165                }
166                else
167                {
168                    uint64_t o = 0;
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 ) )
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 );
181                }
182
183                assert( n <= tr_torPieceCountBytes( tor, p ) );
184                size += n;
185            }
186        }
187
188        assert( size <= inf->totalSize );
189        assert( size >= cp->sizeNow );
190
191        cp->sizeWhenDoneLazy = size;
192        cp->sizeWhenDoneIsDirty = false;
193    }
194
195    return ccp->sizeWhenDoneLazy;
196}
197
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
208void
209tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
210{
211    int i;
212    const bool seed = tr_cpHasAll( cp );
213    const float interval = cp->tor->info.pieceCount / (float)tabCount;
214
215    for( i=0; i<tabCount; ++i ) {
216        if( seed )
217            tab[i] = 1.0f;
218        else {
219            tr_block_index_t f, l;
220            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
221            tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
222            tab[i] = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 )
223                                                            / (float)(l+1-f);
224        }
225    }
226}
227
228size_t
229tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
230{
231    if( tr_cpHasAll( cp ) )
232        return 0;
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}
239
240size_t
241tr_cpMissingBytesInPiece( const tr_completion * cp, tr_piece_index_t piece )
242{
243    if( tr_cpHasAll( cp ) )
244        return 0;
245    else {
246        size_t haveBytes = 0;
247        tr_block_index_t f, l;
248        const size_t pieceByteSize = tr_torPieceCountBytes( cp->tor, piece );
249        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
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 */
258            haveBytes += tr_torBlockCountBytes( cp->tor, l );
259        assert(  haveBytes <= pieceByteSize );
260        return pieceByteSize - haveBytes;
261    }
262}
263
264bool
265tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
266{
267    if( cp->tor->info.files[i].length == 0 )
268        return true;
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    }
274}
275
276void *
277tr_cpCreatePieceBitfield( const tr_completion * cp, size_t * byte_count )
278{
279    void * ret;
280    tr_bitfield pieces;
281    const tr_piece_index_t n = cp->tor->info.pieceCount;
282    tr_bitfieldConstruct( &pieces, n );
283
284    if( tr_cpHasAll( cp ) )
285        tr_bitfieldSetHasAll( &pieces );
286    else if( !tr_cpHasNone( cp ) ) {
287        tr_piece_index_t i;
288        bool * flags = tr_new( bool, n );
289        for( i=0; i<n; ++i )
290            flags[i] = tr_cpPieceIsComplete( cp, i );
291        tr_bitfieldSetFromFlags( &pieces, flags, n );
292        tr_free( flags );
293    }
294
295    ret = tr_bitfieldGetRaw( &pieces, byte_count );
296    tr_bitfieldDestruct( &pieces );
297    return ret;
298}
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.