source: trunk/libtransmission/completion.c @ 5627

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

more hacking on the bencoded resume files

  • Property svn:keywords set to Date Rev Author Id
File size: 9.3 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 5627 2008-04-15 17:00:44Z 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 *
234tr_cpBlockBitfield( const tr_completion * cp )
235{
236    assert( cp );
237    assert( cp->blockBitfield );
238    assert( cp->blockBitfield->bits );
239    assert( cp->blockBitfield->len );
240
241    return cp->blockBitfield;
242}
243
244tr_errno
245tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * bitfield )
246{
247    tr_block_index_t i;
248
249    assert( cp );
250    assert( bitfield );
251    assert( cp->blockBitfield );
252    assert( cp->blockBitfield->len == bitfield->len );
253
254    if( !cp || !bitfield || ( bitfield->len != cp->blockBitfield->len ) )
255        return TR_ERROR_ASSERT;
256
257    tr_cpReset( cp );
258    for( i=0; i < cp->tor->blockCount; ++i )
259        if( tr_bitfieldHas( bitfield, i ) )
260            tr_cpBlockAdd( cp, i );
261
262    return 0;
263}
264
265float
266tr_cpPercentBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
267{
268    assert( cp != NULL );
269
270    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
271}
272
273int
274tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
275{
276    assert( cp != NULL );
277
278    return tr_torPieceCountBlocks(cp->tor,piece) - cp->completeBlocks[piece];
279}
280
281/***
282****
283***/
284
285float
286tr_cpPercentComplete ( const tr_completion * cp )
287{
288    return (double)cp->completeHave / cp->tor->info.totalSize;
289}
290
291uint64_t
292tr_cpLeftUntilComplete ( const tr_completion * cp )
293{
294    assert( cp->tor->info.totalSize >= cp->completeHave );
295
296    return cp->tor->info.totalSize - cp->completeHave;
297}
298
299float
300tr_cpPercentDone( const tr_completion * cp )
301{
302    tr_cpEnsureDoneValid( cp );
303
304    return cp->doneTotal ? (double)cp->doneHave / cp->doneTotal : 1.0;
305}
306
307uint64_t
308tr_cpLeftUntilDone ( const tr_completion * cp )
309{
310    tr_cpEnsureDoneValid( cp );
311
312    return cp->doneTotal - cp->doneHave;
313}
314
315uint64_t
316tr_cpSizeWhenDone( const tr_completion * cp )
317{
318    tr_cpEnsureDoneValid( cp );
319
320    return cp->doneTotal;
321}
322
323cp_status_t
324tr_cpGetStatus ( const tr_completion * cp )
325{
326    assert( cp->tor->info.totalSize >= cp->completeHave );
327
328    if( cp->completeHave == cp->tor->info.totalSize )
329        return TR_CP_COMPLETE;
330
331    tr_cpEnsureDoneValid( cp );
332
333    return cp->doneHave >= cp->doneTotal ? TR_CP_DONE
334                                         : TR_CP_INCOMPLETE;
335}
336
337uint64_t
338tr_cpHaveValid( const tr_completion * cp )
339{
340    uint64_t b = 0;
341    const tr_torrent * tor = cp->tor;
342    const tr_info * info = &tor->info;
343    tr_piece_index_t i;
344
345    for( i=0; i<info->pieceCount; ++i )
346        if( tr_cpPieceIsComplete( cp, i ) )
347            ++b;
348
349    b *= info->pieceSize;
350
351    if( tr_cpPieceIsComplete( cp, info->pieceCount-1 ) )
352        b -= (info->pieceSize - (info->totalSize % info->pieceSize));
353
354    return b;
355}
356
357uint64_t
358tr_cpHaveTotal( const tr_completion * cp )
359{
360    return cp->completeHave;
361}
Note: See TracBrowser for help on using the repository browser.