mirror of
https://github.com/transmission/transmission
synced 2025-03-09 13:50:00 +00:00
reintroduce the "SWIFT" algorithm
This commit is contained in:
parent
c83f25fed5
commit
9a81cd7637
7 changed files with 143 additions and 17 deletions
|
@ -36,7 +36,7 @@
|
||||||
#include "torrent-inspector.h"
|
#include "torrent-inspector.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define UPDATE_INTERVAL_MSEC 1500
|
#define UPDATE_INTERVAL_MSEC 2000
|
||||||
|
|
||||||
/****
|
/****
|
||||||
***** PIECES VIEW
|
***** PIECES VIEW
|
||||||
|
@ -361,10 +361,11 @@ render_status( GtkTreeViewColumn * column UNUSED,
|
||||||
case TR_PEER_STATUS_HANDSHAKE: text = _( "Handshaking" ); break;
|
case TR_PEER_STATUS_HANDSHAKE: text = _( "Handshaking" ); break;
|
||||||
case TR_PEER_STATUS_PEER_IS_CHOKED: text = _( "Peer is Choked" ); break;
|
case TR_PEER_STATUS_PEER_IS_CHOKED: text = _( "Peer is Choked" ); break;
|
||||||
case TR_PEER_STATUS_CLIENT_IS_CHOKED: text = _( "Choked" ); break;
|
case TR_PEER_STATUS_CLIENT_IS_CHOKED: text = _( "Choked" ); break;
|
||||||
case TR_PEER_STATUS_CLIENT_IS_INTERESTED: text = _( "Choked and Interested" ); break;
|
case TR_PEER_STATUS_CLIENT_IS_INTERESTED: text = _( "Choked & Interested" ); break;
|
||||||
case TR_PEER_STATUS_READY: text = _( "Ready" ); break;
|
case TR_PEER_STATUS_READY: text = _( "Ready" ); break;
|
||||||
case TR_PEER_STATUS_REQUEST_SENT: text = _( "Request Sent" ); break;
|
case TR_PEER_STATUS_REQUEST_SENT: text = _( "Request Sent" ); break;
|
||||||
case TR_PEER_STATUS_ACTIVE : text = _( "Active" ); break;
|
case TR_PEER_STATUS_ACTIVE : text = _( "Active" ); break;
|
||||||
|
case TR_PEER_STATUS_ACTIVE_AND_CHOKED: text = _( "Active & Choked" ); break;
|
||||||
default: text = "BUG"; break;
|
default: text = "BUG"; break;
|
||||||
}
|
}
|
||||||
g_object_set (renderer, "text", text, NULL);
|
g_object_set (renderer, "text", text, NULL);
|
||||||
|
|
|
@ -408,12 +408,12 @@ char * tr_clientForId( const uint8_t * id )
|
||||||
isprint( id[3] ) && isprint( id[4] ) && isprint( id[5] ) &&
|
isprint( id[3] ) && isprint( id[4] ) && isprint( id[5] ) &&
|
||||||
isprint( id[6] ) && isprint( id[7] ) )
|
isprint( id[6] ) && isprint( id[7] ) )
|
||||||
{
|
{
|
||||||
tr_asprintf( &ret, "unknown client (%c%c%c%c%c%c%c%c)",
|
tr_asprintf( &ret, "%c%c%c%c%c%c%c%c",
|
||||||
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
|
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tr_asprintf( &ret, "unknown client (0x%02x%02x%02x%02x%02x%02x%02x%02x)",
|
tr_asprintf( &ret, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
|
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,27 @@ enum
|
||||||
ENCRYPTION_PREFERENCE_NO
|
ENCRYPTION_PREFERENCE_NO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*** The "SWIFT" system is described by Karthik Tamilmani,
|
||||||
|
*** Vinay Pai, and Alexander Mohr of Stony Brook University
|
||||||
|
*** in their paper "SWIFT: A System With Incentives For Trading"
|
||||||
|
*** http://citeseer.ist.psu.edu/tamilmani04swift.html
|
||||||
|
***
|
||||||
|
*** More SWIFT constants are defined in peer-mgr.c
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use SWIFT?
|
||||||
|
*/
|
||||||
|
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.33;
|
||||||
|
|
||||||
|
|
||||||
typedef struct tr_peer
|
typedef struct tr_peer
|
||||||
{
|
{
|
||||||
unsigned int peerIsChoked : 1;
|
unsigned int peerIsChoked : 1;
|
||||||
|
@ -66,6 +87,8 @@ typedef struct tr_peer
|
||||||
|
|
||||||
double rateToClient;
|
double rateToClient;
|
||||||
double rateToPeer;
|
double rateToPeer;
|
||||||
|
|
||||||
|
int64_t credit;
|
||||||
}
|
}
|
||||||
tr_peer;
|
tr_peer;
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,35 @@
|
||||||
#include "trevent.h"
|
#include "trevent.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*** The "SWIFT" system is described by Karthik Tamilmani,
|
||||||
|
*** Vinay Pai, and Alexander Mohr of Stony Brook University
|
||||||
|
*** in their paper "SWIFT: A System With Incentives For Trading"
|
||||||
|
*** http://citeseer.ist.psu.edu/tamilmani04swift.html
|
||||||
|
***
|
||||||
|
*** More SWIFT constants are defined in peer-mgr-private.h
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow new peers to download this many bytes from
|
||||||
|
* us when getting started. This can prevent gridlock
|
||||||
|
* with other peers using tit-for-tat algorithms
|
||||||
|
*/
|
||||||
|
static const int SWIFT_INITIAL_CREDIT = 64 * 1024; /* 64 KiB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We expend a fraction of our torrent's total upload speed
|
||||||
|
* on largesse by uniformly distributing free credit to
|
||||||
|
* all of our peers. This too helps prevent gridlock.
|
||||||
|
*/
|
||||||
|
static const double SWIFT_LARGESSE = 0.10; /* 10% of our UL */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How frequently to extend largesse-based credit
|
||||||
|
*/
|
||||||
|
static const int SWIFT_PERIOD_MSEC = 5000;
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* how frequently to change which peers are choked */
|
/* how frequently to change which peers are choked */
|
||||||
|
@ -114,6 +143,7 @@ typedef struct
|
||||||
tr_timer * reconnectTimer;
|
tr_timer * reconnectTimer;
|
||||||
tr_timer * rechokeTimer;
|
tr_timer * rechokeTimer;
|
||||||
tr_timer * refillTimer;
|
tr_timer * refillTimer;
|
||||||
|
tr_timer * swiftTimer;
|
||||||
tr_torrent * tor;
|
tr_torrent * tor;
|
||||||
tr_bitfield * requested;
|
tr_bitfield * requested;
|
||||||
|
|
||||||
|
@ -314,6 +344,7 @@ peerConstructor( const struct in_addr * in_addr )
|
||||||
{
|
{
|
||||||
tr_peer * p;
|
tr_peer * p;
|
||||||
p = tr_new0( tr_peer, 1 );
|
p = tr_new0( tr_peer, 1 );
|
||||||
|
p->credit = SWIFT_INITIAL_CREDIT;
|
||||||
p->rcToClient = tr_rcInit( );
|
p->rcToClient = tr_rcInit( );
|
||||||
p->rcToPeer = tr_rcInit( );
|
p->rcToPeer = tr_rcInit( );
|
||||||
memcpy( &p->in_addr, in_addr, sizeof(struct in_addr) );
|
memcpy( &p->in_addr, in_addr, sizeof(struct in_addr) );
|
||||||
|
@ -397,6 +428,7 @@ torrentDestructor( Torrent * t )
|
||||||
tr_timerFree( &t->reconnectTimer );
|
tr_timerFree( &t->reconnectTimer );
|
||||||
tr_timerFree( &t->rechokeTimer );
|
tr_timerFree( &t->rechokeTimer );
|
||||||
tr_timerFree( &t->refillTimer );
|
tr_timerFree( &t->refillTimer );
|
||||||
|
tr_timerFree( &t->swiftTimer );
|
||||||
|
|
||||||
tr_bitfieldFree( t->requested );
|
tr_bitfieldFree( t->requested );
|
||||||
tr_ptrArrayFree( t->pool, (PtrArrayForeachFunc)tr_free );
|
tr_ptrArrayFree( t->pool, (PtrArrayForeachFunc)tr_free );
|
||||||
|
@ -1167,6 +1199,7 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
|
||||||
|
|
||||||
static int reconnectPulse( void * vtorrent );
|
static int reconnectPulse( void * vtorrent );
|
||||||
static int rechokePulse( void * vtorrent );
|
static int rechokePulse( void * vtorrent );
|
||||||
|
static int swiftPulse( void * vtorrent );
|
||||||
|
|
||||||
void
|
void
|
||||||
tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||||
|
@ -1181,6 +1214,7 @@ tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||||
assert( t != NULL );
|
assert( t != NULL );
|
||||||
assert( ( t->isRunning != 0 ) == ( t->reconnectTimer != NULL ) );
|
assert( ( t->isRunning != 0 ) == ( t->reconnectTimer != NULL ) );
|
||||||
assert( ( t->isRunning != 0 ) == ( t->rechokeTimer != NULL ) );
|
assert( ( t->isRunning != 0 ) == ( t->rechokeTimer != NULL ) );
|
||||||
|
assert( ( t->isRunning != 0 ) == ( t->swiftTimer != NULL ) );
|
||||||
|
|
||||||
if( !t->isRunning )
|
if( !t->isRunning )
|
||||||
{
|
{
|
||||||
|
@ -1194,9 +1228,15 @@ tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||||
rechokePulse, t,
|
rechokePulse, t,
|
||||||
RECHOKE_PERIOD_MSEC );
|
RECHOKE_PERIOD_MSEC );
|
||||||
|
|
||||||
|
t->swiftTimer = tr_timerNew( t->manager->handle,
|
||||||
|
swiftPulse, t,
|
||||||
|
SWIFT_PERIOD_MSEC );
|
||||||
|
|
||||||
reconnectPulse( t );
|
reconnectPulse( t );
|
||||||
|
|
||||||
rechokePulse( t );
|
rechokePulse( t );
|
||||||
|
|
||||||
|
swiftPulse( t );
|
||||||
}
|
}
|
||||||
|
|
||||||
managerUnlock( manager );
|
managerUnlock( manager );
|
||||||
|
@ -1210,6 +1250,7 @@ stopTorrent( Torrent * t )
|
||||||
t->isRunning = 0;
|
t->isRunning = 0;
|
||||||
tr_timerFree( &t->rechokeTimer );
|
tr_timerFree( &t->rechokeTimer );
|
||||||
tr_timerFree( &t->reconnectTimer );
|
tr_timerFree( &t->reconnectTimer );
|
||||||
|
tr_timerFree( &t->swiftTimer );
|
||||||
|
|
||||||
/* disconnect the peers. */
|
/* disconnect the peers. */
|
||||||
tr_ptrArrayForeach( t->peers, (PtrArrayForeachFunc)peerDestructor );
|
tr_ptrArrayForeach( t->peers, (PtrArrayForeachFunc)peerDestructor );
|
||||||
|
@ -1477,8 +1518,8 @@ static double
|
||||||
getWeightedThroughput( const tr_peer * peer )
|
getWeightedThroughput( const tr_peer * peer )
|
||||||
{
|
{
|
||||||
/* FIXME: tweak this? */
|
/* FIXME: tweak this? */
|
||||||
return ( 1 * peer->rateToPeer )
|
return /* 1 * peer->rateToPeer )
|
||||||
+ ( 1 * peer->rateToClient );
|
+*/ ( 1 * peer->rateToClient );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1534,6 +1575,55 @@ rechokePulse( void * vtorrent )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
****
|
||||||
|
***/
|
||||||
|
|
||||||
|
static int
|
||||||
|
swiftPulse( void * vtorrent )
|
||||||
|
{
|
||||||
|
Torrent * t = vtorrent;
|
||||||
|
torrentLock( t );
|
||||||
|
|
||||||
|
if( !tr_torrentIsSeed( t->tor ) )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int peerCount = 0;
|
||||||
|
int deadbeatCount = 0;
|
||||||
|
tr_peer ** peers = getConnectedPeers( t, &peerCount );
|
||||||
|
tr_peer ** deadbeats = tr_new( tr_peer*, peerCount );
|
||||||
|
|
||||||
|
for( i=0; i<peerCount; ++i ) {
|
||||||
|
tr_peer * peer = peers[i];
|
||||||
|
if( peer->credit < 0 )
|
||||||
|
deadbeats[deadbeatCount++] = peer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( deadbeatCount )
|
||||||
|
{
|
||||||
|
const double ul_KiBsec = tr_rcRate( t->tor->upload );
|
||||||
|
const double ul_KiB = ul_KiBsec * (SWIFT_PERIOD_MSEC/1000.0);
|
||||||
|
const double ul_bytes = ul_KiB * 1024;
|
||||||
|
const double freeCreditTotal = ul_bytes * SWIFT_LARGESSE;
|
||||||
|
const int freeCreditPerPeer = (int)( freeCreditTotal / deadbeatCount );
|
||||||
|
for( i=0; i<deadbeatCount; ++i )
|
||||||
|
deadbeats[i]->credit = freeCreditPerPeer;
|
||||||
|
tordbg( t, "%d deadbeats, "
|
||||||
|
"who are each being granted %d bytes' credit "
|
||||||
|
"for a total of %.1f KiB, "
|
||||||
|
"%d%% of the torrent's ul speed %.1f\n",
|
||||||
|
deadbeatCount, freeCreditPerPeer,
|
||||||
|
ul_KiBsec*SWIFT_LARGESSE, (int)(SWIFT_LARGESSE*100), ul_KiBsec );
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_free( deadbeats );
|
||||||
|
tr_free( peers );
|
||||||
|
}
|
||||||
|
|
||||||
|
torrentUnlock( t );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
****
|
****
|
||||||
**** Life and Death
|
**** Life and Death
|
||||||
|
|
|
@ -1034,6 +1034,7 @@ clientGotBytes( tr_peermsgs * msgs, uint32_t byteCount )
|
||||||
tor->activityDate = tr_date( );
|
tor->activityDate = tr_date( );
|
||||||
tor->downloadedCur += byteCount;
|
tor->downloadedCur += byteCount;
|
||||||
msgs->info->pieceDataActivityDate = time( NULL );
|
msgs->info->pieceDataActivityDate = time( NULL );
|
||||||
|
msgs->info->credit += (int)(byteCount * SWIFT_REPAYMENT_RATIO);
|
||||||
tr_rcTransferred( msgs->info->rcToClient, byteCount );
|
tr_rcTransferred( msgs->info->rcToClient, byteCount );
|
||||||
tr_rcTransferred( tor->download, byteCount );
|
tr_rcTransferred( tor->download, byteCount );
|
||||||
tr_rcTransferred( tor->handle->download, byteCount );
|
tr_rcTransferred( tor->handle->download, byteCount );
|
||||||
|
@ -1255,6 +1256,7 @@ peerGotBytes( tr_peermsgs * msgs, uint32_t byteCount )
|
||||||
tor->activityDate = tr_date( );
|
tor->activityDate = tr_date( );
|
||||||
tor->uploadedCur += byteCount;
|
tor->uploadedCur += byteCount;
|
||||||
msgs->info->pieceDataActivityDate = time( NULL );
|
msgs->info->pieceDataActivityDate = time( NULL );
|
||||||
|
msgs->info->credit -= byteCount;
|
||||||
tr_rcTransferred( msgs->info->rcToPeer, byteCount );
|
tr_rcTransferred( msgs->info->rcToPeer, byteCount );
|
||||||
tr_rcTransferred( tor->upload, byteCount );
|
tr_rcTransferred( tor->upload, byteCount );
|
||||||
tr_rcTransferred( tor->handle->upload, byteCount );
|
tr_rcTransferred( tor->handle->upload, byteCount );
|
||||||
|
@ -1440,7 +1442,15 @@ static int
|
||||||
canWrite( const tr_peermsgs * msgs )
|
canWrite( const tr_peermsgs * msgs )
|
||||||
{
|
{
|
||||||
/* don't let our outbuffer get too large */
|
/* don't let our outbuffer get too large */
|
||||||
return tr_peerIoWriteBytesWaiting( msgs->io ) < 4096;
|
if( tr_peerIoWriteBytesWaiting( msgs->io ) > 4096 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* SWIFT */
|
||||||
|
if( SWIFT_ENABLED && !tr_torrentIsSeed( msgs->torrent )
|
||||||
|
&& ( msgs->info->credit < 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
|
@ -1492,20 +1502,21 @@ updatePeerStatus( tr_peermsgs * msgs )
|
||||||
peer->status = TR_PEER_STATUS_HANDSHAKE;
|
peer->status = TR_PEER_STATUS_HANDSHAKE;
|
||||||
|
|
||||||
else if( ( time(NULL) - peer->pieceDataActivityDate ) < 3 )
|
else if( ( time(NULL) - peer->pieceDataActivityDate ) < 3 )
|
||||||
peer->status = TR_PEER_STATUS_ACTIVE;
|
peer->status = peer->clientIsChoked
|
||||||
|
? TR_PEER_STATUS_ACTIVE_AND_CHOKED
|
||||||
else if( peer->clientIsChoked )
|
: TR_PEER_STATUS_ACTIVE;
|
||||||
peer->status = TR_PEER_STATUS_CLIENT_IS_CHOKED;
|
|
||||||
|
|
||||||
else if( peer->peerIsChoked )
|
else if( peer->peerIsChoked )
|
||||||
peer->status = TR_PEER_STATUS_PEER_IS_CHOKED;
|
peer->status = TR_PEER_STATUS_PEER_IS_CHOKED;
|
||||||
|
|
||||||
|
else if( peer->clientIsChoked )
|
||||||
|
peer->status = peer->clientIsInterested
|
||||||
|
? TR_PEER_STATUS_CLIENT_IS_INTERESTED
|
||||||
|
: TR_PEER_STATUS_CLIENT_IS_CHOKED;
|
||||||
|
|
||||||
else if( msgs->clientAskedFor != NULL )
|
else if( msgs->clientAskedFor != NULL )
|
||||||
peer->status = TR_PEER_STATUS_REQUEST_SENT;
|
peer->status = TR_PEER_STATUS_REQUEST_SENT;
|
||||||
|
|
||||||
else if( peer->clientIsInterested )
|
|
||||||
peer->status = TR_PEER_STATUS_CLIENT_IS_INTERESTED;
|
|
||||||
|
|
||||||
else
|
else
|
||||||
peer->status = TR_PEER_STATUS_READY;
|
peer->status = TR_PEER_STATUS_READY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "ratecontrol.h"
|
#include "ratecontrol.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define GRANULARITY_MSEC 100
|
#define GRANULARITY_MSEC 250
|
||||||
#define SHORT_INTERVAL_MSEC 3000
|
#define SHORT_INTERVAL_MSEC 3000
|
||||||
#define LONG_INTERVAL_MSEC 6000
|
#define LONG_INTERVAL_MSEC 6000
|
||||||
#define HISTORY_SIZE (LONG_INTERVAL_MSEC / GRANULARITY_MSEC)
|
#define HISTORY_SIZE (LONG_INTERVAL_MSEC / GRANULARITY_MSEC)
|
||||||
|
@ -108,7 +108,7 @@ tr_rcBytesLeft( const tr_ratecontrol * r )
|
||||||
cur = rateForInterval( r, SHORT_INTERVAL_MSEC );
|
cur = rateForInterval( r, SHORT_INTERVAL_MSEC );
|
||||||
max = r->limit;
|
max = r->limit;
|
||||||
kb = max>cur ? max-cur : 0;
|
kb = max>cur ? max-cur : 0;
|
||||||
bytes = (size_t)(kb * 1024u);
|
bytes = (size_t)(kb * 1024);
|
||||||
|
|
||||||
tr_lockUnlock( (tr_lock*)r->lock );
|
tr_lockUnlock( (tr_lock*)r->lock );
|
||||||
}
|
}
|
||||||
|
|
|
@ -691,7 +691,8 @@ typedef enum
|
||||||
TR_PEER_STATUS_CLIENT_IS_INTERESTED,
|
TR_PEER_STATUS_CLIENT_IS_INTERESTED,
|
||||||
TR_PEER_STATUS_READY,
|
TR_PEER_STATUS_READY,
|
||||||
TR_PEER_STATUS_REQUEST_SENT,
|
TR_PEER_STATUS_REQUEST_SENT,
|
||||||
TR_PEER_STATUS_ACTIVE
|
TR_PEER_STATUS_ACTIVE,
|
||||||
|
TR_PEER_STATUS_ACTIVE_AND_CHOKED
|
||||||
}
|
}
|
||||||
tr_peer_status;
|
tr_peer_status;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue