Ticket #3596: choke.diff

File choke.diff, 8.7 KB (added by charles, 12 years ago)

first draft

  • libtransmission/peer-msgs.c

     
    7171
    7272    MAX_PEX_PEER_COUNT      = 50,
    7373
    74     MIN_CHOKE_PERIOD_SEC    = 10,
    75 
    7674    /* idle seconds before we send a keepalive */
    7775    KEEPALIVE_INTERVAL_SECS = 100,
    7876
     
    737735}
    738736
    739737void
    740 tr_peerMsgsSetChoke( tr_peermsgs * msgs,
    741                      int           choke )
     738tr_peerMsgsSetChoke( tr_peermsgs * msgs, uint8_t state )
    742739{
    743     const time_t now = tr_time( );
    744     const time_t fibrillationTime = now - MIN_CHOKE_PERIOD_SEC;
     740    tr_peer * peer;
    745741
    746742    assert( msgs );
    747     assert( msgs->peer );
    748     assert( choke == 0 || choke == 1 );
     743    peer = msgs->peer;
     744    assert( peer );
     745    assert( choke==PEER_CHOKE_STATE_CHOKED ||
     746            choke==PEER_CHOKE_STATE_UNCHOKED ||
     747            choke==PEER_CHOKE_STATE_UNCHOKED_OPTIMISTIC );
    749748
    750     if( msgs->peer->chokeChangedAt > fibrillationTime )
     749    /* if the state's changed... */
     750    if( peer->peerChokeState != state )
    751751    {
    752         dbgmsg( msgs, "Not changing choke to %d to avoid fibrillation", choke );
     752        tr_bool was_choked;
     753        tr_bool is_choked;
     754
     755        /* change the state... */
     756        was_choked = tr_peerIsChoked( peer );
     757        peer->peerChokeState = state;
     758        peer->peerChokeChangedAt = tr_time( );
     759        is_choked = tr_peerIsChoked( peer );
     760
     761        if( is_choked != was_choked ) {
     762            if( is_choked )
     763                cancelAllRequestsToClient( msgs );
     764            protocolSendChoke( msgs, is_choked  );
     765        }
    753766    }
    754     else if( msgs->peer->peerIsChoked != choke )
    755     {
    756         msgs->peer->peerIsChoked = choke;
    757         if( choke )
    758             cancelAllRequestsToClient( msgs );
    759         protocolSendChoke( msgs, choke );
    760         msgs->peer->chokeChangedAt = now;
    761     }
    762767}
    763768
    764769/**
     
    12251230    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
    12261231    const int reqIsValid = requestIsValid( msgs, req );
    12271232    const int clientHasPiece = reqIsValid && tr_cpPieceIsComplete( &msgs->torrent->completion, req->index );
    1228     const int peerIsChoked = msgs->peer->peerIsChoked;
     1233    const int peerIsChoked = tr_peerIsChoked( msgs->peer );
    12291234
    12301235    int allow = FALSE;
    12311236
     
    23332338    m->peer = peer;
    23342339    m->torrent = torrent;
    23352340    m->peer->clientIsChoked = 1;
    2336     m->peer->peerIsChoked = 1;
     2341    m->peer->peerChokeState = PEER_CHOKE_STATE_CHOKED;
     2342    m->peer->peerChokeChangedAt = 0;
    23372343    m->peer->clientIsInterested = 0;
    23382344    m->peer->peerIsInterested = 0;
    23392345    m->state = AWAITING_BT_LENGTH;
  • libtransmission/peer-msgs.h

     
    3636                             tr_peer_callback     * callback,
    3737                             void                 * callback_data );
    3838
    39 void         tr_peerMsgsSetChoke( tr_peermsgs *, int doChoke );
     39void         tr_peerMsgsSetChoke( tr_peermsgs *, uint8_t peer_choke_state );
    4040
    4141int          tr_peerMsgsIsReadingBlock( const tr_peermsgs * msgs, tr_block_index_t block );
    4242
  • libtransmission/peer-mgr.c

     
    5151    /* how frequently to reallocate bandwidth */
    5252    BANDWIDTH_PERIOD_MSEC = 500,
    5353
     54    /* don't change a peer's choke/unchoke state more frequently than this */
     55    CHOKE_FIBRILATION_PERIOD_SEC = 30,
     56
    5457    /* how frequently to age out old piece request lists */
    5558    REFILL_UPKEEP_PERIOD_MSEC = ( 10 * 1000 ),
    5659
     
    546549static int
    547550clientIsUploadingTo( const tr_peer * peer )
    548551{
    549     return peer->peerIsInterested && !peer->peerIsChoked;
     552    return peer->peerIsInterested && !tr_peerIsChoked( peer );
    550553}
    551554
    552555/***
     
    23462349        stat->isEncrypted         = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
    23472350        stat->rateToPeer_KBps     = toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer, now, TR_CLIENT_TO_PEER ) );
    23482351        stat->rateToClient_KBps   = toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer, now, TR_PEER_TO_CLIENT ) );
    2349         stat->peerIsChoked        = peer->peerIsChoked;
     2352        stat->peerIsChoked        = tr_peerIsChoked( peer );
    23502353        stat->peerIsInterested    = peer->peerIsInterested;
    23512354        stat->clientIsChoked      = peer->clientIsChoked;
    23522355        stat->clientIsInterested  = peer->clientIsInterested;
     
    27022705}
    27032706
    27042707static void
    2705 rechokeUploads( Torrent * t, const uint64_t now )
     2708rechokeUploads( Torrent * t, const uint64_t now_msec )
    27062709{
    27072710    int i, size, unchokedInterested;
    27082711    const int peerCount = tr_ptrArraySize( &t->peers );
    27092712    tr_peer ** peers = (tr_peer**) tr_ptrArrayBase( &t->peers );
    27102713    struct ChokeData * choke = tr_new0( struct ChokeData, peerCount );
     2714    tr_bool have_optimistic_unchoke = FALSE;
    27112715    const tr_session * session = t->manager->session;
    2712     const int chokeAll = !tr_torrentIsPieceTransferAllowed( t->tor, TR_CLIENT_TO_PEER );
    2713     const tr_bool isMaxedOut = isBandwidthMaxedOut( t->tor->bandwidth, now, TR_UP );
     2716    const int choke_all = !tr_torrentIsPieceTransferAllowed( t->tor, TR_CLIENT_TO_PEER );
     2717    const tr_bool is_maxed_out = isBandwidthMaxedOut( t->tor->bandwidth, now_msec, TR_UP );
    27142718
    27152719    assert( torrentIsLocked( t ) );
    27162720
    27172721    /* sort the peers by preference and rate */
    2718     for( i = 0, size = 0; i < peerCount; ++i )
     2722    for( i=size=0; i<peerCount; ++i )
    27192723    {
    27202724        tr_peer * peer = peers[i];
    27212725        struct peer_atom * atom = peer->atom;
     2726        const tr_bool changed_recently = tr_time() - peer->peerChokeChangedAt < CHOKE_FIBRILATION_PERIOD_SEC;
    27222727
    27232728        if( peer->progress >= 1.0 ) /* choke all seeds */
    27242729        {
     
    27282733        {
    27292734            tr_peerMsgsSetChoke( peer->msgs, TRUE );
    27302735        }
    2731         else if( chokeAll ) /* choke everyone if we're not uploading */
     2736        else if( choke_all ) /* choke everyone if we're not uploading */
    27322737        {
    27332738            tr_peerMsgsSetChoke( peer->msgs, TRUE );
    27342739        }
     2740        else if( changed_recently ) /* don't change states too quickly */
     2741        {
     2742            have_optimistic_unchoke = peer->peerChokeState == PEER_CHOKE_STATE_UNCHOKED_OPTIMISTIC;
     2743        }
    27352744        else
    27362745        {
    27372746            struct ChokeData * n = &choke[size++];
    27382747            n->peer         = peer;
    27392748            n->isInterested = peer->peerIsInterested;
    2740             n->wasChoked    = peer->peerIsChoked;
    2741             n->rate         = getRate( t->tor, atom, now );
     2749            n->wasChoked    = tr_peerIsChoked( peer );
     2750            n->rate         = getRate( t->tor, atom, now_msec );
    27422751            n->salt         = tr_cryptoWeakRandInt( INT_MAX );
    27432752            n->isChoked     = TRUE;
    27442753        }
     
    27632772     */
    27642773    unchokedInterested = 0;
    27652774    for( i=0; i<size && unchokedInterested<session->uploadSlotsPerTorrent; ++i ) {
    2766         choke[i].isChoked = isMaxedOut ? choke[i].wasChoked : FALSE;
     2775        choke[i].isChoked = is_maxed_out ? choke[i].wasChoked : FALSE;
    27672776        if( choke[i].isInterested )
    27682777            ++unchokedInterested;
    27692778    }
    27702779
    27712780    /* optimistic unchoke */
    2772     if( !isMaxedOut && (i<size) )
     2781    if( !have_optimistic_unchoke && !is_maxed_out && (i<size) )
    27732782    {
    27742783        int n;
    27752784        struct ChokeData * c;
  • libtransmission/peer-mgr.h

     
    7070/* opaque forward declaration */
    7171struct peer_atom;
    7272
     73enum
     74{
     75    PEER_CHOKE_STATE_CHOKED,
     76    PEER_CHOKE_STATE_UNCHOKED,
     77    PEER_CHOKE_STATE_UNCHOKED_OPTIMISTIC
     78};
     79
    7380/**
    7481 * State information about a connected peer.
    7582 *
     
    7885 */
    7986typedef struct tr_peer
    8087{
    81     tr_bool                  peerIsChoked;
     88    uint8_t                  peerChokeState;
    8289    tr_bool                  peerIsInterested;
    8390    tr_bool                  clientIsChoked;
    8491    tr_bool                  clientIsInterested;
     
    108115    /* the client name from the `v' string in LTEP's handshake dictionary */
    109116    char                   * client;
    110117
    111     time_t                   chokeChangedAt;
     118    time_t                   peerChokeChangedAt;
    112119
    113120    tr_recentHistory       * blocksSentToClient;
    114121    tr_recentHistory       * blocksSentToPeer;
     
    120127}
    121128tr_peer;
    122129
     130static inline tr_bool tr_peerIsChoked( const tr_peer * peer )
     131{
     132    return peer->peerChokeState == PEER_CHOKE_STATE_CHOKED;
     133}
     134
    123135const tr_address * tr_peerAddress( const tr_peer * );
    124136
    125137int tr_pexCompare( const void * a, const void * b );