source: trunk/libtransmission/completion.c @ 4324

Last change on this file since 4324 was 4324, checked in by charles, 14 years ago

a little housekeeping: move tr_torrent stuff into its own header

  • Property svn:keywords set to Date Rev Author Id
File size: 8.0 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 4324 2007-12-25 05:37:32Z charles $
3 *
4 * Copyright (c) 2005 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_torrent * tor;
36
37    /* do we have this block? */
38    tr_bitfield * blockBitfield;
39
40    /* do we have this piece? */
41    tr_bitfield * pieceBitfield;
42
43    /* a block is complete if and only if we have it */
44    uint16_t * completeBlocks;
45
46    uint8_t doneDirty;
47    uint64_t doneHave;
48    uint64_t doneTotal;
49    uint64_t completeHave;
50};
51
52static void
53tr_cpReset( tr_completion * cp )
54{
55    tr_torrent * tor = cp->tor;
56
57    tr_bitfieldClear( cp->pieceBitfield );
58    tr_bitfieldClear( cp->blockBitfield );
59    memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
60
61    cp->doneDirty = TRUE;
62    cp->doneHave = 0;
63    cp->doneTotal = 0;
64    cp->completeHave = 0;
65}
66
67tr_completion * tr_cpInit( tr_torrent * tor )
68{
69    tr_completion * cp;
70
71    cp                   = tr_new( tr_completion, 1 );
72    cp->tor              = tor;
73    cp->blockBitfield    = tr_bitfieldNew( tor->blockCount );
74    cp->pieceBitfield    = tr_bitfieldNew( tor->info.pieceCount );
75    cp->completeBlocks   = tr_new( uint16_t, tor->info.pieceCount );
76
77    tr_cpReset( cp );
78
79    return cp;
80}
81
82void tr_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
90/**
91***
92**/
93
94static void
95tr_cpEnsureDoneValid( const tr_completion * ccp )
96{
97    const tr_torrent * tor = ccp->tor;
98    const tr_info * info = &tor->info;
99    uint64_t have=0, total=0;
100    int i;
101    tr_completion * cp ;
102
103    if( !ccp->doneDirty )
104        return;
105
106    /* too bad C doesn't have 'mutable' */
107    cp = (tr_completion*) ccp;
108    cp->doneDirty = FALSE;
109
110    for( i=0; i<info->pieceCount; ++i ) {
111        if( !info->pieces[i].dnd ) {
112            total += info->pieceSize;
113            have += cp->completeBlocks[ i ];
114        }
115    }
116
117    have *= tor->blockSize;
118
119    /* the last piece/block is probably smaller than the others */
120    if( !info->pieces[info->pieceCount-1].dnd ) {
121        total -= ( info->pieceSize - tr_torPieceCountBytes(tor,info->pieceCount-1) );
122        if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
123            have -= ( tor->blockSize - tr_torBlockCountBytes(tor,tor->blockCount-1) );
124    }
125
126    assert( have <= total );
127    assert( total <= info->totalSize );
128
129    cp->doneHave = have;
130    cp->doneTotal = total;
131}
132
133void
134tr_cpInvalidateDND ( tr_completion * cp )
135{
136    cp->doneDirty = TRUE;
137}
138
139int
140tr_cpPieceIsComplete( const tr_completion * cp, int piece )
141{
142    assert( piece >= 0 );
143    assert( piece < cp->tor->info.pieceCount );
144    assert( cp->completeBlocks[piece] <= tr_torPieceCountBlocks(cp->tor,piece) );
145
146    return cp->completeBlocks[piece] == tr_torPieceCountBlocks(cp->tor,piece);
147}
148
149const tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp )
150{
151    return cp->pieceBitfield;
152}
153
154void tr_cpPieceAdd( tr_completion * cp, int piece )
155{
156    const tr_torrent * tor = cp->tor;
157    const int start = tr_torPieceFirstBlock(tor,piece);
158    const int end = start + tr_torPieceCountBlocks(tor,piece);
159    int i;
160
161    for( i=start; i<end; ++i )
162        tr_cpBlockAdd( cp, i );
163}
164
165void tr_cpPieceRem( tr_completion * cp, int piece )
166{
167    const tr_torrent * tor = cp->tor;
168    const int start = tr_torPieceFirstBlock(tor,piece);
169    const int end = start + tr_torPieceCountBlocks(tor,piece);
170    int block;
171
172    assert( cp != NULL );
173    assert( 0 <= piece );
174    assert( piece < tor->info.pieceCount );
175    assert( 0 <= start );
176    assert( start < tor->blockCount );
177    assert( start <= end );
178    assert( end <= tor->blockCount );
179
180    for( block=start; block<end; ++block ) {
181        if( tr_cpBlockIsComplete( cp, block ) ) {
182            const int blockSize = tr_torBlockCountBytes( tor, block );
183            cp->completeHave -= blockSize;
184            if( !tor->info.pieces[piece].dnd )
185                cp->doneHave -= blockSize;
186        }
187    }
188
189    cp->completeBlocks[piece] = 0;
190    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
191    tr_bitfieldRem( cp->pieceBitfield, piece );
192}
193
194int tr_cpBlockIsComplete( const tr_completion * cp, int block )
195{
196    return tr_bitfieldHas( cp->blockBitfield, block ) ? 1 : 0;
197}
198
199void
200tr_cpBlockAdd( tr_completion * cp, int block )
201{
202    const tr_torrent * tor = cp->tor;
203
204    if( !tr_cpBlockIsComplete( cp, block ) )
205    {
206        const int piece = tr_torBlockPiece( tor, block );
207        const int blockSize = tr_torBlockCountBytes( tor, block );
208
209        ++cp->completeBlocks[piece];
210
211        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
212            tr_bitfieldAdd( cp->pieceBitfield, piece );
213
214        tr_bitfieldAdd( cp->blockBitfield, block );
215
216        cp->completeHave += blockSize;
217
218        if( !tor->info.pieces[piece].dnd )
219            cp->doneHave += blockSize;
220    }
221}
222
223const tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp )
224{
225    assert( cp != NULL );
226
227    return cp->blockBitfield;
228}
229
230void
231tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
232{
233    int i;
234
235    assert( cp != NULL );
236    assert( bitfield != NULL );
237
238    tr_cpReset( cp );
239
240    for( i=0; i < cp->tor->blockCount; ++i )
241        if( tr_bitfieldHas( bitfield, i ) )
242            tr_cpBlockAdd( cp, i );
243}
244
245float tr_cpPercentBlocksInPiece( const tr_completion * cp, int piece )
246{
247    assert( cp != NULL );
248
249    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
250}
251
252/***
253****
254***/
255
256float
257tr_cpPercentComplete ( const tr_completion * cp )
258{
259    return (double)cp->completeHave / cp->tor->info.totalSize;
260}
261
262uint64_t
263tr_cpLeftUntilComplete ( const tr_completion * cp )
264{
265    return cp->tor->info.totalSize - cp->completeHave;
266}
267
268float
269tr_cpPercentDone( const tr_completion * cp )
270{
271    tr_cpEnsureDoneValid( cp );
272
273    return cp->doneTotal ? (double)cp->doneHave / cp->doneTotal : 1.0;
274}
275
276uint64_t
277tr_cpLeftUntilDone ( const tr_completion * cp )
278{
279    tr_cpEnsureDoneValid( cp );
280
281    return cp->doneTotal - cp->doneHave;
282}
283
284cp_status_t
285tr_cpGetStatus ( const tr_completion * cp )
286{
287    if( cp->completeHave >= cp->tor->info.totalSize )
288        return TR_CP_COMPLETE;
289
290    tr_cpEnsureDoneValid( cp );
291
292    if( cp->doneHave >= cp->doneTotal )
293        return TR_CP_DONE;
294
295    return TR_CP_INCOMPLETE;
296}
297
298uint64_t
299tr_cpHaveValid( const tr_completion * cp )
300{
301    uint64_t b = 0;
302    const tr_torrent * tor = cp->tor;
303    const tr_info * info = &tor->info;
304    int i;
305
306    for( i=0; i<info->pieceCount; ++i )
307        if( tr_cpPieceIsComplete( cp, i ) )
308            ++b;
309
310    b *= info->pieceSize;
311
312    if( tr_cpPieceIsComplete( cp, info->pieceCount-1 ) )
313        b -= (info->pieceSize - (info->totalSize % info->pieceSize));
314
315    return b;
316}
317
318uint64_t
319tr_cpHaveTotal( const tr_completion * cp )
320{
321    return cp->completeHave;
322}
Note: See TracBrowser for help on using the repository browser.