Ignore:
Timestamp:
Dec 22, 2008, 12:51:14 AM (12 years ago)
Author:
charles
Message:

(1.4x libT) backport handshake, peer, bandwidth, peer-io to 1.4x.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/1.4x/libtransmission/bandwidth.c

    r7403 r7455  
    11/*
    2  * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    1919#include "bandwidth.h"
    2020#include "crypto.h"
    21 #include "iobuf.h"
     21#include "peer-io.h"
    2222#include "ptrarray.h"
    2323#include "utils.h"
     
    100100    tr_session * session;
    101101    tr_ptrArray * children; /* struct tr_bandwidth */
    102     tr_ptrArray * iobufs; /* struct tr_iobuf */
     102    tr_ptrArray * peers; /* tr_peerIo */
    103103};
    104104
     
    113113}
    114114
    115 static int
    116 isBandwidth( const tr_bandwidth * b )
     115tr_bool
     116tr_isBandwidth( const tr_bandwidth * b )
    117117{
    118118    return ( b != NULL ) && ( b->magicNumber == MAGIC_NUMBER );
    119 }
    120 
    121 static int
    122 isDirection( const tr_direction dir )
    123 {
    124     return ( dir == TR_UP ) || ( dir == TR_DOWN );
    125119}
    126120
     
    135129    b->session = session;
    136130    b->children = tr_ptrArrayNew( );
    137     b->iobufs = tr_ptrArrayNew( );
     131    b->peers = tr_ptrArrayNew( );
    138132    b->magicNumber = MAGIC_NUMBER;
    139     b->band[TR_UP].honorParentLimits = 1;
    140     b->band[TR_DOWN].honorParentLimits = 1;
     133    b->band[TR_UP].honorParentLimits = TRUE;
     134    b->band[TR_DOWN].honorParentLimits = TRUE;
    141135    tr_bandwidthSetParent( b, parent );
    142136    return b;
     
    146140tr_bandwidthFree( tr_bandwidth * b )
    147141{
    148     assert( isBandwidth( b ) );
     142    assert( tr_isBandwidth( b ) );
    149143
    150144    tr_bandwidthSetParent( b, NULL );
    151     tr_ptrArrayFree( b->iobufs, NULL );
     145    tr_ptrArrayFree( b->peers, NULL );
    152146    tr_ptrArrayFree( b->children, NULL );
    153147    b->magicNumber = 0xDEAD;
     
    163157                       tr_bandwidth  * parent )
    164158{
    165     assert( isBandwidth( b ) );
     159    assert( tr_isBandwidth( b ) );
    166160    assert( b != parent );
    167161
    168162    if( b->parent )
    169163    {
    170         assert( isBandwidth( b->parent ) );
     164        assert( tr_isBandwidth( b->parent ) );
    171165
    172166        tr_ptrArrayRemoveSorted( b->parent->children, b, comparePointers );
    173         b->parent= NULL;
     167        b->parent = NULL;
    174168    }
    175169
    176170    if( parent )
    177171    {
    178         assert( isBandwidth( parent ) );
     172        assert( tr_isBandwidth( parent ) );
    179173        assert( parent->parent != b );
    180174
     
    187181tr_bandwidthHonorParentLimits( tr_bandwidth  * b,
    188182                               tr_direction    dir,
    189                                int             honorParentLimits )
    190 {
    191     assert( isBandwidth( b ) );
    192     assert( isDirection( dir ) );
    193 
    194     b->band[dir].honorParentLimits = honorParentLimits != 0;
     183                               tr_bool         honorParentLimits )
     184{
     185    assert( tr_isBandwidth( b ) );
     186    assert( tr_isDirection( dir ) );
     187
     188    b->band[dir].honorParentLimits = honorParentLimits;
    195189}
    196190
     
    204198                             double          desiredSpeed )
    205199{
    206     assert( isBandwidth( b ) );
    207     assert( isDirection( dir ) );
     200    assert( tr_isBandwidth( b ) );
     201    assert( tr_isDirection( dir ) );
    208202
    209203    b->band[dir].desiredSpeed = desiredSpeed;
     
    214208                             tr_direction          dir )
    215209{
    216     assert( isBandwidth( b ) );
    217     assert( isDirection( dir ) );
     210    assert( tr_isBandwidth( b ) );
     211    assert( tr_isDirection( dir ) );
    218212
    219213    return b->band[dir].desiredSpeed;
     
    223217tr_bandwidthSetLimited( tr_bandwidth  * b,
    224218                        tr_direction    dir,
    225                         int             isLimited )
    226 {
    227     assert( isBandwidth( b ) );
    228     assert( isDirection( dir ) );
    229 
    230     b->band[dir].isLimited = isLimited != 0;
    231 }
    232 
    233 int
     219                        tr_bool         isLimited )
     220{
     221    assert( tr_isBandwidth( b ) );
     222    assert( tr_isDirection( dir ) );
     223
     224    b->band[dir].isLimited = isLimited;
     225}
     226
     227tr_bool
    234228tr_bandwidthIsLimited( const tr_bandwidth  * b,
    235229                       tr_direction          dir )
    236230{
    237     assert( isBandwidth( b ) );
    238     assert( isDirection( dir ) );
    239 
    240     return b->band[dir].isLimited != 0;
     231    assert( tr_isBandwidth( b ) );
     232    assert( tr_isDirection( dir ) );
     233
     234    return b->band[dir].isLimited;
    241235}
    242236
     
    250244                   tr_direction    dir,
    251245                   int             period_msec,
    252                    tr_ptrArray   * iobuf_pool )
    253 {
    254     assert( isBandwidth( b ) );
    255     assert( isDirection( dir ) );
    256 
     246                   tr_ptrArray   * peer_pool )
     247{
     248    assert( tr_isBandwidth( b ) );
     249    assert( tr_isDirection( dir ) );
     250
     251    /* set the available bandwidth */
    257252    if( b->band[dir].isLimited )
    258253    {
     
    269264    }
    270265
     266    /* traverse & repeat for the subtree */
    271267    {
    272268        int i;
    273         const int n = tr_ptrArraySize( b->iobufs );
     269        const int n = tr_ptrArraySize( b->peers );
    274270        for( i=0; i<n; ++i )
    275             tr_ptrArrayAppend( iobuf_pool, tr_ptrArrayNth( b->iobufs, i ) );
     271            tr_ptrArrayAppend( peer_pool, tr_ptrArrayNth( b->peers, i ) );
    276272    }
    277273
    278274#ifdef DEBUG_DIRECTION
    279275if( ( dir == DEBUG_DIRECTION ) && ( n > 1 ) )
    280 fprintf( stderr, "bandwidth %p has %d iobufs\n", b, n );
     276fprintf( stderr, "bandwidth %p has %d peers\n", b, n );
    281277#endif
    282278
     
    286282        struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayPeek( b->children, &n );
    287283        for( i=0; i<n; ++i )
    288             allocateBandwidth( children[i], dir, period_msec, iobuf_pool );
     284            allocateBandwidth( children[i], dir, period_msec, peer_pool );
    289285    }
    290286}
     
    295291                      int             period_msec )
    296292{
    297     int n;
     293    int i, n, peerCount;
    298294    tr_ptrArray * tmp;
    299     struct tr_iobuf ** buffers;
    300     const size_t chunkSize = 1024; /* arbitrary */
    301 
     295    struct tr_peerIo ** peers;
     296
     297    /* allocateBandwidth() is a helper function with two purposes:
     298     * 1. allocate bandwidth to b and its subtree
     299     * 2. accumulate an array of all the peerIos from b and its subtree. */
    302300    tmp = tr_ptrArrayNew( );
    303301    allocateBandwidth( b, dir, period_msec, tmp );
    304     buffers = (struct tr_iobuf**) tr_ptrArrayPeek( tmp, &n );
    305 
    306     /* loop through all the peers, reading and writing in small chunks,
    307      * until we run out of bandwidth or peers. we do it this way to
    308      * prevent one peer from using up all the bandwidth */
    309     while( n > 0 )
    310     {
    311         int i;
    312         for( i=0; i<n; )
    313         {
    314             int byteCount;
    315             if( dir == TR_UP )
    316                 byteCount = tr_iobuf_flush_output_buffer( buffers[i], chunkSize );
    317             else
    318                 byteCount = tr_iobuf_tryread( buffers[i], chunkSize );
    319             if( byteCount == (int)chunkSize )
    320                 ++i;
    321             else
    322                 buffers[i] = buffers[--n];
     302    peers = (struct tr_peerIo**) tr_ptrArrayPeek( tmp, &peerCount );
     303
     304    /* Stop all peers from listening for the socket to be ready for IO.
     305     * See "Second phase of IO" lower in this function for more info. */
     306    for( i=0; i<peerCount; ++i )
     307        tr_peerIoSetEnabled( peers[i], dir, FALSE );
     308
     309    /* First phase of IO.  Tries to distribute bandwidth fairly to keep faster
     310     * peers from starving the others.  Loop through the peers, giving each a
     311     * small chunk of bandwidth.  Keep looping until we run out of bandwidth
     312     * or pweers that can use it */
     313    n = peerCount;
     314    i = n ? tr_cryptoWeakRandInt( n ) : 0; /* pick a random starting point */
     315    for( ; n>0; )
     316    {
     317        const int increment = n==1 ? 4096 : 1024;
     318        const int byteCount = tr_peerIoFlush( peers[i], dir, increment);
     319
     320        if( byteCount == increment )
     321            ++i;
     322        else {
     323            /* peer is done writing for now; move it to the end of the list */
     324            tr_peerIo * tmp = peers[i];
     325            peers[i] = peers[n-1];
     326            peers[n-1] = tmp;
     327            --n;
    323328        }
    324     }
     329
     330        assert( i <= n );
     331        if( i == n )
     332            i = 0;
     333    }
     334
     335    /* Second phase of IO.  To help us scale in high bandwidth situations,
     336     * enable on-demand IO for peers with bandwidth left to burn.
     337     * This on-demand IO is enabled until (1) the peer runs out of bandwidth,
     338     * or (2) the next tr_bandwidthAllocate() call, when we start over again. */
     339    for( i=0; i<peerCount; ++i )
     340        if( tr_peerIoHasBandwidthLeft( peers[i], dir ) )
     341            tr_peerIoSetEnabled( peers[i], dir, TRUE );
    325342
    326343    /* cleanup */
     
    333350
    334351void
    335 tr_bandwidthAddBuffer( tr_bandwidth        * b,
    336                        struct tr_iobuf     * iobuf )
    337 {
    338     assert( isBandwidth( b ) );
    339     assert( iobuf );
    340 
    341     tr_ptrArrayInsertSorted( b->iobufs, iobuf, comparePointers );
    342 }
    343 
    344 void
    345 tr_bandwidthRemoveBuffer( tr_bandwidth        * b,
    346                           struct tr_iobuf     * iobuf )
    347 {
    348     assert( isBandwidth( b ) );
    349     assert( iobuf );
    350 
    351     tr_ptrArrayRemoveSorted( b->iobufs, iobuf, comparePointers );
     352tr_bandwidthAddPeer( tr_bandwidth   * b,
     353                     tr_peerIo      * peerIo )
     354{
     355    assert( tr_isBandwidth( b ) );
     356    assert( tr_isPeerIo( peerIo ) );
     357
     358    tr_ptrArrayInsertSorted( b->peers, peerIo, comparePointers );
     359}
     360
     361void
     362tr_bandwidthRemovePeer( tr_bandwidth  * b,
     363                        tr_peerIo     * peerIo )
     364{
     365    assert( tr_isBandwidth( b ) );
     366    assert( tr_isPeerIo( peerIo ) );
     367
     368    tr_ptrArrayRemoveSorted( b->peers, peerIo, comparePointers );
    352369}
    353370
     
    361378                   size_t                byteCount )
    362379{
    363     assert( isBandwidth( b ) );
    364     assert( isDirection( dir ) );
     380    assert( tr_isBandwidth( b ) );
     381    assert( tr_isDirection( dir ) );
    365382
    366383    if( b )
     
    379396tr_bandwidthGetRawSpeed( const tr_bandwidth * b, tr_direction dir )
    380397{
    381     assert( isBandwidth( b ) );
    382     assert( isDirection( dir ) );
     398    assert( tr_isBandwidth( b ) );
     399    assert( tr_isDirection( dir ) );
    383400
    384401    return getSpeed( &b->band[dir].raw, HISTORY_MSEC );
     
    388405tr_bandwidthGetPieceSpeed( const tr_bandwidth * b, tr_direction dir )
    389406{
    390     assert( isBandwidth( b ) );
    391     assert( isDirection( dir ) );
     407    assert( tr_isBandwidth( b ) );
     408    assert( tr_isDirection( dir ) );
    392409
    393410    return getSpeed( &b->band[dir].piece, HISTORY_MSEC );
     
    398415                  tr_direction    dir,
    399416                  size_t          byteCount,
    400                   int             isPieceData )
     417                  tr_bool         isPieceData )
    401418{
    402419    struct tr_band * band;
    403420    size_t oldBytesLeft;
    404421
    405     assert( isBandwidth( b ) );
    406     assert( isDirection( dir ) );
     422    assert( tr_isBandwidth( b ) );
     423    assert( tr_isDirection( dir ) );
    407424
    408425    band = &b->band[dir];
Note: See TracChangeset for help on using the changeset viewer.