source: trunk/libtransmission/completion.c @ 13113

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

(trunk libT) #4684 "tr_cpSizeWhenDone() is slow for huge torrents that we're only partially downloading" -- fixed.

There are actually two different implementations of the byte-counting in that function: a slower implementation was added prior to 2.40 in r12918 to double-check the standard implementation. This checking was added to help smoke out a bug that was fixed in r12920, but I forgot to remove that slower implementation.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.2 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 13113 2011-12-22 19:35:13Z 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                    tr_block_index_t f, l;
169                    tr_torGetPieceBlockRange( cp->tor, p, &f, &l );
170
171                    n = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
172                    n *= cp->tor->blockSize;
173                    if( l == ( cp->tor->blockCount - 1 )  && tr_bitfieldHas( &cp->blockBitfield, l ) )
174                        n -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
175                }
176
177                assert( n <= tr_torPieceCountBytes( tor, p ) );
178                size += n;
179            }
180        }
181
182        assert( size <= inf->totalSize );
183        assert( size >= cp->sizeNow );
184
185        cp->sizeWhenDoneLazy = size;
186        cp->sizeWhenDoneIsDirty = false;
187    }
188
189    return ccp->sizeWhenDoneLazy;
190}
191
192uint64_t
193tr_cpLeftUntilDone( const tr_completion * cp )
194{
195    const uint64_t sizeWhenDone = tr_cpSizeWhenDone( cp );
196
197    assert( sizeWhenDone >= cp->sizeNow );
198
199    return sizeWhenDone - cp->sizeNow;
200}
201
202void
203tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
204{
205    int i;
206    const bool seed = tr_cpHasAll( cp );
207    const float interval = cp->tor->info.pieceCount / (float)tabCount;
208
209    for( i=0; i<tabCount; ++i ) {
210        if( seed )
211            tab[i] = 1.0f;
212        else {
213            tr_block_index_t f, l;
214            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
215            tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
216            tab[i] = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 )
217                                                            / (float)(l+1-f);
218        }
219    }
220}
221
222size_t
223tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
224{
225    if( tr_cpHasAll( cp ) )
226        return 0;
227    else {
228        tr_block_index_t f, l;
229        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
230        return (l+1-f) - tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
231    }
232}
233
234size_t
235tr_cpMissingBytesInPiece( const tr_completion * cp, tr_piece_index_t piece )
236{
237    if( tr_cpHasAll( cp ) )
238        return 0;
239    else {
240        size_t haveBytes = 0;
241        tr_block_index_t f, l;
242        const size_t pieceByteSize = tr_torPieceCountBytes( cp->tor, piece );
243        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
244        if( f != l ) {
245            /* nb: we don't pass the usual l+1 here to tr_bitfieldCountRange().
246               It's faster to handle the last block separately because its size
247               needs to be checked separately. */
248            haveBytes = tr_bitfieldCountRange( &cp->blockBitfield, f, l );
249            haveBytes *= cp->tor->blockSize;
250        }
251        if( tr_bitfieldHas( &cp->blockBitfield, l ) ) /* handle the last block */
252            haveBytes += tr_torBlockCountBytes( cp->tor, l );
253        assert(  haveBytes <= pieceByteSize );
254        return pieceByteSize - haveBytes;
255    }
256}
257
258bool
259tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
260{
261    if( cp->tor->info.files[i].length == 0 )
262        return true;
263    else {
264        tr_block_index_t f, l;
265        tr_torGetFileBlockRange( cp->tor, i, &f, &l );
266        return tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 ) == (l+1-f);
267    }
268}
269
270void *
271tr_cpCreatePieceBitfield( const tr_completion * cp, size_t * byte_count )
272{
273    void * ret;
274    tr_bitfield pieces;
275    const tr_piece_index_t n = cp->tor->info.pieceCount;
276    tr_bitfieldConstruct( &pieces, n );
277
278    if( tr_cpHasAll( cp ) )
279        tr_bitfieldSetHasAll( &pieces );
280    else if( !tr_cpHasNone( cp ) ) {
281        tr_piece_index_t i;
282        bool * flags = tr_new( bool, n );
283        for( i=0; i<n; ++i )
284            flags[i] = tr_cpPieceIsComplete( cp, i );
285        tr_bitfieldSetFromFlags( &pieces, flags, n );
286        tr_free( flags );
287    }
288
289    ret = tr_bitfieldGetRaw( &pieces, byte_count );
290    tr_bitfieldDestruct( &pieces );
291    return ret;
292}
293
294double
295tr_cpPercentComplete( const tr_completion * cp )
296{
297    const double ratio = tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
298
299    if( (int)ratio == TR_RATIO_NA )
300        return 0.0;
301    else if( (int)ratio == TR_RATIO_INF )
302        return 1.0;
303    else
304        return ratio;
305}
306
307double
308tr_cpPercentDone( const tr_completion * cp )
309{
310    const double ratio = tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
311    const int iratio = (int)ratio;
312    return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
313}
Note: See TracBrowser for help on using the repository browser.