source: trunk/libtransmission/completion.c @ 12248

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

(trunk libT) break the mac build and introduce new crashes.

This is partially to address #4145 "Downloads stuck at 100%" by refactoring the bitset, bitfield, and tr_completion; however, the ripple effect is larger than usual so things may get worse in the short term before getting better.

livings124: to fix the mac build, remove bitset.[ch] from xcode

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