source: trunk/libtransmission/completion.c @ 2149

Last change on this file since 2149 was 2149, checked in by livings124, 14 years ago

Merge file selection and torrent creation into the main branch.

The new code for these features is under a new license.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.9 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 2149 2007-06-18 03:40:41Z livings124 $
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                   = malloc( sizeof( tr_completion_t ) );
55    cp->tor              = tor;
56    cp->blockBitfield    = tr_bitfieldNew( tor->blockCount );
57    cp->blockDownloaders = malloc( tor->blockCount );
58    cp->pieceBitfield    = tr_bitfieldNew( tor->info.pieceCount );
59    cp->missingBlocks    = malloc( tor->info.pieceCount * sizeof( int ) );
60    cp->completeBlocks   = malloc( tor->info.pieceCount * sizeof( int ) );
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_bitfieldFree( cp->blockBitfield );
74    free(            cp->blockDownloaders );
75    tr_bitfieldFree( cp->pieceBitfield );
76    free(            cp->missingBlocks );
77    free(            cp->completeBlocks );
78    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     = malloc( count * sizeof( int ) );
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    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    int i;
381    uint64_t have=0;
382    const tr_torrent_t * tor;
383
384    assert( cp != NULL );
385    assert( cp->tor != NULL );
386
387    tor = cp->tor;
388    for( i=0; i<tor->info.pieceCount; ++i )
389        have += cp->completeBlocks[ i ];
390
391    return tor->blockCount ? (float)have / (float)tor->blockCount : 0.0f;
392}
393
394float
395tr_cpPercentDone( const tr_completion_t * cp )
396{
397    int i;
398    uint64_t have=0, total=0;
399    const tr_torrent_t * tor;
400
401    assert( cp != NULL );
402    assert( cp->tor != NULL );
403
404    tor = cp->tor;
405
406    for( i=0; i<tor->info.pieceCount; ++i ) {
407        if( tor->info.pieces[i].priority != TR_PRI_DND) {
408            total += tr_cpCountBlocks( cp, i );
409            have += cp->completeBlocks[ i ];
410        }
411    }
412
413    return !total ? 0.0f : (float)have / (float)total;
414}
415
416uint64_t
417tr_cpDownloadedValid( const tr_completion_t * cp )
418{
419    int i, n;
420    uint64_t b=0;
421
422    for( i=0, n=cp->tor->info.pieceCount; i<n; ++i )
423        b += cp->completeBlocks[ i ];
424
425   return b * cp->tor->blockSize;
426}
Note: See TracBrowser for help on using the repository browser.