source: trunk/libtransmission/completion.c @ 2538

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