remove the "peer is asking for too many blocks!" warning reported by Gimp_ by changing from a fixed-size array to a linked lists of incoming requests

This commit is contained in:
Charles Kerr 2007-07-09 04:37:16 +00:00
parent b1ab3968e7
commit 08f787291a
8 changed files with 205 additions and 85 deletions

117
libtransmission/list.c Normal file
View File

@ -0,0 +1,117 @@
/*
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*/
#include "transmission.h"
#include "list.h"
#include "utils.h"
int
tr_list_length( const tr_list_t * list )
{
int i = 0;
while( list ) {
++i;
list = list->next;
}
return i;
}
tr_list_t*
tr_list_alloc( void )
{
return tr_new0( tr_list_t, 1 );
}
void
tr_list_free1( tr_list_t* node )
{
tr_free( node );
}
void
tr_list_free( tr_list_t* list )
{
while( list )
{
tr_list_t * node = list;
list = list->next;
tr_list_free1( node );
}
}
tr_list_t*
tr_list_prepend( tr_list_t * list, void * data )
{
tr_list_t * node = tr_list_alloc ();
node->data = data;
node->next = list;
if( list )
list->prev = node;
return node;
}
tr_list_t*
tr_list_append( tr_list_t * list, void * data )
{
tr_list_t * node = list;
tr_list_t * l = tr_list_alloc( );
l->data = data;
if( !list )
return l;
while( node->next )
node = node->next;
node->next = l;
l->prev = node;
return list;
}
tr_list_t*
tr_list_find_data ( tr_list_t * list, const void * data )
{
for(; list; list=list->next )
if( list->data == data )
return list;
return NULL;
}
tr_list_t*
tr_list_remove( tr_list_t * list, const void * data )
{
tr_list_t * node = tr_list_find_data( list, data );
tr_list_t * prev = node ? node->prev : NULL;
tr_list_t * next = node ? node->next : NULL;
if( prev ) prev->next = next;
if( next ) next->prev = prev;
if( list == node ) list = next;
tr_list_free1( node );
return list;
}
tr_list_t*
tr_list_find ( tr_list_t * list , TrListCompareFunc func, const void * b )
{
for( ; list; list=list->next )
if( !func( list->data, b ) )
return list;
return NULL;
}
void
tr_list_foreach( tr_list_t * list, TrListForeachFunc func )
{
while( list )
{
func( list->data );
list = list->next;
}
}

38
libtransmission/list.h Normal file
View File

@ -0,0 +1,38 @@
/*
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*/
#ifndef TR_LIST_H
#define TR_LIST_H
typedef struct tr_list_s
{
void * data;
struct tr_list_s * next;
struct tr_list_s * prev;
}
tr_list_t;
void tr_list_free_1 ( void );
void tr_list_free ( tr_list_t* );
int tr_list_length ( const tr_list_t* );
tr_list_t* tr_list_append ( tr_list_t*, void * data );
tr_list_t* tr_list_prepend ( tr_list_t*, void * data );
tr_list_t* tr_list_remove ( tr_list_t*, const void * data );
tr_list_t* tr_list_pop ( tr_list_t*, void ** setme );
typedef int (*TrListCompareFunc)(const void * a, const void * b);
tr_list_t* tr_list_find ( tr_list_t*, TrListCompareFunc func, const void * b );
tr_list_t* tr_list_find_data ( tr_list_t*, const void * data );
typedef void (*TrListForeachFunc)(void *);
void tr_list_foreach( tr_list_t*, TrListForeachFunc func );
#endif /* TR_LIST_H */

View File

