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:
Eric Petit 2006-01-30 01:58:27 +00:00
parent f7622a6ebf
commit 58ec7a7e97
8 changed files with 191 additions and 214 deletions

View File

@ -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__ ;

View File

@ -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;

View File

@ -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;

View File

@ -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 );
}
}

View 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 );
}

View File

@ -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 * );

View File

@ -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
**********************************************************************/

View File

@ -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 );
}