]> granicus.if.org Git - transmission/commitdiff
(trunk libT) #4048 "use bitsets instead of bitfield in tr_completion" -- done.
authorJordan Lee <jordan@transmissionbt.com>
Wed, 23 Feb 2011 03:54:04 +0000 (03:54 +0000)
committerJordan Lee <jordan@transmissionbt.com>
Wed, 23 Feb 2011 03:54:04 +0000 (03:54 +0000)
Excuse the sprawl. Much of this didn't fit into self-contained commits.

19 files changed:
libtransmission/bencode.c
libtransmission/bencode.h
libtransmission/bitfield.c
libtransmission/bitfield.h
libtransmission/bitset.c
libtransmission/bitset.h
libtransmission/cache.c
libtransmission/completion.c
libtransmission/completion.h
libtransmission/peer-mgr.c
libtransmission/peer-msgs.c
libtransmission/resume.c
libtransmission/rpcimpl.c
libtransmission/session.c
libtransmission/torrent.c
libtransmission/torrent.h
libtransmission/transmission.h
libtransmission/utils-test.c
libtransmission/webseed.c

index 30edb373d1c6708e4945314ad975547d08f0fcf8..e641125bf5b9959b1ff565e84873baef3c508511 100644 (file)
@@ -475,6 +475,19 @@ tr_bencGetStr( const tr_benc * val, const char ** setme )
     return success;
 }
 
+tr_bool
+tr_bencGetRaw( const tr_benc * val, const uint8_t ** setme_raw, size_t * setme_len )
+{
+    const tr_bool success = tr_bencIsString( val );
+
+    if( success ) {
+        *setme_raw = (uint8_t*) getStr(val);
+        *setme_len = val->val.s.len;
+    }
+
+    return success;
+}
+
 tr_bool
 tr_bencGetBool( const tr_benc * val, tr_bool * setme )
 {
@@ -563,20 +576,9 @@ tr_bencDictFindDict( tr_benc * dict, const char * key, tr_benc ** setme )
 }
 
 tr_bool
-tr_bencDictFindRaw( tr_benc         * dict,
-                    const char      * key,
-                    const uint8_t  ** setme_raw,
-                    size_t          * setme_len )
+tr_bencDictFindRaw( tr_benc * dict, const char * key, const uint8_t  ** setme_raw, size_t * setme_len )
 {
-    tr_benc * child;
-    const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
-
-    if( found ) {
-        *setme_raw = (uint8_t*) getStr(child);
-        *setme_len = child->val.s.len;
-    }
-
-    return found;
+    return tr_bencGetRaw( tr_bencDictFind( dict, key ), setme_raw, setme_len );
 }
 
 /***
@@ -1704,7 +1706,7 @@ tr_bencToFile( const tr_benc * top, tr_fmt_mode mode, const char * filename )
         }
         else
         {
-            tr_fsync( fd );
+            //tr_fsync( fd );
             tr_close_file( fd );
 
 #ifdef WIN32
index 8de304755fce3a9ef8a90f50be77cc59d801177e..96ee2e105327b32149a22969870f36733e4a5903 100644 (file)
@@ -214,6 +214,10 @@ tr_bool   tr_bencGetInt( const tr_benc * val, int64_t * setme );
     @return TRUE if successful, or FALSE if the variant could not be represented as a string  */
 tr_bool   tr_bencGetStr( const tr_benc * val, const char ** setme );
 
+/** @brief Get a raw byte array from a variant object
+    @return TRUE if successful, or FALSE if the variant could not be represented as a raw byte array */
+tr_bool   tr_bencGetRaw( const tr_benc * val, const uint8_t  ** setme_raw, size_t * setme_len );
+
 /** @brief Get a boolean from a variant object
     @return TRUE if successful, or FALSE if the variant could not be represented as a boolean  */
 tr_bool   tr_bencGetBool( const tr_benc * val, tr_bool * setme );
index 15734db0dda429b22673cb4468c3b6fc51317af9..28b891c216f60aa80f5ea668e27212d06a1fcd81 100644 (file)
@@ -16,6 +16,9 @@
 #include "transmission.h"
 #include "bitfield.h"
 #include "bitset.h"
+#include "utils.h" /* tr_new0() */
+
+const tr_bitfield TR_BITFIELD_INIT = { NULL, 0, 0 };
 
 tr_bitfield*
 tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
@@ -35,14 +38,15 @@ tr_bitfieldDestruct( tr_bitfield * b )
 }
 
 tr_bitfield*
-tr_bitfieldDup( const tr_bitfield * in )
+tr_bitfieldNew( size_t bitCount )
 {
-    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
+    return tr_bitfieldConstruct( tr_new( tr_bitfield, 1 ), bitCount );
+}
 
-    ret->bitCount = in->bitCount;
-    ret->byteCount = in->byteCount;
-    ret->bits = tr_memdup( in->bits, in->byteCount );
-    return ret;
+void
+tr_bitfieldFree( tr_bitfield * b )
+{
+    tr_free( tr_bitfieldDestruct( b ) );
 }
 
 void
@@ -161,21 +165,31 @@ tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
     return a;
 }
 
+static const int trueBitCount[256] =
+{
+    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
 size_t
 tr_bitfieldCountTrueBits( const tr_bitfield* b )
 {
     size_t           ret = 0;
     const uint8_t *  it, *end;
-    static const int trueBitCount[256] = {
-        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
-    };
 
     if( !b )
         return 0;
@@ -185,3 +199,54 @@ tr_bitfieldCountTrueBits( const tr_bitfield* b )
 
     return ret;
 }
+
+size_t
+tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end )
+{
+    size_t ret = 0;
+    const int first_byte = begin >> 3u; 
+    const int last_byte = ( end - 1 ) >> 3u;
+
+    assert( begin < end );
+
+    if( first_byte == last_byte )
+    {
+        int i;
+        uint8_t val = b->bits[first_byte];
+
+        i = begin - (first_byte * 8);
+        val <<= i;
+        val >>= i;
+        i = (last_byte+1)*8 - end;
+        val >>= i;
+        val <<= i;
+
+        ret += trueBitCount[val];
+    }
+    else
+    {
+        int i;
+        uint8_t val;
+
+        /* first byte */
+        i = begin - (first_byte * 8);
+        val = b->bits[first_byte];
+        val <<= i;
+        val >>= i;
+        ret += trueBitCount[val];
+
+        /* middle bytes */
+        for( i=first_byte+1; i<last_byte; ++i )
+            ret += trueBitCount[b->bits[i]];
+
+        /* last byte */
+        i = (last_byte+1)*8 - end;
+        val = b->bits[last_byte];
+        val >>= i;
+        val <<= i;
+        ret += trueBitCount[val];
+    }
+
+    assert( ret <= ( begin - end ) );
+    return ret;
+}
index 6824594db5457264ae584f562fea2688a3296b80..3d77d779cefcfc4ab5d9349640757a3524a802bb 100644 (file)
@@ -18,7 +18,6 @@
 #define TR_BITFIELD_H 1
 
 #include "transmission.h"
-#include "utils.h" /* tr_new0 */
 
 /** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
 typedef struct tr_bitfield
@@ -29,21 +28,15 @@ typedef struct tr_bitfield
 }
 tr_bitfield;
 
-tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitcount );
+extern const tr_bitfield TR_BITFIELD_INIT;
 
-tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
+tr_bitfield* tr_bitfieldConstruct( tr_bitfield*, size_t bitCount );
 
-static inline tr_bitfield* tr_bitfieldNew( size_t bitcount )
-{
-    return tr_bitfieldConstruct( tr_new0( tr_bitfield, 1 ), bitcount );
-}
+tr_bitfield* tr_bitfieldDestruct( tr_bitfield* );
 
-static inline void tr_bitfieldFree( tr_bitfield * b )
-{
-    tr_free( tr_bitfieldDestruct( b ) );
-}
+tr_bitfield* tr_bitfieldNew( size_t bitCount );
 
-tr_bitfield* tr_bitfieldDup( const tr_bitfield* ) TR_GNUC_MALLOC;
+void tr_bitfieldFree( tr_bitfield * b );
 
 void         tr_bitfieldClear( tr_bitfield* );
 
@@ -57,6 +50,9 @@ int          tr_bitfieldRemRange( tr_bitfield*, size_t begin, size_t end );
 
 size_t       tr_bitfieldCountTrueBits( const tr_bitfield* );
 
+size_t       tr_bitfieldCountRange( const tr_bitfield * b, size_t begin, size_t end );
+
+
 tr_bitfield* tr_bitfieldOr( tr_bitfield*, const tr_bitfield* );
 
 /** A stripped-down version of bitfieldHas to be used
index c01d02cd72672cfa2187a64226d970789e7ec20d..3e32feab03472a56b4a6b1358e499782f1d4a5c3 100644 (file)
  */
 
 #include "transmission.h"
+#include "bencode.h"
 #include "bitset.h"
+#include "utils.h"
+
+const tr_bitset TR_BITSET_INIT = { FALSE, FALSE, { NULL, 0, 0 } };
+
+void
+tr_bitsetConstruct( tr_bitset * b, size_t bitCount )
+{
+    *b = TR_BITSET_INIT;
+    b->bitfield.bitCount = bitCount;
+}
 
 void
-tr_bitsetConstructor( tr_bitset * b, size_t size )
+tr_bitsetDestruct( tr_bitset * b )
 {
-    tr_bitfieldConstruct( &b->bitfield, size );
+    tr_free( b->bitfield.bits );
+    *b = TR_BITSET_INIT;
+}
+
+static void
+tr_bitsetClear( tr_bitset * b )
+{
+    tr_free( b->bitfield.bits );
+    b->bitfield.bits = NULL;
+    b->haveAll = FALSE;
+    b->haveNone = FALSE;
 }
 
 void
