source: trunk/libtransmission/completion.c @ 2555

Last change on this file since 2555 was 2555, checked in by charles, 16 years ago

add portability wrapper for in_port_t...

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