From e494cb219b73c8d619b30e6afd8d3faeb679c63c Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 9 Oct 2010 21:11:03 +0000 Subject: [PATCH] made seeding choking algorithm configurable --- ChangeLog | 1 + docs/manual.rst | 18 +++++++ include/libtorrent/session_settings.hpp | 10 ++++ src/peer_connection.cpp | 67 ++++++++++++++++++------- src/session_impl.cpp | 3 +- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 865ef595f..0810832e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * made seeding choking algorithm configurable * deprecated setters for max connections, max half-open, upload and download rates and unchoke slots. These are now set through session_settings * added functions to query an individual peer's upload and download limit diff --git a/docs/manual.rst b/docs/manual.rst index c2893ba08..c2178b8e9 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3713,6 +3713,14 @@ session_settings int choking_algorithm; + enum seed_choking_algorithm_t + { + round_robin, + fastest_upload + }; + + int seed_choking_algorithm; + bool use_parole_mode; int cache_size; int cache_buffer_chunk_size; @@ -4064,6 +4072,16 @@ The options for choking algorithms are: .. _paper: http://bittyrant.cs.washington.edu/#papers +``seed_choking_algorithm`` controls the seeding unchoke behavior. The available +options are: + +* ``round_robin`` which round-robins the peers that are unchoked when seeding. This + distributes the upload bandwidht uniformly and fairly. It minimizes the ability + for a peer to download everything without redistributing it. + +* ``fastest_upload`` unchokes the peers we can send to the fastest. This might be + a bit more reliable in utilizing all available capacity. + ``use_parole_mode`` specifies if parole mode should be used. Parole mode means that peers that participate in pieces that fail the hash check are put in a mode where they are only allowed to download whole pieces. If the whole piece a peer diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 8151799a5..cd8081a0a 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -136,6 +136,7 @@ namespace libtorrent , auto_upload_slots_rate_based(true) #endif , choking_algorithm(rate_based_choker) + , seed_choking_algorithm(round_robin) , use_parole_mode(true) , cache_size(1024) , cache_buffer_chunk_size(16) @@ -460,6 +461,15 @@ namespace libtorrent }; int choking_algorithm; + + enum seed_choking_algorithm_t + { + round_robin, + fastest_upload + }; + + // the choking algorithm to use for seeding torrents + int seed_choking_algorithm; // if set to true, peers that participate in a failing // piece is put in parole mode. i.e. They will only diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 84467bf26..9103421a7 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -398,15 +398,30 @@ namespace libtorrent if (d1 > d2) return true; if (d1 < d2) return false; - // in order to not switch back and forth too often, - // unchoked peers must be at least one piece ahead - // of a choked peer to be sorted at a lower unchoke-priority - int pieces = m_ses.settings().seeding_piece_quota; - bool c1_done = is_choked() || u1 > (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024); - bool c2_done = rhs.is_choked() || u2 > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024); + if (m_ses.settings().seed_choking_algorithm == session_settings::round_robin) + { + // in order to not switch back and forth too often, + // unchoked peers must be at least one piece ahead + // of a choked peer to be sorted at a lower unchoke-priority + int pieces = m_ses.settings().seeding_piece_quota; + bool c1_done = is_choked() || u1 > (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024); + bool c2_done = rhs.is_choked() || u2 > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024); - if (!c1_done && c2_done) return true; - if (c1_done && !c2_done) return false; + if (!c1_done && c2_done) return true; + if (c1_done && !c2_done) return false; + } + else if (m_ses.settings().seed_choking_algorithm == session_settings::fastest_upload) + { + size_type c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke; + size_type c2 = rhs.m_statistics.total_payload_upload() - rhs.m_uploaded_at_last_unchoke; + + // take torrent priority into account + c1 *= 1 + t1->priority(); + c2 *= 1 + t2->priority(); + + if (c1 > c2) return true; + if (c2 > c1) return false; + } // if both peers are still in their send quota or not in their send quota // prioritize the one that has waited the longest to be unchoked @@ -437,20 +452,34 @@ namespace libtorrent if (c1 > c2) return true; if (c1 < c2) return false; - // if they are equal, compare how much we have uploaded - c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke; - c2 = rhs.m_statistics.total_payload_upload() - rhs.m_uploaded_at_last_unchoke; + if (m_ses.settings().seed_choking_algorithm == session_settings::round_robin) + { + // if they are equal, compare how much we have uploaded + c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke; + c2 = rhs.m_statistics.total_payload_upload() - rhs.m_uploaded_at_last_unchoke; - // in order to not switch back and forth too often, - // unchoked peers must be at least one piece ahead - // of a choked peer to be sorted at a lower unchoke-priority - int pieces = m_ses.settings().seeding_piece_quota; - bool c1_done = is_choked() || c1 > (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024); - bool c2_done = rhs.is_choked() || c2 > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024); + // in order to not switch back and forth too often, + // unchoked peers must be at least one piece ahead + // of a choked peer to be sorted at a lower unchoke-priority + int pieces = m_ses.settings().seeding_piece_quota; + bool c1_done = is_choked() || c1 > (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024); + bool c2_done = rhs.is_choked() || c2 > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024); - if (!c1_done && c2_done) return true; - if (c1_done && !c2_done) return false; + if (!c1_done && c2_done) return true; + if (c1_done && !c2_done) return false; + } + else if (m_ses.settings().seed_choking_algorithm == session_settings::fastest_upload) + { + c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke; + c2 = rhs.m_statistics.total_payload_upload() - rhs.m_uploaded_at_last_unchoke; + // take torrent priority into account + c1 *= 1 + t1->priority(); + c2 *= 1 + t2->priority(); + + if (c1 > c2) return true; + if (c2 > c1) return false; + } // if both peers have are still in their send quota or not in their send quota // prioritize the one that has waited the longest to be unchoked return m_last_unchoke < rhs.m_last_unchoke; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 28d0f9680..9c44cf938 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -242,6 +242,7 @@ namespace aux { TORRENT_SETTING(boolean, auto_upload_slots_rate_based) #endif TORRENT_SETTING(integer, choking_algorithm) + TORRENT_SETTING(integer, seed_choking_algorithm) TORRENT_SETTING(boolean, use_parole_mode) TORRENT_SETTING(integer, cache_size) TORRENT_SETTING(integer, cache_buffer_chunk_size) @@ -2870,7 +2871,7 @@ namespace aux { if (m_settings.choking_algorithm == session_settings::bittyrant_choker) { - if (!p->is_choked()) + if (!p->is_choked() && p->is_interesting()) { policy::peer* pi = p->peer_info_struct(); if (!p->has_peer_choked())