source: trunk/libtransmission/completion.c @ 7628

Last change on this file since 7628 was 7628, checked in by charles, 12 years ago

(trunk libT) faster tr_cpBlockBitfieldSet()

  • Property svn:keywords set to Date Rev Author Id
File size: 9.6 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 7628 2009-01-06 07:45:15Z charles $
3 *
4 * Copyright (c) 2005-2008 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 <assert.h>
26#include <string.h>
27
28#include "transmission.h"
29#include "completion.h"
30#include "torrent.h"
31#include "utils.h"
32
33static void
34tr_cpReset( tr_completion * cp )
35{
36    tr_bitfieldClear( &cp->pieceBitfield );
37    tr_bitfieldClear( &cp->blockBitfield );
38    memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
39    cp->sizeNow = 0;
40    cp->sizeWhenDoneIsDirty = 1;
41    cp->haveValidIsDirty = 1;
42}
43
44tr_completion *
45tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
46{
47    cp->tor = tor;
48    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
49    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
50    tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
51    tr_cpReset( cp );
52    return cp;
53}
54
55tr_completion*
56tr_cpDestruct( tr_completion * cp )
57{
58    tr_free( cp->completeBlocks );
59    tr_bitfieldDestruct( &cp->pieceBitfield );
60    tr_bitfieldDestruct( &cp->blockBitfield );
61    return cp;
62}
63
64void
65tr_cpInvalidateDND( tr_completion * cp )
66{
67    cp->sizeWhenDoneIsDirty = 1;
68}
69
70uint64_t
71tr_cpSizeWhenDone( const tr_completion * ccp )
72{
73    if( ccp->sizeWhenDoneIsDirty )
74    {
75        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
76        const tr_torrent * tor = cp->tor;
77        const tr_info *    info = &tor->info;
78        tr_piece_index_t   i;
79        uint64_t           size = 0;
80
81        for( i = 0; i < info->pieceCount; ++i )
82        {
83            if( !info->pieces[i].dnd )
84            {
85                /* we want the piece... */
86                size += tr_torPieceCountBytes( tor, i );
87            }
88            else if( tr_cpPieceIsComplete( cp, i ) )
89            {
90                /* we have the piece... */
91                size += tr_torPieceCountBytes( tor, i );
92            }
93            else if( cp->completeBlocks[i] )
94            {
95                /* we have part of the piece... */
96                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
97                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor,
98                                                                       i );
99                tr_block_index_t       j;
100                for( j = b; j < e; ++j )
101                    if( tr_cpBlockIsComplete( cp, j ) )
102                        size += tr_torBlockCountBytes( tor, j );
103            }
104        }
105
106        cp->sizeWhenDoneLazy = size;
107        cp->sizeWhenDoneIsDirty = 0;
108    }
109
110    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
111    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
112    return ccp->sizeWhenDoneLazy;
113}
114
115void
116tr_cpPieceAdd( tr_completion *  cp,
117               tr_piece_index_t piece )
118{
119    const tr_torrent *     tor = cp->tor;
120    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
121    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
122    tr_block_index_t       i;
123
124    for( i = start; i < end; ++i )
125        tr_cpBlockAdd( cp, i );
126}
127
128void
129tr_cpPieceRem( tr_completion *  cp,
130               tr_piece_index_t piece )
131{
132    const tr_torrent *     tor = cp->tor;
133    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
134    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
135    tr_block_index_t       block;
136
137    assert( cp );
138    assert( piece < tor->info.pieceCount );
139    assert( start < tor->blockCount );
140    assert( start <= end );
141    assert( end <= tor->blockCount );
142
143    for( block = start; block < end; ++block )
144        if( tr_cpBlockIsComplete( cp, block ) )
145            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
146
147    cp->sizeWhenDoneIsDirty = 1;
148    cp->haveValidIsDirty = 1;
149    cp->completeBlocks[piece] = 0;
150    tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
151    tr_bitfieldRem( &cp->pieceBitfield, piece );
152}
153
154void
155tr_cpBlockAdd( tr_completion *  cp,
156               tr_block_index_t block )
157{
158    const tr_torrent * tor = cp->tor;
159
160    if( !tr_cpBlockIsComplete( cp, block ) )
161    {
162        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
163        const int              blockSize = tr_torBlockCountBytes( tor,
164                                                                  block );
165
166        ++cp->completeBlocks[piece];
167
168        if( tr_cpPieceIsComplete( cp, piece ) )
169            tr_bitfieldAdd( &cp->pieceBitfield, piece );
170
171        tr_bitfieldAdd( &cp->blockBitfield, block );
172
173        cp->sizeNow += blockSize;
174
175        cp->haveValidIsDirty = 1;
176        cp->sizeWhenDoneIsDirty = 1;
177    }
178}
179
180#if 0
181int
182tr_cpBlockBitfieldSet( tr_completion * cp,
183                       tr_bitfield *   bitfield )
184{
185    int success = FALSE;
186
187    assert( cp );
188    assert( bitfield );
189
190    if( tr_bitfieldTestFast( bitfield, cp->tor->blockCount - 1 ) )
191    {
192        tr_block_index_t i;
193        tr_cpReset( cp );
194        for( i = 0; i < cp->tor->blockCount; ++i )
195            if( tr_bitfieldHasFast( bitfield, i ) )
196                tr_cpBlockAdd( cp, i );
197        success = TRUE;
198    }
199
200    return success;
201}
202#endif
203
204int
205tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
206{
207    int success = FALSE;
208
209    assert( cp );
210    assert( blockBitfield );
211
212    if(( success = tr_bitfieldTestFast( blockBitfield, cp->tor->blockCount - 1 )))
213    {
214        tr_piece_index_t p;
215        const tr_torrent * tor = cp->tor;
216
217        tr_cpReset( cp );
218
219        for( p=0; p<tor->info.pieceCount; ++p )
220        {
221            tr_block_index_t i;
222            uint16_t completeBlocksInPiece = 0;
223
224            const tr_block_index_t start = tr_torPieceFirstBlock( tor, p );
225            const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, p );
226
227            for( i=start; i!=end; ++i ) {
228                if( tr_bitfieldTestFast( blockBitfield, i ) ) {
229                    ++completeBlocksInPiece;
230                    cp->sizeNow += tr_torBlockCountBytes( tor, i );
231                }
232            }
233
234            cp->completeBlocks[p] = completeBlocksInPiece;
235
236            if( completeBlocksInPiece == end - start )
237                tr_bitfieldAdd( &cp->pieceBitfield, p );
238        }
239
240        memcpy( cp->blockBitfield->bits, blockBitfield->bits, cp->blockBitfield->byteCount );
241
242        cp->haveValidIsDirty = 1;
243        cp->sizeWhenDoneIsDirty = 1;
244    }
245
246    return success;
247}
248
249/***
250****
251***/
252
253tr_completeness
254tr_cpGetStatus( const tr_completion * cp )
255{
256    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
257    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
258    return TR_LEECH;
259}
260
261static uint64_t
262calculateHaveValid( const tr_completion * ccp )
263{
264    uint64_t                  b = 0;
265    tr_piece_index_t          i;
266    const tr_torrent        * tor            = ccp->tor;
267    const uint64_t            pieceSize      = tor->info.pieceSize;
268    const uint64_t            lastPieceSize  = tor->lastPieceSize;
269    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
270
271    for( i=0; i!=lastPiece; ++i )
272        if( tr_cpPieceIsComplete( ccp, i ) )
273            b += pieceSize;
274
275    if( tr_cpPieceIsComplete( ccp, lastPiece ) )
276        b += lastPieceSize;
277
278    return b;
279}
280
281uint64_t
282tr_cpHaveValid( const tr_completion * ccp )
283{
284    if( ccp->haveValidIsDirty )
285    {
286        tr_completion * cp = (tr_completion *) ccp; /* mutable */
287        cp->haveValidLazy = calculateHaveValid( ccp );
288        cp->haveValidIsDirty = 0;
289    }
290
291    return ccp->haveValidLazy;
292}
293
294void
295tr_cpGetAmountDone( const tr_completion * cp,
296                    float *               tab,
297                    int                   tabCount )
298{
299    int                i;
300    const tr_torrent * tor = cp->tor;
301    const float        interval = tor->info.pieceCount / (float)tabCount;
302    const int          isSeed = tr_cpGetStatus( cp ) == TR_SEED;
303
304    for( i = 0; i < tabCount; ++i )
305    {
306        const tr_piece_index_t piece = i * interval;
307
308        if( tor == NULL )
309            tab[i] = 0.0f;
310        else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
311            tab[i] = 1.0f;
312        else
313            tab[i] = (float)cp->completeBlocks[piece] /
314                     tr_torPieceCountBlocks( tor, piece );
315    }
316}
317
318int
319tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
320{
321    return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
322}
323
324
325int
326tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
327{
328    return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
329}
Note: See TracBrowser for help on using the repository browser.