mirror of
https://github.com/transmission/transmission
synced 2024-12-25 01:03:01 +00:00
Rewrote rate control, background work for the download limit, the dl/ul
limits per torrent and for the choking algorithm
This commit is contained in:
parent
f7622a6ebf
commit
58ec7a7e97
8 changed files with 191 additions and 214 deletions
|
@ -2,8 +2,8 @@ SubDir TOP libtransmission ;
|
|||
|
||||
LIBTRANSMISSION_SRC =
|
||||
transmission.c bencode.c net.c tracker.c peer.c inout.c
|
||||
metainfo.c sha1.c utils.c upload.c fdlimit.c clients.c
|
||||
completion.c platform.c ;
|
||||
metainfo.c sha1.c utils.c fdlimit.c clients.c completion.c
|
||||
platform.c ratecontrol.c ;
|
||||
|
||||
Library libtransmission.a : $(LIBTRANSMISSION_SRC) ;
|
||||
ObjectDefines $(LIBTRANSMISSION_SRC) : __TRANSMISSION__ ;
|
||||
|
|
|
@ -93,15 +93,18 @@ typedef struct tr_completion_s tr_completion_t;
|
|||
#include "peer.h"
|
||||
#include "net.h"
|
||||
#include "inout.h"
|
||||
#include "upload.h"
|
||||
#include "ratecontrol.h"
|
||||
#include "clients.h"
|
||||
|
||||
struct tr_torrent_s
|
||||
{
|
||||
tr_info_t info;
|
||||
|
||||
tr_upload_t * upload;
|
||||
tr_fd_t * fdlimit;
|
||||
tr_ratecontrol_t * globalUpload;
|
||||
tr_ratecontrol_t * globalDownload;
|
||||
tr_ratecontrol_t * upload;
|
||||
tr_ratecontrol_t * download;
|
||||
tr_fd_t * fdlimit;
|
||||
|
||||
int status;
|
||||
int finished;
|
||||
|
@ -156,7 +159,8 @@ struct tr_handle_s
|
|||
int torrentCount;
|
||||
tr_torrent_t * torrents[TR_MAX_TORRENT_COUNT];
|
||||
|
||||
tr_upload_t * upload;
|
||||
tr_ratecontrol_t * upload;
|
||||
tr_ratecontrol_t * download;
|
||||
tr_fd_t * fdlimit;
|
||||
|
||||
int bindPort;
|
||||
|
|
|
@ -197,7 +197,7 @@ void tr_peerRem( tr_torrent_t * tor, int i )
|
|||
}
|
||||
if( !peer->amChoking )
|
||||
{
|
||||
tr_uploadChoked( tor->upload );
|
||||
//tr_uploadChoked( tor->upload );
|
||||
}
|
||||
tr_peerDestroy( tor->fdlimit, peer );
|
||||
tor->peerCount--;
|
||||
|
@ -242,6 +242,8 @@ int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
peer->pos += ret;
|
||||
if( NULL != tor )
|
||||
{
|
||||
tr_rcTransferred( tor->download, ret );
|
||||
tr_rcTransferred( tor->globalDownload, ret );
|
||||
if( parseBuf( tor, peer, ret ) )
|
||||
{
|
||||
return 1;
|
||||
|
@ -358,7 +360,7 @@ writeBegin:
|
|||
/* Send pieces if we can */
|
||||
while( ( p = blockPending( tor, peer, &size ) ) )
|
||||
{
|
||||
if( !tr_uploadCanUpload( tor->upload ) )
|
||||
if( !tr_rcCanTransfer( tor->globalUpload ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -374,7 +376,8 @@ writeBegin:
|
|||
}
|
||||
|
||||
blockSent( peer, ret );
|
||||
tr_uploadUploaded( tor->upload, ret );
|
||||
tr_rcTransferred( tor->upload, ret );
|
||||
tr_rcTransferred( tor->globalUpload, ret );
|
||||
|
||||
tor->uploaded[9] += ret;
|
||||
peer->outTotal += ret;
|
||||
|
|
|
@ -165,13 +165,13 @@ static int checkPeer( tr_torrent_t * tor, int i )
|
|||
{
|
||||
/* He doesn't need us */
|
||||
sendChoke( peer, 1 );
|
||||
tr_uploadChoked( tor->upload );
|
||||
//tr_uploadChoked( tor->upload );
|
||||
}
|
||||
if( peer->amChoking && peer->peerInterested &&
|
||||
!peer->outSlow && tr_uploadCanUnchoke( tor->upload ) )
|
||||
if( peer->amChoking && peer->peerInterested /* &&
|
||||
!peer->outSlow && tr_uploadCanUnchoke( tor->upload ) */ )
|
||||
{
|
||||
sendChoke( peer, 0 );
|
||||
tr_uploadUnchoked( tor->upload );
|
||||
//tr_uploadUnchoked( tor->upload );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
147
libtransmission/ratecontrol.c
Normal file
147
libtransmission/ratecontrol.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/******************************************************************************
|
||||
* Copyright (c) 2005 Eric Petit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#define MAX_HISTORY 30
|
||||
|
||||
typedef struct tr_transfer_s tr_transfer_t;
|
||||
struct tr_ratecontrol_s
|
||||
{
|
||||
tr_lock_t lock;
|
||||
int limit;
|
||||
tr_transfer_t * first;
|
||||
tr_transfer_t * last;
|
||||
};
|
||||
struct tr_transfer_s
|
||||
{
|
||||
uint64_t date;
|
||||
int size;
|
||||
tr_transfer_t * next;
|
||||
tr_transfer_t * prev;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* rateForInterval
|
||||
***********************************************************************
|
||||
* Returns the transfer rate on the last 'interval' milliseconds
|
||||
**********************************************************************/
|
||||
static inline float rateForInterval( tr_ratecontrol_t * r, int interval )
|
||||
{
|
||||
tr_transfer_t * t;
|
||||
uint64_t start = tr_date() - interval;
|
||||
int total = 0;
|
||||
|
||||
for( t = r->first; t && t->date > start; t = t->next )
|
||||
{
|
||||
total += t->size;
|
||||
}
|
||||
|
||||
return ( 1000.0 / 1024.0 ) * total / interval;
|
||||
}
|
||||
|
||||
static inline void cleanOldTransfers( tr_ratecontrol_t * r )
|
||||
{
|
||||
tr_transfer_t * t, * prev;
|
||||
uint64_t old = tr_date() - MAX_HISTORY * 1000;
|
||||
|
||||
for( t = r->last; t && t->date < old; )
|
||||
{
|
||||
prev = t->prev;
|
||||
prev->next = NULL;
|
||||
free( t );
|
||||
t = prev;
|
||||
}
|
||||
}
|
||||
|
||||
tr_ratecontrol_t * tr_rcInit()
|
||||
{
|
||||
tr_ratecontrol_t * r;
|
||||
|
||||
r = calloc( sizeof( tr_ratecontrol_t ), 1 );
|
||||
r->limit = -1;
|
||||
tr_lockInit( &r->lock );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void tr_rcSetLimit( tr_ratecontrol_t * r, int limit )
|
||||
{
|
||||
tr_lockLock( &r->lock );
|
||||
r->limit = limit;
|
||||
tr_lockUnlock( &r->lock );
|
||||
}
|
||||
|
||||
int tr_rcCanTransfer( tr_ratecontrol_t * r )
|
||||
{
|
||||
int ret;
|
||||
|
||||
tr_lockLock( &r->lock );
|
||||
ret = ( r->limit < -1 ) || ( rateForInterval( r, 1000 ) < r->limit );
|
||||
tr_lockUnlock( &r->lock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tr_rcTransferred( tr_ratecontrol_t * r, int size )
|
||||
{
|
||||
tr_transfer_t * t;
|
||||
|
||||
tr_lockLock( &r->lock );
|
||||
t = malloc( sizeof( tr_transfer_t ) );
|
||||
|
||||
if( r->first )
|
||||
r->first->prev = t;
|
||||
t->next = r->first;
|
||||
t->prev = NULL;
|
||||
r->first = t;
|
||||
|
||||
t->date = tr_date();
|
||||
t->size = size;
|
||||
|
||||
cleanOldTransfers( r );
|
||||
tr_lockUnlock( &r->lock );
|
||||
}
|
||||
|
||||
float tr_rcRate( tr_ratecontrol_t * r )
|
||||
{
|
||||
float ret;
|
||||
|
||||
tr_lockLock( &r->lock );
|
||||
ret = rateForInterval( r, MAX_HISTORY * 1000 );
|
||||
tr_lockUnlock( &r->lock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tr_rcClose( tr_ratecontrol_t * r )
|
||||
{
|
||||
tr_transfer_t * t, * next;
|
||||
for( t = r->first; t; )
|
||||
{
|
||||
next = t->next;
|
||||
free( t );
|
||||
t = next;
|
||||
}
|
||||
tr_lockClose( &r->lock );
|
||||
free( r );
|
||||
}
|
|
@ -20,13 +20,11 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct tr_upload_s tr_upload_t;
|
||||
typedef struct tr_ratecontrol_s tr_ratecontrol_t;
|
||||
|
||||
tr_upload_t * tr_uploadInit();
|
||||
void tr_uploadSetLimit( tr_upload_t *, int );
|
||||
int tr_uploadCanUnchoke( tr_upload_t * );
|
||||
void tr_uploadChoked( tr_upload_t * );
|
||||
void tr_uploadUnchoked( tr_upload_t * );
|
||||
int tr_uploadCanUpload( tr_upload_t * );
|
||||
void tr_uploadUploaded( tr_upload_t *, int );
|
||||
void tr_uploadClose( tr_upload_t * );
|
||||
tr_ratecontrol_t * tr_rcInit();
|
||||
void tr_rcSetLimit( tr_ratecontrol_t *, int );
|
||||
int tr_rcCanTransfer( tr_ratecontrol_t * );
|
||||
void tr_rcTransferred( tr_ratecontrol_t *, int );
|
||||
float tr_rcRate( tr_ratecontrol_t * );
|
||||
void tr_rcClose( tr_ratecontrol_t * );
|
|
@ -27,8 +27,6 @@
|
|||
**********************************************************************/
|
||||
static void torrentReallyStop( tr_handle_t * h, int t );
|
||||
static void downloadLoop( void * );
|
||||
static float rateDownload( tr_torrent_t * );
|
||||
static float rateUpload( tr_torrent_t * );
|
||||
static void acceptLoop( void * );
|
||||
static void acceptStop( tr_handle_t * h );
|
||||
|
||||
|
@ -65,8 +63,9 @@ tr_handle_t * tr_init()
|
|||
signal( SIGPIPE, SIG_IGN );
|
||||
|
||||
/* Initialize rate and file descripts controls */
|
||||
h->upload = tr_uploadInit();
|
||||
h->fdlimit = tr_fdInit();
|
||||
h->upload = tr_rcInit();
|
||||
h->download = tr_rcInit();
|
||||
h->fdlimit = tr_fdInit();
|
||||
|
||||
h->bindPort = TR_DEFAULT_PORT;
|
||||
h->bindSocket = -1;
|
||||
|
@ -145,7 +144,7 @@ void tr_setBindPort( tr_handle_t * h, int port )
|
|||
**********************************************************************/
|
||||
void tr_setUploadLimit( tr_handle_t * h, int limit )
|
||||
{
|
||||
tr_uploadSetLimit( h->upload, limit );
|
||||
tr_rcSetLimit( h->upload, limit );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -155,20 +154,8 @@ void tr_setUploadLimit( tr_handle_t * h, int limit )
|
|||
**********************************************************************/
|
||||
void tr_torrentRates( tr_handle_t * h, float * dl, float * ul )
|
||||
{
|
||||
int i;
|
||||
tr_torrent_t * tor;
|
||||
|
||||
*dl = 0.0;
|
||||
*ul = 0.0;
|
||||
|
||||
for( i = 0; i < h->torrentCount; i++ )
|
||||
{
|
||||
tor = h->torrents[i];
|
||||
tr_lockLock( &tor->lock );
|
||||
*dl += rateDownload( tor );
|
||||
*ul += rateUpload( tor );
|
||||
tr_lockUnlock( &tor->lock );
|
||||
}
|
||||
*dl = tr_rcRate( h->download );
|
||||
*ul = tr_rcRate( h->upload );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -248,8 +235,11 @@ int tr_torrentInit( tr_handle_t * h, const char * path )
|
|||
|
||||
tr_lockInit( &tor->lock );
|
||||
|
||||
tor->upload = h->upload;
|
||||
tor->fdlimit = h->fdlimit;
|
||||
tor->globalUpload = h->upload;
|
||||
tor->globalDownload = h->download;
|
||||
tor->fdlimit = h->fdlimit;
|
||||
tor->upload = tr_rcInit();
|
||||
tor->download = tr_rcInit();
|
||||
|
||||
/* We have a new torrent */
|
||||
tr_lockLock( &h->acceptLock );
|
||||
|
@ -419,8 +409,8 @@ int tr_torrentStat( tr_handle_t * h, tr_stat_t ** stat )
|
|||
}
|
||||
|
||||
s[i].progress = tr_cpCompletionAsFloat( tor->completion );
|
||||
s[i].rateDownload = rateDownload( tor );
|
||||
s[i].rateUpload = rateUpload( tor );
|
||||
s[i].rateDownload = tr_rcRate( tor->download );
|
||||
s[i].rateUpload = tr_rcRate( tor->upload );
|
||||
|
||||
s[i].seeders = tr_trackerSeeders(tor);
|
||||
s[i].leechers = tr_trackerLeechers(tor);
|
||||
|
@ -496,6 +486,9 @@ void tr_torrentClose( tr_handle_t * h, int t )
|
|||
tr_lockClose( &tor->lock );
|
||||
tr_cpClose( tor->completion );
|
||||
|
||||
tr_rcClose( tor->upload );
|
||||
tr_rcClose( tor->download );
|
||||
|
||||
if( tor->destination )
|
||||
{
|
||||
free( tor->destination );
|
||||
|
@ -514,7 +507,7 @@ void tr_close( tr_handle_t * h )
|
|||
{
|
||||
acceptStop( h );
|
||||
tr_fdClose( h->fdlimit );
|
||||
tr_uploadClose( h->upload );
|
||||
tr_rcClose( h->upload );
|
||||
free( h );
|
||||
}
|
||||
|
||||
|
@ -585,38 +578,6 @@ static void downloadLoop( void * _tor )
|
|||
tr_dbg( "Thread exited" );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* rateDownload, rateUpload
|
||||
**********************************************************************/
|
||||
static float rateGeneric( uint64_t * dates, uint64_t * counts )
|
||||
{
|
||||
float ret;
|
||||
int i;
|
||||
|
||||
ret = 0.0;
|
||||
for( i = 0; i < 9; i++ )
|
||||
{
|
||||
if( dates[i+1] == dates[i] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ret += (float) ( i + 1 ) * 1000.0 / 1024.0 *
|
||||
(float) ( counts[i+1] - counts[i] ) /
|
||||
(float) ( dates[i+1] - dates[i] );
|
||||
}
|
||||
ret *= 1000.0 / 1024.0 / 45.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
static float rateDownload( tr_torrent_t * tor )
|
||||
{
|
||||
return rateGeneric( tor->dates, tor->downloaded );
|
||||
}
|
||||
static float rateUpload( tr_torrent_t * tor )
|
||||
{
|
||||
return rateGeneric( tor->dates, tor->uploaded );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* acceptLoop
|
||||
**********************************************************************/
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
/******************************************************************************
|
||||
* Copyright (c) 2005 Eric Petit
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#define FOO 10
|
||||
|
||||
struct tr_upload_s
|
||||
{
|
||||
tr_lock_t lock;
|
||||
int limit; /* Max upload rate in KB/s */
|
||||
int count; /* Number of peers currently unchoked */
|
||||
uint64_t dates[FOO]; /* The last times we uploaded something */
|
||||
int sizes[FOO]; /* How many bytes we uploaded */
|
||||
};
|
||||
|
||||
tr_upload_t * tr_uploadInit()
|
||||
{
|
||||
tr_upload_t * u;
|
||||
|
||||
u = calloc( sizeof( tr_upload_t ), 1 );
|
||||
tr_lockInit( &u->lock );
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
void tr_uploadSetLimit( tr_upload_t * u, int limit )
|
||||
{
|
||||
tr_lockLock( &u->lock );
|
||||
u->limit = limit;
|
||||
tr_lockUnlock( &u->lock );
|
||||
}
|
||||
|
||||
int tr_uploadCanUnchoke( tr_upload_t * u )
|
||||
{
|
||||
int ret;
|
||||
|
||||
tr_lockLock( &u->lock );
|
||||
if( u->limit < 0 )
|
||||
{
|
||||
/* Infinite number of slots */
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* One slot per 2 KB/s */
|
||||
ret = ( u->count < ( u->limit + 1 ) / 2 );
|
||||
}
|
||||
tr_lockUnlock( &u->lock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tr_uploadChoked( tr_upload_t * u )
|
||||
{
|
||||
tr_lockLock( &u->lock );
|
||||
(u->count)--;
|
||||
tr_lockUnlock( &u->lock );
|
||||
}
|
||||
|
||||
void tr_uploadUnchoked( tr_upload_t * u )
|
||||
{
|
||||
tr_lockLock( &u->lock );
|
||||
(u->count)++;
|
||||
tr_lockUnlock( &u->lock );
|
||||
}
|
||||
|
||||
int tr_uploadCanUpload( tr_upload_t * u )
|
||||
{
|
||||
int ret, i, size;
|
||||
uint64_t now;
|
||||
|
||||
tr_lockLock( &u->lock );
|
||||
if( u->limit < 0 )
|
||||
{
|
||||
/* No limit */
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
size = 0;
|
||||
now = tr_date();
|
||||
|
||||
/* Check the last FOO times we sent something and decide if
|
||||
we must wait */
|
||||
for( i = 0; i < FOO; i++ )
|
||||
{
|
||||
size += u->sizes[i];
|
||||
if( (uint64_t) size * 1000 <
|
||||
( now - u->dates[i] ) * u->limit * 1024 )
|
||||
{
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tr_lockUnlock( &u->lock );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tr_uploadUploaded( tr_upload_t * u, int size )
|
||||
{
|
||||
tr_lockLock( &u->lock );
|
||||
memmove( &u->dates[1], &u->dates[0], (FOO-1) * sizeof( uint64_t ) );
|
||||
memmove( &u->sizes[1], &u->sizes[0], (FOO-1) * sizeof( int ) );
|
||||
u->dates[0] = tr_date();
|
||||
u->sizes[0] = size;
|
||||
tr_lockUnlock( &u->lock );
|
||||
}
|
||||
|
||||
void tr_uploadClose( tr_upload_t * u )
|
||||
{
|
||||
tr_lockClose( &u->lock );
|
||||
free( u );
|
||||
}
|
Loading…
Reference in a new issue