source: trunk/libtransmission/completion.c @ 3105

Last change on this file since 3105 was 3105, checked in by livings124, 14 years ago

merge encryption branch to trunk (xcode project is still out of date)

  • Property svn:keywords set to Date Rev Author Id
File size: 7.8 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 3105 2007-09-20 16:32:01Z livings124 $
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_t * 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_t * 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.