source: trunk/libtransmission/completion.c @ 2544

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

this looks bug but it's not: just janitorial cleanup, moving #includes from headers into source file

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