source: trunk/libtransmission/completion.c @ 12177

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

(trunk) it's bad form to #include so many system headers in libtransmission/utils.h...

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