source: trunk/libtransmission/completion.c @ 3775

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

undoing the r3773-r3774 experiment.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.0 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 3775 2007-11-09 20:07:52Z 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    assert( piece >= 0 );
141    assert( piece < cp->tor->info.pieceCount );
142    assert( cp->completeBlocks[piece] <= tr_torPieceCountBlocks(cp->tor,piece) );
143
144    return cp->completeBlocks[piece] == tr_torPieceCountBlocks(cp->tor,piece);
145}
146
147const tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp )
148{
149    return cp->pieceBitfield;
150}
151
152void tr_cpPieceAdd( tr_completion * cp, int piece )
153{
154    const tr_torrent * tor = cp->tor;
155    const int start = tr_torPieceFirstBlock(tor,piece);
156    const int end = start + tr_torPieceCountBlocks(tor,piece);
157    int i;
158
159    for( i=start; i<end; ++i )
160        tr_cpBlockAdd( cp, i );
161}
162
163void tr_cpPieceRem( tr_completion * cp, int piece )
164{
165    const tr_torrent * tor = cp->tor;
166    const int start = tr_torPieceFirstBlock(tor,piece);
167    const int end = start + tr_torPieceCountBlocks(tor,piece);
168    int block;
169
170    assert( cp != NULL );
171    assert( 0 <= piece );
172    assert( piece < tor->info.pieceCount );
173    assert( 0 <= start );
174    assert( start < tor->blockCount );
175    assert( start <= end );
176    assert( end <= tor->blockCount );
177
178    for( block=start; block<end; ++block ) {
179        if( tr_cpBlockIsComplete( cp, block ) ) {
180            const int blockSize = tr_torBlockCountBytes( tor, block );
181            cp->completeHave -= blockSize;
182            if( !tor->info.pieces[piece].dnd )
183                cp->doneHave -= blockSize;
184        }
185    }
186
187    cp->completeBlocks[piece] = 0;
188    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
189    tr_bitfieldRem( cp->pieceBitfield, piece );
190}
191
192int tr_cpBlockIsComplete( const tr_completion * cp, int block )
193{
194    return tr_bitfieldHas( cp->blockBitfield, block ) ? 1 : 0;
195}
196
197void
198tr_cpBlockAdd( tr_completion * cp, int block )
199{
200    const tr_torrent * tor = cp->tor;
201
202    if( !tr_cpBlockIsComplete( cp, block ) )
203    {
204        const int piece = tr_torBlockPiece( tor, block );
205        const int blockSize = tr_torBlockCountBytes( tor, block );
206
207        ++cp->completeBlocks[piece];
208
209        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
210            tr_bitfieldAdd( cp->pieceBitfield, piece );
211
212        tr_bitfieldAdd( cp->blockBitfield, block );
213
214        cp->completeHave += blockSize;
215
216        if( !tor->info.pieces[piece].dnd )
217            cp->doneHave += blockSize;
218    }
219}
220
221const tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp )
222{
223    assert( cp != NULL );
224
225    return cp->blockBitfield;
226}
227
228void
229tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
230{
231    int i;
232
233    assert( cp != NULL );
234    assert( bitfield != NULL );
235
236    tr_cpReset( cp );
237
238    for( i=0; i < cp->tor->blockCount; ++i )
239        if( tr_bitfieldHas( bitfield, i ) )
240            tr_cpBlockAdd( cp, i );
241}
242
243float tr_cpPercentBlocksInPiece( const tr_completion * cp, int piece )
244{
245    assert( cp != NULL );
246
247    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
248}
249
250/***
251****
252***/
253
254float
255tr_cpPercentComplete ( const tr_completion * cp )
256{
257    return (double)cp->completeHave / cp->tor->info.totalSize;
258}
259
260uint64_t
261tr_cpLeftUntilComplete ( const tr_completion * cp )
262{
263    return cp->tor->info.totalSize - cp->completeHave;
264}
265
266float
267tr_cpPercentDone( const tr_completion * cp )
268{
269    tr_cpEnsureDoneValid( cp );
270
271    return cp->doneTotal ? (double)cp->doneHave / cp->doneTotal : 1.0;
272}
273
274uint64_t
275tr_cpLeftUntilDone ( const tr_completion * cp )
276{
277    tr_cpEnsureDoneValid( cp );
278
279    return cp->doneTotal - cp->doneHave;
280}
281
282cp_status_t
283tr_cpGetStatus ( const tr_completion * cp )
284{
285    if( cp->completeHave >= cp->tor->info.totalSize )
286        return TR_CP_COMPLETE;
287
288    tr_cpEnsureDoneValid( cp );
289
290    if( cp->doneHave >= cp->doneTotal )
291        return TR_CP_DONE;
292
293    return TR_CP_INCOMPLETE;
294}
295
296uint64_t
297tr_cpHaveValid( const tr_completion * cp )
298{
299    uint64_t b = 0;
300    const tr_torrent * tor = cp->tor;
301    const tr_info * info = &tor->info;
302    int i;
303
304    for( i=0; i<info->pieceCount; ++i )
305        if( tr_cpPieceIsComplete( cp, i ) )
306            ++b;
307
308    b *= info->pieceSize;
309
310    if( tr_cpPieceIsComplete( cp, info->pieceCount-1 ) )
311        b -= (info->pieceSize - (info->totalSize % info->pieceSize));
312
313   return b;
314}
315
316uint64_t
317tr_cpHaveTotal( const tr_completion * cp )
318{
319   return cp->completeHave;
320}
Note: See TracBrowser for help on using the repository browser.