source: trunk/libtransmission/completion.c @ 2891

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

added support for `corrupt' announce tag s.t. corrupted bytes don't count towards your download ratio

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