source: trunk/libtransmission/completion.c @ 3773

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

on Darwin, use NSCParameterAssert() instead of assert().

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