-tr_bitsetDestructor( tr_bitset * b )
+tr_bitsetSetHaveAll( tr_bitset * b )
 {
-    tr_bitfieldDestruct( &b->bitfield );
+    tr_bitsetClear( b );
+    b->haveAll = TRUE;
+}
+
+void
+tr_bitsetSetHaveNone( tr_bitset * b )
+{
+    tr_bitsetClear( b );
+    b->haveNone = TRUE;
+}
+
+void
+tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield )
+{
+    const size_t n = tr_bitfieldCountTrueBits( bitfield );
+
+    if( n == 0 )
+    {
+        tr_bitsetSetHaveNone( b );
+    }
+    else if( n == bitfield->bitCount )
+    {
+        tr_bitsetSetHaveAll( b );
+    }
+    else
+    {
+        tr_bitsetDestruct( b );
+        b->bitfield.bits = tr_memdup( bitfield->bits, bitfield->byteCount );
+        b->bitfield.bitCount = bitfield->bitCount;
+        b->bitfield.byteCount = bitfield->byteCount;
+    }
 }
 
+/***
+****
+***/
+
 void
-tr_bitsetReserve( tr_bitset * b, size_t size )
+tr_bitsetAdd( tr_bitset * b, size_t i )
 {
-    if( b->bitfield.bitCount < size )
+    tr_bitfield * bf = &b->bitfield;
+
+    if( b->haveAll )
+        return;
+
+    b->haveNone = FALSE;
+
+    /* do we need to resize the bitfield to accomodate this bit? */
+    if( !bf->bits || ( bf->bitCount < i+1 ) )
     {
-        tr_bitfield * tmp = tr_bitfieldDup( &b->bitfield );
+        const size_t oldByteCount = bf->byteCount;
+        if( bf->bitCount < i + 1 )
+            bf->bitCount = i + 1;
+        bf->byteCount = ( bf->bitCount + 7u ) / 8u;
+        bf->bits = tr_renew( uint8_t, bf->bits, bf->byteCount );
+        if( bf->byteCount > oldByteCount )
+            memset( bf->bits + oldByteCount, 0, bf->byteCount - oldByteCount );
+    }
 
-        tr_bitfieldDestruct( &b->bitfield );
-        tr_bitfieldConstruct( &b->bitfield, size );
+    tr_bitfieldAdd( bf, i );
+}
 
-        if( ( tmp->bits != NULL ) && ( tmp->byteCount > 0 ) )
-            memcpy( b->bitfield.bits, tmp->bits, tmp->byteCount );
+void
+tr_bitsetRem( tr_bitset * b, size_t i )
+{
+    if( b->haveNone )
+        return;
+
+    b->haveAll = FALSE;
 
-        tr_bitfieldFree( tmp );
+    if( !b->bitfield.bits )
+    {
+        tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
+        tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
     }
+
+    tr_bitfieldRem( &b->bitfield, i );
 }
 
+void
+tr_bitsetRemRange( tr_bitset * b, size_t begin, size_t end )
+{
+    if( b->haveNone )
+        return;
+
+    b->haveAll = FALSE; 
+    if( !b->bitfield.bits )
+    {
+        tr_bitfieldConstruct( &b->bitfield, b->bitfield.bitCount );
+        tr_bitfieldAddRange( &b->bitfield, 0, b->bitfield.bitCount );
+    }
+
+    tr_bitfieldRemRange( &b->bitfield, begin, end );
+}
+
+/***
+****
+***/
+
 tr_bool
 tr_bitsetHas( const tr_bitset * b, const size_t nth )
 {
@@ -51,13 +151,12 @@ tr_bitsetHas( const tr_bitset * b, const size_t nth )
     return tr_bitfieldHas( &b->bitfield, nth );
 }
 
-void
-tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
+size_t
+tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end )
 {
-    if( b->haveAll )
-        tr_bitfieldAddRange( a, 0, a->bitCount );
-    else if( !b->haveNone )
-        tr_bitfieldOr( a, &b->bitfield );
+    if( b->haveAll ) return end - begin;
+    if( b->haveNone ) return 0;
+    return tr_bitfieldCountRange( &b->bitfield, begin, end );
 }
 
 double
@@ -70,27 +169,79 @@ tr_bitsetPercent( const tr_bitset * b )
 }
 
 void
-tr_bitsetSetHaveAll( tr_bitset * b )
+tr_bitsetOr( tr_bitfield * a, const tr_bitset * b )
 {
-    b->haveAll = 1;
-    b->haveNone = 0;
+    if( b->haveAll )
+        tr_bitfieldAddRange( a, 0, a->bitCount );
+    else if( !b->haveNone )
+        tr_bitfieldOr( a, &b->bitfield );
 }
 
-void
-tr_bitsetSetHaveNone( tr_bitset * b )
+/***
+****
+***/
+
+tr_bool
+tr_bitsetFromBenc( tr_bitset * bitset, tr_benc * benc )
 {
-    b->haveAll = 0;
-    b->haveNone = 1;
+    size_t buflen;
+    const uint8_t * buf;
+    tr_bool handled = FALSE;
+
+    if( tr_bencGetRaw( benc, &buf, &buflen ) )
+    {
+        if( ( buflen == 3 ) && !memcmp( buf, "all", 3 ) )
+        {
+            tr_bitsetSetHaveAll( bitset );
+            handled = TRUE;
+        }
+        else if( ( buflen == 4 ) && !memcmp( buf, "none", 4 ) )
+        {
+            tr_bitsetSetHaveNone( bitset );
+            handled = TRUE;
+        }
+        else
+        {
+            bitset->haveAll = FALSE;
+            bitset->haveNone = FALSE;
+            tr_free( bitset->bitfield.bits );
+            bitset->bitfield.bits = tr_memdup( buf, buflen );
+            bitset->bitfield.byteCount = buflen;
+            bitset->bitfield.bitCount = buflen * 8;
+            handled = TRUE;
+        }
+    }
+
+    return handled;
 }
 
-int
-tr_bitsetAdd( tr_bitset * b, size_t i )
+void
+tr_bitsetToBenc( const tr_bitset * bitset, tr_benc * benc )
 {
-    int ret = 0;
-    if( !b->haveAll ) {
-        b->haveNone = 0;
-        tr_bitsetReserve( b, i+1 );
-        ret = tr_bitfieldAdd( &b->bitfield, i );
+    if( bitset->haveAll )
+    {
+        tr_bencInitStr( benc, "all", 3 );
+    }
+    else if( bitset->haveNone )
+    {
+        tr_bencInitStr( benc, "none", 4 );
+    }
+    else
+    {
+        const tr_bitfield * bf = &bitset->bitfield;
+        const size_t n = tr_bitfieldCountTrueBits( bf );
+
+        if( n == bf->bitCount )
+        {
+            tr_bencInitStr( benc, "all", 3 );
+        }
+        else if( n == 0 )
+        {
+            tr_bencInitStr( benc, "none", 4 );
+        }
+        else
+        {
+            tr_bencInitRaw( benc, bf->bits, bf->byteCount );
+        }
     }
-    return ret;
 }
index 0afc8a98aedc89b3cb79763a2035c6e9a4a8c2c2..b4f98a2ec99f38cca366f5e2b12bf39a33a70773 100644 (file)
@@ -29,14 +29,23 @@ typedef struct tr_bitset
 }
 tr_bitset;
 
-void tr_bitsetReserve( tr_bitset * b, size_t size );
-void tr_bitsetConstructor( tr_bitset * b, size_t size );
-void tr_bitsetDestructor( tr_bitset * b );
+extern const tr_bitset TR_BITSET_INIT;
+
+void tr_bitsetConstruct( tr_bitset * b, size_t bitCount );
+void tr_bitsetDestruct( tr_bitset * b );
 
 void tr_bitsetSetHaveAll( tr_bitset * b );
 void tr_bitsetSetHaveNone( tr_bitset * b );
 
-int  tr_bitsetAdd( tr_bitset * b, size_t i );
+void tr_bitsetSetBitfield( tr_bitset * b, const tr_bitfield * bitfield );
+
+void tr_bitsetAdd( tr_bitset * b, size_t i );
+void tr_bitsetRem( tr_bitset * b, size_t i );
+void tr_bitsetRemRange ( tr_bitset * b, size_t begin, size_t end );
+
+struct tr_benc;
+tr_bool tr_bitsetFromBenc( tr_bitset * bitset, struct tr_benc * benc );
+void tr_bitsetToBenc( const tr_bitset * bitset, struct tr_benc * benc );
 
 /***
 ****
@@ -45,6 +54,7 @@ int  tr_bitsetAdd( tr_bitset * b, size_t i );
 double tr_bitsetPercent( const tr_bitset * b );
 
 tr_bool tr_bitsetHas( const tr_bitset * b, const size_t nth );
+size_t tr_bitsetCountRange( const tr_bitset * b, const size_t begin, const size_t end );
 
 void tr_bitsetOr( tr_bitfield * a, const tr_bitset * b );
 
index 837716421555f25673bba3483c032ec6bb4f0b71..3e1edeab38be5d46c1b793e2d3b2507aa654bfdc 100644 (file)
@@ -389,11 +389,11 @@ tr_cachePrefetchBlock( tr_cache         * cache,
 ***/
 
 static int
-findPiece( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece )
+findBlockPos( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t block )
 {
     struct cache_block key;
     key.tor = torrent;
-    key.block = tr_torPieceFirstBlock( torrent, piece );
+    key.block = block;
     return tr_ptrArrayLowerBound( &cache->blocks, &key, cache_block_compare, NULL );
 }
 
