Ticket #3596: choke.diff
File choke.diff, 8.7 KB (added by charles, 12 years ago) |
---|
-
libtransmission/peer-msgs.c
71 71 72 72 MAX_PEX_PEER_COUNT = 50, 73 73 74 MIN_CHOKE_PERIOD_SEC = 10,75 76 74 /* idle seconds before we send a keepalive */ 77 75 KEEPALIVE_INTERVAL_SECS = 100, 78 76 … … 737 735 } 738 736 739 737 void 740 tr_peerMsgsSetChoke( tr_peermsgs * msgs, 741 int choke ) 738 tr_peerMsgsSetChoke( tr_peermsgs * msgs, uint8_t state ) 742 739 { 743 const time_t now = tr_time( ); 744 const time_t fibrillationTime = now - MIN_CHOKE_PERIOD_SEC; 740 tr_peer * peer; 745 741 746 742 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 ); 749 748 750 if( msgs->peer->chokeChangedAt > fibrillationTime ) 749 /* if the state's changed... */ 750 if( peer->peerChokeState != state ) 751 751 { 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 } 753 766 } 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 }762 767 } 763 768 764 769 /** … … 1225 1230 const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io ); 1226 1231 const int reqIsValid = requestIsValid( msgs, req ); 1227 1232 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 ); 1229 1234 1230 1235 int allow = FALSE; 1231 1236 … … 2333 2338 m->peer = peer; 2334 2339 m->torrent = torrent; 2335 2340 m->peer->clientIsChoked = 1; 2336 m->peer->peerIsChoked = 1; 2341 m->peer->peerChokeState = PEER_CHOKE_STATE_CHOKED; 2342 m->peer->peerChokeChangedAt = 0; 2337 2343 m->peer->clientIsInterested = 0; 2338 2344 m->peer->peerIsInterested = 0; 2339 2345 m->state = AWAITING_BT_LENGTH; -
libtransmission/peer-msgs.h
36 36 tr_peer_callback * callback, 37 37 void * callback_data ); 38 38 39 void tr_peerMsgsSetChoke( tr_peermsgs *, int doChoke );39 void tr_peerMsgsSetChoke( tr_peermsgs *, uint8_t peer_choke_state ); 40 40 41 41 int tr_peerMsgsIsReadingBlock( const tr_peermsgs * msgs, tr_block_index_t block ); 42 42 -
libtransmission/peer-mgr.c
51 51 /* how frequently to reallocate bandwidth */ 52 52 BANDWIDTH_PERIOD_MSEC = 500, 53 53 54 /* don't change a peer's choke/unchoke state more frequently than this */ 55 CHOKE_FIBRILATION_PERIOD_SEC = 30, 56 54 57 /* how frequently to age out old piece request lists */ 55 58 REFILL_UPKEEP_PERIOD_MSEC = ( 10 * 1000 ), 56 59 … … 546 549 static int 547 550 clientIsUploadingTo( const tr_peer * peer ) 548 551 { 549 return peer->peerIsInterested && ! peer->peerIsChoked;552 return peer->peerIsInterested && !tr_peerIsChoked( peer ); 550 553 } 551 554 552 555 /*** … … 2346 2349 stat->isEncrypted = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0; 2347 2350 stat->rateToPeer_KBps = toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer, now, TR_CLIENT_TO_PEER ) ); 2348 2351 stat->rateToClient_KBps = toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer, now, TR_PEER_TO_CLIENT ) ); 2349 stat->peerIsChoked = peer->peerIsChoked;2352 stat->peerIsChoked = tr_peerIsChoked( peer ); 2350 2353 stat->peerIsInterested = peer->peerIsInterested; 2351 2354 stat->clientIsChoked = peer->clientIsChoked; 2352 2355 stat->clientIsInterested = peer->clientIsInterested; … … 2702 2705 } 2703 2706 2704 2707 static void 2705 rechokeUploads( Torrent * t, const uint64_t now )2708 rechokeUploads( Torrent * t, const uint64_t now_msec ) 2706 2709 { 2707 2710 int i, size, unchokedInterested; 2708 2711 const int peerCount = tr_ptrArraySize( &t->peers ); 2709 2712 tr_peer ** peers = (tr_peer**) tr_ptrArrayBase( &t->peers ); 2710 2713 struct ChokeData * choke = tr_new0( struct ChokeData, peerCount ); 2714 tr_bool have_optimistic_unchoke = FALSE; 2711 2715 const tr_session * session = t->manager->session; 2712 const int choke All = !tr_torrentIsPieceTransferAllowed( t->tor, TR_CLIENT_TO_PEER );2713 const tr_bool is MaxedOut = 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 ); 2714 2718 2715 2719 assert( torrentIsLocked( t ) ); 2716 2720 2717 2721 /* sort the peers by preference and rate */ 2718 for( i = 0, size = 0; i <peerCount; ++i )2722 for( i=size=0; i<peerCount; ++i ) 2719 2723 { 2720 2724 tr_peer * peer = peers[i]; 2721 2725 struct peer_atom * atom = peer->atom; 2726 const tr_bool changed_recently = tr_time() - peer->peerChokeChangedAt < CHOKE_FIBRILATION_PERIOD_SEC; 2722 2727 2723 2728 if( peer->progress >= 1.0 ) /* choke all seeds */ 2724 2729 { … … 2728 2733 { 2729 2734 tr_peerMsgsSetChoke( peer->msgs, TRUE ); 2730 2735 } 2731 else if( choke All ) /* choke everyone if we're not uploading */2736 else if( choke_all ) /* choke everyone if we're not uploading */ 2732 2737 { 2733 2738 tr_peerMsgsSetChoke( peer->msgs, TRUE ); 2734 2739 } 2740 else if( changed_recently ) /* don't change states too quickly */ 2741 { 2742 have_optimistic_unchoke = peer->peerChokeState == PEER_CHOKE_STATE_UNCHOKED_OPTIMISTIC; 2743 } 2735 2744 else 2736 2745 { 2737 2746 struct ChokeData * n = &choke[size++]; 2738 2747 n->peer = peer; 2739 2748 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 ); 2742 2751 n->salt = tr_cryptoWeakRandInt( INT_MAX ); 2743 2752 n->isChoked = TRUE; 2744 2753 } … … 2763 2772 */ 2764 2773 unchokedInterested = 0; 2765 2774 for( i=0; i<size && unchokedInterested<session->uploadSlotsPerTorrent; ++i ) { 2766 choke[i].isChoked = is MaxedOut ? choke[i].wasChoked : FALSE;2775 choke[i].isChoked = is_maxed_out ? choke[i].wasChoked : FALSE; 2767 2776 if( choke[i].isInterested ) 2768 2777 ++unchokedInterested; 2769 2778 } 2770 2779 2771 2780 /* optimistic unchoke */ 2772 if( ! isMaxedOut && (i<size) )2781 if( !have_optimistic_unchoke && !is_maxed_out && (i<size) ) 2773 2782 { 2774 2783 int n; 2775 2784 struct ChokeData * c; -
libtransmission/peer-mgr.h
70 70 /* opaque forward declaration */ 71 71 struct peer_atom; 72 72 73 enum 74 { 75 PEER_CHOKE_STATE_CHOKED, 76 PEER_CHOKE_STATE_UNCHOKED, 77 PEER_CHOKE_STATE_UNCHOKED_OPTIMISTIC 78 }; 79 73 80 /** 74 81 * State information about a connected peer. 75 82 * … … 78 85 */ 79 86 typedef struct tr_peer 80 87 { 81 tr_bool peerIsChoked;88 uint8_t peerChokeState; 82 89 tr_bool peerIsInterested; 83 90 tr_bool clientIsChoked; 84 91 tr_bool clientIsInterested; … … 108 115 /* the client name from the `v' string in LTEP's handshake dictionary */ 109 116 char * client; 110 117 111 time_t chokeChangedAt;118 time_t peerChokeChangedAt; 112 119 113 120 tr_recentHistory * blocksSentToClient; 114 121 tr_recentHistory * blocksSentToPeer; … … 120 127 } 121 128 tr_peer; 122 129 130 static inline tr_bool tr_peerIsChoked( const tr_peer * peer ) 131 { 132 return peer->peerChokeState == PEER_CHOKE_STATE_CHOKED; 133 } 134 123 135 const tr_address * tr_peerAddress( const tr_peer * ); 124 136 125 137 int tr_pexCompare( const void * a, const void * b );