From f00c8ff34d75ba1e0cfad2fe7583736d6d6fc2f4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 11 Oct 2008 04:07:50 +0000 Subject: [PATCH] possible fix for #1305 "Transmission losing data - Session Transfer significantly higher than actual download". This patch may need more user testing and will definitely make webseeds slower. suck it up. --- libtransmission/peer-mgr.c | 163 ++++++++++++++++++++++++++++++------ libtransmission/peer-msgs.c | 156 ++++++++++++---------------------- libtransmission/peer-msgs.h | 8 +- libtransmission/webseed.c | 118 ++++++++++---------------- libtransmission/webseed.h | 4 +- 5 files changed, 243 insertions(+), 206 deletions(-) diff --git a/libtransmission/peer-mgr.c b/libtransmission/peer-mgr.c index 1dc2f0c94..bec323aa4 100644 --- a/libtransmission/peer-mgr.c +++ b/libtransmission/peer-mgr.c @@ -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; iinfo.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; blockcompletion, 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; imsgs, 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; diff --git a/libtransmission/peer-msgs.c b/libtransmission/peer-msgs.c index d5bf85ba3..6a8506a71 100644 --- a/libtransmission/peer-msgs.c +++ b/libtransmission/peer-msgs.c @@ -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 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 ); + } +} + /** *** **/ diff --git a/libtransmission/peer-msgs.h b/libtransmission/peer-msgs.h index 5214c782b..98aa08e53 100644 --- a/libtransmission/peer-msgs.h +++ b/libtransmission/peer-msgs.h @@ -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 ); diff --git a/libtransmission/webseed.c b/libtransmission/webseed.c index 51e010937..50d365407 100644 --- a/libtransmission/webseed.c +++ b/libtransmission/webseed.c @@ -24,10 +24,9 @@ #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 ) } } } - diff --git a/libtransmission/webseed.h b/libtransmission/webseed.h index ca99d6800..eeba6f4b7 100644 --- a/libtransmission/webseed.h +++ b/libtransmission/webseed.h @@ -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, -- 2.40.0