source: trunk/libtransmission/completion.c @ 7578

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

(trunk libT) avoid some unnecessary memory fragmentation... for composited objects that have a tr_completion, contain the it directly rather than a pointer to one allocated elsewhere on the heap.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.3 KB
Line 
1/******************************************************************************
2 * $Id: completion.c 7578 2009-01-02 17:01:55Z 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,
39            sizeof( uint16_t ) * cp->tor->info.pieceCount );
40    cp->sizeNow = 0;
41    cp->sizeWhenDoneIsDirty = 1;
42    cp->haveValidIsDirty = 1;
43}
44
45tr_completion *
46tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
47{
48    cp->tor = tor;
49    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
50    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
51    tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
52    tr_cpReset( cp );
53    return cp;
54}
55
56tr_completion*
57tr_cpDestruct( tr_completion * cp )
58{
59    tr_free( cp->completeBlocks );
60    tr_bitfieldDestruct( &cp->pieceBitfield );
61    tr_bitfieldDestruct( &cp->blockBitfield );
62    return cp;
63}
64
65void
66tr_cpInvalidateDND( tr_completion * cp )
67{
68    cp->sizeWhenDoneIsDirty = 1;
69}
70
71uint64_t
72tr_cpSizeWhenDone( const tr_completion * ccp )
73{
74    if( ccp->sizeWhenDoneIsDirty )
75    {
76        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
77        const tr_torrent * tor = cp->tor;
78        const tr_info *    info = &tor->info;
79        tr_piece_index_t   i;
80        uint64_t           size = 0;
81
82        for( i = 0; i < info->pieceCount; ++i )
83        {
84            if( !info->pieces[i].dnd )
85            {
86                /* we want the piece... */
87                size += tr_torPieceCountBytes( tor, i );
88            }
89            else if( tr_cpPieceIsComplete( cp, i ) )
90            {
91                /* we have the piece... */
92                size += tr_torPieceCountBytes( tor, i );
93            }
94            else if( cp->completeBlocks[i] )
95            {
96                /* we have part of the piece... */
97                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
98                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor,
99                                                                       i );
100                tr_block_index_t       j;
101                for( j = b; j < e; ++j )
102                    if( tr_cpBlockIsComplete( cp, j ) )
103                        size += tr_torBlockCountBytes( tor, j );
104            }
105        }
106
107        cp->sizeWhenDoneLazy = size;
108        cp->sizeWhenDoneIsDirty = 0;
109    }
110
111    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
112    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
113    return ccp->sizeWhenDoneLazy;
114}
115
116void
117tr_cpPieceAdd( tr_completion *  cp,
118               tr_piece_index_t piece )
119{
120    const tr_torrent *     tor = cp->tor;
121    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
122    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
123    tr_block_index_t       i;
124
125    for( i = start; i < end; ++i )
126        tr_cpBlockAdd( cp, i );
127}
128
129void
130tr_cpPieceRem( tr_completion *  cp,
131               tr_piece_index_t piece )
132{
133    const tr_torrent *     tor = cp->tor;
134    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
135    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
136    tr_block_index_t       block;
137
138    assert( cp );
139    assert( piece < tor->info.pieceCount );
140    assert( start < tor->blockCount );
141    assert( start <= end );
142    assert( end <= tor->blockCount );
143
144    for( block = start; block < end; ++block )
145        if( tr_cpBlockIsComplete( cp, block ) )
146            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
147
148    cp->sizeWhenDoneIsDirty = 1;
149    cp->haveValidIsDirty = 1;
150    cp->completeBlocks[piece] = 0;
151    tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
152    tr_bitfieldRem( &cp->pieceBitfield, piece );
153}
154
155void
156tr_cpBlockAdd( tr_completion *  cp,
157               tr_block_index_t block )
158{
159    const tr_torrent * tor = cp->tor;
160
161    if( !tr_cpBlockIsComplete( cp, block ) )
162    {
163        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
164        const int              blockSize = tr_torBlockCountBytes( tor,
165                                                                  block );
166
167        ++cp->completeBlocks[piece];
168
169        if( tr_cpPieceIsComplete( cp, piece ) )
170            tr_bitfieldAdd( &cp->pieceBitfield, piece );
171
172        tr_bitfieldAdd( &cp->blockBitfield, block );
173
174        cp->sizeNow += blockSize;
175
176        cp->haveValidIsDirty = 1;
177        cp->sizeWhenDoneIsDirty = 1;
178    }
179}
180
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
203/***
204****
205***/
206
207tr_completeness
208tr_cpGetStatus( const tr_completion * cp )
209{
210    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
211    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
212    return TR_LEECH;
213}
214
215static uint64_t
216calculateHaveValid( const tr_completion * ccp )
217{
218    uint64_t                  b = 0;
219    tr_piece_index_t          i;
220    const tr_torrent        * tor            = ccp->tor;
221    const uint64_t            pieceSize      = tor->info.pieceSize;
222    const uint64_t            lastPieceSize  = tor->lastPieceSize;
223    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
224
225    for( i=0; i!=lastPiece; ++i )
226        if( tr_cpPieceIsComplete( ccp, i ) )
227            b += pieceSize;
228
229    if( tr_cpPieceIsComplete( ccp, lastPiece ) )
230        b += lastPieceSize;
231
232    return b;
233}
234
235uint64_t
236tr_cpHaveValid( const tr_completion * ccp )
237{
238    if( ccp->haveValidIsDirty )
239    {
240        tr_completion * cp = (tr_completion *) ccp; /* mutable */
241        cp->haveValidLazy = calculateHaveValid( ccp );
242        cp->haveValidIsDirty = 0;
243    }
244
245    return ccp->haveValidLazy;
246}
247
248void
249tr_cpGetAmountDone( const tr_completion * cp,
250                    float *               tab,
251                    int                   tabCount )
252{
253    int                i;
254    const tr_torrent * tor = cp->tor;
255    const float        interval = tor->info.pieceCount / (float)tabCount;
256    const int          isSeed = tr_cpGetStatus( cp ) == TR_SEED;
257
258    for( i = 0; i < tabCount; ++i )
259    {
260        const tr_piece_index_t piece = i * interval;
261
262        if( tor == NULL )
263            tab[i] = 0.0f;
264        else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
265            tab[i] = 1.0f;
266        else
267            tab[i] = (float)cp->completeBlocks[piece] /
268                     tr_torPieceCountBlocks( tor, piece );
269    }
270}
271
272int
273tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
274{
275    return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
276}
277
278
279int
280tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
281{
282    return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
283}
Note: See TracBrowser for help on using the repository browser.