source: trunk/libtransmission/completion.c @ 2316

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

splitting dnd and priorities apart, and moving the file storage for those fields into fastresume

  • Property svn:keywords set to Date Rev Author Id
File size: 10.1 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 2316 2007-07-10 03:12:46Z 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 "transmission.h"
26#include "completion.h"
27
28struct tr_completion_s
29{
30    tr_torrent_t * tor;
31
32    /* number of peers from whom we've requested this block */
33    uint8_t * blockDownloaders;
34
35    /* do we have this block? */
36    tr_bitfield_t * blockBitfield;
37
38    /* do we have this piece? */
39    tr_bitfield_t * pieceBitfield;
40
41    /* a block is complete if and only if we have it */
42    int * completeBlocks;
43
44    /* rather than calculating these over and over again in loops,
45       just calculate them once */
46    int nBlocksInPiece;
47    int nBlocksInLastPiece;
48};
49
50#define tr_cpCountBlocks(cp,piece) (piece==cp->tor->info.pieceCount-1 \
51    ? cp->nBlocksInLastPiece \
52    : cp->nBlocksInPiece)
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->blockDownloaders = tr_new( uint8_t, tor->blockCount );
62    cp->pieceBitfield    = tr_bitfieldNew( tor->info.pieceCount );
63    cp->completeBlocks   = tr_new( int, tor->info.pieceCount );
64
65    cp->nBlocksInLastPiece = tr_pieceCountBlocks( tor->info.pieceCount - 1 );
66    cp->nBlocksInPiece = tor->info.pieceCount==1 ? cp->nBlocksInLastPiece
67                                                 : tr_pieceCountBlocks( 0 );
68
69    tr_cpReset( cp );
70
71    return cp;
72}
73
74void tr_cpClose( tr_completion_t * cp )
75{
76    tr_free(         cp->completeBlocks );
77    tr_bitfieldFree( cp->pieceBitfield );
78    tr_free(         cp->blockDownloaders );
79    tr_bitfieldFree( cp->blockBitfield );
80    tr_free(         cp );
81}
82
83void tr_cpReset( tr_completion_t * cp )
84{
85    tr_torrent_t * tor = cp->tor;
86    int i;
87
88    tr_bitfieldClear( cp->blockBitfield );
89    memset( cp->blockDownloaders, 0, tor->blockCount );
90    tr_bitfieldClear( cp->pieceBitfield );
91    for( i = 0; i < tor->info.pieceCount; ++i )
92        cp->completeBlocks[i] = 0;
93}
94
95int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
96{
97    return tr_cpPieceIsComplete( cp, piece );
98}
99
100int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
101{
102    return tr_bitfieldHas( cp->pieceBitfield, piece );
103}
104
105const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
106{
107    return cp->pieceBitfield;
108}
109
110void tr_cpPieceAdd( tr_completion_t * cp, int piece )
111{
112    const tr_torrent_t * tor = cp->tor;
113    const int n_blocks = tr_cpCountBlocks( cp, piece );
114    const int startBlock = tr_pieceStartBlock( piece );
115    const int endBlock   = startBlock + n_blocks;
116
117    cp->completeBlocks[piece] = n_blocks;
118    tr_bitfieldAddRange( cp->blockBitfield, startBlock, endBlock-1 );
119    tr_bitfieldAdd( cp->pieceBitfield, piece );
120}
121
122void tr_cpPieceRem( tr_completion_t * cp, int piece )
123{
124    const tr_torrent_t * tor = cp->tor;
125    const int n_blocks = tr_cpCountBlocks( cp, piece );
126    const int startBlock = tr_pieceStartBlock( piece );
127    const int endBlock   = startBlock + n_blocks;
128
129    cp->completeBlocks[piece] = 0;
130    tr_bitfieldRemRange ( cp->blockBitfield, startBlock, endBlock-1 );
131    tr_bitfieldRem( cp->pieceBitfield, piece );
132}
133
134/* Blocks */
135void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
136{
137    ++cp->blockDownloaders[block];
138}
139
140void tr_cpDownloaderRem( tr_completion_t * cp, int block )
141{
142    --cp->blockDownloaders[block];
143}
144
145int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
146{
147    return tr_bitfieldHas( cp->blockBitfield, block );
148}
149
150void tr_cpBlockAdd( tr_completion_t * cp, int block )
151{
152    const tr_torrent_t * tor;
153
154    assert( cp != NULL );
155    assert( cp->tor != NULL );
156    assert( 0 <= block );
157
158    tor = cp->tor;
159
160    if( !tr_cpBlockIsComplete( cp, block ) )
161    {
162        const int piece = tr_blockPiece( block );
163        ++cp->completeBlocks[piece];
164
165        if( cp->completeBlocks[piece] == tr_cpCountBlocks( cp, piece ) )
166            tr_bitfieldAdd( cp->pieceBitfield, piece );
167
168        tr_bitfieldAdd( cp->blockBitfield, block );
169    }
170}
171
172const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
173{
174    assert( cp != NULL );
175
176    return cp->blockBitfield;
177}
178
179void
180tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
181{
182    int i;
183
184    assert( cp != NULL );
185    assert( bitfield != NULL );
186
187    tr_cpReset( cp );
188
189    for( i=0; i < cp->tor->blockCount; ++i )
190        if( tr_bitfieldHas( bitfield, i ) )
191            tr_cpBlockAdd( cp, i );
192}
193
194float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
195{
196    assert( cp != NULL );
197
198    return cp->completeBlocks[piece] / (double)tr_cpCountBlocks( cp, piece );
199}
200
201int
202tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
203{
204    int i;
205    int n;
206    const tr_torrent_t * tor = cp->tor;
207    const int start = tr_pieceStartBlock( piece );
208    const int end   = start + tr_cpCountBlocks( cp, piece );
209
210    n = 0;
211    for( i = start; i < end; ++i )
212        if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
213            ++n;
214
215    return n;
216}
217
218int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
219{
220    int i;
221    const tr_torrent_t * tor = cp->tor;
222    const int start = tr_pieceStartBlock( piece );
223    const int end   = start + tr_cpCountBlocks( cp, piece );
224
225    for( i = start; i < end; ++i )
226        if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
227            return i;
228
229    return -1;
230}
231
232int tr_cpMostMissingBlockInPiece( const tr_completion_t * cp,
233                                  int                     piece,
234                                  int                   * downloaders )
235{
236    tr_torrent_t * tor = cp->tor;
237    int start, count, end, i;
238    int * pool, poolSize, min, ret;
239
240    start = tr_pieceStartBlock( piece );
241    count = tr_cpCountBlocks( cp, piece );
242    end   = start + count;
243
244    pool     = tr_new( int, count );
245    poolSize = 0;
246    min      = 255;
247
248    for( i = start; i < end; i++ )
249    {
250        if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] > min )
251        {
252            continue;
253        }
254        if( cp->blockDownloaders[i] < min )
255        {
256            min      = cp->blockDownloaders[i];
257            poolSize = 0;
258        }
259        if( cp->blockDownloaders[i] <= min )
260        {
261            pool[poolSize++] = i;
262        }
263    }
264
265    if( poolSize > 0 )
266    {
267        ret = pool[0];
268        *downloaders = min;
269    }
270    else
271    {
272        ret = -1;
273    }
274
275    tr_free( pool );
276    return ret;
277}
278
279
280/***
281****
282***/
283
284cp_status_t
285tr_cpGetStatus ( const tr_completion_t * cp )
286{
287    int i;
288    int ret = TR_CP_COMPLETE;
289    const tr_info_t * info;
290
291    assert( cp != NULL );
292    assert( cp->tor != NULL );
293
294    info = &cp->tor->info;
295    for( i=0; i<info->pieceCount; ++i ) {
296        if( tr_cpPieceIsComplete( cp, i ) )
297            continue;
298        if( !info->pieces[i].dnd )
299            return TR_CP_INCOMPLETE;
300        ret = TR_CP_DONE;
301    }
302
303    return ret;
304}
305
306uint64_t
307tr_cpLeftUntilComplete ( const tr_completion_t * cp )
308{
309    int i;
310    uint64_t b=0;
311    const tr_torrent_t * tor;
312    const tr_info_t * info;
313
314    assert( cp != NULL );
315    assert( cp->tor != NULL );
316
317    tor = cp->tor;
318    info = &tor->info;
319    for( i=0; i<info->pieceCount; ++i )
320        if( !tr_cpPieceIsComplete( cp, i ) )
321            b += ( tr_cpCountBlocks( cp, i ) - cp->completeBlocks[ i ] );
322
323    b *= tor->blockSize;
324
325    if( !tr_cpBlockIsComplete( cp, tor->blockCount - 1 ) )
326        b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
327
328    return b;
329}
330
331uint64_t
332tr_cpLeftUntilDone ( const tr_completion_t * cp )
333{
334    int i;
335    uint64_t b=0;
336    const tr_torrent_t * tor;
337    const tr_info_t * info;
338
339    assert( cp != NULL );
340    assert( cp->tor != NULL );
341
342    tor = cp->tor;
343    info = &tor->info;
344
345    for( i=0; i<info->pieceCount; ++i )
346        if( !tr_cpPieceIsComplete( cp, i ) && !info->pieces[i].dnd )
347            b += ( tr_cpCountBlocks( cp, i ) - cp->completeBlocks[ i ] );
348
349    b *= tor->blockSize;
350
351    i = tor->blockCount - 1;
352    if( !tr_cpBlockIsComplete( cp, tor->blockCount-1 ) && !info->pieces[info->pieceCount-1].dnd )
353        b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
354
355    return b;
356}
357
358float
359tr_cpPercentComplete ( const tr_completion_t * cp )
360{
361    const uint64_t tilComplete = tr_cpLeftUntilComplete( cp );
362    const uint64_t total = cp->tor->info.totalSize;
363    const float f = 1.0 - (double)tilComplete / total;
364    return MAX(0.0, f);
365}
366
367float
368tr_cpPercentDone( const tr_completion_t * cp )
369{
370    const uint64_t tilDone = tr_cpLeftUntilDone( cp );
371    const uint64_t total = cp->tor->info.totalSize;
372    const float f = 1.0 - (double)tilDone / total;
373    return MAX(0.0, f);
374}
375
376uint64_t
377tr_cpDownloadedValid( const tr_completion_t * cp )
378{
379    const tr_torrent_t * tor = cp->tor;
380
381    uint64_t b = tr_bitfieldCountTrueBits( cp->blockBitfield ) * tor->blockSize;
382
383    if( tr_bitfieldHas( cp->blockBitfield, tor->blockCount - 1 ) )
384        b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
385
386   return b;
387}
Note: See TracBrowser for help on using the repository browser.