source: trunk/libtransmission/completion.c @ 5001

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

#698: have' gets too far ahead of verified'

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