@ -24,6 +24,7 @@
#include "transmission.h"
#include "peertree.h"
#include "list.h"
/*****
******
@ -189,10 +190,7 @@ struct tr_peer_s
int inLength;
uint64_t inTotal;
int outRequestCount;
int outRequestMax;
int outRequestAlloc;
tr_request_t * outRequests;
tr_list_t * outRequests;
uint64_t outTotal;
uint64_t outDate;
@ -247,9 +245,6 @@ tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from )
peer->download = tr_rcInit();
peer->upload = tr_rcInit();
peer->outRequestMax = peer->outRequestAlloc = 2;
peer->outRequests = tr_new0( tr_request_t, peer->outRequestAlloc );
peer->inRequestMax = peer->inRequestAlloc = 2;
peer->inRequests = tr_new0( tr_request_t, peer->inRequestAlloc );
@ -288,8 +283,9 @@ void tr_peerDestroy( tr_peer_t * peer )
tr_bitfieldFree( peer->blamefield );
tr_bitfieldFree( peer->banfield );
tr_bitfieldFree( peer->reqfield );
tr_list_foreach( peer->outRequests, tr_free );
tr_list_free( peer->outRequests );
tr_free( peer->inRequests );
tr_free( peer->outRequests );
tr_free( peer->buf );
tr_free( peer->outMessages );
if( peer->status > PEER_STATUS_IDLE )
@ -870,7 +866,6 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
for( i=0; i<tor->peerCount; ++i )
{
double outboundSpeedKiBs;
double inboundSpeedKiBs;
int size;
tr_peer_t * peer = tor->peers[ i ];
@ -888,18 +883,6 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
peer->inRequestAlloc = peer->inRequestMax;
peer->inRequests = tr_renew( tr_request_t, peer->inRequests, peer->inRequestAlloc );
}
/* decide how many blocks we'll concurrently let the peer ask us for */
inboundSpeedKiBs = tr_rcRate(peer->download);
size = queueTimeSec * inboundSpeedKiBs / blockSizeKiB;
if( size < 4 ) /* don't let it get TOO small */
size = 4;
size += 4; /* and always leave room to grow */
peer->outRequestMax = size;
if( peer->outRequestAlloc < peer->outRequestMax ) {
peer->outRequestAlloc = peer->outRequestMax;
peer->outRequests = tr_renew( tr_request_t, peer->outRequests, peer->outRequestAlloc );
}
}
deadbeats = tr_new( tr_peer_t*, tor->peerCount );

View File

