source: trunk/libtransmission/completion.c @ 5597

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

minor tr_torrentStat cleanup

  • Property svn:keywords set to Date Rev Author Id
File size: 9.1 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 5597 2008-04-12 15:56:21Z 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    if( ccp->doneDirty )
98    {
99        const tr_torrent * tor = ccp->tor;
100        const tr_info * info = &tor->info;
101        uint64_t have = 0;
102        uint64_t total = 0;
103        tr_piece_index_t i;
104        tr_completion * cp ;
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}
133
134void
135tr_cpInvalidateDND ( tr_completion * cp )
136{
137    cp->doneDirty = TRUE;
138}
139
140int
141tr_cpPieceIsComplete( const tr_completion  * cp,
142                      tr_piece_index_t       piece )
143{
144    assert( piece < cp->tor->info.pieceCount );
145    assert( cp->completeBlocks[piece] <= tr_torPieceCountBlocks(cp->tor,piece) );
146
147    return cp->completeBlocks[piece] == tr_torPieceCountBlocks(cp->tor,piece);
148}
149
150const tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp )
151{
152    return cp->pieceBitfield;
153}
154
155void
156tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
157{
158    const tr_torrent * tor = cp->tor;
159    const tr_block_index_t start = tr_torPieceFirstBlock(tor,piece);
160    const tr_block_index_t end = start + tr_torPieceCountBlocks(tor, piece);
161    tr_block_index_t i;
162
163    for( i=start; i<end; ++i )
164        tr_cpBlockAdd( cp, i );
165}
166
167void
168tr_cpPieceRem( tr_completion * cp, tr_piece_index_t piece )
169{
170    const tr_torrent * tor = cp->tor;
171    const tr_block_index_t start = tr_torPieceFirstBlock(tor,piece);
172    const tr_block_index_t end = start + tr_torPieceCountBlocks(tor,piece);
173    tr_block_index_t block;
174
175    assert( cp != NULL );
176    assert( piece < tor->info.pieceCount );
177    assert( start < tor->blockCount );
178    assert( start <= end );
179    assert( end <= tor->blockCount );
180
181    for( block=start; block<end; ++block ) {
182        if( tr_cpBlockIsComplete( cp, block ) ) {
183            const int blockSize = tr_torBlockCountBytes( tor, block );
184            cp->completeHave -= blockSize;
185            if( !tor->info.pieces[piece].dnd )
186                cp->doneHave -= blockSize;
187        }
188    }
189
190    cp->completeBlocks[piece] = 0;
191    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
192    tr_bitfieldRem( cp->pieceBitfield, piece );
193
194    assert( cp->completeHave <= tor->info.totalSize );
195    assert( cp->doneHave <= tor->info.totalSize );
196    assert( cp->doneHave <= cp->completeHave );
197}
198
199int
200tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
201{
202    return tr_bitfieldHas( cp->blockBitfield, block ) ? 1 : 0;
203}
204
205void
206tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
207{
208    const tr_torrent * tor = cp->tor;
209
210    if( !tr_cpBlockIsComplete( cp, block ) )
211    {
212        const tr_piece_index_t 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    tr_block_index_t 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
256tr_cpPercentBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
257{
258    assert( cp != NULL );
259
260    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
261}
262
263int
264tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
265{
266    assert( cp != NULL );
267
268    return tr_torPieceCountBlocks(cp->tor,piece) - cp->completeBlocks[piece];
269}
270
271/***
272****
273***/
274
275float
276tr_cpPercentComplete ( const tr_completion * cp )
277{
278    return (double)cp->completeHave / cp->tor->info.totalSize;
279}
280
281uint64_t
282tr_cpLeftUntilComplete ( const tr_completion * cp )
283{
284    assert( cp->tor->info.totalSize >= cp->completeHave );
285
286    return cp->tor->info.totalSize - cp->completeHave;
287}
288
289float
290tr_cpPercentDone( const tr_completion * cp )
291{
292    tr_cpEnsureDoneValid( cp );
293
294    return cp->doneTotal ? (double)cp->doneHave / cp->doneTotal : 1.0;
295}
296
297uint64_t
298tr_cpLeftUntilDone ( const tr_completion * cp )
299{
300    tr_cpEnsureDoneValid( cp );
301
302    return cp->doneTotal - cp->doneHave;
303}
304
305uint64_t
306tr_cpSizeWhenDone( const tr_completion * cp )
307{
308    tr_cpEnsureDoneValid( cp );
309
310    return cp->doneTotal;
311}
312
313cp_status_t
314tr_cpGetStatus ( const tr_completion * cp )
315{
316    assert( cp->tor->info.totalSize >= cp->completeHave );
317
318    if( cp->completeHave == cp->tor->info.totalSize )
319        return TR_CP_COMPLETE;
320
321    tr_cpEnsureDoneValid( cp );
322
323    return cp->doneHave >= cp->doneTotal ? TR_CP_DONE
324                                         : TR_CP_INCOMPLETE;
325}
326
327uint64_t
328tr_cpHaveValid( const tr_completion * cp )
329{
330    uint64_t b = 0;
331    const tr_torrent * tor = cp->tor;
332    const tr_info * info = &tor->info;
333    tr_piece_index_t i;
334
335    for( i=0; i<info->pieceCount; ++i )
336        if( tr_cpPieceIsComplete( cp, i ) )
337            ++b;
338
339    b *= info->pieceSize;
340
341    if( tr_cpPieceIsComplete( cp, info->pieceCount-1 ) )
342        b -= (info->pieceSize - (info->totalSize % info->pieceSize));
343
344    return b;
345}
346
347uint64_t
348tr_cpHaveTotal( const tr_completion * cp )
349{
350    return cp->completeHave;
351}
Note: See TracBrowser for help on using the repository browser.