source: trunk/libtransmission/completion.c @ 12101

Last change on this file since 12101 was 12101, checked in by jordan, 11 years ago

(trunk libT) #4083 "Wrong shades of progress in Inspector pieces view." -- fixed.

The problem was reported by Rolcol and tracked down by livings124. It's flashing orange because the completion in "availability" doesn't match the completion in in "progress", which corresponds with tr_torrentAvailability() and tr_torrentAmountFinished(). tr_cpGetAmountDone() was recently reworked in r12012 for #4048, which caused the problem. Both functions need to sample the torrent using the same methodology so that their results can be used together.

  • Property svn:keywords set to Date Rev Author Id
File size: 9.3 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 12101 2011-03-05 03:51:57Z jordan $
11 */
12
13#include "transmission.h"
14#include "completion.h"
15#include "torrent.h"
16#include "utils.h"
17
18/***
19****
20***/
21
22static void
23tr_cpReset( tr_completion * cp )
24{
25    tr_bitsetSetHaveNone( &cp->blockBitset );
26    tr_free( cp->completeBlocks );
27    cp->completeBlocks = NULL;
28    cp->sizeNow = 0;
29    cp->sizeWhenDoneIsDirty = TRUE;
30    cp->blocksWantedIsDirty = TRUE;
31    cp->haveValidIsDirty = TRUE;
32}
33
34tr_completion *
35tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
36{
37    cp->tor = tor;
38    cp->completeBlocks = NULL;
39    tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
40    tr_cpReset( cp );
41    return cp;
42}
43
44tr_completion*
45tr_cpDestruct( tr_completion * cp )
46{
47    tr_free( cp->completeBlocks );
48    tr_bitsetDestruct( &cp->blockBitset );
49    return cp;
50}
51
52/***
53****
54***/
55
56static inline tr_bool
57isSeed( const tr_completion * cp )
58{
59    return cp->blockBitset.haveAll;
60}
61
62tr_completeness
63tr_cpGetStatus( const tr_completion * cp )
64{
65    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
66    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
67    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
68    return TR_LEECH;
69}
70
71/* how many blocks are in this piece? */
72static inline uint16_t
73countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
74{
75    return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
76                                             : tor->blockCountInPiece;
77}
78
79static uint16_t *
80getCompleteBlocks( const tr_completion * ccp )
81{
82    if( ccp->completeBlocks == NULL )
83    {
84        tr_completion * cp = (tr_completion*) ccp;
85        cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
86    }
87
88    return ccp->completeBlocks;
89}
90
91void
92tr_cpInvalidateDND( tr_completion * cp )
93{
94    cp->sizeWhenDoneIsDirty = TRUE;
95    cp->blocksWantedIsDirty = TRUE;
96}
97
98tr_block_index_t
99tr_cpBlocksMissing( const tr_completion * ccp )
100{
101    if( isSeed( ccp ) )
102        return 0;
103
104    if( ccp->blocksWantedIsDirty )
105    {
106        tr_piece_index_t   i;
107        tr_block_index_t   wanted = 0;
108        tr_block_index_t   complete = 0;
109        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
110        const uint16_t   * complete_blocks = getCompleteBlocks( cp );
111        const tr_torrent * tor = ccp->tor;
112        const tr_info    * info = &tor->info;
113
114        for( i = 0; i < info->pieceCount; ++i )
115        {
116            if( !info->pieces[i].dnd )
117            {
118                wanted += countBlocksInPiece( tor, i );
119                complete += complete_blocks[i];
120            }
121        }
122
123        cp->blocksWantedLazy = wanted;
124        cp->blocksWantedCompleteLazy = complete;
125        cp->blocksWantedIsDirty = FALSE;
126    }
127
128    return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
129}
130
131void
132tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
133{
134    tr_block_index_t i;
135    tr_block_index_t first;
136    tr_block_index_t last;
137    const tr_torrent * tor = cp->tor;
138    uint16_t * complete_blocks = getCompleteBlocks( cp );
139
140    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
141    for( i=first; i<=last; ++i )
142        if( tr_cpBlockIsComplete( cp, i ) )
143            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
144
145    if( !tor->info.pieces[piece].dnd )
146        cp->blocksWantedCompleteLazy -= complete_blocks[piece];
147
148    cp->sizeWhenDoneIsDirty = TRUE;
149    cp->haveValidIsDirty = TRUE;
150    complete_blocks[piece] = 0;
151    tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
152}
153
154void
155tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
156{
157    tr_block_index_t i;
158    tr_block_index_t first;
159    tr_block_index_t last;
160    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
161
162    for( i=first; i<=last; ++i )
163        tr_cpBlockAdd( cp, i );
164}
165
166void
167tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
168{
169    const tr_torrent * tor = cp->tor;
170
171    if( !tr_cpBlockIsComplete( cp, block ) )
172    {
173        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
174        const int blockSize = tr_torBlockCountBytes( tor, block );
175
176        getCompleteBlocks(cp)[piece]++;
177
178        tr_bitsetAdd( &cp->blockBitset, block );
179
180        cp->sizeNow += blockSize;
181        if( !tor->info.pieces[piece].dnd )
182            cp->blocksWantedCompleteLazy++;
183
184        cp->sizeWhenDoneIsDirty = TRUE;
185        cp->haveValidIsDirty = TRUE;
186    }
187}
188
189
190tr_bool
191tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
192{
193    tr_bool success = FALSE;
194    tr_torrent * tor = cp->tor;
195
196    /* start cp with a state where it thinks we have nothing */
197    tr_cpReset( cp );
198
199    if( blocks->haveAll )
200    {
201        tr_bitsetSetHaveAll( &cp->blockBitset );
202        cp->sizeNow = tor->info.totalSize;
203
204        success = TRUE;
205    }
206    else if( blocks->haveNone )
207    {
208        /* already reset... */
209        success = TRUE;
210    }
211    else
212    {
213        const tr_bitfield * src = &blocks->bitfield;
214        tr_bitfield * tgt = &cp->blockBitset.bitfield;
215
216        tr_bitfieldConstruct( tgt, tor->blockCount );
217
218        /* The bitfield of block flags is typically loaded from a resume file.
219           Test the bitfield's length in case the resume file is corrupt */
220        if(( success = src->byteCount == tgt->byteCount ))
221        {
222            size_t i = 0;
223            uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
224
225            /* init our block bitfield from the one passed in */
226            memcpy( tgt->bits, src->bits, src->byteCount );
227
228            /* update cp.sizeNow and the cp.blockBitset flags */
229            i = tr_bitfieldCountTrueBits( tgt );
230            if( i == tor->blockCount ) {
231                tr_bitsetSetHaveAll( &cp->blockBitset );
232                cp->sizeNow = cp->tor->info.totalSize;
233            } else if( !i ) {
234                tr_bitsetSetHaveNone( &cp->blockBitset );
235                cp->sizeNow = 0;
236            } else {
237                cp->blockBitset.haveAll = cp->blockBitset.haveNone = FALSE;
238                cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
239                cp->sizeNow *= tor->blockSize;
240                if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
241                    cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
242            }
243
244            /* update complete_blocks_in_piece */
245            for( i=0; i<tor->info.pieceCount; ++i ) {
246                 tr_block_index_t first, last;
247                 tr_torGetPieceBlockRange( tor, i, &first, &last );
248                 complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
249            }
250        }
251    }
252
253    return success;
254}
255
256/***
257****
258***/
259
260uint64_t
261tr_cpHaveValid( const tr_completion * ccp )
262{
263    if( ccp->haveValidIsDirty )
264    {
265        tr_piece_index_t   i;
266        uint64_t           size = 0;
267        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
268        const tr_torrent * tor = ccp->tor;
269        const tr_info    * info = &tor->info;
270
271        for( i=0; i<info->pieceCount; ++i )
272            if( tr_cpPieceIsComplete( ccp, i ) )
273                size += tr_torPieceCountBytes( tor, i );
274
275        cp->haveValidIsDirty = FALSE;
276        cp->haveValidLazy = size;
277    }
278
279    return ccp->haveValidLazy;
280}
281
282uint64_t
283tr_cpSizeWhenDone( const tr_completion * ccp )
284{
285    if( ccp->sizeWhenDoneIsDirty )
286    {
287        tr_piece_index_t   i;
288        uint64_t           size = 0;
289        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
290        const tr_torrent * tor = ccp->tor;
291        const tr_info    * info = &tor->info;
292
293        for( i=0; i<info->pieceCount; ++i )
294            if( !info->pieces[i].dnd || tr_cpPieceIsComplete( cp, i ) )
295                size += tr_torPieceCountBytes( tor, i );
296
297        cp->sizeWhenDoneIsDirty = FALSE;
298        cp->sizeWhenDoneLazy = size;
299    }
300
301    return ccp->sizeWhenDoneLazy;
302}
303
304void
305tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
306{
307    int i;
308    const float interval = cp->tor->info.pieceCount / (float)tabCount;
309    const tr_bool seed = isSeed( cp );
310
311    for( i=0; i<tabCount; ++i ) {
312        if( seed )
313            tab[i] = 1.0f;
314        else {
315            const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
316            tab[i] = getCompleteBlocks(cp)[piece] / (float)countBlocksInPiece( cp->tor, piece );
317        }
318    }
319}
320
321int
322tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
323{
324    if( isSeed( cp ) )
325        return 0;
326
327    return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
328}
329
330tr_bool
331tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
332{
333    tr_block_index_t f, l;
334
335    if( cp->tor->info.files[i].length == 0 )
336        return TRUE;
337
338    tr_torGetFileBlockRange( cp->tor, i, &f, &l );
339    return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
340}
341
342tr_bitfield *
343tr_cpCreatePieceBitfield( const tr_completion * cp )
344{
345    tr_piece_index_t i;
346    const tr_piece_index_t n = cp->tor->info.pieceCount;
347    tr_bitfield * bf = tr_bitfieldNew( n );
348
349    for( i=0; i<n; ++i )
350        if( tr_cpPieceIsComplete( cp, i ) )
351            tr_bitfieldAdd( bf, i );
352
353    return bf;
354}
Note: See TracBrowser for help on using the repository browser.