diff --git a/libtransmission/choking.c b/libtransmission/choking.c index e5a27b12b..4006e2b20 100644 --- a/libtransmission/choking.c +++ b/libtransmission/choking.c @@ -200,7 +200,7 @@ void tr_chokingPulse( tr_choking_t * c ) } else { - if( tr_peerLastChoke( peer ) + 10000 < now ) + if( !tr_peerTimesChoked(peer) || tr_peerLastChoke( peer ) + 10000 < now ) canUnchoke[canUnchokeCount++] = peer; } } diff --git a/libtransmission/peer.c b/libtransmission/peer.c index 5cae3f7ad..d43af1a1a 100644 --- a/libtransmission/peer.c +++ b/libtransmission/peer.c @@ -45,7 +45,7 @@ static const int SWIFT_ENABLED = 1; * For every byte the peer uploads to us, * allow them to download this many bytes from us */ -static const double SWIFT_REPAYMENT_RATIO = 1.1; +static const double SWIFT_REPAYMENT_RATIO = 1.33; /** * Allow new peers to download this many bytes from @@ -70,7 +70,7 @@ static const int SWIFT_REFRESH_INTERVAL_SEC = 5; ****** *****/ -#define PERCENT_PEER_WANTED 25 /* Percent before we start relax peers min activeness */ +#define PERCENT_PEER_WANTED 75 /* Percent before we start relax peers min activeness */ #define MIN_UPLOAD_IDLE 60000 /* In high peer situations we wait only 1 min until dropping peers for idling */ #define MAX_UPLOAD_IDLE 240000 /* In low peer situations we wait the @@ -83,9 +83,6 @@ static const int SWIFT_REFRESH_INTERVAL_SEC = 5; during low peer situations */ #define MAX_CON_TIMEOUT 30000 /* Time to timeout connecting to peer, during high peer situations */ -#define MAX_REQUEST_COUNT 32 -#define OUR_REQUEST_COUNT 12 /* TODO: we should detect if we are on a - high-speed network and adapt */ #define PEX_PEER_CUTOFF 50 /* only try to add new peers from pex if we have fewer existing peers than this */ #define PEX_INTERVAL 60 /* don't send pex messages more frequently @@ -150,6 +147,7 @@ struct tr_peer_s char peerInterested; int optimistic; + int timesChoked; uint64_t lastChoke; uint8_t id[TR_ID_LEN]; @@ -180,14 +178,18 @@ struct tr_peer_s int outBlockSending; int inRequestCount; - tr_request_t inRequests[OUR_REQUEST_COUNT]; + int inRequestMax; + int inRequestAlloc; + tr_request_t * inRequests; int inIndex; int inBegin; int inLength; uint64_t inTotal; int outRequestCount; - tr_request_t outRequests[MAX_REQUEST_COUNT]; + int outRequestMax; + int outRequestAlloc; + tr_request_t * outRequests; uint64_t outTotal; uint64_t outDate; @@ -233,6 +235,12 @@ tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from ) assert( 0 <= from && TR_PEER_FROM__MAX > from ); + 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 ); + peer->socket = s; peer->addr = addr; peer->port = port; @@ -354,10 +362,17 @@ int tr_peerRead( tr_peer_t * peer ) peer->size *= 2; peer->buf = realloc( peer->buf, peer->size ); } +#if 0 /* Never read more than 1K each time, otherwise the rate control is no use */ ret = tr_netRecv( peer->socket, &peer->buf[peer->pos], - MIN( 1024, peer->size - peer->pos ) ); + MIN( 1024, peer->size - peer->pos ) ); +#else + /* Hm, it doesn't *seem* to break rate control... */ + ret = tr_netRecv( peer->socket, &peer->buf[peer->pos], + peer->size - peer->pos ); +#endif + if( ret & TR_NET_CLOSE ) { peer_dbg( "connection closed" ); @@ -595,21 +610,13 @@ writeEnd: if( peer->amInterested && !peer->peerChoking && !peer->banned - && peer->inRequestCount < OUR_REQUEST_COUNT ) + && peer->inRequestCount < peer->inRequestMax ) { int i; int poolSize=0, endgame=0; int * pool = getPreferredPieces ( tor, peer, &poolSize, &endgame ); - /* TODO: add some asserts to see if this bitfield is really necessary */ - tr_bitfield_t * requestedBlocks = tr_bitfieldNew( tor->blockCount ); - for( i=0; iinRequestCount; ++i) { - const tr_request_t * r = &peer->inRequests[i]; - const int block = tr_block( r->index, r->begin ); - tr_bitfieldAdd( requestedBlocks, block ); - } - - for( i=0; iinRequestCountinRequestCountinRequestMax; ) { int unused; const int piece = pool[i]; @@ -617,15 +624,11 @@ writeEnd: ? tr_cpMostMissingBlockInPiece( tor->completion, piece, &unused) : tr_cpMissingBlockInPiece ( tor->completion, piece ); - if( block>=0 && (endgame || !tr_bitfieldHas( requestedBlocks, block ) ) ) - { - tr_bitfieldAdd( requestedBlocks, block ); + if( block>=0 ) sendRequest( tor, peer, block ); - } else ++i; } - tr_bitfieldFree( requestedBlocks ); free( pool ); } @@ -684,10 +687,16 @@ float tr_peerUploadRate( const tr_peer_t * peer ) return tr_rcRate( peer->upload ); } +int tr_peerTimesChoked( const tr_peer_t * peer ) +{ + return peer->timesChoked; +} + void tr_peerChoke( tr_peer_t * peer ) { sendChoke( peer, 1 ); peer->lastChoke = tr_date(); + ++peer->timesChoked; } void tr_peerUnchoke( tr_peer_t * peer ) @@ -838,6 +847,44 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor ) tr_torrentWriterLock( tor ); + for( i=0; ipeerCount; ++i ) + { + /* preferred # of seconds for the request queue's turnaround time. + this is just an arbitrary number. */ + const int queueTime = 5; + int j; + tr_peer_t * peer = tor->peers[ i ]; + + if( !tr_peerIsConnected( peer ) ) + continue; + + /* decide how deep the request queue should be */ + peer->outRequestMax = queueTime * tr_rcRate(peer->download) / tor->blockSize; + peer->inRequestMax += 2; /* room to grow */ + + /* make room for new requests */ + if( peer->outRequestAlloc < peer->outRequestMax ) { + peer->outRequestAlloc = peer->outRequestMax; + peer->outRequests = tr_renew( tr_request_t, peer->outRequests, peer->outRequestAlloc ); + } + + /* decide how deep the request queue should be */ + peer->inRequestMax = queueTime * tr_rcRate(peer->download) / (tor->blockSize/1024); + peer->inRequestMax += 2; /* room to grow */ + + /* make room for new requests */ + if( peer->inRequestAlloc < peer->inRequestMax ) { + peer->inRequestAlloc = peer->inRequestMax; + peer->inRequests = tr_renew( tr_request_t, peer->inRequests, peer->inRequestAlloc ); + } + + /* queue shrank... notify completion that we won't be sending those requests */ + for( j=peer->inRequestMax; jinRequestCount; ++j ) { + tr_request_t * r = &peer->inRequests[j]; + tr_cpDownloaderRem( tor->completion, tr_block(r->index,r->begin) ); + } + } + deadbeats = tr_calloc( tor->peerCount, sizeof(tr_peer_t*) ); for( i=0; ipeerCount; ++i ) { tr_peer_t * peer = tor->peers[ i ]; @@ -847,7 +894,7 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor ) if( deadbeatCount ) { - const double ul_KiBsec = tr_rcRate( tor->upload ); + const double ul_KiBsec = tr_rcRate( tor->download ); const double ul_KiB = ul_KiBsec * SWIFT_REFRESH_INTERVAL_SEC; const double ul_bytes = ul_KiB * 1024; const double freeCreditTotal = ul_bytes * SWIFT_LARGESSE; diff --git a/libtransmission/peer.h b/libtransmission/peer.h index b82831305..c465527ab 100644 --- a/libtransmission/peer.h +++ b/libtransmission/peer.h @@ -45,6 +45,7 @@ int tr_peerIsFrom ( const tr_peer_t * ); int tr_peerAmChoking ( const tr_peer_t * ); int tr_peerAmInterested ( const tr_peer_t * ); int tr_peerIsChoking ( const tr_peer_t * ); +int tr_peerTimesChoked ( const tr_peer_t * ); int tr_peerIsInterested ( const tr_peer_t * ); float tr_peerProgress ( const tr_peer_t * ); int tr_peerPort ( const tr_peer_t * ); diff --git a/libtransmission/peerparse.h b/libtransmission/peerparse.h index 6143159e6..0eceba7dc 100644 --- a/libtransmission/peerparse.h +++ b/libtransmission/peerparse.h @@ -237,7 +237,7 @@ static inline int parseRequest( tr_torrent_t * tor, tr_peer_t * peer, return TR_ERROR; } - if( peer->outRequestCount >= MAX_REQUEST_COUNT ) + if( peer->outRequestCount >= peer->outRequestMax ) { tr_err( "Too many requests" ); return TR_ERROR; @@ -523,7 +523,8 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer, } peer_dbg( "GET unknown extended message '%hhu'", extid ); } - return 1; + /* ignore the unknown extension */ + return 0; case AZ_MSG_BT_KEEP_ALIVE: return TR_OK; case AZ_MSG_AZ_PEER_EXCHANGE: @@ -536,7 +537,7 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer, return 0; } - peer_dbg( "GET unknown message '%d'", id ); + tr_err( "GET unknown message '%d'", id ); return TR_ERROR; } diff --git a/libtransmission/ratecontrol.c b/libtransmission/ratecontrol.c index 3db5f72d5..448eb46d6 100644 --- a/libtransmission/ratecontrol.c +++ b/libtransmission/ratecontrol.c @@ -165,18 +165,19 @@ void tr_rcClose( tr_ratecontrol_t * r ) static float rateForInterval( tr_ratecontrol_t * r, int interval ) { tr_transfer_t * t = NULL; - uint64_t now, start; - int i, total; + uint64_t now, then, start; + float total = 0; + int i; - now = tr_date(); + now = then = tr_date(); start = now - interval; /* Browse the history back in time */ - total = 0; for( i = r->transferStop; i != r->transferStart; i-- ) { t = &r->transfers[i]; - if( t->date < start ) + then = t->date; + if( then < start ) break; total += t->size; @@ -184,6 +185,7 @@ static float rateForInterval( tr_ratecontrol_t * r, int interval ) if( !i ) i = HISTORY_SIZE; /* Loop */ } +#if 0 if( ( r->transferStop + 1 ) % HISTORY_SIZE == r->transferStart && i == r->transferStart ) { @@ -192,7 +194,10 @@ static float rateForInterval( tr_ratecontrol_t * r, int interval ) * interval so that we return the correct rate */ interval = now - t->date; } +#endif - return ( 1000.0f / 1024.0f ) * total / interval; + if( now == then ) + return 0.0; + return ( 1000.0f / 1024.0f ) * total / (now - then); } diff --git a/libtransmission/shared.c b/libtransmission/shared.c index 35733df86..60eba59d5 100644 --- a/libtransmission/shared.c +++ b/libtransmission/shared.c @@ -26,7 +26,8 @@ #include "peer.h" /* Maximum number of peers that we keep in our local list */ -#define MAX_PEER_COUNT 42 +/* This is an arbitrary number, but it seems to work well */ +#define MAX_PEER_COUNT 128 struct tr_shared_s { diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index b6b482f38..358d62fcd 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -544,8 +544,8 @@ tr_stat_t * tr_torrentStat( tr_torrent_t * tor ) s->peersDownloading = 0; for( i=0; ipeerCount; ++i ) { const tr_peer_t * peer = tor->peers[i]; - if( tr_peerIsConnected( peer ) ) { ++s->peersTotal; + if( tr_peerIsConnected( peer ) ) { ++s->peersFrom[tr_peerIsFrom(peer)]; if( tr_peerAmInterested( peer ) && !tr_peerIsChoking( peer ) ) ++s->peersUploading; @@ -953,7 +953,7 @@ torrentThreadLoop ( void * _tor ) cp_status_t cpStatus; /* sleep a little while */ - tr_wait( tor->runStatus == TR_RUN_STOPPED ? 1000 : 100 ); + tr_wait( tor->runStatus == TR_RUN_STOPPED ? 1600 : 800 ); /* if we're stopping... */ if( tor->runStatus == TR_RUN_STOPPING ) diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 6a7c162b3..735778075 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -180,6 +180,8 @@ static inline int _tr_block( const tr_torrent_t * tor, int index, int begin ) ((struct_type *) tr_malloc (((size_t) sizeof (struct_type)) * ((size_t) (n_structs)))) #define tr_new0(struct_type, n_structs) \ ((struct_type *) tr_malloc0 (((size_t) sizeof (struct_type)) * ((size_t) (n_structs)))) +#define tr_renew(struct_type, mem, n_structs) \ + ((struct_type *) realloc ((mem), ((size_t) sizeof (struct_type)) * ((size_t) (n_structs)))) void* tr_malloc ( size_t ); void* tr_malloc0 ( size_t );