source: trunk/libtransmission/completion.c @ 12531

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

(trunk libT) #4336 "availablility nonsense" -- fix bug in tr_cpMissingBytesInPiece() introduced last week by r12515 for #4332. Add assertions to the nightly build to watch for regressions of this fix.

The bug was that I fixed #4332's off-by-one improperly in tr_cpMissingBlocksInPiece(). The piece's last block has to be calculated separately because its byte size may be different than the other blocks, The mistake in r12515 was that the last block could wind up being counted twice.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.4 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 12531 2011-07-02 13:20:17Z 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        for( i=0; i<n; ++i )
259            if( tr_cpPieceIsComplete( cp, i ) )
260                tr_bitfieldAdd( &pieces, i );
261    }
262
263    ret = tr_bitfieldGetRaw( &pieces, byte_count );
264    tr_bitfieldDestruct( &pieces );
265    return ret;
266}
267
268double
269tr_cpPercentComplete( const tr_completion * cp )
270{
271    const double ratio = tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
272
273    if( (int)ratio == TR_RATIO_NA )
274        return 0.0;
275    else if( (int)ratio == TR_RATIO_INF )
276        return 1.0;
277    else
278        return ratio;
279}
280
281double
282tr_cpPercentDone( const tr_completion * cp )
283{
284    const double ratio = tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
285    const int iratio = (int)ratio;
286    return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
287}
Note: See TracBrowser for help on using the repository browser.