(trunk) experimental support for tr_torrentSetPriority()

This commit is contained in:
Charles Kerr 2009-04-18 23:17:30 +00:00
parent b5487b3454
commit 03fa0b3e7d
10 changed files with 154 additions and 66 deletions

View File

@ -88,6 +88,7 @@
string | value type & description
----------------------------------+-------------------------------------------------
"bandwidthPriority" | number this torrent's bandwidth tr_priority_t
"downloadLimit" | number maximum download speed (in K/s)
"downloadLimited" | boolean true if "downloadLimit" is honored
"files-wanted" | array indices of file(s) to download
@ -132,6 +133,7 @@
addedDate | number | tr_stat
announceResponse | string | tr_stat
announceURL | string | tr_stat
bandwidthPriority | number | tr_priority_t
comment | string | tr_info
corruptEver | number | tr_stat
creator | string | tr_info
@ -469,6 +471,8 @@
5 | 1.60 | yes | torrent-get | new arg "pieces"
| | yes | torrent-get | new arg "fileStats"
| | yes | torrent-set | new arg "ratio"
| | yes | torrent-get | new arg "bandwidthPriority"
| | yes | torrent-set | new arg "bandwidthPriority"
| | yes | torrent-set | new arg "downloadLimited"
| | yes | torrent-set | new arg "uploadLimited"
| | yes | torrent-set | new arg "honorsSessionLimits"

View File

@ -148,10 +148,13 @@ tr_bandwidthSetParent( tr_bandwidth * b,
static void
allocateBandwidth( tr_bandwidth * b,
tr_priority_t parent_priority,
tr_direction dir,
int period_msec,
tr_ptrArray * peer_pool )
{
tr_priority_t priority;
assert( tr_isBandwidth( b ) );
assert( tr_isDirection( dir ) );
@ -170,9 +173,13 @@ allocateBandwidth( tr_bandwidth * b,
#endif
}
priority = MAX( parent_priority, b->priority );
/* add this bandwidth's peer, if any, to the peer pool */
if( b->peer != NULL )
if( b->peer != NULL ) {
b->peer->priority = priority;
tr_ptrArrayAppend( peer_pool, b->peer );
}
#ifdef DEBUG_DIRECTION
if( ( dir == DEBUG_DIRECTION ) && ( n > 1 ) )
@ -185,28 +192,16 @@ fprintf( stderr, "bandwidth %p has %d peers\n", b, n );
struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayBase( &b->children );
const int n = tr_ptrArraySize( &b->children );
for( i=0; i<n; ++i )
allocateBandwidth( children[i], dir, period_msec, peer_pool );
allocateBandwidth( children[i], priority, dir, period_msec, peer_pool );
}
}
void
tr_bandwidthAllocate( tr_bandwidth * b,
tr_direction dir,
int period_msec )
static void
phaseOne( tr_ptrArray * peerArray, tr_direction dir )
{
int i, n, peerCount;
tr_ptrArray tmp = TR_PTR_ARRAY_INIT;
struct tr_peerIo ** peers;
/* allocateBandwidth() is a helper function with two purposes:
* 1. allocate bandwidth to b and its subtree
* 2. accumulate an array of all the peerIos from b and its subtree. */
allocateBandwidth( b, dir, period_msec, &tmp );
peers = (struct tr_peerIo**) tr_ptrArrayBase( &tmp );
peerCount = tr_ptrArraySize( &tmp );
for( i=0; i<peerCount; ++i )
tr_peerIoRef( peers[i] );
int i, n;
int peerCount = tr_ptrArraySize( peerArray );
struct tr_peerIo ** peers = (struct tr_peerIo**) tr_ptrArrayBase( peerArray );
/* First phase of IO. Tries to distribute bandwidth fairly to keep faster
* peers from starving the others. Loop through the peers, giving each a
@ -235,6 +230,43 @@ tr_bandwidthAllocate( tr_bandwidth * b,
if( i == n )
i = 0;
}
}
void
tr_bandwidthAllocate( tr_bandwidth * b,
tr_direction dir,
int period_msec )
{
int i, peerCount;
tr_ptrArray tmp = TR_PTR_ARRAY_INIT;
tr_ptrArray low = TR_PTR_ARRAY_INIT;
tr_ptrArray high = TR_PTR_ARRAY_INIT;
tr_ptrArray normal = TR_PTR_ARRAY_INIT;
struct tr_peerIo ** peers;
/* allocateBandwidth() is a helper function with two purposes:
* 1. allocate bandwidth to b and its subtree
* 2. accumulate an array of all the peerIos from b and its subtree. */
allocateBandwidth( b, TR_PRI_LOW, dir, period_msec, &tmp );
peers = (struct tr_peerIo**) tr_ptrArrayBase( &tmp );
peerCount = tr_ptrArraySize( &tmp );
for( i=0; i<peerCount; ++i ) {
tr_peerIoRef( peers[i] );
switch( peers[i]->priority ) {
case TR_PRI_HIGH: tr_ptrArrayAppend( &high, peers[i] ); break;
case TR_PRI_LOW: tr_ptrArrayAppend( &low, peers[i] ); break;
default: tr_ptrArrayAppend( &normal, peers[i] ); break;
}
}
/* First phase of IO. Tries to distribute bandwidth fairly to keep faster
* peers from starving the others. Loop through the peers, giving each a
* small chunk of bandwidth. Keep looping until we run out of bandwidth
* and/or peers that can use it */
phaseOne( &high, dir );
phaseOne( &normal, dir );
phaseOne( &low, dir );
/* Second phase of IO. To help us scale in high bandwidth situations,
* enable on-demand IO for peers with bandwidth left to burn.
@ -247,6 +279,9 @@ tr_bandwidthAllocate( tr_bandwidth * b,
tr_peerIoUnref( peers[i] );
/* cleanup */
tr_ptrArrayDestruct( &normal, NULL );
tr_ptrArrayDestruct( &high, NULL );
tr_ptrArrayDestruct( &low, NULL );
tr_ptrArrayDestruct( &tmp, NULL );
}

