source: trunk/libtransmission/completion.c @ 3111

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

remove the backwards compatability typedefs at BentMyWookie?'s suggestion. update libT, gtk, daemon, and cli accordingly...

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