@ -104,34 +104,33 @@ fillHeader( tr_peer_t * peer, int size, int id, uint8_t * buf )
return buf;
}
static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
int * size )
static uint8_t *
blockPending( tr_torrent_t * tor,
tr_peer_t * peer,
int * size )
{
if( !peer->outBlockLoaded )
if( !peer->outBlockLoaded ) /* we need to load the block for the next request */
{
uint8_t * buf;
tr_request_t * r;
int hdrlen;
if( peer->amChoking || peer->outRequestCount < 1 )
{
/* No piece to send */
if( peer->amChoking )
return NULL;
}
/* We need to load the block for the next request */
r = &peer->outRequests[0];
if( !peer->outRequests ) /* nothing to send */
return NULL;
/* Sanity check */
if( !tr_cpPieceIsComplete( tor->completion, r->index ) )
r = (tr_request_t*) peer->outRequests->data;
assert( r != NULL );
peer->outRequests = tr_list_remove( peer->outRequests, r );
if( !tr_cpPieceIsComplete( tor->completion, r->index ) ) /* sanity clause */
{
/* We have been asked for something we don't have, buggy client?
Let's just drop this request */
/* We've been asked for something we don't have. buggy client? */
tr_inf( "Block %d/%d/%d was requested but we don't have it",
r->index, r->begin, r->length );
(peer->outRequestCount)--;
memmove( &peer->outRequests[0], &peer->outRequests[1],
peer->outRequestCount * sizeof( tr_request_t ) );
tr_free( r );
return NULL;
}
@ -146,21 +145,12 @@ static uint8_t * blockPending( tr_torrent_t * tor, tr_peer_t * peer,
tr_ioRead( tor->io, r->index, r->begin, r->length, buf );
if( peer->outRequestCount < 1 )
{
/* We were choked during the read */
return NULL;
}
peer_dbg( "SEND piece %d/%d (%d bytes)",
r->index, r->begin, r->length );
peer->outBlockSize = hdrlen;
peer->outBlockLoaded = 1;
(peer->outRequestCount)--;
memmove( &peer->outRequests[0], &peer->outRequests[1],
peer->outRequestCount * sizeof( tr_request_t ) );
tr_free( r );
}
*size = MIN( 1024, peer->outBlockSize );
@ -234,9 +224,10 @@ static void sendChoke( tr_peer_t * peer, int yes )
if( !yes )
{
/* Drop older requests from the last time it was unchoked,
if any */
peer->outRequestCount = 0;
/* Drop older requests from the last time it was unchoked, if any */
tr_list_foreach( peer->outRequests, tr_free );
tr_list_free( peer->outRequests );
peer->outRequests = NULL;
}
peer_dbg( "SEND %schoke", yes ? "" : "un" );

View File

@ -237,18 +237,11 @@ static inline int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
return TR_ERROR;
}
if( peer->outRequestCount >= peer->outRequestMax )
{
tr_dbg( "Peer is asking for too many blocks!");
return TR_ERROR;
}
r = &peer->outRequests[peer->outRequestCount];
r->index = index;
r->begin = begin;
r = tr_new0( tr_request_t, 1 );
r->index = index;
r->begin = begin;
r->length = length;
(peer->outRequestCount)++;
peer->outRequests = tr_list_append( peer->outRequests, r );
return TR_OK;
}
@ -378,13 +371,22 @@ static inline int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
return TR_OK;
}
static int reqCompare( const void * va, const void * vb )
{
const tr_request_t * a = (const tr_request_t *) va;
const tr_request_t * b = (const tr_request_t *) vb;
if( a->index != b->index ) return a->index - b->index;
if( a->begin != b->begin ) return a->begin - b->begin;
return a->length - b->length;
}
static inline int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
uint8_t * p, int len )
{
tr_info_t * inf = &tor->info;
int index, begin, length;
int i;
tr_request_t * r;
tr_request_t req;
tr_list_t * l;
if( len != 12 )
{
@ -410,17 +412,13 @@ static inline int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
peer_dbg( "GET cancel %d/%d (%d bytes)",
index, begin, length );
for( i = 0; i < peer->outRequestCount; i++ )
{
r = &peer->outRequests[i];
if( r->index == index && r->begin == begin &&
r->length == length )
{
(peer->outRequestCount)--;
memmove( &r[0], &r[1], sizeof( tr_request_t ) *
( peer->outRequestCount - i ) );
break;
}
/* remove it from the outRequests list */
req.index = index;
req.begin = begin;
req.length = length;
while(( l = tr_list_find( peer->outRequests, reqCompare, &req ) )) {
tr_free( l->data );
peer->outRequests = tr_list_remove( peer->outRequests, l );
}
return TR_OK;

View File

@ -22,9 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer );
static int peerCmp( tr_peer_t * peer1, tr_peer_t * peer2 )
{
/* Wait until we got the peers' ids */

View File

@ -27,7 +27,7 @@
#define GRANULARITY_MSEC 200
#define SHORT_INTERVAL_MSEC 1000
#define LONG_INTERVAL_MSEC 10000
#define LONG_INTERVAL_MSEC 20000
#define HISTORY_SIZE (LONG_INTERVAL_MSEC / GRANULARITY_MSEC)
typedef struct
@ -52,22 +52,18 @@ rateForInterval( const tr_ratecontrol_t * r, int interval_msec )
uint64_t bytes = 0;
const uint64_t now = tr_date ();
int i = r->newest;
int real_interval_msec = 0;
for( ;; )
{
if( r->transfers[i].date + interval_msec < now )
break;
bytes += r->transfers[i].size;
real_interval_msec = now - r->transfers[i].date;
if( --i == -1 ) i = HISTORY_SIZE - 1; /* circular history */
if( i == r->newest ) break; /* we've come all the way around */
}
return !bytes || !real_interval_msec
? 0.0
: (bytes/1024.0) * (1000.0/real_interval_msec);
return (bytes/1024.0) * (1000.0/interval_msec);
}
/***

View File

@ -4,8 +4,8 @@ include ../mk/config.mk
include ../mk/common.mk
SRCS = bencode.c choking.c clients.c completion.c fastresume.c fdlimit.c \
http.c inout.c ipcparse.c makemeta.c metainfo.c natpmp.c net.c \
peer.c platform.c ratecontrol.c sha1.c shared.c strlcat.c \
http.c inout.c ipcparse.c list.c makemeta.c metainfo.c natpmp.c \
net.c peer.c platform.c ratecontrol.c sha1.c shared.c strlcat.c \
strlcpy.c torrent.c tracker.c transmission.c upnp.c utils.c xml.c
OBJS = $(SRCS:%.c=%.o)