source: trunk/libtransmission/completion.c @ 11709

Last change on this file since 11709 was 11709, checked in by jordan, 11 years ago

Update the copyright year in the source code comments.

The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli.

Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.8 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: completion.c 11709 2011-01-19 13:48:47Z jordan $
11 */
12
13#include <assert.h>
14#include <string.h>
15
16#include "transmission.h"
17#include "completion.h"
18#include "torrent.h"
19#include "torrent-magnet.h"
20#include "utils.h"
21
22static void
23tr_cpReset( tr_completion * cp )
24{
25    tr_bitfieldClear( &cp->pieceBitfield );
26    tr_bitfieldClear( &cp->blockBitfield );
27    memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
28    cp->sizeNow = 0;
29    cp->sizeWhenDoneIsDirty = 1;
30    cp->haveValidIsDirty = 1;
31}
32
33tr_completion *
34tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
35{
36    cp->tor = tor;
37    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
38    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
39    tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
40    tr_cpReset( cp );
41    return cp;
42}
43
44tr_completion*
45tr_cpDestruct( tr_completion * cp )
46{
47    tr_free( cp->completeBlocks );
48    tr_bitfieldDestruct( &cp->pieceBitfield );
49    tr_bitfieldDestruct( &cp->blockBitfield );
50    return cp;
51}
52
53void
54tr_cpInvalidateDND( tr_completion * cp )
55{
56    cp->sizeWhenDoneIsDirty = 1;
57}
58
59uint64_t
60tr_cpSizeWhenDone( const tr_completion * ccp )
61{
62    if( ccp->sizeWhenDoneIsDirty )
63    {
64        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
65        const tr_torrent * tor = cp->tor;
66        const tr_info *    info = &tor->info;
67        tr_piece_index_t   i;
68        uint64_t           size = 0;
69
70        for( i = 0; i < info->pieceCount; ++i )
71        {
72            if( !info->pieces[i].dnd )
73            {
74                /* we want the piece... */
75                size += tr_torPieceCountBytes( tor, i );
76            }
77            else if( tr_cpPieceIsComplete( cp, i ) )
78            {
79                /* we have the piece... */
80                size += tr_torPieceCountBytes( tor, i );
81            }
82            else if( cp->completeBlocks[i] )
83            {
84                /* we have part of the piece... */
85                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
86                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
87                tr_block_index_t j;
88                for( j = b; j < e; ++j )
89                    if( tr_cpBlockIsCompleteFast( cp, j ) )
90                        size += tr_torBlockCountBytes( tor, j );
91            }
92        }
93
94        cp->sizeWhenDoneLazy = size;
95        cp->sizeWhenDoneIsDirty = 0;
96    }
97
98    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
99    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
100    return ccp->sizeWhenDoneLazy;
101}
102
103void
104tr_cpPieceAdd( tr_completion *  cp,
105               tr_piece_index_t piece )
106{
107    const tr_torrent *     tor = cp->tor;
108    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
109    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
110    tr_block_index_t       i;
111
112    for( i = start; i < end; ++i )
113        tr_cpBlockAdd( cp, i );
114}
115
116void
117tr_cpPieceRem( 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       block;
124
125    assert( cp );
126    assert( piece < tor->info.pieceCount );
127    assert( start < tor->blockCount );
128    assert( start <= end );
129    assert( end <= tor->blockCount );
130
131    for( block = start; block < end; ++block )
132        if( tr_cpBlockIsCompleteFast( cp, block ) )
133            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
134
135    cp->sizeWhenDoneIsDirty = 1;
136    cp->haveValidIsDirty = 1;
137    cp->completeBlocks[piece] = 0;
138    tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
139    tr_bitfieldRem( &cp->pieceBitfield, piece );
140}
141
142void
143tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
144{
145    const tr_torrent * tor = cp->tor;
146
147    if( !tr_cpBlockIsComplete( cp, block ) )
148    {
149        const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
150        const int              blockSize = tr_torBlockCountBytes( tor,
151                                                                  block );
152
153        ++cp->completeBlocks[piece];
154
155        if( tr_cpPieceIsComplete( cp, piece ) )
156            tr_bitfieldAdd( &cp->pieceBitfield, piece );
157
158        tr_bitfieldAdd( &cp->blockBitfield, block );
159
160        cp->sizeNow += blockSize;
161
162        cp->haveValidIsDirty = 1;
163        cp->sizeWhenDoneIsDirty = 1;
164    }
165}
166
167
168void
169tr_cpSetHaveAll( tr_completion * cp )
170{
171    tr_piece_index_t i;
172    tr_torrent * tor = cp->tor;
173
174    tr_cpReset( cp );
175
176    cp->sizeNow = tor->info.totalSize;
177    tr_bitfieldAddRange( &cp->blockBitfield, 0, tor->blockCount );
178    tr_bitfieldAddRange( &cp->pieceBitfield, 0, tor->info.pieceCount );
179    for( i=0; i<tor->info.pieceCount; ++i )
180        cp->completeBlocks[i] = tr_torPieceCountBlocks( tor, i );
181    cp->sizeWhenDoneIsDirty = 1;
182    cp->haveValidIsDirty = 1;
183}
184
185/* Initialize a completion object from a bitfield indicating which blocks we have */
186tr_bool
187tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
188{
189    tr_bool success = FALSE;
190
191    assert( cp );
192    assert( blockBitfield );
193
194    /* The bitfield of block flags is typically loaded from a resume file.
195       Test the bitfield's length in case the resume file somehow got corrupted */
196    if(( success = blockBitfield->byteCount == cp->blockBitfield.byteCount ))
197    {
198        tr_block_index_t b = 0;
199        tr_piece_index_t p = 0;
200        uint32_t pieceBlock = 0;
201        uint16_t completeBlocksInPiece = 0;
202        tr_block_index_t completeBlocksInTorrent = 0;
203        uint32_t blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
204
205        /* start cp with a state where it thinks we have nothing */
206        tr_cpReset( cp );
207
208        /* init our block bitfield from the one passed in */
209        memcpy( cp->blockBitfield.bits, blockBitfield->bits, blockBitfield->byteCount );
210
211        /* invalidate the fields that are lazy-evaluated */
212        cp->sizeWhenDoneIsDirty = TRUE;
213        cp->haveValidIsDirty = TRUE;
214
215        /* to set the remaining fields, we walk through every block... */
216        while( b < cp->tor->blockCount )
217        {
218            if( tr_bitfieldHasFast( blockBitfield, b ) )
219                ++completeBlocksInPiece;
220
221            ++b;
222            ++pieceBlock;
223
224            /* by the time we reach the end of a piece, we have enough info
225               to update that piece's slot in cp.completeBlocks and cp.pieceBitfield */
226            if( pieceBlock == blocksInCurrentPiece )
227            {
228                cp->completeBlocks[p] = completeBlocksInPiece;
229                completeBlocksInTorrent += completeBlocksInPiece;
230                if( completeBlocksInPiece == blocksInCurrentPiece )
231                    tr_bitfieldAdd( &cp->pieceBitfield, p );
232
233                /* reset the per-piece counters because we're starting on a new piece now */
234                ++p;
235                completeBlocksInPiece = 0;
236                pieceBlock = 0;
237                blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
238            }
239        }
240
241        /* update sizeNow */
242        cp->sizeNow = completeBlocksInTorrent;
243        cp->sizeNow *= tr_torBlockCountBytes( cp->tor, 0 );
244        if( tr_bitfieldHasFast( &cp->blockBitfield, cp->tor->blockCount-1 ) ) {
245            /* the last block is usually smaller than the other blocks,
246               so handle that special case or cp->sizeNow might be too large */
247            cp->sizeNow -= tr_torBlockCountBytes( cp->tor, 0 );
248            cp->sizeNow += tr_torBlockCountBytes( cp->tor, cp->tor->blockCount-1 );
249        }
250    }
251
252    return success;
253}
254
255/***
256****
257***/
258
259tr_completeness
260tr_cpGetStatus( const tr_completion * cp )
261{
262    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
263    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
264    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
265    return TR_LEECH;
266}
267
268static uint64_t
269calculateHaveValid( const tr_completion * ccp )
270{
271    uint64_t                  b = 0;
272    tr_piece_index_t          i;
273    const tr_torrent        * tor            = ccp->tor;
274    const uint64_t            pieceSize      = tor->info.pieceSize;
275    const uint64_t            lastPieceSize  = tor->lastPieceSize;
276    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
277
278    if( !tr_torrentHasMetadata( tor ) )
279        return 0;
280
281    for( i=0; i!=lastPiece; ++i )
282        if( tr_cpPieceIsComplete( ccp, i ) )
283            b += pieceSize;
284
285    if( tr_cpPieceIsComplete( ccp, lastPiece ) )
286        b += lastPieceSize;
287
288    return b;
289}
290
291uint64_t
292tr_cpHaveValid( const tr_completion * ccp )
293{
294    if( ccp->haveValidIsDirty )
295    {
296        tr_completion * cp = (tr_completion *) ccp; /* mutable */
297        cp->haveValidLazy = calculateHaveValid( ccp );
298        cp->haveValidIsDirty = 0;
299    }
300
301    return ccp->haveValidLazy;
302}
303
304void
305tr_cpGetAmountDone( const tr_completion * cp,
306                    float *               tab,
307                    int                   tabCount )
308{
309    int                i;
310    const tr_torrent * tor = cp->tor;
311    const float        interval = tor->info.pieceCount / (float)tabCount;
312    const int          isSeed = tr_cpGetStatus( cp ) == TR_SEED;
313
314    for( i = 0; i < tabCount; ++i )
315    {
316        const tr_piece_index_t piece = i * interval;
317
318        if( tor == NULL )
319            tab[i] = 0.0f;
320        else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
321            tab[i] = 1.0f;
322        else
323            tab[i] = (float)cp->completeBlocks[piece] /
324                     tr_torPieceCountBlocks( tor, piece );
325    }
326}
327
328int
329tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
330{
331    return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
332}
333
334
335tr_bool
336tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
337{
338    return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
339}
340
341tr_bool
342tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t fileIndex )
343{
344    tr_block_index_t block;
345
346    const tr_torrent * tor = cp->tor;
347    const tr_file * file = &tor->info.files[fileIndex];
348    const tr_block_index_t firstBlock = file->offset / tor->blockSize;
349    const tr_block_index_t lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
350
351    assert( tr_torBlockPiece( tor, firstBlock ) == file->firstPiece );
352    assert( tr_torBlockPiece( tor, lastBlock ) == file->lastPiece );
353
354    for( block=firstBlock; block<=lastBlock; ++block )
355        if( !tr_cpBlockIsCompleteFast( cp, block ) )
356            return FALSE;
357
358    return TRUE;
359}
Note: See TracBrowser for help on using the repository browser.