@@ -419,19 +419,20 @@ int tr_cacheFlushDone( tr_cache * cache )
 int
 tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
 {
+    int pos;
     int err = 0;
-    const tr_file * file = &torrent->info.files[i];
-    const tr_block_index_t begin = tr_torPieceFirstBlock( torrent, file->firstPiece );
-    const tr_block_index_t end  = tr_torPieceFirstBlock( torrent, file->lastPiece ) + tr_torPieceCountBlocks( torrent, file->lastPiece );
-    const int pos = findPiece( cache, torrent, file->firstPiece );
-    dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu)", (int)i, (size_t)begin, (size_t)end );
+    tr_block_index_t first;
+    tr_block_index_t last;
+    tr_torGetFileBlockRange( torrent, i, &first, &last );
+    pos = findBlockPos( cache, torrent, first );
+    dbgmsg( "flushing file %d from cache to disk: blocks [%zu...%zu]", (int)i, (size_t)first, (size_t)last );
 
     /* flush out all the blocks in that file */
     while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
     {
         const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
         if( b->tor != torrent ) break;
-        if( ( b->block < begin ) || ( b->block >= end ) ) break;
+        if( ( b->block < first ) || ( b->block > last ) ) break;
         err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
     }
 
@@ -442,7 +443,7 @@ int
 tr_cacheFlushTorrent( tr_cache * cache, tr_torrent * torrent )
 {
     int err = 0;
-    const int pos = findPiece( cache, torrent, 0 );
+    const int pos = findBlockPos( cache, torrent, 0 );
 
     /* flush out all the blocks in that torrent */
     while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
index d9081596d8c6a84d07d7d0d032732a6c9c23b450..63e5e4d86ac8071a73f2fcb45fbdbb9b45523b6f 100644 (file)
  * $Id$
  */
 
-#include <assert.h>
-#include <string.h>
-
 #include "transmission.h"
 #include "completion.h"
 #include "torrent.h"
-#include "torrent-magnet.h"
 #include "utils.h"
 
+/***
+****
+***/
+
 static void
 tr_cpReset( tr_completion * cp )
 {
-    tr_bitfieldClear( &cp->pieceBitfield );
-    tr_bitfieldClear( &cp->blockBitfield );
-    memset( cp->completeBlocks, 0, sizeof( uint16_t ) * cp->tor->info.pieceCount );
+    tr_bitsetSetHaveNone( &cp->blockBitset );
+    tr_free( cp->completeBlocks );
+    cp->completeBlocks = NULL;
     cp->sizeNow = 0;
-    cp->sizeWhenDoneIsDirty = 1;
-    cp->blocksWantedIsDirty = 1;
-    cp->haveValidIsDirty = 1;
+    cp->sizeWhenDoneIsDirty = TRUE;
+    cp->blocksWantedIsDirty = TRUE;
+    cp->haveValidIsDirty = TRUE;
 }
 
 tr_completion *
 tr_cpConstruct( tr_completion * cp, tr_torrent * tor )
 {
     cp->tor = tor;
-    cp->completeBlocks  = tr_new( uint16_t, tor->info.pieceCount );
-    tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount );
-    tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount );
+    cp->completeBlocks = NULL;
+    tr_bitsetConstruct( &cp->blockBitset, tor->blockCount );
     tr_cpReset( cp );
     return cp;
 }
@@ -46,37 +45,79 @@ tr_completion*
 tr_cpDestruct( tr_completion * cp )
 {
     tr_free( cp->completeBlocks );
-    tr_bitfieldDestruct( &cp->pieceBitfield );
-    tr_bitfieldDestruct( &cp->blockBitfield );
+    tr_bitsetDestruct( &cp->blockBitset );
     return cp;
 }
 
+/***
+****
+***/
+
+static inline tr_bool
+isSeed( const tr_completion * cp )
+{
+    return cp->blockBitset.haveAll;
+}
+
+tr_completeness
+tr_cpGetStatus( const tr_completion * cp )
+{
+    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
+    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
+    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
+    return TR_LEECH;
+}
+
+/* how many blocks are in this piece? */
+static inline uint16_t
+countBlocksInPiece( const tr_torrent * tor, const tr_piece_index_t piece )
+{
+    return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
+                                             : tor->blockCountInPiece;
+}
+
+static uint16_t *
+getCompleteBlocks( const tr_completion * ccp )
+{
+    if( ccp->completeBlocks == NULL )
+    {
+        tr_completion * cp = (tr_completion*) ccp;
+        cp->completeBlocks = tr_new0( uint16_t, ccp->tor->info.pieceCount );
+    }
+
+    return ccp->completeBlocks;
+}
+
 void
 tr_cpInvalidateDND( tr_completion * cp )
 {
-    cp->sizeWhenDoneIsDirty = 1;
-    cp->blocksWantedIsDirty = 1;
+    cp->sizeWhenDoneIsDirty = TRUE;
+    cp->blocksWantedIsDirty = TRUE;
 }
 
 tr_block_index_t
 tr_cpBlocksMissing( const tr_completion * ccp )
 {
+    if( isSeed( ccp ) )
+        return 0;
+
     if( ccp->blocksWantedIsDirty )
     {
-        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
-        const tr_torrent * tor = cp->tor;
-        const tr_info *    info = &tor->info;
         tr_piece_index_t   i;
         tr_block_index_t   wanted = 0;
         tr_block_index_t   complete = 0;
+        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
+        const uint16_t   * complete_blocks = getCompleteBlocks( cp );
+        const tr_torrent * tor = ccp->tor;
+        const tr_info    * info = &tor->info;
 
         for( i = 0; i < info->pieceCount; ++i )
         {
-            if( info->pieces[i].dnd )
-                continue;
-
-            wanted += tr_torPieceCountBlocks( tor, i );
-            complete += cp->completeBlocks[i];
+            if( !info->pieces[i].dnd )
+            {
+                wanted += countBlocksInPiece( tor, i );
+                complete += complete_blocks[i];
+            }
         }
 
         cp->blocksWantedLazy = wanted;
@@ -87,92 +128,41 @@ tr_cpBlocksMissing( const tr_completion * ccp )
     return ccp->blocksWantedLazy - ccp->blocksWantedCompleteLazy;
 }
 
-uint64_t
-tr_cpSizeWhenDone( const tr_completion * ccp )
+void
+tr_cpPieceRem( tr_completion *  cp, tr_piece_index_t piece )
 {
-    if( ccp->sizeWhenDoneIsDirty )
-    {
-        tr_completion *    cp = (tr_completion *) ccp; /* mutable */
-        const tr_torrent * tor = cp->tor;
-        const tr_info *    info = &tor->info;
-        tr_piece_index_t   i;
-        uint64_t           size = 0;
+    tr_block_index_t i;
+    tr_block_index_t first;
+    tr_block_index_t last;
+    const tr_torrent * tor = cp->tor;
+    uint16_t * complete_blocks = getCompleteBlocks( cp );
 
-        for( i = 0; i < info->pieceCount; ++i )
-        {
-            if( !info->pieces[i].dnd )
-            {
-                /* we want the piece... */
-                size += tr_torPieceCountBytes( tor, i );
-            }
-            else if( tr_cpPieceIsComplete( cp, i ) )
-            {
-                /* we have the piece... */
-                size += tr_torPieceCountBytes( tor, i );
-            }
-            else if( cp->completeBlocks[i] )
-            {
-                /* we have part of the piece... */
-                const tr_block_index_t b = tr_torPieceFirstBlock( tor, i );
-                const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, i );
-                tr_block_index_t j;
-                for( j = b; j < e; ++j )
-                    if( tr_cpBlockIsCompleteFast( cp, j ) )
-                        size += tr_torBlockCountBytes( tor, j );
-            }
-        }
+    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
+    for( i=first; i<=last; ++i )
+        if( tr_cpBlockIsComplete( cp, i ) )
+            cp->sizeNow -= tr_torBlockCountBytes( tor, i );
 
-        cp->sizeWhenDoneLazy = size;
-        cp->sizeWhenDoneIsDirty = 0;
-    }
+    if( !tor->info.pieces[piece].dnd )
+        cp->blocksWantedCompleteLazy -= complete_blocks[piece];
 
-    assert( ccp->sizeWhenDoneLazy <= ccp->tor->info.totalSize );
-    assert( ccp->sizeWhenDoneLazy >= ccp->sizeNow );
-    return ccp->sizeWhenDoneLazy;
+    cp->sizeWhenDoneIsDirty = TRUE;
+    cp->haveValidIsDirty = TRUE;
+    complete_blocks[piece] = 0;
+    tr_bitsetRemRange( &cp->blockBitset, first, last+1 );
 }
 
 void
-tr_cpPieceAdd( tr_completion *  cp,
-               tr_piece_index_t piece )
+tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t piece )
 {
-    const tr_torrent *     tor = cp->tor;
-    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
-    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
-    tr_block_index_t       i;
+    tr_block_index_t i;
+    tr_block_index_t first;
+    tr_block_index_t last;
+    tr_torGetPieceBlockRange( cp->tor, piece, &first, &last );
 
-    for( i = start; i < end; ++i )
+    for( i=first; i<=last; ++i )
         tr_cpBlockAdd( cp, i );
 }
 
