source: trunk/libtransmission/completion.c @ 6072

Last change on this file since 6072 was 6072, checked in by charles, 13 years ago

add first draft of tr_bitfieldFindTrue() courtesy of erdgeist

  • Property svn:keywords set to Date Rev Author Id
File size: 8.9 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 6072 2008-06-07 14:41:31Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <string.h>
27
28#include "transmission.h"
29#include "completion.h"
30#include "torrent.h"
31#include "utils.h"
32
33struct tr_completion
34{
35    unsigned int sizeWhenDoneIsDirty : 1;
36
37    tr_torrent * tor;
38
39    /* do we have this block? */
40    tr_bitfield * blockBitfield;
41
42    /* do we have this piece? */
43    tr_bitfield * pieceBitfield;
44
45    /* a block is complete if and only if we have it */
46    uint16_t * completeBlocks;
47
48    /* number of bytes we'll have when done downloading. [0..info.totalSize]
49       DON'T access this directly; it's a lazy field.
50       use tr_cpSizeWhenDone() instead! */
51    uint64_t sizeWhenDoneLazy;
52
53    /* number of bytes we want or have now. [0..sizeWhenDone] */
54    uint64_t sizeNow;
55};
56
57static void
58tr_cpReset( tr_completion * cp )
59{
60    tr_bitfieldClear( cp->pieceBitfield );
61    tr_bitfieldClear( cp->blockBitfield );
62    memset( cp->completeBlocks, 0, sizeof(uint16_t) * cp->tor->info.pieceCount );
63    cp->sizeNow = 0;
64    cp->sizeWhenDoneIsDirty = 1;
65}
66
67tr_completion *
68tr_cpInit( tr_torrent * tor )
69{
70    tr_completion * cp  = tr_new( tr_completion, 1 );
71    cp->tor             = tor;
72    cp->blockBitfield   = tr_bitfieldNew( tor->blockCount );
73    cp->pieceBitfield   = tr_bitfieldNew( tor->info.pieceCount );
74    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
75    tr_cpReset( cp );
76    return cp;
77}
78
79void
80tr_cpClose( tr_completion * cp )
81{
82    tr_free        ( cp->completeBlocks );
83    tr_bitfieldFree( cp->pieceBitfield );
84    tr_bitfieldFree( cp->blockBitfield );
85    tr_free        ( cp );
86}
87
88void
89tr_cpInvalidateDND ( tr_completion * cp )
90{
91    cp->sizeWhenDoneIsDirty = 1;
92}
93
94uint64_t
95tr_cpSizeWhenDone( const tr_completion * ccp )
96{
97    if( ccp->sizeWhenDoneIsDirty )
98    {
99        tr_completion * cp = (tr_completion *) ccp; /* mutable */
100        const tr_torrent * tor = cp->tor;
101        const tr_info * info = &tor->info;
102        tr_piece_index_t i;
103        uint64_t size = 0;
104
105        for( i=0; i<info->pieceCount; ++i )
106        {
107            if( !info->pieces[i].dnd ) {
108                /* we want the piece... */
109                size += tr_torPieceCountBytes( tor, i );
110            } else if( tr_cpPieceIsComplete( cp, i ) ) {
111                /* we have the piece... */
112                size += tr_torPieceCountBytes( tor, i );
113            } else if( cp->completeBlocks[i] ) {
114                /* we have part of the piece... */
115                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
116                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
117                tr_block_index_t j;
118                for( j=b; j<e; ++j )
119                    if( tr_cpBlockIsComplete( cp, j ) )
120                        size += tr_torBlockCountBytes( tor, j );
121            }
122        }
123
124        cp->sizeWhenDoneLazy = size;
125        cp->sizeWhenDoneIsDirty = 0;
126    }
127
128    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
129    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
130    return ccp->sizeWhenDoneLazy;
131}
132
133int
134tr_cpPieceIsComplete( const tr_completion  * cp,
135                      tr_piece_index_t       piece )
136{
137    return cp->completeBlocks[piece] == tr_torPieceCountBlocks(cp->tor,piece);
138}
139
140const tr_bitfield *
141tr_cpPieceBitfield( const tr_completion * cp )
142{
143    return cp->pieceBitfield;
144}
145
146void
147tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
148{
149    const tr_torrent * tor = cp->tor;
150    const tr_block_index_t start = tr_torPieceFirstBlock(tor,piece);
151    const tr_block_index_t end = start + tr_torPieceCountBlocks(tor, piece);
152    tr_block_index_t i;
153
154    for( i=start; i<end; ++i )
155        tr_cpBlockAdd( cp, i );
156}
157
158void
159tr_cpPieceRem( tr_completion * cp, tr_piece_index_t piece )
160{
161    const tr_torrent * tor = cp->tor;
162    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
163    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
164    tr_block_index_t block;
165
166    assert( cp != NULL );
167    assert( piece < tor->info.pieceCount );
168    assert( start < tor->blockCount );
169    assert( start <= end );
170    assert( end <= tor->blockCount );
171
172    for( block=start; block<end; ++block )
173        if( tr_cpBlockIsComplete( cp, block ) )
174            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
175
176    cp->sizeWhenDoneIsDirty = 1;
177    cp->completeBlocks[piece] = 0;
178    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
179    tr_bitfieldRem( cp->pieceBitfield, piece );
180}
181
182int
183tr_cpBlockFindComplete( const tr_completion * cp,
184                        size_t                startPos,
185                        size_t              * foundPos )
186{
187    return tr_bitfieldFindTrue( cp->blockBitfield, startPos, foundPos );
188}
189
190int
191tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
192{
193    return tr_bitfieldHas( cp->blockBitfield, block );
194}
195
196void
197tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
198{
199    const tr_torrent * tor = cp->tor;
200
201    if( !tr_cpBlockIsComplete( cp, block ) )
202    {
203        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
204        const int blockSize = tr_torBlockCountBytes( tor, block );
205
206        ++cp->completeBlocks[piece];
207
208        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
209            tr_bitfieldAdd( cp->pieceBitfield, piece );
210
211        tr_bitfieldAdd( cp->blockBitfield, block );
212
213        cp->sizeNow += blockSize;
214
215        cp->sizeWhenDoneIsDirty = 1;
216    }
217}
218
219const tr_bitfield *
220tr_cpBlockBitfield( const tr_completion * cp )
221{
222    assert( cp );
223    assert( cp->blockBitfield );
224    assert( cp->blockBitfield->bits );
225    assert( cp->blockBitfield->bitCount );
226
227    return cp->blockBitfield;
228}
229
230tr_errno
231tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
232{
233    tr_block_index_t i;
234
235    assert( cp );
236    assert( bitfield );
237    assert( cp->blockBitfield );
238
239    if( !cp || !bitfield || ( bitfield->byteCount != cp->blockBitfield->byteCount ) )
240        return TR_ERROR_ASSERT;
241
242    tr_cpReset( cp );
243    i = 0;
244    while( tr_bitfieldFindTrue( bitfield, i, &i ) )
245        tr_cpBlockAdd( cp, i++ );
246
247    return 0;
248}
249
250int
251tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
252{
253    return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
254}
255
256/***
257****
258***/
259
260float
261tr_cpPercentDone( const tr_completion * cp )
262{
263    return tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone(cp) );
264}
265
266float
267tr_cpPercentComplete ( const tr_completion * cp )
268{
269    return tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
270}
271
272uint64_t
273tr_cpLeftUntilDone ( const tr_completion * cp )
274{
275    return tr_cpSizeWhenDone(cp) - cp->sizeNow;
276}
277
278uint64_t
279tr_cpLeftUntilComplete ( const tr_completion * cp )
280{
281    return cp->tor->info.totalSize - cp->sizeNow;
282}
283
284cp_status_t
285tr_cpGetStatus ( const tr_completion * cp )
286{
287    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_CP_COMPLETE;
288    if( cp->sizeNow == tr_cpSizeWhenDone(cp) ) return TR_CP_DONE;
289    return TR_CP_INCOMPLETE;
290}
291
292uint64_t
293tr_cpHaveValid( const tr_completion * cp )
294{
295    uint64_t b = 0;
296    tr_piece_index_t i;
297    const tr_torrent * tor = cp->tor;
298
299    for( i=0; i<tor->info.pieceCount; ++i )
300        if( tr_cpPieceIsComplete( cp, i ) )
301            b += tr_torPieceCountBytes( tor, i );
302
303    return b;
304}
305
306uint64_t
307tr_cpHaveTotal( const tr_completion * cp )
308{
309    return cp->sizeNow;
310}
311
312void
313tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
314{
315    const int tabSpan = cp->tor->blockCount / tabCount;
316    tr_block_index_t block_i = 0;
317    int tab_i;
318    for( tab_i=0; tab_i<tabCount; ++tab_i ) {
319        int loop, have;
320        for( loop=have=0; loop<tabSpan; ++loop )
321            if( tr_cpBlockIsComplete( cp, block_i++ ) )
322                ++have;
323        tab[tab_i] = (float)have / tabSpan;
324    }
325}
Note: See TracBrowser for help on using the repository browser.