source: trunk/libtransmission/completion.c @ 7173

Last change on this file since 7173 was 7173, checked in by charles, 12 years ago

use tr_bool instead of C bitfields. (http://blogs.msdn.com/oldnewthing/archive/2008/11/26/9143050.aspx)

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