-void
-tr_cpPieceRem( tr_completion *  cp,
-               tr_piece_index_t piece )
-{
-    const tr_torrent *     tor = cp->tor;
-    const tr_block_index_t start = tr_torPieceFirstBlock( tor, piece );
-    const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, piece );
-    tr_block_index_t       block;
-
-    assert( cp );
-    assert( piece < tor->info.pieceCount );
-    assert( start < tor->blockCount );
-    assert( start <= end );
-    assert( end <= tor->blockCount );
-
-    for( block = start; block < end; ++block )
-        if( tr_cpBlockIsCompleteFast( cp, block ) )
-            cp->sizeNow -= tr_torBlockCountBytes( tor, block );
-
-    if( !tor->info.pieces[piece].dnd )
-        cp->blocksWantedCompleteLazy -= cp->completeBlocks[piece];
-
-    cp->sizeWhenDoneIsDirty = 1;
-    cp->haveValidIsDirty = 1;
-    cp->completeBlocks[piece] = 0;
-    tr_bitfieldRemRange ( &cp->blockBitfield, start, end );
-    tr_bitfieldRem( &cp->pieceBitfield, piece );
-}
-
 void
 tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
 {
@@ -181,109 +171,82 @@ tr_cpBlockAdd( tr_completion * cp, tr_block_index_t block )
     if( !tr_cpBlockIsComplete( cp, block ) )
     {
         const tr_piece_index_t piece = tr_torBlockPiece( tor, block );
-        const int              blockSize = tr_torBlockCountBytes( tor,
-                                                                  block );
-
-        ++cp->completeBlocks[piece];
+        const int blockSize = tr_torBlockCountBytes( tor, block );
 
-        if( tr_cpPieceIsComplete( cp, piece ) )
-            tr_bitfieldAdd( &cp->pieceBitfield, piece );
+        getCompleteBlocks(cp)[piece]++;
 
-        tr_bitfieldAdd( &cp->blockBitfield, block );
+        tr_bitsetAdd( &cp->blockBitset, block );
 
         cp->sizeNow += blockSize;
         if( !tor->info.pieces[piece].dnd )
             cp->blocksWantedCompleteLazy++;
 
-        cp->haveValidIsDirty = 1;
-        cp->sizeWhenDoneIsDirty = 1;
+        cp->sizeWhenDoneIsDirty = TRUE;
+        cp->haveValidIsDirty = TRUE;
     }
 }
 
 
-void
-tr_cpSetHaveAll( tr_completion * cp )
-{
-    tr_piece_index_t i;
-    tr_torrent * tor = cp->tor;
-
-    tr_cpReset( cp );
-
-    cp->sizeNow = tor->info.totalSize;
-    tr_bitfieldAddRange( &cp->blockBitfield, 0, tor->blockCount );
-    tr_bitfieldAddRange( &cp->pieceBitfield, 0, tor->info.pieceCount );
-    for( i=0; i<tor->info.pieceCount; ++i )
-        cp->completeBlocks[i] = tr_torPieceCountBlocks( tor, i );
-    cp->sizeWhenDoneIsDirty = 1;
-    cp->blocksWantedIsDirty = 1;
-    cp->haveValidIsDirty = 1;
-}
-
-/* Initialize a completion object from a bitfield indicating which blocks we have */
 tr_bool
-tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
+tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks )
 {
     tr_bool success = FALSE;
+    tr_torrent * tor = cp->tor;
 
-    assert( cp );
-    assert( blockBitfield );
+    /* start cp with a state where it thinks we have nothing */
+    tr_cpReset( cp );
 
-    /* The bitfield of block flags is typically loaded from a resume file.
-       Test the bitfield's length in case the resume file somehow got corrupted */
-    if(( success = blockBitfield->byteCount == cp->blockBitfield.byteCount ))
+    if( blocks->haveAll )
     {
-        tr_block_index_t b = 0;
-        tr_piece_index_t p = 0;
-        uint32_t pieceBlock = 0;
-        uint16_t completeBlocksInPiece = 0;
-        tr_block_index_t completeBlocksInTorrent = 0;
-        uint32_t blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
-
-        /* start cp with a state where it thinks we have nothing */
-        tr_cpReset( cp );
+        tr_bitsetSetHaveAll( &cp->blockBitset );
+        cp->sizeNow = tor->info.totalSize;
 
-        /* init our block bitfield from the one passed in */
-        memcpy( cp->blockBitfield.bits, blockBitfield->bits, blockBitfield->byteCount );
+        success = TRUE;
+    }
+    else if( blocks->haveNone )
+    {
+        /* already reset... */
+        success = TRUE;
+    }
+    else
+    {
+        const tr_bitfield * src = &blocks->bitfield;
+        tr_bitfield * tgt = &cp->blockBitset.bitfield;
 
-        /* invalidate the fields that are lazy-evaluated */
-        cp->sizeWhenDoneIsDirty = TRUE;
-        cp->blocksWantedIsDirty = TRUE;
-        cp->haveValidIsDirty = TRUE;
+        tr_bitfieldConstruct( tgt, tor->blockCount );
 
-        /* to set the remaining fields, we walk through every block... */
-        while( b < cp->tor->blockCount )
+        /* The bitfield of block flags is typically loaded from a resume file.
+           Test the bitfield's length in case the resume file is corrupt */
+        if(( success = src->byteCount == tgt->byteCount ))
         {
-            if( tr_bitfieldHasFast( blockBitfield, b ) )
-                ++completeBlocksInPiece;
-
-            ++b;
-            ++pieceBlock;
-
-            /* by the time we reach the end of a piece, we have enough info
-               to update that piece's slot in cp.completeBlocks and cp.pieceBitfield */
-            if( pieceBlock == blocksInCurrentPiece )
-            {
-                cp->completeBlocks[p] = completeBlocksInPiece;
-                completeBlocksInTorrent += completeBlocksInPiece;
-                if( completeBlocksInPiece == blocksInCurrentPiece )
-                    tr_bitfieldAdd( &cp->pieceBitfield, p );
-
-                /* reset the per-piece counters because we're starting on a new piece now */
-                ++p;
-                completeBlocksInPiece = 0;
-                pieceBlock = 0;
-                blocksInCurrentPiece = tr_torPieceCountBlocks( cp->tor, p );
+            size_t i = 0;
+            uint16_t * complete_blocks_in_piece = getCompleteBlocks( cp );
+
+            /* init our block bitfield from the one passed in */
+            memcpy( tgt->bits, src->bits, src->byteCount );
+
+            /* update cp.sizeNow and the cp.blockBitset flags */
+            i = tr_bitfieldCountTrueBits( tgt );
+            if( i == tor->blockCount ) {
+                tr_bitsetSetHaveAll( &cp->blockBitset );
+                cp->sizeNow = cp->tor->info.totalSize;
+            } else if( !i ) {
+                tr_bitsetSetHaveNone( &cp->blockBitset );
+                cp->sizeNow = 0;
+            } else {
+                cp->blockBitset.haveAll = cp->blockBitset.haveNone = FALSE;
+                cp->sizeNow = tr_bitfieldCountRange( tgt, 0, tor->blockCount-1 );
+                cp->sizeNow *= tor->blockSize;
+                if( tr_bitfieldHas( tgt, tor->blockCount-1 ) )
+                    cp->sizeNow += tr_torBlockCountBytes( tor, tor->blockCount-1 );
             }
-        }
 
-        /* update sizeNow */
-        cp->sizeNow = completeBlocksInTorrent;
-        cp->sizeNow *= tr_torBlockCountBytes( cp->tor, 0 );
-        if( tr_bitfieldHasFast( &cp->blockBitfield, cp->tor->blockCount-1 ) ) {
-            /* the last block is usually smaller than the other blocks,
-               so handle that special case or cp->sizeNow might be too large */
-            cp->sizeNow -= tr_torBlockCountBytes( cp->tor, 0 );
-            cp->sizeNow += tr_torBlockCountBytes( cp->tor, cp->tor->blockCount-1 );
+            /* update complete_blocks_in_piece */
+            for( i=0; i<tor->info.pieceCount; ++i ) {
+                 tr_block_index_t first, last;
+                 tr_torGetPieceBlockRange( tor, i, &first, &last );
+                 complete_blocks_in_piece[i] = tr_bitfieldCountRange( src, first, last+1 );
+            }
         }
     }
 
@@ -294,142 +257,91 @@ tr_cpBlockBitfieldSet( tr_completion * cp, tr_bitfield * blockBitfield )
 ****
 ***/
 
-tr_completeness
-tr_cpGetStatus( const tr_completion * cp )
-{
-    if( !tr_torrentHasMetadata( cp->tor ) ) return TR_LEECH;
-    if( cp->sizeNow == cp->tor->info.totalSize ) return TR_SEED;
-    if( cp->sizeNow == tr_cpSizeWhenDone( cp ) ) return TR_PARTIAL_SEED;
-    return TR_LEECH;
-}
-
-static uint64_t
-calculateHaveValid( const tr_completion * ccp )
+uint64_t
+tr_cpHaveValid( const tr_completion * ccp )
 {
-    uint64_t                  b = 0;
-    tr_piece_index_t          i;
-    const tr_torrent        * tor            = ccp->tor;
-    const uint64_t            pieceSize      = tor->info.pieceSize;
-    const uint64_t            lastPieceSize  = tor->lastPieceSize;
-    const tr_piece_index_t    lastPiece      = tor->info.pieceCount - 1;
-
-    if( !tr_torrentHasMetadata( tor ) )
-        return 0;
+    if( ccp->haveValidIsDirty )
+    {
+        tr_piece_index_t   i;
+        uint64_t           size = 0;
+        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
+        const tr_torrent * tor = ccp->tor;
+        const tr_info    * info = &tor->info;
 
-    for( i=0; i!=lastPiece; ++i )
-        if( tr_cpPieceIsComplete( ccp, i ) )
-            b += pieceSize;
+        for( i=0; i<info->pieceCount; ++i )
+            if( tr_cpPieceIsComplete( ccp, i ) )
+                size += tr_torPieceCountBytes( tor, i );
 
-    if( tr_cpPieceIsComplete( ccp, lastPiece ) )
-        b += lastPieceSize;
+        cp->haveValidIsDirty = FALSE;
+        cp->haveValidLazy = size;
+    }
 
-    return b;
+    return ccp->haveValidLazy;
 }
 
 uint64_t
-tr_cpHaveValid( const tr_completion * ccp )
+tr_cpSizeWhenDone( const tr_completion * ccp )
 {
-    if( ccp->haveValidIsDirty )
+    if( ccp->sizeWhenDoneIsDirty )
     {
-        tr_completion * cp = (tr_completion *) ccp; /* mutable */
-        cp->haveValidLazy = calculateHaveValid( ccp );
-        cp->haveValidIsDirty = 0;
+        tr_piece_index_t   i;
+        uint64_t           size = 0;
+        tr_completion    * cp = (tr_completion *) ccp; /* mutable */
+        const tr_torrent * tor = ccp->tor;
+        const tr_info    * info = &tor->info;
+
+        for( i=0; i<info->pieceCount; ++i )
+            if( !info->pieces[i].dnd || tr_cpPieceIsComplete( cp, i ) )
+                size += tr_torPieceCountBytes( tor, i );
+
+        cp->sizeWhenDoneIsDirty = FALSE;
+        cp->sizeWhenDoneLazy = size;
     }
 
-    return ccp->haveValidLazy;
+    return ccp->sizeWhenDoneLazy;
 }
 
 void
-tr_cpGetAmountDone( const tr_completion * cp,
-                    float *               tab,
-                    int                   tabCount )
+tr_cpGetAmountDone( const tr_completion * cp, float * tab, int tabCount )
 {
-    int                i;
-    const tr_torrent * tor = cp->tor;
-    const float        interval = tor->info.pieceCount / (float)tabCount;
-    const int          isSeed = tr_cpGetStatus( cp ) == TR_SEED;
+    int i, b;
+    const int span = cp->tor->blockCount / tabCount;
 
-    for( i = 0; i < tabCount; ++i )
-    {
-        const tr_piece_index_t piece = i * interval;
-
-        if( tor == NULL )
-            tab[i] = 0.0f;
-        else if( isSeed || tr_cpPieceIsComplete( cp, piece ) )
-            tab[i] = 1.0f;
-        else
-            tab[i] = (float)cp->completeBlocks[piece] /
-                     tr_torPieceCountBlocks( tor, piece );
-    }
+    for( i=b=0; i<tabCount; ++i, b+=span )
+        tab[i] = tr_bitsetCountRange(&cp->blockBitset,b,b+span) / (float)span;
 }
 
 int
-tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t piece )
+tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i )
 {
-    return tr_torPieceCountBlocks( cp->tor, piece ) - cp->completeBlocks[piece];
-}
-
+    if( isSeed( cp ) )
+        return 0;
 
