source: trunk/libtransmission/completion.c @ 3815

Last change on this file since 3815 was 3815, checked in by charles, 15 years ago

minor tweaks.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.0 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 3815 2007-11-12 22:26:10Z 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
51static void
52tr_cpReset( tr_completion * cp )
53{
54    tr_torrent * tor = cp->tor;
55
56    tr_bitfieldClear( cp->pieceBitfield );
57    tr_bitfieldClear( cp->blockBitfield );
58    memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
59
60    cp->doneDirty = TRUE;
61    cp->doneHave = 0;
62    cp->doneTotal = 0;
63    cp->completeHave = 0;
64}
65
66tr_completion * tr_cpInit( tr_torrent * tor )
67{
68    tr_completion * cp;
69
70    cp                   = tr_new( tr_completion, 1 );
71    cp->tor              = tor;
72    cp->blockBitfield    = tr_bitfieldNew( tor->blockCount );
73    cp->pieceBitfield    = tr_bitfieldNew( tor->info.pieceCount );
74    cp->completeBlocks   = tr_new( uint16_t, tor->info.pieceCount );
75
76    tr_cpReset( cp );
77
78    return cp;
79}
80
81void tr_cpClose( tr_completion * cp )
82{
83    tr_free(         cp->completeBlocks );
84    tr_bitfieldFree( cp->pieceBitfield );
85    tr_bitfieldFree( cp->blockBitfield );
86    tr_free(         cp );
87}
88
89/**
90***
91**/
92
93static void
94tr_cpEnsureDoneValid( const tr_completion * ccp )
95{
96    const tr_torrent * tor = ccp->tor;
97    const tr_info * info = &tor->info;
98    uint64_t have=0, total=0;
99    int i;
100    tr_completion * cp ;
101
102    if( !ccp->doneDirty )
103        return;
104
105    /* too bad C doesn't have 'mutable' */
106    cp = (tr_completion*) ccp;
107    cp->doneDirty = FALSE;
108
109    for( i=0; i<info->pieceCount; ++i ) {
110        if( !info->pieces[i].dnd ) {
111            total += info->pieceSize;
112            have += cp->completeBlocks[ i ];
113        }
114    }
115
116    have *= tor->blockSize;
117
118    /* the last piece/block is probably smaller than the others */
119    if( !info->pieces[info->pieceCount-1].dnd ) {
120        total -= ( info->pieceSize - tr_torPieceCountBytes(tor,info->pieceCount-1) );
121        if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
122            have -= ( tor->blockSize - tr_torBlockCountBytes(tor,tor->blockCount-1) );
123    }
124
125    assert( have <= total );
126    assert( total <= info->totalSize );
127
128    cp->doneHave = have;
129    cp->doneTotal = total;
130}
131
132void
133tr_cpInvalidateDND ( tr_completion * cp )
134{
135    cp->doneDirty = TRUE;
136}
137
138int
139tr_cpPieceIsComplete( const tr_completion * cp, int piece )
140{
141    assert( piece >= 0 );
142    assert( piece < cp->tor->info.pieceCount );
143    assert( cp->completeBlocks[piece] <= tr_torPieceCountBlocks(cp->tor,piece) );
144
145    return cp->completeBlocks[piece] == tr_torPieceCountBlocks(cp->tor,piece);
146}
147
148const tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp )
149{
150    return cp->pieceBitfield;
151}
152
153void tr_cpPieceAdd( tr_completion * cp, int piece )
154{
155    const tr_torrent * 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 * cp, int piece )
165{
166    const tr_torrent * 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
193int tr_cpBlockIsComplete( const tr_completion * cp, int block )
194{
195    return tr_bitfieldHas( cp->blockBitfield, block ) ? 1 : 0;
196}
197
198void
199tr_cpBlockAdd( tr_completion * cp, int block )
200{
201    const tr_torrent * tor = cp->tor;
202
203    if( !tr_cpBlockIsComplete( cp, block ) )
204    {
205        const int piece = tr_torBlockPiece( tor, block );
206        const int blockSize = tr_torBlockCountBytes( tor, block );
207
208        ++cp->completeBlocks[piece];
209
210        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
211            tr_bitfieldAdd( cp->pieceBitfield, piece );
212
213        tr_bitfieldAdd( cp->blockBitfield, block );
214
215        cp->completeHave += blockSize;
216
217        if( !tor->info.pieces[piece].dnd )
218            cp->doneHave += blockSize;
219    }
220}
221
222const tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp )
223{
224    assert( cp != NULL );
225
226    return cp->blockBitfield;
227}
228
229void
230tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
231{
232    int i;
233
234    assert( cp != NULL );
235    assert( bitfield != NULL );
236
237    tr_cpReset( cp );
238
239    for( i=0; i < cp->tor->blockCount; ++i )
240        if( tr_bitfieldHas( bitfield, i ) )
241            tr_cpBlockAdd( cp, i );
242}
243
244float tr_cpPercentBlocksInPiece( const tr_completion * cp, int piece )
245{
246    assert( cp != NULL );
247
248    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
249}
250
251/***
252****
253***/
254
255float
256tr_cpPercentComplete ( const tr_completion * cp )
257{
258    return (double)cp->completeHave / cp->tor->info.totalSize;
259}
260
261uint64_t
262tr_cpLeftUntilComplete ( const tr_completion * cp )
263{
264    return cp->tor->info.totalSize - cp->completeHave;
265}
266
267float
268tr_cpPercentDone( const tr_completion * cp )
269{
270    tr_cpEnsureDoneValid( cp );
271
272    return cp->doneTotal ? (double)cp->doneHave / cp->doneTotal : 1.0;
273}
274
275uint64_t
276tr_cpLeftUntilDone ( const tr_completion * cp )
277{
278    tr_cpEnsureDoneValid( cp );
279
280    return cp->doneTotal - cp->doneHave;
281}
282
283cp_status_t
284tr_cpGetStatus ( const tr_completion * cp )
285{
286    if( cp->completeHave >= cp->tor->info.totalSize )
287        return TR_CP_COMPLETE;
288
289    tr_cpEnsureDoneValid( cp );
290
291    if( cp->doneHave >= cp->doneTotal )
292        return TR_CP_DONE;
293
294    return TR_CP_INCOMPLETE;
295}
296
297uint64_t
298tr_cpHaveValid( const tr_completion * cp )
299{
300    uint64_t b = 0;
301    const tr_torrent * tor = cp->tor;
302    const tr_info * info = &tor->info;
303    int i;
304
305    for( i=0; i<info->pieceCount; ++i )
306        if( tr_cpPieceIsComplete( cp, i ) )
307            ++b;
308
309    b *= info->pieceSize;
310
311    if( tr_cpPieceIsComplete( cp, info->pieceCount-1 ) )
312        b -= (info->pieceSize - (info->totalSize % info->pieceSize));
313
314    return b;
315}
316
317uint64_t
318tr_cpHaveTotal( const tr_completion * cp )
319{
320    return cp->completeHave;
321}
Note: See TracBrowser for help on using the repository browser.