source: trunk/libtransmission/completion.c @ 7027

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

(libT) micro-optimizations suggested by cachegrind

  • Property svn:keywords set to Date Rev Author Id
File size: 9.9 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 7027 2008-11-03 17:01:08Z 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,
63            sizeof( uint16_t ) * cp->tor->info.pieceCount );
64    cp->sizeNow = 0;
65    cp->sizeWhenDoneIsDirty = 1;
66}
67
68tr_completion *
69tr_cpInit( tr_torrent * tor )
70{
71    tr_completion * cp  = tr_new( tr_completion, 1 );
72
73    cp->tor             = tor;
74    cp->blockBitfield   = tr_bitfieldNew( tor->blockCount );
75    cp->pieceBitfield   = tr_bitfieldNew( tor->info.pieceCount );
76    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
77    tr_cpReset( cp );
78    return cp;
79}
80
81void
82tr_cpClose( tr_completion * cp )
83{
84    tr_free        ( cp->completeBlocks );
85    tr_bitfieldFree( cp->pieceBitfield );
86    tr_bitfieldFree( cp->blockBitfield );
87    tr_free        ( cp );
88}
89
90void
91tr_cpInvalidateDND( tr_completion * cp )
92{
93    cp->sizeWhenDoneIsDirty = 1;
94}
95
96uint64_t
97tr_cpSizeWhenDone( const tr_completion * ccp )
98{
99    if( ccp->sizeWhenDoneIsDirty )
100    {
101        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
102        const tr_torrent * tor = cp->tor;
103        const tr_info *    info = &tor->info;
104        tr_piece_index_t   i;
105        uint64_t           size = 0;
106
107        for( i = 0; i < info->pieceCount; ++i )
108        {
109            if( !info->pieces[i].dnd )
110            {
111                /* we want the piece... */
112                size += tr_torPieceCountBytes( tor, i );
113            }
114            else if( tr_cpPieceIsComplete( cp, i ) )
115            {
116                /* we have the piece... */
117                size += tr_torPieceCountBytes( tor, i );
118            }
119            else if( cp->completeBlocks[i] )
120            {
121                /* we have part of the piece... */
122                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
123                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor,
124                                                                       i );
125                tr_block_index_t       j;
126                for( j = b; j < e; ++j )
127                    if( tr_cpBlockIsComplete( cp, j ) )
128                        size += tr_torBlockCountBytes( tor, j );
129            }
130        }
131
132        cp->sizeWhenDoneLazy = size;
133        cp->sizeWhenDoneIsDirty = 0;
134    }
135
136    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
137    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
138    return ccp->sizeWhenDoneLazy;
139}
140
141int
142tr_cpPieceIsComplete( const tr_completion * cp,
143                      tr_piece_index_t      piece )
144{
145    return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor,
146                                                                piece );
147}
148
149const tr_bitfield *
150tr_cpPieceBitfield( const tr_completion * cp )
151{
152    return cp->pieceBitfield;
153}
154
155void
156tr_cpPieceAdd( tr_completion *  cp,
157               tr_piece_index_t piece )
158{
159    const tr_torrent *     tor = cp->tor;
160    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
161    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
162    tr_block_index_t       i;
163
164    for( i = start; i < end; ++i )
165        tr_cpBlockAdd( cp, i );
166}
167
168void
169tr_cpPieceRem( tr_completion *  cp,
170               tr_piece_index_t piece )
171{
172    const tr_torrent *     tor = cp->tor;
173    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
174    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
175    tr_block_index_t       block;
176
177    assert( cp );
178    assert( piece < tor->info.pieceCount );
179    assert( start < tor->blockCount );
180    assert( start <= end );
181    assert( end <= tor->blockCount );
182
183    for( block = start; block < end; ++block )
184        if( tr_cpBlockIsComplete( cp, block ) )
185            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
186
187    cp->sizeWhenDoneIsDirty = 1;
188    cp->completeBlocks[piece] = 0;
189    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
190    tr_bitfieldRem( cp->pieceBitfield, piece );
191}
192
193int
194tr_cpBlockIsComplete( const tr_completion * cp,
195                      tr_block_index_t      block )
196{
197    return tr_bitfieldHas( cp->blockBitfield, block );
198}
199
200void
201tr_cpBlockAdd( tr_completion *  cp,
202               tr_block_index_t block )
203{
204    const tr_torrent * tor = cp->tor;
205
206    if( !tr_cpBlockIsComplete( cp, block ) )
207    {
208        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
209        const int              blockSize = tr_torBlockCountBytes( tor,
210                                                                  block );
211
212        ++cp->completeBlocks[piece];
213
214        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
215            tr_bitfieldAdd( cp->pieceBitfield, piece );
216
217        tr_bitfieldAdd( cp->blockBitfield, block );
218
219        cp->sizeNow += blockSize;
220
221        cp->sizeWhenDoneIsDirty = 1;
222    }
223}
224
225const tr_bitfield *
226tr_cpBlockBitfield( const tr_completion * cp )
227{
228    assert( cp );
229    assert( cp->blockBitfield );
230    assert( cp->blockBitfield->bits );
231    assert( cp->blockBitfield->bitCount );
232
233    return cp->blockBitfield;
234}
235
236int
237tr_cpBlockBitfieldSet( tr_completion * cp,
238                       tr_bitfield *   bitfield )
239{
240    int success = FALSE;
241
242    assert( cp );
243    assert( bitfield );
244    assert( cp->blockBitfield );
245
246    if( tr_bitfieldTestFast( bitfield, cp->tor->blockCount - 1 ) )
247    {
248        tr_block_index_t i;
249        tr_cpReset( cp );
250        for( i = 0; i < cp->tor->blockCount; ++i )
251            if( tr_bitfieldHasFast( bitfield, i ) )
252                tr_cpBlockAdd( cp, i );
253        success = TRUE;
254    }
255
256    return success;
257}
258
259int
260tr_cpMissingBlocksInPiece( const tr_completion * cp,
261                           tr_piece_index_t      piece )
262{
263    return tr_torPieceCountBlocks( cp->tor,
264                                   piece ) - cp->completeBlocks[piece];
265}
266
267/***
268****
269***/
270
271float
272tr_cpPercentDone( const tr_completion * cp )
273{
274    return tr_getRatio( cp->sizeNow, tr_cpSizeWhenDone( cp ) );
275}
276
277float
278tr_cpPercentComplete( const tr_completion * cp )
279{
280    return tr_getRatio( cp->sizeNow, cp->tor->info.totalSize );
281}
282
283uint64_t
284tr_cpLeftUntilDone( const tr_completion * cp )
285{
286    return tr_cpSizeWhenDone( cp ) - cp->sizeNow;
287}
288
289uint64_t
290tr_cpLeftUntilComplete( const tr_completion * cp )
291{
292    return cp->tor->info.totalSize - cp->sizeNow;
293}
294
295tr_completeness
296tr_cpGetStatus( const tr_completion * cp )
297{
298    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_CP_COMPLETE;
299    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_CP_DONE;
300    return TR_CP_INCOMPLETE;
301}
302
303uint64_t
304tr_cpHaveValid( const tr_completion * cp )
305{
306    uint64_t                  b = 0;
307    tr_piece_index_t          i;
308    const tr_torrent        * tor            = cp->tor;
309    const uint64_t            pieceSize      = tor->info.pieceSize;
310    const uint64_t            lastPieceSize  = tor->lastPieceSize;
311    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
312
313    for( i=0; i!=lastPiece; ++i )
314        if( tr_cpPieceIsComplete( cp, i ) )
315            b += pieceSize;
316
317    if( tr_cpPieceIsComplete( cp, lastPiece ) )
318        b += lastPieceSize;
319
320    return b;
321}
322
323uint64_t
324tr_cpHaveTotal( const tr_completion * cp )
325{
326    return cp->sizeNow;
327}
328
329void
330tr_cpGetAmountDone( const tr_completion * cp,
331                    float *               tab,
332                    int                   tabCount )
333{
334    int                i;
335    const tr_torrent * tor = cp->tor;
336    const float        interval = tor->info.pieceCount / (float)tabCount;
337    const int          isComplete = tr_cpGetStatus ( tor->completion ) ==
338                                    TR_CP_COMPLETE;
339
340    for( i = 0; i < tabCount; ++i )
341    {
342        const tr_piece_index_t piece = i * interval;
343
344        if( tor == NULL )
345            tab[i] = 0.0f;
346        else if( isComplete || tr_cpPieceIsComplete( cp, piece ) )
347            tab[i] = 1.0f;
348        else
349            tab[i] = (float)cp->completeBlocks[piece] /
350                     tr_torPieceCountBlocks( tor, piece );
351    }
352}
353
Note: See TracBrowser for help on using the repository browser.