-tr_bool
-tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t piece )
-{
-    return cp->completeBlocks[piece] == tr_torPieceCountBlocks( cp->tor, piece );
+    return countBlocksInPiece( cp->tor, i ) - getCompleteBlocks(cp)[i];
 }
 
 tr_bool
-tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t fileIndex )
+tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t i )
 {
-    tr_block_index_t block;
+    tr_block_index_t f, l;
 
-    const tr_torrent * tor = cp->tor;
-    const tr_file * file = &tor->info.files[fileIndex];
+    if( cp->tor->info.files[i].length == 0 )
+        return TRUE;
 
-    if( file->firstPiece == file->lastPiece )
-    {
-        const tr_block_index_t firstBlock = file->offset / tor->blockSize;
-        const tr_block_index_t lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
-        for( block=firstBlock; block<=lastBlock; ++block )
-            if( !tr_cpBlockIsCompleteFast( cp, block ) )
-                return FALSE;
-    }
-    else
-    {
-        tr_piece_index_t piece;
-        tr_block_index_t firstBlock;
-        tr_block_index_t firstBlockInLastPiece;
-        tr_block_index_t lastBlock;
-        tr_block_index_t lastBlockInFirstPiece;
-        uint64_t lastByteInFirstPiece;
-        uint64_t firstByteInLastPiece;
-
-        /* go piece-by-piece in the middle pieces... it's faster than block-by-block */
-        for( piece=file->firstPiece+1; piece<file->lastPiece; ++piece )
-            if( !tr_cpPieceIsComplete( cp, piece ) )
-                return FALSE;
-
-        /* go block-by-block in the first piece */
-        firstBlock = file->offset / tor->blockSize;
-        lastByteInFirstPiece = ( (uint64_t)(file->firstPiece+1) * tor->info.pieceSize ) - 1;
-        lastBlockInFirstPiece = lastByteInFirstPiece / tor->blockSize;
-        assert( lastBlockInFirstPiece >= firstBlock );
-        assert( lastBlockInFirstPiece - firstBlock <= tr_torPieceCountBlocks( tor, file->firstPiece ) );
-        for( block=firstBlock; block<=lastBlockInFirstPiece; ++block )
-            if( !tr_cpBlockIsCompleteFast( cp, block ) )
-                return FALSE;
-
-        /* go block-by-block in the last piece */
-        lastBlock = file->length ? ( ( file->offset + file->length - 1 ) / tor->blockSize ) : firstBlock;
-        firstByteInLastPiece = (uint64_t)file->lastPiece * tor->info.pieceSize;
-        firstBlockInLastPiece = firstByteInLastPiece / tor->blockSize;
-        assert( firstBlockInLastPiece <= lastBlock );
-        assert( firstBlockInLastPiece >= firstBlock );
-        assert( firstBlockInLastPiece >= lastBlockInFirstPiece );
-        assert( lastBlock - firstBlockInLastPiece <= tr_torPieceCountBlocks( tor, file->lastPiece ) );
-        for( block=firstBlockInLastPiece; block<=lastBlock; ++block )
-            if( !tr_cpBlockIsCompleteFast( cp, block ) )
-                return FALSE;
-    }
+    tr_torGetFileBlockRange( cp->tor, i, &f, &l );
+    return tr_bitsetCountRange( &cp->blockBitset, f, l+1 ) == (l+1-f);
+}
+
+tr_bitfield *
+tr_cpCreatePieceBitfield( const tr_completion * cp )
+{
+    tr_piece_index_t i;
+    const tr_piece_index_t n = cp->tor->info.pieceCount;
+    tr_bitfield * bf = tr_bitfieldNew( n );
 
-    return TRUE;
+    for( i=0; i<n; ++i )
+        if( tr_cpPieceIsComplete( cp, i ) )
+            tr_bitfieldAdd( bf, i );
 
+    return bf;
 }
index ea0ad5e27f1e57963806c87dc40257966793aa2f..e2cf2a49fa6c014cd019201df76fa774af787ee0 100644 (file)
@@ -20,7 +20,8 @@
 #include <assert.h>
 
 #include "transmission.h"
