mirror of
https://github.com/transmission/transmission
synced 2025-03-09 05:14:09 +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 "util.h"
|
||||
|
||||
#define UPDATE_INTERVAL_MSEC 1500
|
||||
#define UPDATE_INTERVAL_MSEC 2000
|
||||
|
||||
/****
|
||||
***** PIECES VIEW
|
||||
|
@ -361,10 +361,11 @@ render_status( GtkTreeViewColumn * column UNUSED,
|
|||
case TR_PEER_STATUS_HANDSHAKE: text = _( "Handshaking" ); 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_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_REQUEST_SENT: text = _( "Request Sent" ); break;
|
||||
case TR_PEER_STATUS_ACTIVE : text = _( "Active" ); break;
|
||||
case TR_PEER_STATUS_ACTIVE_AND_CHOKED: text = _( "Active & Choked" ); break;
|
||||
default: text = "BUG"; break;
|
||||
}
|
||||
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[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] );
|
||||
}
|
||||
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] );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,27 @@ enum
|
|||
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
|
||||
{
|
||||
unsigned int peerIsChoked : 1;
|
||||
|
@ -66,6 +87,8 @@ typedef struct tr_peer
|
|||
|
||||
double rateToClient;
|
||||
double rateToPeer;
|
||||
|
||||
int64_t credit;
|
||||
}
|
||||
tr_peer;
|
||||
|
||||
|
|
|
@ -39,6 +39,35 @@
|
|||
#include "trevent.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
|
||||
{
|
||||
/* how frequently to change which peers are choked */
|
||||
|
@ -114,6 +143,7 @@ typedef struct
|
|||
tr_timer * reconnectTimer;
|
||||
tr_timer * rechokeTimer;
|
||||
tr_timer * refillTimer;
|
||||
tr_timer * swiftTimer;
|
||||
tr_torrent * tor;
|
||||
tr_bitfield * requested;
|
||||
|
||||
|
@ -314,6 +344,7 @@ peerConstructor( const struct in_addr * in_addr )
|
|||
{
|
||||
tr_peer * p;
|
||||
p = tr_new0( tr_peer, 1 );
|
||||
p->credit = SWIFT_INITIAL_CREDIT;
|
||||
p->rcToClient = tr_rcInit( );
|
||||
p->rcToPeer = tr_rcInit( );
|
||||
memcpy( &p->in_addr, in_addr, sizeof(struct in_addr) );
|
||||
|
@ -397,6 +428,7 @@ torrentDestructor( Torrent * t )
|
|||
tr_timerFree( &t->reconnectTimer );
|
||||
tr_timerFree( &t->rechokeTimer );
|
||||
tr_timerFree( &t->refillTimer );
|
||||
tr_timerFree( &t->swiftTimer );
|
||||
|
||||
tr_bitfieldFree( t->requested );
|
||||
tr_ptrArrayFree( t->pool, (PtrArrayForeachFunc)tr_free );
|
||||
|
@ -1167,6 +1199,7 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
|
|||
|
||||
static int reconnectPulse( void * vtorrent );
|
||||
static int rechokePulse( void * vtorrent );
|
||||
static int swiftPulse( void * vtorrent );
|
||||
|
||||
void
|
||||
tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||
|
@ -1181,6 +1214,7 @@ tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
|||
assert( t != NULL );
|
||||
assert( ( t->isRunning != 0 ) == ( t->reconnectTimer != NULL ) );
|
||||
assert( ( t->isRunning != 0 ) == ( t->rechokeTimer != NULL ) );
|
||||
assert( ( t->isRunning != 0 ) == ( t->swiftTimer != NULL ) );
|
||||
|
||||
if( !t->isRunning )
|
||||
{
|
||||
|
@ -1194,9 +1228,15 @@ tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
|||
rechokePulse, t,
|
||||
RECHOKE_PERIOD_MSEC );
|
||||
|
||||
t->swiftTimer = tr_timerNew( t->manager->handle,
|
||||
swiftPulse, t,
|
||||
SWIFT_PERIOD_MSEC );
|
||||
|
||||
reconnectPulse( t );
|
||||
|
||||
rechokePulse( t );
|
||||
|
||||
swiftPulse( t );
|
||||
}
|
||||
|
||||
managerUnlock( manager );
|
||||
|
@ -1210,6 +1250,7 @@ stopTorrent( Torrent * t )
|
|||
t->isRunning = 0;
|
||||
tr_timerFree( &t->rechokeTimer );
|
||||
tr_timerFree( &t->reconnectTimer );
|
||||
tr_timerFree( &t->swiftTimer );
|
||||
|
||||
/* disconnect the peers. */
|
||||
tr_ptrArrayForeach( t->peers, (PtrArrayForeachFunc)peerDestructor );
|
||||
|
@ -1477,8 +1518,8 @@ static double
|
|||
getWeightedThroughput( const tr_peer * peer )
|
||||
{
|
||||
/* FIXME: tweak this? */
|
||||
return ( 1 * peer->rateToPeer )
|
||||
+ ( 1 * peer->rateToClient );
|
||||
return /* 1 * peer->rateToPeer )
|
||||
+*/ ( 1 * peer->rateToClient );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1534,6 +1575,55 @@ rechokePulse( void * vtorrent )
|
|||
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
|
||||
|
|
|
@ -1034,6 +1034,7 @@ clientGotBytes( tr_peermsgs * msgs, uint32_t byteCount )
|
|||
tor->activityDate = tr_date( );
|
||||
tor->downloadedCur += byteCount;
|
||||
msgs->info->pieceDataActivityDate = time( NULL );
|
||||
msgs->info->credit += (int)(byteCount * SWIFT_REPAYMENT_RATIO);
|
||||
tr_rcTransferred( msgs->info->rcToClient, byteCount );
|
||||
tr_rcTransferred( tor->download, byteCount );
|
||||
tr_rcTransferred( tor->handle->download, byteCount );
|
||||
|
@ -1255,6 +1256,7 @@ peerGotBytes( tr_peermsgs * msgs, uint32_t byteCount )
|
|||
tor->activityDate = tr_date( );
|
||||
tor->uploadedCur += byteCount;
|
||||
msgs->info->pieceDataActivityDate = time( NULL );
|
||||
msgs->info->credit -= byteCount;
|
||||
tr_rcTransferred( msgs->info->rcToPeer, byteCount );
|
||||
tr_rcTransferred( tor->upload, byteCount );
|
||||
tr_rcTransferred( tor->handle->upload, byteCount );
|
||||
|
@ -1440,7 +1442,15 @@ static int
|
|||
canWrite( const tr_peermsgs * msgs )
|
||||
{
|
||||
/* 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
|
||||
|
@ -1492,20 +1502,21 @@ updatePeerStatus( tr_peermsgs * msgs )
|
|||
peer->status = TR_PEER_STATUS_HANDSHAKE;
|
||||
|
||||
else if( ( time(NULL) - peer->pieceDataActivityDate ) < 3 )
|
||||
peer->status = TR_PEER_STATUS_ACTIVE;
|
||||
|
||||
else if( peer->clientIsChoked )
|
||||
peer->status = TR_PEER_STATUS_CLIENT_IS_CHOKED;
|
||||
peer->status = peer->clientIsChoked
|
||||
? TR_PEER_STATUS_ACTIVE_AND_CHOKED
|
||||
: TR_PEER_STATUS_ACTIVE;
|
||||
|
||||
else if( peer->peerIsChoked )
|
||||
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 )
|
||||
peer->status = TR_PEER_STATUS_REQUEST_SENT;
|
||||
|
||||
else if( peer->clientIsInterested )
|
||||
peer->status = TR_PEER_STATUS_CLIENT_IS_INTERESTED;
|
||||
|
||||
else
|
||||
peer->status = TR_PEER_STATUS_READY;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "ratecontrol.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define GRANULARITY_MSEC 100
|
||||
#define GRANULARITY_MSEC 250
|
||||
#define SHORT_INTERVAL_MSEC 3000
|
||||
#define LONG_INTERVAL_MSEC 6000
|
||||
#define HISTORY_SIZE (LONG_INTERVAL_MSEC / GRANULARITY_MSEC)
|
||||
|
@ -108,7 +108,7 @@ tr_rcBytesLeft( const tr_ratecontrol * r )
|
|||
cur = rateForInterval( r, SHORT_INTERVAL_MSEC );
|
||||
max = r->limit;
|
||||
kb = max>cur ? max-cur : 0;
|
||||
bytes = (size_t)(kb * 1024u);
|
||||
bytes = (size_t)(kb * 1024);
|
||||
|
||||
tr_lockUnlock( (tr_lock*)r->lock );
|
||||
}
|
||||
|
|
|
@ -691,7 +691,8 @@ typedef enum
|
|||
TR_PEER_STATUS_CLIENT_IS_INTERESTED,
|
||||
TR_PEER_STATUS_READY,
|
||||
TR_PEER_STATUS_REQUEST_SENT,
|
||||
TR_PEER_STATUS_ACTIVE
|
||||
TR_PEER_STATUS_ACTIVE,
|
||||
TR_PEER_STATUS_ACTIVE_AND_CHOKED
|
||||
}
|
||||
tr_peer_status;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue