source: branches/file_selection/libtransmission/completion.c @ 2066

Last change on this file since 2066 was 2066, checked in by charles, 15 years ago

fix oops

  • Property svn:keywords set to Date Rev Author Id
File size: 10.0 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 2066 2007-06-13 16:16:51Z 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                   = 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 = cp->tor;
165    (cp->blockDownloaders[block])--;
166    if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
167    {
168        cp->missingBlocks[tr_blockPiece(block)]++;
169    }
170}
171
172int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
173{
174    return tr_bitfieldHas( cp->blockBitfield, block );
175}
176
177void tr_cpBlockAdd( tr_completion_t * cp, int block )
178{
179    const tr_torrent_t * tor = cp->tor;
180
181    if( !tr_cpBlockIsComplete( cp, block ) )
182    {
183        const int piece = tr_blockPiece( block );
184        ++cp->completeBlocks[piece];
185
186        if( cp->completeBlocks[piece] == tr_cpCountBlocks( cp, piece ) )
187            tr_bitfieldAdd( cp->pieceBitfield, piece );
188
189        if( !cp->blockDownloaders[block] )
190            cp->missingBlocks[piece]--;
191
192        tr_bitfieldAdd( cp->blockBitfield, block );
193    }
194}
195
196const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
197{
198    return cp->blockBitfield;
199}
200
201void
202tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
203{
204    int i;
205    tr_torrent_t * tor = cp->tor;
206
207    tr_cpReset( cp );
208    cp->tor = tor;
209
210    for( i=0; i < cp->tor->blockCount; ++i )
211        if( tr_bitfieldHas( bitfield, i ) )
212            tr_cpBlockAdd( cp, i );
213}
214
215float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
216{
217    return cp->completeBlocks[piece] / (double)tr_cpCountBlocks( cp, piece );
218}
219
220int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
221{
222    int i;
223    const tr_torrent_t * tor = cp->tor;
224    const int start = tr_pieceStartBlock( piece );
225    const int end   = start + tr_cpCountBlocks( cp, piece );
226
227    for( i = start; i < end; ++i )
228        if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
229            return i;
230
231    return -1;
232}
233
234int tr_cpMostMissingBlockInPiece( const tr_completion_t * cp,
235                                  int                     piece,
236                                  int                   * downloaders )
237{
238    tr_torrent_t * tor = cp->tor;
239    int start, count, end, i;
240    int * pool, poolSize, min, ret;
241
242    start = tr_pieceStartBlock( piece );
243    count = tr_cpCountBlocks( cp, piece );
244    end   = start + count;
245
246    pool     = malloc( count * sizeof( int ) );
247    poolSize = 0;
248    min      = 255;
249
250    for( i = start; i < end; i++ )
251    {
252        if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] > min )
253        {
254            continue;
255        }
256        if( cp->blockDownloaders[i] < min )
257        {
258            min      = cp->blockDownloaders[i];
259            poolSize = 0;
260        }
261        if( cp->blockDownloaders[i] <= min )
262        {
263            pool[poolSize++] = i;
264        }
265    }
266
267    if( poolSize > 0 )
268    {
269        ret = pool[0];
270        *downloaders = min;
271    }
272    else
273    {
274        ret = -1;
275    }
276
277    free( pool );
278    return ret;
279}
280
281
282int
283tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
284{
285    return cp->missingBlocks[piece];
286}
287
288/***
289****
290***/
291
292/* returns one of CP_COMPLETE, CP_DONE, or CP_INCOMPLETE */
293int
294tr_cpGetState ( const tr_completion_t * cp )
295{
296    int i;
297    int ret = CP_COMPLETE;
298    const tr_info_t * info = &cp->tor->info;
299
300    for( i=0; i<info->pieceCount; ++i ) {
301        if( tr_cpPieceIsComplete( cp, i ) )
302            continue;
303        if( info->pieces[i].priority != TR_PRI_DND)
304            return CP_INCOMPLETE;
305        ret = CP_DONE;
306    }
307
308    return ret;
309}
310
311uint64_t
312tr_cpBytesUntilComplete ( const tr_completion_t * cp )
313{
314    int i;
315    uint64_t b=0;
316    const tr_torrent_t * tor = cp->tor;
317    const tr_info_t * info = &tor->info;
318
319    for( i=0; i<info->pieceCount; ++i )
320        if( !tr_cpPieceIsComplete( cp, i ) )
321            b += tor->blockSize * (tr_cpCountBlocks( cp, i ) - cp->completeBlocks[ i ] );
322
323    return b;
324}
325
326uint64_t
327tr_cpBytesUntilDone ( const tr_completion_t * cp )
328{
329    int i;
330    uint64_t b=0;
331    const tr_torrent_t * tor = cp->tor;
332    const tr_info_t * info = &tor->info;
333
334    for( i=0; i<info->pieceCount; ++i )
335        if( !tr_cpPieceIsComplete( cp, i ) && info->pieces[i].priority != TR_PRI_DND )
336            b += tor->blockSize * (tr_cpCountBlocks( cp, i ) - cp->completeBlocks[ i ] );
337
338    return b;
339}
340
341float
342tr_cpPercentComplete ( const tr_completion_t * cp )
343{
344    int i;
345    uint64_t have=0;
346    const tr_torrent_t * tor = cp->tor;
347
348    for( i=0; i<tor->info.pieceCount; ++i )
349        have += cp->completeBlocks[ i ];
350
351    return tor->blockCount ? (float)have / (float)tor->blockCount : 0.0f;
352}
353
354float
355tr_cpPercentDone( const tr_completion_t * cp )
356{
357    int i;
358    uint64_t have=0, total=0;
359    const tr_torrent_t * tor = cp->tor;
360
361    for( i=0; i<tor->info.pieceCount; ++i ) {
362        if( tor->info.pieces[i].priority != TR_PRI_DND) {
363            total += tr_cpCountBlocks( cp, i );
364            have += cp->completeBlocks[ i ];
365        }
366    }
367
368    return !total ? 0.0f : (float)have / (float)total;
369}
Note: See TracBrowser for help on using the repository browser.