source: trunk/libtransmission/completion.c @ 12902

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

#4496 'freeze when having a huge torrent' -- add a bitfield helper function to init the bitfield from an array of flags.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.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 12902 2011-09-20 23:39:40Z 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    cp->sizeNow *= cp->tor->blockSize;
52    if( tr_bitfieldHas( b, cp->tor->blockCount-1 ) )
53        cp->sizeNow -= ( cp->tor->blockSize - cp->tor->lastBlockSize );
54}
55
56/***
57****
58***/
59
60tr_completeness
61tr_cpGetStatus( const tr_completion * cp )
62{
63    if( tr_cpHasAll( cp ) ) return TR_SEED;
64    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
65    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
66    return TR_LEECH;
67}
68
69void
70tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
71{
72    tr_block_index_t i, f, l;
73    const tr_torrent * tor = cp->tor;
74
75    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
76
77    for( i=f; i<=l; ++i )
78        if( tr_cpBlockIsComplete( cp, i ) )
79            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
80
81    cp->haveValidIsDirty = true;
82    cp->sizeWhenDoneIsDirty = true;
83    tr_bitfieldRemRange( &cp->blockBitfield, f, l+1 );
84}
85
86void
87tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
88{
89    tr_block_index_t i, f, l;
90    tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
91
92    for( i=f; i<=l; ++i )
93        tr_cpBlockAdd( cp, i );
94}
95
96void
97tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
98{
99    const tr_torrent * tor = cp->tor;
100
101    if( !tr_cpBlockIsComplete( cp, block ) )
102    {
103        tr_bitfieldAdd( &cp->blockBitfield, block );
104        cp->sizeNow += tr_torBlockCountBytes( tor, block );
105
106        cp->haveValidIsDirty = true;
107        cp->sizeWhenDoneIsDirty = true;
108    }
109}
110
111/***
112****
113***/
114
115uint64_t
116tr_cpHaveValid( const tr_completion * ccp )
117{
118    if( ccp->haveValidIsDirty )
119    {
120        tr_piece_index_t i;
121        uint64_t size = 0;
122        tr_completion * cp = (tr_completion *) ccp; /* mutable */
123        const tr_torrent * tor = ccp->tor;
124        const tr_info * info = &tor->info;
125
126        for( i=0; i<info->pieceCount; ++i )
127            if( tr_cpPieceIsComplete( ccp, i ) )
128                size += tr_torPieceCountBytes( tor, i );
129
130        cp->haveValidLazy = size;
131        cp->haveValidIsDirty = false;
132    }
133
134    return ccp->haveValidLazy;
135}
136
137uint64_t
138tr_cpSizeWhenDone( const tr_completion * ccp )
139{
140    if( ccp->sizeWhenDoneIsDirty )
141    {
142        uint64_t size = 0;
143        const tr_torrent * tor = ccp->tor;
144        tr_completion * cp = (tr_completion *) ccp; /* mutable */
145
146        if( tr_cpHasAll( ccp ) )
147        {
148            size = tor->info.totalSize;
149        }
150        else
151        {
152            tr_piece_index_t p;
153
154            for( p=0; p<tor->info.pieceCount; ++p )
155            {
156                if( !tor->info.pieces[p].dnd )
157                {
158                    size += tr_torPieceCountBytes( tor, p );
159                }
160                else
161                {
162                    tr_block_index_t b, f, l;
163                    tr_torGetPieceBlockRange( cp->tor, p, &f, &l );
164                    for( b=f; b<=l; ++b )
165                        if( tr_cpBlockIsComplete( cp, b ) )
166                            size += tr_torBlockCountBytes( tor, b );
167                }
168            }
169        }
170
171        cp->sizeWhenDoneLazy = size;
172        cp->sizeWhenDoneIsDirty = false;
173    }
174
175    return ccp->sizeWhenDoneLazy;
176}
177
178void
179tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
180{
181    int i;
182    const bool seed = tr_cpHasAll( cp );
183    const float interval = cp->tor->info.pieceCount / (float)tabCount;
184
185    for( i=0; i<tabCount; ++i ) {
186        if( seed )
187            tab[i] = 1.0f;
188        else {
189            tr_block_index_t f, l;
190            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
191            tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
192            tab[i] = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 )
193                                                            / (float)(l+1-f);
194        }
195    }
196}
197
198size_t
199tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
200{
201    if( tr_cpHasAll( cp ) )
202        return 0;
203    else {
204        tr_block_index_t f, l;
205        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
206        return (l+1-f) - tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 );
207    }
208}
209
210size_t
211tr_cpMissingBytesInPiece( const tr_completion * cp, tr_piece_index_t piece )
212{
213    if( tr_cpHasAll( cp ) )
214        return 0;
215    else {
216        size_t haveBytes = 0;
217        tr_block_index_t f, l;
218        const size_t pieceByteSize = tr_torPieceCountBytes( cp->tor, piece );
219        tr_torGetPieceBlockRange( cp->tor, piece, &f, &l );
220        if( f != l ) {
221            /* nb: we don't pass the usual l+1 here to tr_bitfieldCountRange().
222               It's faster to handle the last block separately because its size
223               needs to be checked separately. */
224            haveBytes = tr_bitfieldCountRange( &cp->blockBitfield, f, l );
225            haveBytes *= cp->tor->blockSize;
226        }
227        if( tr_bitfieldHas( &cp->blockBitfield, l ) ) /* handle the last block */
228            haveBytes += tr_torBlockCountBytes( cp->tor, l );
229        assert(  haveBytes <= pieceByteSize );
230        return pieceByteSize - haveBytes;
231    }
232}
233
234bool
235tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
236{
237    if( cp->tor->info.files[i].length == 0 )
238        return true;
239    else {
240        tr_block_index_t f, l;
241        tr_torGetFileBlockRange( cp->tor, i, &f, &l );
242        return tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 ) == (l+1-f);
243    }
244}
245
246void *
247tr_cpCreatePieceBitfield( const tr_completion * cp, size_t * byte_count )
248{
249    void * ret;
250    tr_bitfield pieces;
251    const tr_piece_index_t n = cp->tor->info.pieceCount;
252    tr_bitfieldConstruct( &pieces, n );
253
254    if( tr_cpHasAll( cp ) )
255        tr_bitfieldSetHasAll( &pieces );
256    else if( !tr_cpHasNone( cp ) ) {
257        tr_piece_index_t i;
258        bool * flags = tr_new( bool, n );
259        for( i=0; i<n; ++i )
260            flags[i] = tr_cpPieceIsComplete( cp, i );
261        tr_bitfieldSetFromFlags( &pieces, flags, n );
262        tr_free( flags );
263    }
264
265    ret = tr_bitfieldGetRaw( &pieces, byte_count );
266    tr_bitfieldDestruct( &pieces );
267    return ret;
268}
269
270double
271tr_cpPercentComplete( const tr_completion * cp )
272{
273    const double ratio = tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
274
275    if( (int)ratio == TR_RATIO_NA )
276        return 0.0;
277    else if( (int)ratio == TR_RATIO_INF )
278        return 1.0;
279    else
280        return ratio;
281}
282
283double
284tr_cpPercentDone( const tr_completion * cp )
285{
286    const double ratio = tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
287    const int iratio = (int)ratio;
288    return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
289}
Note: See TracBrowser for help on using the repository browser.