1
0
Fork 0
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:
Charles Kerr 2007-11-18 01:00:49 +00:00
parent c83f25fed5
commit 9a81cd7637
7 changed files with 143 additions and 17 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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