-#include "bitfield.h"
+#include "bitset.h"
+#include "utils.h" /* tr_getRatio() */
 
 typedef struct tr_completion
 {
@@ -31,10 +32,7 @@ typedef struct tr_completion
     tr_torrent *    tor;
 
     /* do we have this block? */
-    tr_bitfield    blockBitfield;
-
-    /* do we have this piece? */
-    tr_bitfield    pieceBitfield;
+    tr_bitset    blockBitset;
 
     /* a block is complete if and only if we have it */
     uint16_t *  completeBlocks;
@@ -76,19 +74,19 @@ tr_completion * tr_cpDestruct( tr_completion * );
 *** General
 **/
 
-tr_completeness            tr_cpGetStatus( const tr_completion * );
+tr_completeness    tr_cpGetStatus( const tr_completion * );
 
-uint64_t                   tr_cpHaveValid( const tr_completion * );
+uint64_t           tr_cpHaveValid( const tr_completion * );
 
-tr_block_index_t           tr_cpBlocksMissing( const tr_completion * );
+tr_block_index_t   tr_cpBlocksMissing( const tr_completion * );
 
-uint64_t                   tr_cpSizeWhenDone( const tr_completion * );
+uint64_t           tr_cpSizeWhenDone( const tr_completion * );
 
-void                       tr_cpInvalidateDND( tr_completion * );
+void               tr_cpInvalidateDND( tr_completion * );
 
-void                       tr_cpGetAmountDone( const   tr_completion * completion,
-                                               float                 * tab,
-                                               int                     tabCount );
+void               tr_cpGetAmountDone( const   tr_completion * completion,
+                                       float                 * tab,
+                                       int                     tabCount );
 
 static inline uint64_t tr_cpHaveTotal( const tr_completion * cp )
 {
@@ -127,17 +125,17 @@ static inline double tr_cpPercentDone( const tr_completion * cp )
 *** Pieces
 **/
 
-int tr_cpMissingBlocksInPiece( const tr_completion  * cp,
-                               tr_piece_index_t       piece );
+int tr_cpMissingBlocksInPiece( const tr_completion * cp, tr_piece_index_t i );
 
-tr_bool  tr_cpPieceIsComplete( const tr_completion * cp,
-                               tr_piece_index_t      piece );
+static inline tr_bool
+tr_cpPieceIsComplete( const tr_completion * cp, tr_piece_index_t i )
+{
+    return tr_cpMissingBlocksInPiece( cp, i ) == 0;
+}
 
-void   tr_cpPieceAdd( tr_completion    * completion,
-                      tr_piece_index_t   piece );
+void   tr_cpPieceAdd( tr_completion * cp, tr_piece_index_t i );
 
-void   tr_cpPieceRem( tr_completion     * completion,
-                      tr_piece_index_t   piece );
+void   tr_cpPieceRem( tr_completion * cp, tr_piece_index_t i );
 
 tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
 
@@ -145,37 +143,26 @@ tr_bool tr_cpFileIsComplete( const tr_completion * cp, tr_file_index_t );
 *** Blocks
 **/
 
-static inline tr_bool tr_cpBlockIsCompleteFast( const tr_completion * cp, tr_block_index_t block )
+static inline tr_bool
+tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t i )
 {
-    return tr_bitfieldHasFast( &cp->blockBitfield, block );
+    return tr_bitsetHas( &cp->blockBitset, i );
 }
 
-static inline tr_bool tr_cpBlockIsComplete( const tr_completion * cp, tr_block_index_t block )
-{
-    return tr_bitfieldHas( &cp->blockBitfield, block );
-}
+void tr_cpBlockAdd( tr_completion * cp, tr_block_index_t i );
 
-void      tr_cpBlockAdd( tr_completion * completion,
-                         tr_block_index_t block );
-
-tr_bool   tr_cpBlockBitfieldSet( tr_completion      * completion,
-                                 struct tr_bitfield * blocks );
-
-void      tr_cpSetHaveAll( tr_completion * completion );
+tr_bool tr_cpBlockBitsetInit( tr_completion * cp, const tr_bitset * blocks );
 
 /***
 ****
 ***/
 
-static inline const struct tr_bitfield * tr_cpPieceBitfield( const tr_completion * cp ) {
-    return &cp->pieceBitfield;
+static inline const tr_bitset *
+tr_cpBlockBitset( const tr_completion * cp )
+{
+    return &cp->blockBitset;
 }
 
-static inline const struct tr_bitfield * tr_cpBlockBitfield( const tr_completion * cp ) {
-    assert( cp );
-    assert( cp->blockBitfield.bits );
-    assert( cp->blockBitfield.bitCount );
-    return &cp->blockBitfield;
-}
+tr_bitfield * tr_cpCreatePieceBitfield( const tr_completion * cp );
 
 #endif
index 122674d106e501cf147f8098141ee930488b2b1f..6ecca40ce82059d12b47dd1898f045030ec8b691 100644 (file)
@@ -383,7 +383,7 @@ peerConstructor( struct peer_atom * atom )
 {
     tr_peer * peer = tr_new0( tr_peer, 1 );
 
-    tr_bitsetConstructor( &peer->have, 0 );
+    peer->have = TR_BITSET_INIT;
 
     peer->atom = atom;
     atom->peer = peer;
@@ -434,7 +434,7 @@ peerDestructor( Torrent * t, tr_peer * peer )
     tr_historyFree( peer->cancelsSentToClient );
     tr_historyFree( peer->cancelsSentToPeer   );
 
-    tr_bitsetDestructor( &peer->have );
+    tr_bitsetDestruct( &peer->have );
     tr_bitfieldFree( peer->blame );
     tr_free( peer->client );
     peer->atom->peer = NULL;
@@ -1335,17 +1335,20 @@ tr_peerMgrGetNextRequests( tr_torrent           * tor,
         /* if the peer has this piece that we want... */
         if( tr_bitsetHas( have, p->index ) )
         {
-            tr_block_index_t b = tr_torPieceFirstBlock( tor, p->index );
-            const tr_block_index_t e = b + tr_torPieceCountBlocks( tor, p->index );
+            tr_block_index_t b;
+            tr_block_index_t first;
+            tr_block_index_t last;
             tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
 
-            for( ; b!=e && got<numwant; ++b )
+            tr_torGetPieceBlockRange( tor, p->index, &first, &last );
+
+            for( b=first; b<=last && got<numwant; ++b )
             {
                 int peerCount;
                 tr_peer ** peers;
 
                 /* don't request blocks we've already got */
-                if( tr_cpBlockIsCompleteFast( &tor->completion, b ) )
+                if( tr_cpBlockIsComplete( &tor->completion, b ) )
                     continue;
 
                 /* always add peer if this block has no peers yet */
@@ -1546,17 +1549,19 @@ peerSuggestedPiece( Torrent            * t UNUSED,
 
     /* request the blocks that we don't have in this piece */
     {
-        tr_block_index_t block;
+        tr_block_index_t b;
+        tr_block_index_t first;
+        tr_block_index_t last;
         const tr_torrent * tor = t->tor;
-        const tr_block_index_t start = tr_torPieceFirstBlock( tor, pieceIndex );
-        const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, pieceIndex );
 
-        for( block=start; block<end; ++block )
+        tr_torGetPieceBlockRange( t->tor, pieceIndex, &first, &last );
+
+        for( b=first; b<=last; ++b )
         {
-            if( !tr_cpBlockIsComplete( tor->completion, block ) )
+            if( !tr_cpBlockIsComplete( tor->completion, b ) )
             {
-                const uint32_t offset = getBlockOffsetInPiece( tor, block );
-                const uint32_t length = tr_torBlockCountBytes( tor, block );
+                const uint32_t offset = getBlockOffsetInPiece( tor, b );
+                const uint32_t length = tr_torBlockCountBytes( tor, b );
                 tr_peerMsgsAddRequest( peer->msgs, pieceIndex, offset, length );
                 incrementPieceRequests( t, pieceIndex );
             }
index 8f829021a38ecde9967a86b793eb5b8c88b2ba39..e1af82f2df9709175208063e2d02a632a3852729 100644 (file)
@@ -88,10 +88,6 @@ enum
     HIGH_PRIORITY_INTERVAL_SECS = 2,
     LOW_PRIORITY_INTERVAL_SECS = 10,
 
-    /* number of pieces to remove from the bitfield when
-     * lazy bitfields are turned on */
-    LAZY_PIECE_COUNT = 26,
-
     /* number of pieces we'll allow in our fast set */
     MAX_FAST_SET_SIZE = 3,
 
@@ -120,25 +116,14 @@ struct peer_request
     uint32_t    length;
 };
 
-static uint32_t
-getBlockOffsetInPiece( const tr_torrent * tor, uint64_t b )
-{
-    const uint64_t piecePos = tor->info.pieceSize * tr_torBlockPiece( tor, b );
-    const uint64_t blockPos = tor->blockSize * b;
-    assert( blockPos >= piecePos );
-    return (uint32_t)( blockPos - piecePos );
-}
-
 static void
 blockToReq( const tr_torrent     * tor,
             tr_block_index_t       block,
             struct peer_request  * setme )
 {
-    assert( setme != NULL );
-
-    setme->index = tr_torBlockPiece( tor, block );
-    setme->offset = getBlockOffsetInPiece( tor, block );
-    setme->length = tr_torBlockCountBytes( tor, block );
+    tr_torrentGetBlockLocation( tor, block, &setme->index,
+                                            &setme->offset,
+                                            &setme->length );
 }
 
 /**
@@ -1451,21 +1436,24 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
             }
 
             /* a peer can send the same HAVE message twice... */
-            if( !tr_bitsetHas( &msgs->peer->have, ui32 ) )
-                if( !tr_bitsetAdd( &msgs->peer->have, ui32 ) )
-                    fireClientGotHave( msgs, ui32 );
+            if( !tr_bitsetHas( &msgs->peer->have, ui32 ) ) {
+                tr_bitsetAdd( &msgs->peer->have, ui32 );
+                fireClientGotHave( msgs, ui32 );
+            }
             updatePeerProgress( msgs );
             break;
 
         case BT_BITFIELD: {
+            tr_bitfield tmp = TR_BITFIELD_INIT;
             const size_t bitCount = tr_torrentHasMetadata( msgs->torrent )
                                   ? msgs->torrent->info.pieceCount
                                   : msglen * 8;
+            tr_bitfieldConstruct( &tmp, bitCount );
             dbgmsg( msgs, "got a bitfield" );
-            tr_bitsetReserve( &msgs->peer->have, bitCount );
-            tr_peerIoReadBytes( msgs->peer->io, inbuf,
-                                msgs->peer->have.bitfield.bits, msglen );
-            fireClientGotBitfield( msgs, &msgs->peer->have.bitfield );
+            tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp.bits, msglen );
+            tr_bitsetSetBitfield( &msgs->peer->have, &tmp );
+            fireClientGotBitfield( msgs, &tmp );
+            tr_bitfieldDestruct( &tmp );
             updatePeerProgress( msgs );
             break;
         }
@@ -2049,52 +2037,15 @@ static void
 sendBitfield( tr_peermsgs * msgs )
 {
     struct evbuffer * out = msgs->outMessages;
-    tr_bitfield *     field;
-    tr_piece_index_t  lazyPieces[LAZY_PIECE_COUNT];
-    size_t            i;
-    size_t            lazyCount = 0;
+    tr_bitfield * bf = tr_cpCreatePieceBitfield( &msgs->torrent->completion );
 
-    field = tr_bitfieldDup( tr_cpPieceBitfield( &msgs->torrent->completion ) );
-
-    if( tr_sessionIsLazyBitfieldEnabled( getSession( msgs ) ) )
-    {
-        /** Lazy bitfields aren't a high priority or secure, so I'm opting for
-            speed over a truly random sample -- let's limit the pool size to
-            the first 1000 pieces so large torrents don't bog things down */
-        size_t poolSize;
-        const size_t maxPoolSize = MIN( msgs->torrent->info.pieceCount, 1000 );
-        tr_piece_index_t * pool = tr_new( tr_piece_index_t, maxPoolSize );
-
-        /* build the pool */
-        for( i=poolSize=0; i<maxPoolSize; ++i )
-            if( tr_bitfieldHas( field, i ) )
-                pool[poolSize++] = i;
-
-        /* pull random piece indices from the pool */
-        while( ( poolSize > 0 ) && ( lazyCount < LAZY_PIECE_COUNT ) )
-        {
-            const int pos = tr_cryptoWeakRandInt( poolSize );
-            const tr_piece_index_t piece = pool[pos];
-            tr_bitfieldRem( field, piece );
-            lazyPieces[lazyCount++] = piece;
-            pool[pos] = pool[--poolSize];
-        }
-
-        /* cleanup */
-        tr_free( pool );
-    }
-
-    evbuffer_add_uint32( out, sizeof( uint8_t ) + field->byteCount );
+    evbuffer_add_uint32( out, sizeof( uint8_t ) + bf->byteCount );
     evbuffer_add_uint8 ( out, BT_BITFIELD );
-    evbuffer_add       ( out, field->bits, field->byteCount );
-    dbgmsg( msgs, "sending bitfield... outMessage size is now %zu",
-            evbuffer_get_length( out ) );
+    evbuffer_add       ( out, bf->bits, bf->byteCount );
+    dbgmsg( msgs, "sending bitfield... outMessage size is now %zu", evbuffer_get_length( out ) );
     pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
 
-    for( i = 0; i < lazyCount; ++i )
-        protocolSendHave( msgs, lazyPieces[i] );
-
-    tr_bitfieldFree( field );
+    tr_bitfieldFree( bf );
 }
 
 static void
@@ -2102,11 +2053,11 @@ tellPeerWhatWeHave( tr_peermsgs * msgs )
 {
     const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
 
-    if( fext && ( tr_cpGetStatus( &msgs->torrent->completion ) == TR_SEED ) )
+    if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveAll ) )
     {
         protocolSendHaveAll( msgs );
     }
-    else if( fext && ( tr_cpHaveValid( &msgs->torrent->completion ) == 0 ) )
+    else if( fext && ( tr_cpBlockBitset( &msgs->torrent->completion )->haveNone ) )
     {
         protocolSendHaveNone( msgs );
     }
index a88996927ce849175836ebf8d491a569c2c81d0f..e099b9197f80b4ff92799309027d555d6f366fd5 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "transmission.h"
 #include "bencode.h"
+#include "bitset.h"
 #include "completion.h"
 #include "metainfo.h" /* tr_metainfoGetBasename() */
 #include "peer-mgr.h" /* pex */
@@ -65,6 +66,7 @@
 #define KEY_PROGRESS_CHECKTIME "time-checked"
 #define KEY_PROGRESS_MTIMES    "mtimes"
 #define KEY_PROGRESS_BITFIELD  "bitfield"
+#define KEY_PROGRESS_BLOCKS    "blocks"
 #define KEY_PROGRESS_HAVE      "have"
 
 enum
@@ -407,12 +409,11 @@ loadIdleLimits( tr_benc *    dict,
 ***/
 
 static void
-saveProgress( tr_benc * dict, const tr_torrent * tor )
+saveProgress( tr_benc * dict, tr_torrent * tor )
 {
     tr_benc * l;
     tr_benc * prog;
     tr_file_index_t fi;
-    const struct tr_bitfield * bitfield;
     const tr_info * inf = tr_torrentInfo( tor );
     const time_t now = tr_time( );
 
@@ -467,10 +468,9 @@ saveProgress( tr_benc * dict, const tr_torrent * tor )
     if( tor->completeness == TR_SEED )
         tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" );
 
-    /* add the pieces bitfield */
-    bitfield = tr_cpBlockBitfield( &tor->completion );
-    tr_bencDictAddRaw( prog, KEY_PROGRESS_BITFIELD, bitfield->bits,
-                                                    bitfield->byteCount );
+    /* add the blocks bitfield */
+    tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ),
+                     tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) );
 }
 
 static uint64_t
@@ -491,6 +491,8 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
         const uint8_t * raw;
         size_t rawlen;
         tr_benc * l;
+        tr_benc * b;
+        struct tr_bitset bitset = TR_BITSET_INIT;
 
         if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
         {
@@ -565,24 +567,29 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
         }
 
         err = NULL;
-        if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
+
+        if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
+        {
+            if( !tr_bitsetFromBenc( &bitset, b ) )
+                err = "Invalid value for PIECES";
+        }
+        else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
         {
             if( !strcmp( str, "all" ) )
-                tr_cpSetHaveAll( &tor->completion );
+                tr_bitsetSetHaveAll( &bitset );
             else
                 err = "Invalid value for HAVE";
         }
         else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
         {
-            tr_bitfield tmp;
-            tmp.byteCount = rawlen;
-            tmp.bitCount = tmp.byteCount * 8;
-            tmp.bits = (uint8_t*) raw;
-            if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
-                err = "Error loading bitfield";
+            bitset.bitfield.bits = (void*) raw;
+            bitset.bitfield.byteCount = rawlen;
+            bitset.bitfield.bitCount = rawlen * 8;
         }
-        else err = "Couldn't find 'have' or 'bitfield'";
+        else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
 
+        if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) )
+            err = "Error loading bitfield";
         if( err != NULL )
             tr_tordbg( tor, "Torrent needs to be verified - %s", err );
 
index b3a4efdafc6e8c626f7aad3f53f8a049b4664f40..fc8a5a42fa057504f96dab456ef9132da465a509 100644 (file)
@@ -561,10 +561,11 @@ addField( const tr_torrent * tor, tr_benc * d, const char * key )
     else if( tr_streq( key, keylen, "peersSendingToUs" ) )
         tr_bencDictAddInt( d, key, st->peersSendingToUs );
     else if( tr_streq( key, keylen, "pieces" ) ) {
-        const tr_bitfield * pieces = tr_cpPieceBitfield( &tor->completion );
-        char * str = tr_base64_encode( pieces->bits, pieces->byteCount, NULL );
+        tr_bitfield * bf = tr_cpCreatePieceBitfield( &tor->completion );
+        char * str = tr_base64_encode( bf->bits, bf->byteCount, NULL );
         tr_bencDictAddStr( d, key, str!=NULL ? str : "" );
         tr_free( str );
+        tr_bitfieldFree( bf );
     }
     else if( tr_streq( key, keylen, "pieceCount" ) )
         tr_bencDictAddInt( d, key, inf->pieceCount );
index 95b05cab48d13e21ae3e629cbda1cbfac55c7513..e729f5f8b834374a0fc2004a4ede1dd18f732c3a 100644 (file)
@@ -325,7 +325,6 @@ tr_sessionGetDefaultSettings( const char * configDir UNUSED, tr_benc * d )
     tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED,       FALSE );
     tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           tr_getDefaultDownloadDir( ) );
     tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   FALSE );
