]> granicus.if.org Git - transmission/commitdiff
possible fix for #1305 "Transmission losing data - Session Transfer significantly...
authorCharles Kerr <charles@transmissionbt.com>
Sat, 11 Oct 2008 04:07:50 +0000 (04:07 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Sat, 11 Oct 2008 04:07:50 +0000 (04:07 +0000)
libtransmission/peer-mgr.c
libtransmission/peer-msgs.c
libtransmission/peer-msgs.h
libtransmission/webseed.c
libtransmission/webseed.h

index 1dc2f0c9473d9396f29d72cdc82086764dce2ad1..bec323aa43c182a858e4e470bfb3310d923035fc 100644 (file)
@@ -114,7 +114,7 @@ typedef struct
     tr_timer *      refillTimer;
     tr_torrent *    tor;
     tr_peer *       optimistic; /* the optimistic peer, or NULL if none */
-    tr_bitfield *   requestedPieces;
+    tr_bitfield *   requestedBlocks;
 
     unsigned int    isRunning : 1;
 
@@ -405,7 +405,7 @@ torrentDestructor( void * vt )
     tr_timerFree( &t->rechokeTimer );
     tr_timerFree( &t->refillTimer );
 
-    tr_bitfieldFree( t->requestedPieces );
+    tr_bitfieldFree( t->requestedBlocks );
     tr_ptrArrayFree( t->webseeds, (PtrArrayForeachFunc)tr_webseedFree );
     tr_ptrArrayFree( t->pool, (PtrArrayForeachFunc)tr_free );
     tr_ptrArrayFree( t->outgoingHandshakes, NULL );
@@ -432,7 +432,7 @@ torrentConstructor( tr_peerMgr * manager,
     t->peers = tr_ptrArrayNew( );
     t->webseeds = tr_ptrArrayNew( );
     t->outgoingHandshakes = tr_ptrArrayNew( );
-    t->requestedPieces = tr_bitfieldNew( tor->info.pieceCount );
+    t->requestedBlocks = tr_bitfieldNew( tor->blockCount );
     memcpy( t->hash, tor->info.hash, SHA_DIGEST_LENGTH );
 
     for( i = 0; i < tor->info.webseedCount; ++i )
@@ -593,6 +593,7 @@ tr_peerMgrPeerIsSeed( const tr_peerMgr *     mgr,
 
 struct tr_refill_piece
 {
+    int              missingBlockCount;
     tr_priority_t    priority;
     int              random;
     uint32_t         piece;
@@ -606,6 +607,10 @@ compareRefillPiece( const void * aIn,
     const struct tr_refill_piece * a = aIn;
     const struct tr_refill_piece * b = bIn;
 
+    /* fewer missing pieces goes first */
+    if( a->missingBlockCount != b->missingBlockCount )
+        return a->missingBlockCount < b->missingBlockCount ? -1 : 1;
+
     /* if one piece has a higher priority, it goes first */
     if( a->priority != b->priority )
         return a->priority > b->priority ? -1 : 1;
@@ -671,6 +676,7 @@ getPreferredPieces( Torrent *  t,
             setme->priority = inf->pieces[piece].priority;
             setme->peerCount = 0;
             setme->random = tr_cryptoWeakRandInt( INT_MAX );
+            setme->missingBlockCount = tr_cpMissingBlocksInPiece( tor->completion, piece );
 
             for( k = 0; k < peerCount; ++k )
             {
@@ -696,6 +702,94 @@ getPreferredPieces( Torrent *  t,
     return pool;
 }
 
+static uint64_t*
+getPreferredBlocks( Torrent * t, tr_block_index_t * setmeCount )
+{
+    int s;
+    uint32_t i;
+    uint32_t pieceCount;
+    uint32_t blockCount;
+    uint32_t unreqCount[3], reqCount[3];
+    uint32_t * pieces;
+    uint64_t * ret, * walk;
+    uint64_t * unreq[3], *req[3];
+    const tr_torrent * tor = t->tor;
+
+    assert( torrentIsLocked( t ) );
+
+    pieces = getPreferredPieces( t, &pieceCount );
+
+    /**
+     * Now we walk through those preferred pieces to find all the blocks
+     * are still missing from them.  We put unrequested blocks first,
+     * of course, but by including requested blocks afterwards, endgame
+     * handling happens naturally.
+     *
+     * By doing this once per priority we also effectively get an endgame
+     * mode for each priority level.  The helps keep high priority files
+     * from getting stuck at 99% due of unresponsive peers.
+     */
+
+    /* make temporary bins for the four tiers of blocks */
+    for( i=0; i<3; ++i ) {
+        req[i] = tr_new( uint64_t, pieceCount *  tor->blockCountInPiece );
+        reqCount[i] = 0;
+        unreq[i] = tr_new( uint64_t, pieceCount *  tor->blockCountInPiece );
+        unreqCount[i] = 0;
+    }
+
+    /* sort the blocks into our temp bins */
+    for( i=blockCount=0; i<pieceCount; ++i )
+    {
+        const tr_piece_index_t index = pieces[i];
+        const int priorityIndex = tor->info.pieces[index].priority + 1;
+        const tr_block_index_t begin = tr_torPieceFirstBlock( tor, index );
+        const tr_block_index_t end = begin + tr_torPieceCountBlocks( tor, index );
+        tr_block_index_t block;
+
+        assert( tr_bitfieldTestFast( t->requestedBlocks, end-1 ) );
+
+        for( block=begin; block<end; ++block )
+        {
+            if( tr_cpBlockIsComplete( tor->completion, block ) )
+                continue;
+
+            ++blockCount;
+
+            if( tr_bitfieldHasFast( t->requestedBlocks, block ) )
+            {
+                const uint32_t n = reqCount[priorityIndex]++;
+                req[priorityIndex][n] = block;
+            }
+            else
+            {
+                const uint32_t n = unreqCount[priorityIndex]++;
+                unreq[priorityIndex][n] = block;
+            }
+        }
+    }
+
+    /* join the bins together, going from highest priority to lowest so
+     * the the blocks we want to request first will be first in the list */
+    ret = walk = tr_new( uint64_t, blockCount );
+    for( s=2; s>=0; --s ) {
+        memcpy( walk, unreq[s], sizeof(uint64_t) * unreqCount[s] );
+        walk += unreqCount[s];
+        memcpy( walk, req[s], sizeof(uint64_t) * reqCount[s] );
+        walk += reqCount[s];
+    }
+    assert( ( walk - ret ) == ( int )blockCount );
+    *setmeCount = blockCount;
+
+    /* cleanup */
+    tr_free( pieces );
+    for( i=0; i<3; ++i ) {
+        tr_free( unreq[i] );
+        tr_free( req[i] );
+    }
+    return ret;
+}
+
 static tr_peer**
 getPeersUploadingToClient( Torrent * t,
                            int *     setmeCount )
@@ -732,13 +826,13 @@ refillPulse( void * vtorrent )
 {
     Torrent *        t = vtorrent;
     tr_torrent *     tor = t->tor;
+    tr_block_index_t i;
     int              peerCount;
     int              webseedCount;
     tr_peer **       peers;
     tr_webseed **    webseeds;
-    uint32_t         pieceCount;
-    uint32_t *       pieces;
-    tr_piece_index_t i;
+    tr_block_index_t blockCount;
+    uint64_t       * blocks;
 
     if( !t->isRunning )
         return TRUE;
@@ -748,26 +842,32 @@ refillPulse( void * vtorrent )
     torrentLock( t );
     tordbg( t, "Refilling Request Buffers..." );
 
-    pieces = getPreferredPieces( t, &pieceCount );
+    blocks = getPreferredBlocks( t, &blockCount );
     peers = getPeersUploadingToClient( t, &peerCount );
     webseedCount = tr_ptrArraySize( t->webseeds );
     webseeds = tr_memdup( tr_ptrArrayBase(
                              t->webseeds ), webseedCount *
                          sizeof( tr_webseed* ) );
 
-    for( i = 0; ( webseedCount || peerCount ) && i < pieceCount; ++i )
+    for( i = 0; ( webseedCount || peerCount ) && i < blockCount; ++i )
     {
-        int                    j;
-        int                    handled = FALSE;
-        const tr_piece_index_t piece = pieces[i];
+        int j;
+        int handled = FALSE;
 
-        assert( piece < tor->info.pieceCount );
+        const tr_block_index_t block = blocks[i];
+        const tr_piece_index_t index = tr_torBlockPiece( tor, block );
+        const uint32_t begin = (block * tor->blockSize) - (index * tor->info.pieceSize);
+        const uint32_t length = tr_torBlockCountBytes( tor, block );
 
-        /* find a peer who can ask for this piece */
+        assert( tr_torrentReqIsValid( tor, index, begin, length ) );
+        assert( _tr_block( tor, index, begin ) == block );
+        assert( begin < tr_torPieceCountBytes( tor, index ) );
+        assert( (begin + length) <= tr_torPieceCountBytes( tor, index ) );
+
+        /* find a peer who can ask for this block */
         for( j = 0; !handled && j < peerCount; )
         {
-            const tr_addreq_t val = tr_peerMsgsAddRequest( peers[j]->msgs,
-                                                           piece );
+            const int val = tr_peerMsgsAddRequest( peers[j]->msgs, index, begin, length );
             switch( val )
             {
                 case TR_ADDREQ_FULL:
@@ -781,7 +881,7 @@ refillPulse( void * vtorrent )
                     break;
 
                 case TR_ADDREQ_OK:
-                    tr_bitfieldAdd( t->requestedPieces, piece );
+                    tr_bitfieldAdd( t->requestedBlocks, block );
                     handled = TRUE;
                     break;
 
@@ -794,8 +894,7 @@ refillPulse( void * vtorrent )
         /* maybe one of the webseeds can do it */
         for( j = 0; !handled && j < webseedCount; )
         {
-            const tr_addreq_t val = tr_webseedAddRequest( webseeds[j],
-                                                          piece );
+            const tr_addreq_t val = tr_webseedAddRequest( webseeds[j], index, begin, length );
             switch( val )
             {
                 case TR_ADDREQ_FULL:
@@ -803,7 +902,7 @@ refillPulse( void * vtorrent )
                     break;
 
                 case TR_ADDREQ_OK:
-                    tr_bitfieldAdd( t->requestedPieces, piece );
+                    tr_bitfieldAdd( t->requestedBlocks, block );
                     handled = TRUE;
                     break;
 
@@ -817,13 +916,27 @@ refillPulse( void * vtorrent )
     /* cleanup */
     tr_free( webseeds );
     tr_free( peers );
-    tr_free( pieces );
+    tr_free( blocks );
 
     t->refillTimer = NULL;
     torrentUnlock( t );
     return FALSE;
 }
 
+static void
+broadcastGotBlock( Torrent * t, uint32_t index, uint32_t offset, uint32_t length )
+{
+    int i, size;
+    tr_peer ** peers;
+
+    assert( torrentIsLocked( t ) );
+
+    peers = getConnectedPeers( t, &size );
+    for( i=0; i<size; ++i )
+        tr_peerMsgsCancel( peers[i]->msgs, index, offset, length );
+    tr_free( peers );
+}
+
 static void
 addStrike( Torrent * t,
            tr_peer * peer )
@@ -880,7 +993,7 @@ peerCallbackFunc( void * vpeer,
             break;
 
         case TR_PEER_CANCEL:
-            tr_bitfieldRem( t->requestedPieces, e->pieceIndex );
+            tr_bitfieldRem( t->requestedBlocks, _tr_block( t->tor, e->pieceIndex, e->offset ) );
             break;
 
         case TR_PEER_PEER_GOT_DATA:
@@ -913,10 +1026,8 @@ peerCallbackFunc( void * vpeer,
             if( peer )
                 tor->downloadedCur += e->length;
             tr_statsAddDownloaded( tor->session, e->length );
-            if( peer )
-            {
-                struct peer_atom * atom = getExistingAtom( t,
-                                                           &peer->in_addr );
+            if( peer ) {
+                struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
                 atom->piece_data_time = time( NULL );
             }
             break;
@@ -956,6 +1067,8 @@ peerCallbackFunc( void * vpeer,
 
             tr_cpBlockAdd( tor->completion, block );
 
+            broadcastGotBlock( t, e->pieceIndex, e->offset, e->length );
+
             if( tr_cpPieceIsComplete( tor->completion, e->pieceIndex ) )
             {
                 const tr_piece_index_t p = e->pieceIndex;
index d5bf85ba3ad0227ee952d42783621bf0031e4fb0..6a8506a71a7e8005d08177c1828a967019bd7e47 100644 (file)
@@ -198,36 +198,6 @@ reqListAppend( struct request_list *       list,
     list->requests[list->count - 1] = *req;
 }
 
-static void
-reqListAppendPiece( const tr_torrent *    tor,
-                    struct request_list * list,
-                    tr_piece_index_t      piece )
-{
-    const time_t           now = time( NULL );
-    const size_t           n = tr_torPieceCountBlocks( tor, piece );
-    const tr_block_index_t begin = tr_torPieceFirstBlock( tor, piece );
-    const tr_block_index_t end = begin + n;
-    tr_block_index_t       i;
-
-    if( list->count + n >= list->max )
-        reqListReserve( list, list->max + n );
-
-    for( i = begin; i < end; ++i )
-    {
-        if( !tr_cpBlockIsComplete( tor->completion, i ) )
-        {
-            struct peer_request * req = list->requests + list->count++;
-            req->index = piece;
-            req->offset =
-                ( i * tor->blockSize ) - ( piece * tor->info.pieceSize );
-            req->length = tr_torBlockCountBytes( tor, i );
-            req->time_requested = now;
-            assert( tr_torrentReqIsValid( tor, req->index, req->offset,
-                                          req->length ) );
-        }
-    }
-}
-
 static int
 reqListPop( struct request_list * list,
             struct peer_request * setme )
@@ -245,19 +215,6 @@ reqListPop( struct request_list * list,
     return success;
 }
 
-static int
-reqListHasPiece( struct request_list *  list,
-                 const tr_piece_index_t piece )
-{
-    uint16_t i;
-
-    for( i = 0; i < list->count; ++i )
-        if( list->requests[i].index == piece )
-            return 1;
-
-    return 0;
-}
-
 static int
 reqListFind( struct request_list *       list,
              const struct peer_request * key )
@@ -548,13 +505,13 @@ firePeerGotData( tr_peermsgs * msgs,
 }
 
 static void
-fireCancelledReq( tr_peermsgs *          msgs,
-                  const tr_piece_index_t pieceIndex )
+fireCancelledReq( tr_peermsgs * msgs, const struct peer_request * req )
 {
     tr_peer_event e = blankEvent;
-
     e.eventType = TR_PEER_CANCEL;
-    e.pieceIndex = pieceIndex;
+    e.pieceIndex = req->index;
+    e.offset = req->offset;
+    e.length = req->length;
     publish( msgs, &e );
 }
 
@@ -805,43 +762,9 @@ reqIsValid( const tr_peermsgs * peer,
 }
 
 static int
-requestIsValid( const tr_peermsgs *         peer,
-                const struct peer_request * req )
+requestIsValid( const tr_peermsgs * msgs, const struct peer_request * req )
 {
-    return reqIsValid( peer, req->index, req->offset, req->length );
-}
-
-static void
-tr_peerMsgsCancel( tr_peermsgs * msgs,
-                   uint32_t      pieceIndex )
-{
-    uint16_t              i;
-    struct request_list   tmp = REQUEST_LIST_INIT;
-    struct request_list * src;
-
-    src = &msgs->clientWillAskFor;
-    for( i = 0; i < src->count; ++i )
-        if( src->requests[i].index != pieceIndex )
-            reqListAppend( &tmp, src->requests + i );
-
-    /* swap */
-    reqListClear( &msgs->clientWillAskFor );
-    msgs->clientWillAskFor = tmp;
-    tmp = REQUEST_LIST_INIT;
-
-    src = &msgs->clientAskedFor;
-    for( i = 0; i < src->count; ++i )
-        if( src->requests[i].index == pieceIndex )
-            protocolSendCancel( msgs, src->requests + i );
-        else
-            reqListAppend( &tmp, src->requests + i );
-
-    /* swap */
-    reqListClear( &msgs->clientAskedFor );
-    msgs->clientAskedFor = tmp;
-    tmp = REQUEST_LIST_INIT;
-
-    fireCancelledReq( msgs, pieceIndex );
+    return reqIsValid( msgs, req->index, req->offset, req->length );
 }
 
 static void
@@ -858,7 +781,7 @@ expireOldRequests( tr_peermsgs * msgs )
     {
         const struct peer_request * req = &tmp.requests[i];
         if( req->time_requested < oldestAllowed )
-            tr_peerMsgsCancel( msgs, req->index );
+            tr_peerMsgsCancel( msgs, req->index, req->offset, req->length );
     }
     reqListClear( &tmp );
 
@@ -869,7 +792,7 @@ expireOldRequests( tr_peermsgs * msgs )
     {
         const struct peer_request * req = &tmp.requests[i];
         if( req->time_requested < oldestAllowed )
-            tr_peerMsgsCancel( msgs, req->index );
+            tr_peerMsgsCancel( msgs, req->index, req->offset, req->length );
     }
     reqListClear( &tmp );
 }
@@ -925,19 +848,20 @@ static int
 requestQueueIsFull( const tr_peermsgs * msgs )
 {
     const int req_max = msgs->maxActiveRequests;
-
     return msgs->clientWillAskFor.count >= req_max;
 }
 
 tr_addreq_t
 tr_peerMsgsAddRequest( tr_peermsgs *    msgs,
-                       tr_piece_index_t piece )
+                       uint32_t         index,
+                       uint32_t         offset,
+                       uint32_t         length )
 {
     struct peer_request req;
 
     assert( msgs );
     assert( msgs->torrent );
-    assert( piece < msgs->torrent->info.pieceCount );
+    assert( reqIsValid( msgs, index, offset, length ) );
 
     /**
     ***  Reasons to decline the request
@@ -951,20 +875,24 @@ tr_peerMsgsAddRequest( tr_peermsgs *    msgs,
     }
 
     /* peer doesn't have this piece */
-    if( !tr_bitfieldHas( msgs->info->have, piece ) )
+    if( !tr_bitfieldHas( msgs->info->have, index ) )
         return TR_ADDREQ_MISSING;
 
     /* peer's queue is full */
-    if( requestQueueIsFull( msgs ) )
-    {
+    if( requestQueueIsFull( msgs ) ) {
         dbgmsg( msgs, "declining request because we're full" );
         return TR_ADDREQ_FULL;
     }
 
     /* have we already asked for this piece? */
-    if( reqListHasPiece( &msgs->clientAskedFor, piece )
-      || reqListHasPiece( &msgs->clientWillAskFor, piece ) )
-    {
+    req.index = index;
+    req.offset = offset;
+    req.length = length;
+    if( reqListFind( &msgs->clientAskedFor, &req ) != -1 ) {
+        dbgmsg( msgs, "declining because it's a duplicate" );
+        return TR_ADDREQ_DUPLICATE;
+    }
+    if( reqListFind( &msgs->clientWillAskFor, &req ) != -1 ) {
         dbgmsg( msgs, "declining because it's a duplicate" );
         return TR_ADDREQ_DUPLICATE;
     }
@@ -973,9 +901,9 @@ tr_peerMsgsAddRequest( tr_peermsgs *    msgs,
     ***  Accept this request
     **/
 
-    dbgmsg( msgs, "added req for piece %lu", (unsigned long)piece );
+    dbgmsg( msgs, "added req for piece %lu", (unsigned long)index );
     req.time_requested = time( NULL );
-    reqListAppendPiece( msgs->torrent, &msgs->clientWillAskFor, piece );
+    reqListAppend( &msgs->clientWillAskFor, &req );
     return TR_ADDREQ_OK;
 }
 
@@ -989,12 +917,11 @@ cancelAllRequestsToPeer( tr_peermsgs * msgs )
     msgs->clientAskedFor = REQUEST_LIST_INIT;
     msgs->clientWillAskFor = REQUEST_LIST_INIT;
 
-    for( i = 0; i < a.count; ++i )
-        fireCancelledReq( msgs, a.requests[i].index );
+    for( i=0; i<a.count; ++i )
+        fireCancelledReq( msgs, &a.requests[i] );
 
-    for( i = 0; i < b.count; ++i )
-    {
-        fireCancelledReq( msgs, b.requests[i].index );
+    for( i = 0; i < b.count; ++i ) {
+        fireCancelledReq( msgs, &b.requests[i] );
         protocolSendCancel( msgs, &b.requests[i] );
     }
 
@@ -1002,6 +929,33 @@ cancelAllRequestsToPeer( tr_peermsgs * msgs )
     reqListClear( &b );
 }
 
+void
+tr_peerMsgsCancel( tr_peermsgs * msgs,
+                   uint32_t      pieceIndex,
+                   uint32_t      offset,
+                   uint32_t      length )
+{
+    struct peer_request req;
+
+    assert( msgs != NULL );
+    assert( length > 0 );
+
+    /* have we asked the peer for this piece? */
+    req.index = pieceIndex;
+    req.offset = offset;
+    req.length = length;
+
+    /* if it's only in the queue and hasn't been sent yet, free it */
+    if( !reqListRemove( &msgs->clientWillAskFor, &req ) )
+        fireCancelledReq( msgs, &req );
+
+    /* if it's already been sent, send a cancel message too */
+    if( !reqListRemove( &msgs->clientAskedFor, &req ) ) {
+        protocolSendCancel( msgs, &req );
+        fireCancelledReq( msgs, &req );
+    }
+}
+
 /**
 ***
 **/
index 5214c782bea614fb37117c2a6e78ee4c0b105e5c..98aa08e5396acde4304e899dbb145abf08abad01 100644 (file)
@@ -38,18 +38,18 @@ void         tr_peerMsgsHave( tr_peermsgs * msgs,
 
 void         tr_peerMsgsPulse( tr_peermsgs * msgs );
 
-#if 0
 void         tr_peerMsgsCancel( tr_peermsgs * msgs,
                                 uint32_t      pieceIndex,
                                 uint32_t      offset,
                                 uint32_t      length );
 
-#endif
 
 void         tr_peerMsgsFree( tr_peermsgs* );
 
-tr_addreq_t  tr_peerMsgsAddRequest( tr_peermsgs *    peer,
-                                    tr_piece_index_t piece );
+tr_addreq_t  tr_peerMsgsAddRequest( tr_peermsgs * peer,
+                                    uint32_t      pieceIndex,
+                                    uint32_t      offset,
+                                    uint32_t      length );
 
 void         tr_peerMsgsUnsubscribe( tr_peermsgs *    peer,
                                      tr_publisher_tag tag );
index 51e010937f7678b7301073de8de09237177439b2..50d3654077ebfb377ec233b204ab0b0c697b7b3b 100644 (file)
 #include "web.h"
 #include "webseed.h"
 
-#define MAX_QUEUE_SIZE 4
-
 struct tr_webseed
 {
+    unsigned int        busy : 1;
     unsigned int        dead : 1;
 
     tr_torrent *        torrent;
@@ -36,10 +35,9 @@ struct tr_webseed
     tr_delivery_func *  callback;
     void *              callback_userdata;
 
-    uint64_t            bytesSaved;
-
-    tr_piece_index_t    queue[MAX_QUEUE_SIZE];
-    int                 queueSize;
+    tr_piece_index_t    pieceIndex;
+    uint32_t            pieceOffset;
+    uint32_t            byteCount;
 
     tr_ratecontrol *    rateDown;
 
@@ -221,54 +219,27 @@ webResponseFunc( tr_handle   * session UNUSED,
     {
         /* FIXME */
     }
-    else if( w->dead )
-    {
-        tr_webseedFree( w );
-    }
     else
     {
-        const tr_piece_index_t piece = w->queue[0];
-        tr_block_index_t       block;
-        size_t                 len;
-
         evbuffer_add( w->content, response, response_byte_count );
-
-        fireClientGotData( w, response_byte_count );
-
-        block = _tr_block( w->torrent, piece, w->bytesSaved );
-        len = tr_torBlockCountBytes( w->torrent, block );
-
-        while( EVBUFFER_LENGTH( w->content ) >= len )
+        if( !w->dead )
         {
-/*fprintf( stderr, "saving piece index %lu, offset %lu, len %lu\n", (unsigned
-  long)piece, (unsigned long)w->bytesSaved, (unsigned long)len );*/
-            /* save one block */
-            tr_ioWrite( w->torrent, piece, w->bytesSaved, len,
-                       EVBUFFER_DATA( w->content ) );
-            evbuffer_drain( w->content, len );
-            tr_rcTransferred( w->rateDown, len );
-            fireClientGotBlock( w, piece, w->bytesSaved, len );
-            w->bytesSaved += len;
-
-            /* march to the next one */
-            ++block;
-            len = tr_torBlockCountBytes( w->torrent, block );
+            fireClientGotData( w, response_byte_count );
+            tr_rcTransferred( w->rateDown, response_byte_count );
         }
 
-        if( w->bytesSaved < tr_torPieceCountBytes( w->torrent, piece ) )
+        if( EVBUFFER_LENGTH( w->content ) < w->byteCount )
             requestNextChunk( w );
-        else
-        {
-            w->bytesSaved = 0;
+        else {
+            tr_ioWrite( w->torrent, w->pieceIndex, w->pieceOffset, w->byteCount, EVBUFFER_DATA(w->content) );
             evbuffer_drain( w->content, EVBUFFER_LENGTH( w->content ) );
-/*fprintf( stderr, "w->callback_userdata is %p\n", w->callback_userdata );*/
-            memmove( w->queue, w->queue + 1, sizeof( tr_piece_index_t ) *
-                    ( MAX_QUEUE_SIZE - 1 ) );
-/*fprintf( stderr, "w->callback_userdata is %p\n", w->callback_userdata );*/
-            if( --w->queueSize )
-                requestNextChunk( w );
-            if( w->queueSize < ( MAX_QUEUE_SIZE / 2 ) )
+            w->busy = 0;
+            if( w->dead )
+                tr_webseedFree( w );
+            else  {
+                fireClientGotBlock( w, w->pieceIndex, w->pieceOffset, w->byteCount );
                 fireNeedReq( w );
+            }
         }
     }
 }
@@ -276,51 +247,49 @@ webResponseFunc( tr_handle   * session UNUSED,
 static void
 requestNextChunk( tr_webseed * w )
 {
-    const tr_info *        inf = tr_torrentInfo( w->torrent );
-    const uint32_t         have = w->bytesSaved + EVBUFFER_LENGTH(
-        w->content );
-    const tr_piece_index_t piece = w->queue[0];
-    const uint32_t         left =
-        tr_torPieceCountBytes( w->torrent, piece ) - have;
-    const uint32_t         pieceOffset = have;
-    tr_file_index_t        fileIndex;
-    uint64_t               fileOffset;
-    uint32_t               thisPass;
-    char *                 url;
-    char *                 range;
-
-    tr_ioFindFileLocation( w->torrent, piece, pieceOffset,
+    const tr_info * inf = tr_torrentInfo( w->torrent );
+    const uint32_t have = EVBUFFER_LENGTH( w->content );
+    const uint32_t left = w->byteCount - have;
+    const uint32_t pieceOffset = w->pieceOffset + have;
+    tr_file_index_t fileIndex;
+    uint64_t fileOffset;
+    uint32_t thisPass;
+    char * url;
+    char * range;
+
+    tr_ioFindFileLocation( w->torrent, w->pieceIndex, pieceOffset,
                            &fileIndex, &fileOffset );
     thisPass = MIN( left, inf->files[fileIndex].length - fileOffset );
 
     url = makeURL( w, &inf->files[fileIndex] );
-    range = tr_strdup_printf( "%" PRIu64 "-%" PRIu64, fileOffset,
-                              fileOffset + thisPass - 1 );
-/*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are
-  left, and we're asking for %lu this time\n", range, (unsigned
-  long)tr_torPieceCountBytes(w->torrent,piece), (unsigned long)have, (unsigned
-  long)left, (unsigned long)thisPass );*/
+//fprintf( stderr, "url is [%s]\n", url );
+    range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 );
+//fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );
     tr_webRun( w->torrent->session, url, range, webResponseFunc, w );
     tr_free( range );
     tr_free( url );
 }
 
 tr_addreq_t
-tr_webseedAddRequest( tr_webseed *     w,
-                      tr_piece_index_t piece )
+tr_webseedAddRequest( tr_webseed  * w,
+                      uint32_t      pieceIndex,
+                      uint32_t      pieceOffset,
+                      uint32_t      byteCount )
 {
     int ret;
 
-    if( w->dead || w->queueSize >= MAX_QUEUE_SIZE )
+    if( w->busy || w->dead )
     {
         ret = TR_ADDREQ_FULL;
     }
     else
     {
-        int wasEmpty = w->queueSize == 0;
-        w->queue[w->queueSize++] = piece;
-        if( wasEmpty )
-            requestNextChunk( w );
+        w->busy = 1;
+        w->pieceIndex = pieceIndex;
+        w->pieceOffset = pieceOffset;
+        w->byteCount = byteCount;
+        evbuffer_drain( w->content, EVBUFFER_LENGTH( w->content ) );
+        requestNextChunk( w );
         ret = TR_ADDREQ_OK;
     }
 
@@ -330,7 +299,7 @@ tr_webseedAddRequest( tr_webseed *     w,
 int
 tr_webseedIsActive( const tr_webseed * w )
 {
-    return w->queueSize > 0;
+    return w->busy != 0;
 }
 
 int
@@ -370,7 +339,7 @@ tr_webseedFree( tr_webseed * w )
 {
     if( w )
     {
-        if( w->queueSize > 0 )
+        if( w->busy )
         {
             w->dead = 1;
         }
@@ -383,4 +352,3 @@ tr_webseedFree( tr_webseed * w )
         }
     }
 }
-
index ca99d68003075eef16d7789858b8db8bf8c4cc2e..eeba6f4b77a79c56dbb26bfe6d4e3654a35306de 100644 (file)
@@ -25,7 +25,9 @@ tr_webseed* tr_webseedNew( struct tr_torrent * torrent,
 void        tr_webseedFree( tr_webseed * );
 
 tr_addreq_t tr_webseedAddRequest( tr_webseed *     w,
-                                  tr_piece_index_t piece );
+                                  uint32_t         index,
+                                  uint32_t         offset,
+                                  uint32_t         length );
 
 /** @return true if a request is being processed, or false if idle */
 int         tr_webseedGetSpeed( const tr_webseed * w,