diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index b6ef25e20..1ed0712c7 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -286,6 +286,15 @@ namespace libtorrent int desired_queue_size() const { return m_desired_queue_size; } + // compares this connection against the given connection + // for which one is more eligible for an unchoke. + // returns true if this is more eligible + bool unchoke_compare(boost::intrusive_ptr const& p) const; + + // resets the byte counters that are used to measure + // the number of bytes transferred within unchoke cycles + void reset_choke_counters(); + #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING boost::shared_ptr m_logger; #endif @@ -750,6 +759,14 @@ namespace libtorrent // was called to when on_connection_complete // was called. The rtt is specified in milliseconds int m_rtt; + + // the total payload download bytes + // at the last unchoke cycle. This is used to + // measure the number of bytes transferred during + // an unchoke cycle, to unchoke peers the more bytes + // they sent us + size_type m_downloaded_at_last_unchoke; + #ifndef NDEBUG public: bool m_in_constructor; diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 7aaa34bfe..981b912ca 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -119,6 +119,7 @@ namespace libtorrent , m_outstanding_writing_bytes(0) , m_fast_reconnect(false) , m_rtt(0) + , m_downloaded_at_last_unchoke(0) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -202,6 +203,7 @@ namespace libtorrent , m_outstanding_writing_bytes(0) , m_fast_reconnect(false) , m_rtt(0) + , m_downloaded_at_last_unchoke(0) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -239,6 +241,31 @@ namespace libtorrent std::fill(m_peer_id.begin(), m_peer_id.end(), 0); } + bool peer_connection::unchoke_compare(boost::intrusive_ptr const& p) const + { + TORRENT_ASSERT(p); + peer_connection const& rhs = *p; + + // first compare how many bytes they've sent us + size_type c1 = m_statistics.total_payload_download() - m_downloaded_at_last_unchoke; + size_type c2 = rhs.m_statistics.total_payload_download() - rhs.m_downloaded_at_last_unchoke; + if (c1 > c2) return true; + if (c1 < c2) return false; + + // if they are equal, compare how much we have uploaded + if (m_peer_info) c1 = m_peer_info->total_upload(); + else c1 = m_statistics.total_payload_upload(); + if (rhs.m_peer_info) c2 = rhs.m_peer_info->total_upload(); + else c2 = rhs.m_statistics.total_payload_upload(); + + return c1 < c2; + } + + void peer_connection::reset_choke_counters() + { + m_downloaded_at_last_unchoke = m_statistics.total_payload_download(); + } + void peer_connection::update_interest() { INVARIANT_CHECK; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 89cc122e0..653ae4ab4 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1016,17 +1016,15 @@ namespace aux { peers.push_back(i->get()); } - // sort the peers that are eligible for unchoke by download rate and secondary + // sorts the peers that are eligible for unchoke by download rate and secondary // by total upload. The reason for this is, if all torrents are being seeded, // the download rate will be 0, and the peers we have sent the least to should // be unchoked std::sort(peers.begin(), peers.end() - , bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _1)) - < bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _2))); + , bind(&peer_connection::unchoke_compare, _1, _2)); - std::stable_sort(peers.begin(), peers.end() - , bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _1)) - > bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _2))); + std::for_each(m_connections.begin(), m_connections.end() + , bind(&peer_connection::reset_choke_counters, _1)); // auto unchoke int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();