-    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          atoi( TR_DEFAULT_OPEN_FILE_LIMIT_STR ) );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        atoi( TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ) );
@@ -390,7 +389,6 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
     tr_bencDictAddBool( d, TR_PREFS_KEY_IDLE_LIMIT_ENABLED,       tr_sessionIsIdleLimited( s ) );
     tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           tr_sessionGetIncompleteDir( s ) );
     tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   tr_sessionIsIncompleteDirEnabled( s ) );
-    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_OPEN_FILE_LIMIT,          tr_fdGetFileLimit( s ) );
     tr_bencDictAddInt ( d, TR_PREFS_KEY_PEER_LIMIT_GLOBAL,        tr_sessionGetPeerLimit( s ) );
@@ -758,8 +756,6 @@ sessionSetImpl( void * vdata )
     /* misc features */
     if( tr_bencDictFindInt( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, &i ) )
         tr_sessionSetCacheLimit_MB( session, i );
-    if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal ) )
-        tr_sessionSetLazyBitfieldEnabled( session, boolVal );
     if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
         tr_sessionSetPeerLimitPerTorrent( session, i );
     if( tr_bencDictFindBool( settings, TR_PREFS_KEY_PEX_ENABLED, &boolVal ) )
index 4ecf360f0a1ef59ac49f9f8998ba580289086fbc..4f702b8c3f34eee116142bd4202589f58274f0b9 100644 (file)
@@ -1308,61 +1308,31 @@ fileBytesCompleted( const tr_torrent * tor, tr_file_index_t index )
 
     if( f->length )
     {
-        const tr_block_index_t firstBlock = f->offset / tor->blockSize;
-        const uint64_t lastByte = f->offset + f->length - 1;
-        const tr_block_index_t lastBlock = lastByte / tor->blockSize;
+        tr_block_index_t first;
+        tr_block_index_t last;
+        tr_torGetFileBlockRange( tor, index, &first, &last );
 
-        if( firstBlock == lastBlock )
+        if( first == last )
         {
-            if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
+            if( tr_cpBlockIsComplete( &tor->completion, first ) )
                 total = f->length;
         }
         else
         {
-            tr_block_index_t i;
-
             /* the first block */
-            if( tr_cpBlockIsCompleteFast( &tor->completion, firstBlock ) )
+            if( tr_cpBlockIsComplete( &tor->completion, first ) )
                 total += tor->blockSize - ( f->offset % tor->blockSize );
 
             /* the middle blocks */
-            if( f->firstPiece == f->lastPiece )
-            {
-                for( i=firstBlock+1; i<lastBlock; ++i )
-                    if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
-                        total += tor->blockSize;
-            }
-            else
-            {
-                uint64_t b = 0;
-                const tr_block_index_t firstBlockOfLastPiece
-                           = tr_torPieceFirstBlock( tor, f->lastPiece );
-                const tr_block_index_t lastBlockOfFirstPiece
-                           = tr_torPieceFirstBlock( tor, f->firstPiece )
-                             + tr_torPieceCountBlocks( tor, f->firstPiece ) - 1;
-
-                /* the rest of the first piece */
-                for( i=firstBlock+1; i<lastBlock && i<=lastBlockOfFirstPiece; ++i )
-                    if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
-                        ++b;
-
-                /* the middle pieces */
-                if( f->firstPiece + 1 < f->lastPiece )
-                    for( i=f->firstPiece+1; i<f->lastPiece; ++i )
-                        b += tor->blockCountInPiece - tr_cpMissingBlocksInPiece( &tor->completion, i );
-
-                /* the rest of the last piece */
-                for( i=firstBlockOfLastPiece; i<lastBlock; ++i )
-                    if( tr_cpBlockIsCompleteFast( &tor->completion, i ) )
-                        ++b;
-
-                b *= tor->blockSize;
-                total += b;
+            if( first + 1 < last ) {
+                uint64_t u = tr_bitsetCountRange( tr_cpBlockBitset( &tor->completion ), first+1, last );
+                u *= tor->blockSize;
+                total += u;
             }
 
             /* the last block */
-            if( tr_cpBlockIsCompleteFast( &tor->completion, lastBlock ) )
-                total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * lastBlock );
+            if( tr_cpBlockIsComplete( &tor->completion, last ) )
+                total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * last );
         }
     }
 
@@ -2282,6 +2252,21 @@ tr_torrentGetPeerLimit( const tr_torrent * tor )
 ****
 ***/
 
