source: trunk/libtransmission/completion.c @ 2207

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

Modified tr_torrentCanAdd() to give the new functionality BMW suggests

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