View File

@ -100,6 +100,7 @@ typedef struct tr_bandwidth
struct tr_band band[2];
struct tr_bandwidth * parent;
tr_priority_t priority;
int magicNumber;
tr_session * session;
tr_ptrArray children; /* struct tr_bandwidth */

View File

@ -181,7 +181,7 @@ internalIdToPublicBitfield( uint8_t id )
ret = TR_FR_PROGRESS; break;
case FR_ID_PRIORITY:
ret = TR_FR_PRIORITY; break;
ret = TR_FR_FILE_PRIORITIES; break;
case FR_ID_SPEED:
ret = TR_FR_SPEEDLIMIT; break;
@ -366,7 +366,7 @@ parsePriorities( tr_torrent * tor,
tr_free( dnd );
tr_free( dl );
ret = TR_FR_PRIORITY;
ret = TR_FR_FILE_PRIORITIES;
}
return ret;

View File

@ -69,6 +69,8 @@ typedef struct tr_peerIo
* for reading or writing */
tr_bool hasFinishedConnecting;
tr_priority_t priority;
int pendingEvents;
int magicNumber;

View File

@ -36,7 +36,8 @@
#define KEY_PAUSED "paused"
#define KEY_PEERS "peers"
#define KEY_PEERS6 "peers6"
#define KEY_PRIORITY "priority"
#define KEY_FILE_PRIORITIES "priority"
#define KEY_BANDWIDTH_PRIORITY "bandwidth-priority"
#define KEY_PROGRESS "progress"
#define KEY_SPEEDLIMIT_OLD "speed-limit"
#define KEY_SPEEDLIMIT_UP "speed-limit-up"
@ -189,7 +190,7 @@ loadDND( tr_benc * dict,
tr_free( dnd );
tr_free( dl );
ret = TR_FR_PRIORITY;
ret = TR_FR_DND;
}
else
{
@ -207,29 +208,27 @@ loadDND( tr_benc * dict,
***/
static void
savePriorities( tr_benc * dict,
const tr_torrent * tor )
saveFilePriorities( tr_benc * dict, const tr_torrent * tor )
{
const tr_info * inf = tr_torrentInfo( tor );
const tr_file_index_t n = inf->fileCount;
tr_file_index_t i;
tr_benc * list;
list = tr_bencDictAddList( dict, KEY_PRIORITY, n );
list = tr_bencDictAddList( dict, KEY_FILE_PRIORITIES, n );
for( i = 0; i < n; ++i )
tr_bencListAddInt( list, inf->files[i].priority );
}
static uint64_t
loadPriorities( tr_benc * dict,
tr_torrent * tor )
loadFilePriorities( tr_benc * dict, tr_torrent * tor )
{
uint64_t ret = 0;
tr_info * inf = &tor->info;
const tr_file_index_t n = inf->fileCount;
tr_benc * list;
if( tr_bencDictFindList( dict, KEY_PRIORITY, &list )
if( tr_bencDictFindList( dict, KEY_FILE_PRIORITIES, &list )
&& ( tr_bencListSize( list ) == n ) )
{
int64_t priority;
@ -237,7 +236,7 @@ loadPriorities( tr_benc * dict,
for( i = 0; i < n; ++i )
if( tr_bencGetInt( tr_bencListChild( list, i ), &priority ) )
tr_torrentInitFilePriority( tor, i, priority );
ret = TR_FR_PRIORITY;
ret = TR_FR_FILE_PRIORITIES;
}
return ret;
@ -502,9 +501,11 @@ tr_torrentSaveResume( const tr_torrent * tor )
tor->uploadedPrev + tor->uploadedCur );
tr_bencDictAddInt( &top, KEY_MAX_PEERS,
tor->maxConnectedPeers );
tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY,
tr_torrentGetPriority( tor ) );
tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
savePeers( &top, tor );
savePriorities( &top, tor );
saveFilePriorities( &top, tor );
saveDND( &top, tor );
saveProgress( &top, tor );
saveSpeedLimits( &top, tor );
@ -614,11 +615,19 @@ loadFromFile( tr_torrent * tor,
fieldsLoaded |= TR_FR_ACTIVITY_DATE;
}
if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
&& tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
&& tr_isPriority( i ) )
{
tr_torrentSetPriority( tor, i );
fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
}
if( fieldsToLoad & TR_FR_PEERS )
fieldsLoaded |= loadPeers( &top, tor );
if( fieldsToLoad & TR_FR_PRIORITY )
fieldsLoaded |= loadPriorities( &top, tor );
if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
fieldsLoaded |= loadFilePriorities( &top, tor );
if( fieldsToLoad & TR_FR_PROGRESS )
fieldsLoaded |= loadProgress( &top, tor );

View File

@ -25,15 +25,16 @@ enum
TR_FR_PEERS = ( 1 << 3 ),
TR_FR_PROGRESS = ( 1 << 4 ),
TR_FR_DND = ( 1 << 5 ),
TR_FR_PRIORITY = ( 1 << 6 ),
TR_FR_SPEEDLIMIT = ( 1 << 7 ),
TR_FR_RUN = ( 1 << 8 ),
TR_FR_DOWNLOAD_DIR = ( 1 << 9 ),
TR_FR_MAX_PEERS = ( 1 << 10 ),
TR_FR_ADDED_DATE = ( 1 << 11 ),
TR_FR_DONE_DATE = ( 1 << 12 ),
TR_FR_ACTIVITY_DATE = ( 1 << 13 ),
TR_FR_RATIOLIMIT = ( 1 << 14 )
TR_FR_FILE_PRIORITIES = ( 1 << 6 ),
TR_FR_BANDWIDTH_PRIORITY = ( 1 << 7 ),
TR_FR_SPEEDLIMIT = ( 1 << 8 ),
TR_FR_RUN = ( 1 << 9 ),
TR_FR_DOWNLOAD_DIR = ( 1 << 10 ),
TR_FR_MAX_PEERS = ( 1 << 11 ),
TR_FR_ADDED_DATE = ( 1 << 12 ),
TR_FR_DONE_DATE = ( 1 << 13 ),
TR_FR_ACTIVITY_DATE = ( 1 << 14 ),
TR_FR_RATIOLIMIT = ( 1 << 15 )
};
/**

View File

@ -409,6 +409,8 @@ addField( const tr_torrent * tor,
tr_bencDictAddStr( d, key, st->announceResponse );
else if( !strcmp( key, "announceURL" ) )
tr_bencDictAddStr( d, key, st->announceURL );
else if( !strcmp( key, "bandwidthPriority" ) )
tr_bencDictAddInt( d, key, tr_torrentGetPriority( tor ) );
else if( !strcmp( key, "comment" ) )
tr_bencDictAddStr( d, key, inf->comment ? inf->comment : "" );
else if( !strcmp( key, "corruptEver" ) )
@ -721,6 +723,9 @@ torrentSet( tr_session * session,
tr_bool boolVal;
tr_torrent * tor = torrents[i];
if( tr_bencDictFindInt( args_in, "bandwidthPriority", &tmp ) )
if( tr_isPriority( tmp ) )
tr_torrentSetPriority( tor, tmp );
if( tr_bencDictFindList( args_in, "files-unwanted", &files ) )
setFileDLs( tor, FALSE, files );
if( tr_bencDictFindList( args_in, "files-wanted", &files ) )

View File

@ -1521,7 +1521,7 @@ tr_torrentInitFilePriority( tr_torrent * tor,
assert( tr_isTorrent( tor ) );
assert( fileIndex < tor->info.fileCount );
assert( priority == TR_PRI_LOW || priority == TR_PRI_NORMAL || priority == TR_PRI_HIGH );
assert( tr_isPriority( priority ) );
file = &tor->info.files[fileIndex];
file->priority = priority;
@ -1696,6 +1696,27 @@ tr_torrentSetFileDLs( tr_torrent * tor,
****
***/
tr_priority_t
tr_torrentGetPriority( const tr_torrent * tor )
{
assert( tr_isTorrent( tor ) );
return tor->bandwidth->priority;
}
void
tr_torrentSetPriority( tr_torrent * tor, tr_priority_t priority )
{
assert( tr_isTorrent( tor ) );
assert( tr_isPriority( priority ) );
tor->bandwidth->priority = priority;
}
/***
****
***/
void
tr_torrentSetPeerLimit( tr_torrent * tor,
uint16_t maxConnectedPeers )

View File

@ -72,6 +72,13 @@ enum
typedef int8_t tr_priority_t;
static TR_INLINE tr_bool tr_isPriority( tr_priority_t p )
{
return ( p == TR_PRI_LOW )
|| ( p == TR_PRI_NORMAL )
|| ( p == TR_PRI_HIGH );
}
/**
* @brief returns Transmission's default configuration file directory.
*
@ -650,6 +657,9 @@ uint16_t tr_sessionGetPeerLimit( const tr_session * );
void tr_sessionSetPeerLimitPerTorrent( tr_session *, uint16_t maxGlobalPeers );
uint16_t tr_sessionGetPeerLimitPerTorrent( const tr_session * );
tr_priority_t tr_torrentGetPriority( const tr_torrent * );
void tr_torrentSetPriority( tr_torrent *, tr_priority_t );
/**
* Load all the torrents in tr_getTorrentDir().