+void
+tr_torrentGetBlockLocation( const tr_torrent * tor, 
+                            tr_block_index_t   block,
+                            tr_piece_index_t * piece,
+                            uint32_t         * offset,
+                            uint32_t         * length )
+{
+    uint64_t pos = block;
+    pos *= tor->blockSize;
+    *piece = pos / tor->info.pieceSize;
+    *offset = pos - ( *piece * tor->info.pieceSize );
+    *length = tr_torBlockCountBytes( tor, block );
+}
+
+
 tr_block_index_t
 _tr_block( const tr_torrent * tor,
            tr_piece_index_t   index,
@@ -2344,6 +2329,37 @@ tr_pieceOffset( const tr_torrent * tor,
     return ret;
 }
 
+void
+tr_torGetFileBlockRange( const tr_torrent        * tor,
+                         const tr_file_index_t     file,
+                         tr_block_index_t        * first,
+                         tr_block_index_t        * last )
+{
+    const tr_file * f = &tor->info.files[file];
+    uint64_t offset = f->offset;
+    *first = offset / tor->blockSize;
+    if( !f->length )
+        *last = *first;
+    else {
+        offset += f->length - 1;
+        *last = offset / tor->blockSize;
+    }
+}
+
+void
+tr_torGetPieceBlockRange( const tr_torrent        * tor,
+                          const tr_piece_index_t    piece,
+                          tr_block_index_t        * first,
+                          tr_block_index_t        * last )
+{
+    uint64_t offset = tor->info.pieceSize;
+    offset *= piece;
+    *first = offset / tor->blockSize;
+    offset += ( tr_torPieceCountBytes( tor, piece ) - 1 );
+    *last = offset / tor->blockSize;
+}
+
+
 /***
 ****
 ***/
index 923799625c4b9f83f580ad93af9a845090e41c6a..20bf8032b595a9704c77c0590d96fdf7fd493ad6 100644 (file)
@@ -82,6 +82,22 @@ uint64_t         tr_pieceOffset( const tr_torrent * tor,
                                  uint32_t           offset,
                                  uint32_t           length );
 
+void             tr_torrentGetBlockLocation( const tr_torrent * tor, 
+                                             tr_block_index_t   block,
+                                             tr_piece_index_t * piece, 
+                                             uint32_t         * offset,
+                                             uint32_t         * length );
+
+void             tr_torGetFileBlockRange( const tr_torrent        * tor,
+                                          const tr_file_index_t     file,
+                                          tr_block_index_t        * first,
+                                          tr_block_index_t        * last );
+
+void             tr_torGetPieceBlockRange( const tr_torrent        * tor,
+                                           const tr_piece_index_t    piece,
+                                           tr_block_index_t        * first,
+                                           tr_block_index_t        * last );
+
 void             tr_torrentInitFilePriority( tr_torrent       * tor,
                                              tr_file_index_t    fileIndex,
                                              tr_priority_t      priority );
@@ -255,13 +271,6 @@ tr_torrentNext( tr_session * session, tr_torrent * current )
     return current ? current->next : session->torrentList;
 }
 
-/* get the index of this piece's first block */
-static inline tr_block_index_t
-tr_torPieceFirstBlock( const tr_torrent * tor, const tr_piece_index_t piece )
-{
-    return piece * tor->blockCountInPiece;
-}
-
 /* what piece index is this block in? */
 static inline tr_piece_index_t
 tr_torBlockPiece( const tr_torrent * tor, const tr_block_index_t block )
@@ -269,14 +278,6 @@ tr_torBlockPiece( const tr_torrent * tor, const tr_block_index_t block )
     return block / tor->blockCountInPiece;
 }
 
-/* how many blocks are in this piece? */
-static inline uint16_t
-tr_torPieceCountBlocks( const tr_torrent * tor, const tr_piece_index_t piece )
-{
-    return piece + 1 == tor->info.pieceCount ? tor->blockCountInLastPiece
-                                             : tor->blockCountInPiece;
-}
-
 /* how many bytes are in this piece? */
 static inline uint32_t
 tr_torPieceCountBytes( const tr_torrent * tor, const tr_piece_index_t piece )
index 1095cef60e775c9a085933f4e5eedfae03b3cc44..730f70a41c79bfafb5e4ce7895a4d7c2a2d43457 100644 (file)
@@ -170,7 +170,6 @@ const char* tr_getDefaultDownloadDir( void );
 #define TR_PREFS_KEY_IDLE_LIMIT_ENABLED            "idle-seeding-limit-enabled"
 #define TR_PREFS_KEY_INCOMPLETE_DIR                "incomplete-dir"
 #define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED        "incomplete-dir-enabled"
-#define TR_PREFS_KEY_LAZY_BITFIELD                 "lazy-bitfield-enabled"
 #define TR_PREFS_KEY_MSGLEVEL                      "message-level"
 #define TR_PREFS_KEY_OPEN_FILE_LIMIT               "open-file-limit"
 #define TR_PREFS_KEY_PEER_LIMIT_GLOBAL             "peer-limit-global"
index 2e265061890632fe5976e4e149a9636fc3acb149..581383a26a4c1af1fa911cd70c1d4d7280332866 100644 (file)
@@ -45,6 +45,44 @@ static int test = 0;
     }
 #endif
 
+static int
+test_bitfield_count_range( void )
+{
+    int i;
+    int n;
+    int begin;
+    int end;
+    int count1;
+    int count2;
+    const int bitCount = 100 + tr_cryptoWeakRandInt( 1000 );
+    tr_bitfield * bf;
+
+    /* generate a random bitfield */
+    bf = tr_bitfieldNew( bitCount );
+    for( i=0, n=tr_cryptoWeakRandInt(bitCount); i<n; ++i )
+        tr_bitfieldAdd( bf, tr_cryptoWeakRandInt(bitCount) );
+
+    begin = tr_cryptoWeakRandInt( bitCount );
+    do {
+        end = tr_cryptoWeakRandInt( bitCount );
+    } while( end == begin );
+    if( end < begin ) {
+        const int tmp = begin;
+        begin = end;
+        end = tmp;
+    }
+
+    count1 = 0;
+    for( i=begin; i<end; ++i )
+        if( tr_bitfieldHas( bf, i ) )
+            ++count1;
+    count2 = tr_bitfieldCountRange( bf, begin, end );
+    check( count1 == count2 );
+
+    tr_bitfieldFree( bf );
+    return 0;
+}
+
 static int
 test_bitfields( void )
 {
@@ -406,6 +444,15 @@ test_truncd( void )
     return 0;
 }
 
+struct blah
+{
+    uint8_t  hash[SHA_DIGEST_LENGTH];  /* pieces hash */
+    int8_t   priority;                 /* TR_PRI_HIGH, _NORMAL, or _LOW */
+    int8_t   dnd;                      /* "do not download" flag */
+    time_t   timeChecked;              /* the last time we tested this piece */
+};
+
+
 int
 main( void )
 {
@@ -414,6 +461,12 @@ main( void )
     int   i;
     int   l;
 
+fprintf( stderr, "sizeof time_t %zu\n", sizeof(time_t));
+fprintf( stderr, "sizeof char[20] %zu\n", (size_t)20);
+fprintf( stderr, "sizeof uint8_t %zu\n", sizeof(uint8_t));
+fprintf( stderr, "sizeof blah %zu\n", sizeof(struct blah));
+return 0;
+
     /* base64 */
     out = tr_base64_encode( "YOYO!", -1, &len );
     check( out );
@@ -465,6 +518,11 @@ main( void )
         if( ( i = test_bitfields( ) ) )
             return i;
 
+    /* bitfield count range */
+    for( l=0; l<1000000; ++l )
+        if(( i = test_bitfield_count_range( )))
+            return i;
+
     return 0;
 }
 
index 2396aebbe70dd9eba98c156afffd04a2ee33dc86..45e29604013163b5d8ff3dda255ed19b73bd19de 100644 (file)
@@ -64,7 +64,7 @@ enum
 static void
 webseed_free( struct tr_webseed * w )
 {
-    tr_bitsetDestructor( &w->parent.have );
+    tr_bitsetDestruct( &w->parent.have );
     tr_free( w->parent.client );
 
     event_free( w->timer );
@@ -89,9 +89,7 @@ fire_client_got_rej( tr_torrent * tor, tr_webseed * w, tr_block_index_t block )
 {
     tr_peer_event e = TR_PEER_EVENT_INIT;
     e.eventType = TR_PEER_CLIENT_GOT_REJ;
-    e.pieceIndex = tr_torBlockPiece( tor, block );
-    e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
-    e.length = tr_torBlockCountBytes( tor, block );
+    tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
     publish( w, &e );
 }
 
@@ -100,9 +98,7 @@ fire_client_got_block( tr_torrent * tor, tr_webseed * w, tr_block_index_t block
 {
     tr_peer_event e = TR_PEER_EVENT_INIT;
     e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
-    e.pieceIndex = tr_torBlockPiece( tor, block );
-    e.offset = tor->blockSize * block - tor->info.pieceSize * e.pieceIndex;
-    e.length = tr_torBlockCountBytes( tor, block );
+    tr_torrentGetBlockLocation( tor, block, &e.pieceIndex, &e.offset, &e.length );
     publish( w, &e );
 }
 
@@ -334,10 +330,10 @@ tr_webseedNew( struct tr_torrent * tor,
 
     peer->peerIsChoked = TRUE;
     peer->clientIsInterested = !tr_torrentIsSeed( tor );
-    tr_bitsetConstructor( &peer->have, tor->info.pieceCount );
-    tr_bitsetSetHaveAll( &peer->have );
     peer->progress = 1.0;
     peer->client = tr_strdup( "webseed" );
+    peer->have = TR_BITSET_INIT;
+    tr_bitsetSetHaveAll( &peer->have );
 
     w->torrent_id = tr_torrentId( tor );
     w->session = tor->session;