experimental support for the BitTyrant choking algorithm
This commit is contained in:
parent
1a97405189
commit
fb47469834
|
@ -13,6 +13,7 @@
|
||||||
* optimized disk cache to work with large caches
|
* optimized disk cache to work with large caches
|
||||||
* support variable number of optimistic unchoke slots and to dynamically
|
* support variable number of optimistic unchoke slots and to dynamically
|
||||||
adjust based on the total number of unchoke slots
|
adjust based on the total number of unchoke slots
|
||||||
|
* support for BitTyrant choker algorithm
|
||||||
|
|
||||||
0.15 release
|
0.15 release
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,11 @@ void bind_session_settings()
|
||||||
.def_readwrite("free_torrent_hashes", &session_settings::free_torrent_hashes)
|
.def_readwrite("free_torrent_hashes", &session_settings::free_torrent_hashes)
|
||||||
.def_readwrite("upnp_ignore_nonrouters", &session_settings::upnp_ignore_nonrouters)
|
.def_readwrite("upnp_ignore_nonrouters", &session_settings::upnp_ignore_nonrouters)
|
||||||
.def_readwrite("send_buffer_watermark", &session_settings::send_buffer_watermark)
|
.def_readwrite("send_buffer_watermark", &session_settings::send_buffer_watermark)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
.def_readwrite("auto_upload_slots", &session_settings::auto_upload_slots)
|
.def_readwrite("auto_upload_slots", &session_settings::auto_upload_slots)
|
||||||
.def_readwrite("auto_upload_slots_rate_based", &session_settings::auto_upload_slots_rate_based)
|
.def_readwrite("auto_upload_slots_rate_based", &session_settings::auto_upload_slots_rate_based)
|
||||||
|
#endif
|
||||||
|
.def_readwrite("choking_algorithm", &session_settings::choking_algorithm)
|
||||||
.def_readwrite("use_parole_mode", &session_settings::use_parole_mode)
|
.def_readwrite("use_parole_mode", &session_settings::use_parole_mode)
|
||||||
.def_readwrite("cache_size", &session_settings::cache_size)
|
.def_readwrite("cache_size", &session_settings::cache_size)
|
||||||
.def_readwrite("cache_buffer_chunk_size", &session_settings::cache_buffer_chunk_size)
|
.def_readwrite("cache_buffer_chunk_size", &session_settings::cache_buffer_chunk_size)
|
||||||
|
@ -126,6 +129,13 @@ void bind_session_settings()
|
||||||
.value("largest_contiguous", session_settings::largest_contiguous)
|
.value("largest_contiguous", session_settings::largest_contiguous)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
enum_<session_settings::disk_cache_algo_t>("choking_algorithm_t")
|
||||||
|
.value("fixed_slots_choker", session_settings::fixed_slots_choker)
|
||||||
|
.value("auto_expand_choker", session_settings::auto_expand_choker)
|
||||||
|
.value("rate_based_choker", session_settings::rate_based_choker)
|
||||||
|
.value("bittyrant_choker", session_settings::bittyrant_choker)
|
||||||
|
;
|
||||||
|
|
||||||
enum_<session_settings::io_buffer_mode_t>("io_buffer_mode_t")
|
enum_<session_settings::io_buffer_mode_t>("io_buffer_mode_t")
|
||||||
.value("enable_os_cache", session_settings::enable_os_cache)
|
.value("enable_os_cache", session_settings::enable_os_cache)
|
||||||
.value("disable_os_cache_for_aligned_files", session_settings::disable_os_cache_for_aligned_files)
|
.value("disable_os_cache_for_aligned_files", session_settings::disable_os_cache_for_aligned_files)
|
||||||
|
|
|
@ -547,26 +547,37 @@ quite unthrottled.
|
||||||
A rate limit of 0 means infinite.
|
A rate limit of 0 means infinite.
|
||||||
|
|
||||||
|
|
||||||
set_max_uploads() set_max_connections() max_uploads() max_connections()
|
set_max_uploads() max_uploads()
|
||||||
-----------------------------------------------------------------------
|
-------------------------------
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
void set_max_uploads(int limit);
|
void set_max_uploads(int limit);
|
||||||
void set_max_connections(int limit);
|
|
||||||
int max_uploads() const;
|
int max_uploads() const;
|
||||||
|
|
||||||
|
``set_max_uploads`` sets a global limit on the number of unchoked peers (uploads).
|
||||||
|
The number of uploads is at least one per torrent.
|
||||||
|
|
||||||
|
``max_uploads()`` returns the current settings.
|
||||||
|
|
||||||
|
The number of unchoke slots may be ignored depending on what
|
||||||
|
``session_settings::choking_algorithm`` is set to.
|
||||||
|
|
||||||
|
|
||||||
|
set_max_connections() max_connections()
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void set_max_connections(int limit);
|
||||||
int max_connections() const;
|
int max_connections() const;
|
||||||
|
|
||||||
These functions will set a global limit on the number of unchoked peers (uploads)
|
``set_max_connections`` sets a global limit on the number of connections
|
||||||
and the number of connections opened. The number of connections is set to a hard
|
opened. The number of connections is set to a hard minimum of at least two per
|
||||||
minimum of at least two connections per torrent, so if you set a too low
|
torrent, so if you set a too low connections limit, and open too many torrents,
|
||||||
connections limit, and open too many torrents, the limit will not be met. The
|
the limit will not be met.
|
||||||
number of uploads is at least one per torrent.
|
|
||||||
|
|
||||||
``max_uploads()`` and ``max_connections()`` returns the current settings.
|
``max_connections()`` returns the current settings.
|
||||||
|
|
||||||
The number of unchoke slots may be ignored. In order to make this setting
|
|
||||||
take effect, disable ``session_settings::auto_upload_slots_rate_based``.
|
|
||||||
|
|
||||||
|
|
||||||
num_uploads() num_connections()
|
num_uploads() num_connections()
|
||||||
|
@ -2640,6 +2651,9 @@ consume, even if there's is more quota. Other peers will still be weighed in whe
|
||||||
bandwidth is being distributed. With other words, bandwidth is not distributed strictly
|
bandwidth is being distributed. With other words, bandwidth is not distributed strictly
|
||||||
in order of priority, but the priority is used as a weight.
|
in order of priority, but the priority is used as a weight.
|
||||||
|
|
||||||
|
Torrents with higher priority are also more likely to have its peers unchoked, to
|
||||||
|
distribute more upload capacity to them.
|
||||||
|
|
||||||
use_interface()
|
use_interface()
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -2663,25 +2677,34 @@ info_hash()
|
||||||
``info_hash()`` returns the info-hash for the torrent.
|
``info_hash()`` returns the info-hash for the torrent.
|
||||||
|
|
||||||
|
|
||||||
set_max_uploads() max_uploads() set_max_connections() max_connections()
|
set_max_uploads() max_uploads()
|
||||||
-----------------------------------------------------------------------
|
-------------------------------
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
void set_max_uploads(int max_uploads) const;
|
void set_max_uploads(int max_uploads) const;
|
||||||
int max_uploads() const;
|
int max_uploads() const;
|
||||||
void set_max_connections(int max_connections) const;
|
|
||||||
int max_connections() const;
|
|
||||||
|
|
||||||
``set_max_uploads()`` sets the maximum number of peers that's unchoked at the same time on this
|
``set_max_uploads()`` sets the maximum number of peers that's unchoked at the same time on this
|
||||||
torrent. If you set this to -1, there will be no limit.
|
torrent. If you set this to -1, there will be no limit.
|
||||||
|
|
||||||
|
``max_uploads()`` returns the current settings.
|
||||||
|
|
||||||
|
|
||||||
|
set_max_connections() max_connections()
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void set_max_connections(int max_connections) const;
|
||||||
|
int max_connections() const;
|
||||||
|
|
||||||
``set_max_connections()`` sets the maximum number of connection this torrent will open. If all
|
``set_max_connections()`` sets the maximum number of connection this torrent will open. If all
|
||||||
connections are used up, incoming connections may be refused or poor connections may be closed.
|
connections are used up, incoming connections may be refused or poor connections may be closed.
|
||||||
This must be at least 2. The default is unlimited number of connections. If -1 is given to the
|
This must be at least 2. The default is unlimited number of connections. If -1 is given to the
|
||||||
function, it means unlimited.
|
function, it means unlimited.
|
||||||
|
|
||||||
``max_uploads()`` and ``max_connections()`` returns the current settings.
|
``max_connections()`` returns the current settings.
|
||||||
|
|
||||||
|
|
||||||
save_resume_data()
|
save_resume_data()
|
||||||
|
@ -3648,8 +3671,22 @@ session_settings
|
||||||
bool free_torrent_hashes;
|
bool free_torrent_hashes;
|
||||||
bool upnp_ignore_nonrouters;
|
bool upnp_ignore_nonrouters;
|
||||||
int send_buffer_watermark;
|
int send_buffer_watermark;
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
bool auto_upload_slots;
|
bool auto_upload_slots;
|
||||||
bool auto_upload_slots_rate_based;
|
bool auto_upload_slots_rate_based;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum choking_algorithm_t
|
||||||
|
{
|
||||||
|
fixed_slots_choker,
|
||||||
|
auto_expand_choker,
|
||||||
|
rate_based_choker,
|
||||||
|
bittyrant_choker
|
||||||
|
};
|
||||||
|
|
||||||
|
int choking_algorithm;
|
||||||
|
|
||||||
bool use_parole_mode;
|
bool use_parole_mode;
|
||||||
int cache_size;
|
int cache_size;
|
||||||
int cache_buffer_chunk_size;
|
int cache_buffer_chunk_size;
|
||||||
|
@ -3928,6 +3965,34 @@ the max upload slots setting is used as a minimum number of unchoked slots.
|
||||||
This algorithm is designed to prevent the peer from spreading its upload
|
This algorithm is designed to prevent the peer from spreading its upload
|
||||||
capacity too thin, but still open more slots in order to utilize the full capacity.
|
capacity too thin, but still open more slots in order to utilize the full capacity.
|
||||||
|
|
||||||
|
``choking_algorithm`` specifies which algorithm to use to determine which peers
|
||||||
|
to unchoke. This setting replaces the deprecated settings ``auto_upload_slots``
|
||||||
|
and ``auto_upload_slots_rate_based``.
|
||||||
|
|
||||||
|
The options for choking algorithms are:
|
||||||
|
|
||||||
|
* ``fixed_slots_choker`` is the traditional choker with a fixed number of unchoke
|
||||||
|
slots (as specified by ``session::set_max_uploads()``).
|
||||||
|
|
||||||
|
* ``auto_expand_choker`` opens at least the number of slots as specified by
|
||||||
|
``session::set_max_uploads()`` but opens up more slots if the upload capacity
|
||||||
|
is not saturated. This unchoker will work just like the ``fixed_slot_choker``
|
||||||
|
if there's no global upload rate limit set.
|
||||||
|
|
||||||
|
* ``rate_based_choker`` opens up unchoke slots based on the upload rate
|
||||||
|
achieved to peers. The more slots that are opened, the marginal upload
|
||||||
|
rate required to open up another slot increases.
|
||||||
|
|
||||||
|
* ``bittyrant_choker`` attempts to optimize download rate by finding the
|
||||||
|
reciprocation rate of each peer individually and prefers peers that gives
|
||||||
|
the highest *return on investment*. It still allocates all upload capacity,
|
||||||
|
but shuffles it around to the best peers first. For this choker to be
|
||||||
|
efficient, you need to set a global upload rate limit
|
||||||
|
(``session::set_upload_rate_limit()``). For more information about this
|
||||||
|
choker, see the paper_.
|
||||||
|
|
||||||
|
.. _paper: http://bittyrant.cs.washington.edu/#papers
|
||||||
|
|
||||||
``use_parole_mode`` specifies if parole mode should be used. Parole mode means
|
``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
|
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
|
where they are only allowed to download whole pieces. If the whole piece a peer
|
||||||
|
|
|
@ -342,7 +342,7 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
|
||||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||||
out += "country ";
|
out += "country ";
|
||||||
#endif
|
#endif
|
||||||
if (print_peer_rate) out += "peer-rate ";
|
if (print_peer_rate) out += "peer-rate est.rec.rate ";
|
||||||
out += "client \n";
|
out += "client \n";
|
||||||
|
|
||||||
char str[500];
|
char str[500];
|
||||||
|
@ -462,7 +462,11 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
|
||||||
#endif
|
#endif
|
||||||
if (print_peer_rate)
|
if (print_peer_rate)
|
||||||
{
|
{
|
||||||
snprintf(str, sizeof(str), " %s", add_suffix(i->remote_dl_rate, "/s").c_str());
|
bool unchoked = (i->flags & peer_info::choked) == 0;
|
||||||
|
|
||||||
|
snprintf(str, sizeof(str), " %s %s %s"
|
||||||
|
, add_suffix(i->remote_dl_rate, "/s").c_str()
|
||||||
|
, unchoked ? add_suffix(i->estimated_reciprocation_rate, "/s").c_str() : " ");
|
||||||
out += str;
|
out += str;
|
||||||
}
|
}
|
||||||
out += " ";
|
out += " ";
|
||||||
|
@ -771,7 +775,7 @@ int main(int argc, char* argv[])
|
||||||
session_settings settings;
|
session_settings settings;
|
||||||
|
|
||||||
settings.user_agent = "client_test/" LIBTORRENT_VERSION;
|
settings.user_agent = "client_test/" LIBTORRENT_VERSION;
|
||||||
settings.auto_upload_slots_rate_based = true;
|
settings.choking_algorithm = session_settings::auto_expand_choker;
|
||||||
//settings.announce_to_all_trackers = true;
|
//settings.announce_to_all_trackers = true;
|
||||||
settings.optimize_hashing_for_speed = false;
|
settings.optimize_hashing_for_speed = false;
|
||||||
settings.disk_cache_algorithm = session_settings::largest_contiguous;
|
settings.disk_cache_algorithm = session_settings::largest_contiguous;
|
||||||
|
|
|
@ -188,8 +188,8 @@ namespace libtorrent
|
||||||
upload_limit_too_low,
|
upload_limit_too_low,
|
||||||
download_limit_too_low,
|
download_limit_too_low,
|
||||||
send_buffer_watermark_too_low,
|
send_buffer_watermark_too_low,
|
||||||
too_many_optimistic_unchoke_slots
|
too_many_optimistic_unchoke_slots,
|
||||||
|
bittyrant_with_no_uplimit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -643,6 +643,9 @@ namespace libtorrent
|
||||||
// statistics gathered from all torrents.
|
// statistics gathered from all torrents.
|
||||||
stat m_stat;
|
stat m_stat;
|
||||||
|
|
||||||
|
int m_peak_up_rate;
|
||||||
|
int m_peak_down_rate;
|
||||||
|
|
||||||
// is false by default and set to true when
|
// is false by default and set to true when
|
||||||
// the first incoming connection is established
|
// the first incoming connection is established
|
||||||
// this is used to know if the client is behind
|
// this is used to know if the client is behind
|
||||||
|
|
|
@ -385,6 +385,8 @@ namespace libtorrent
|
||||||
|
|
||||||
int desired_queue_size() const { return m_desired_queue_size; }
|
int desired_queue_size() const { return m_desired_queue_size; }
|
||||||
|
|
||||||
|
bool peer_connection::bittyrant_unchoke_compare(
|
||||||
|
boost::intrusive_ptr<peer_connection const> const& p) const;
|
||||||
// compares this connection against the given connection
|
// compares this connection against the given connection
|
||||||
// for which one is more eligible for an unchoke.
|
// for which one is more eligible for an unchoke.
|
||||||
// returns true if this is more eligible
|
// returns true if this is more eligible
|
||||||
|
@ -399,6 +401,10 @@ namespace libtorrent
|
||||||
// interested in the other), disconnect it
|
// interested in the other), disconnect it
|
||||||
void disconnect_if_redundant();
|
void disconnect_if_redundant();
|
||||||
|
|
||||||
|
void increase_est_reciprocation_rate();
|
||||||
|
void decrease_est_reciprocation_rate();
|
||||||
|
int est_reciprocation_rate() const { return m_est_reciprocation_rate; }
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
boost::shared_ptr<logger> m_logger;
|
boost::shared_ptr<logger> m_logger;
|
||||||
#endif
|
#endif
|
||||||
|
@ -692,6 +698,10 @@ namespace libtorrent
|
||||||
// the time when we unchoked this peer
|
// the time when we unchoked this peer
|
||||||
ptime m_last_unchoke;
|
ptime m_last_unchoke;
|
||||||
|
|
||||||
|
// if we're unchoked by this peer, this
|
||||||
|
// was the time
|
||||||
|
ptime m_last_unchoked;
|
||||||
|
|
||||||
// timeouts
|
// timeouts
|
||||||
ptime m_last_receive;
|
ptime m_last_receive;
|
||||||
ptime m_last_sent;
|
ptime m_last_sent;
|
||||||
|
@ -702,11 +712,6 @@ namespace libtorrent
|
||||||
// download queue. Used for request timeout
|
// download queue. Used for request timeout
|
||||||
ptime m_requested;
|
ptime m_requested;
|
||||||
|
|
||||||
// if the timeout is extended for the outstanding
|
|
||||||
// requests, this is the number of seconds it was
|
|
||||||
// extended.
|
|
||||||
int m_timeout_extend;
|
|
||||||
|
|
||||||
// a timestamp when the remote download rate
|
// a timestamp when the remote download rate
|
||||||
// was last updated
|
// was last updated
|
||||||
ptime m_remote_dl_update;
|
ptime m_remote_dl_update;
|
||||||
|
@ -804,6 +809,11 @@ namespace libtorrent
|
||||||
// (-1, -1) if we're not receiving one
|
// (-1, -1) if we're not receiving one
|
||||||
piece_block m_receiving_block;
|
piece_block m_receiving_block;
|
||||||
|
|
||||||
|
// if the timeout is extended for the outstanding
|
||||||
|
// requests, this is the number of seconds it was
|
||||||
|
// extended.
|
||||||
|
int m_timeout_extend;
|
||||||
|
|
||||||
// the number of bytes that the other
|
// the number of bytes that the other
|
||||||
// end has to send us in order to respond
|
// end has to send us in order to respond
|
||||||
// to all outstanding piece requests we
|
// to all outstanding piece requests we
|
||||||
|
@ -905,6 +915,12 @@ namespace libtorrent
|
||||||
int m_download_rate_peak;
|
int m_download_rate_peak;
|
||||||
int m_upload_rate_peak;
|
int m_upload_rate_peak;
|
||||||
|
|
||||||
|
// when using the BitTyrant choker, this is our
|
||||||
|
// estimated reciprocation rate. i.e. the rate
|
||||||
|
// we need to send to this peer for it to unchoke
|
||||||
|
// us
|
||||||
|
int m_est_reciprocation_rate;
|
||||||
|
|
||||||
// estimated round trip time to this peer
|
// estimated round trip time to this peer
|
||||||
// based on the time from when async_connect
|
// based on the time from when async_connect
|
||||||
// was called to when on_connection_complete
|
// was called to when on_connection_complete
|
||||||
|
|
|
@ -214,6 +214,8 @@ namespace libtorrent
|
||||||
// the peers progress
|
// the peers progress
|
||||||
float progress; // [0, 1]
|
float progress; // [0, 1]
|
||||||
int progress_ppm; // [0, 1000000]
|
int progress_ppm; // [0, 1000000]
|
||||||
|
|
||||||
|
int estimated_reciprocation_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT peer_list_entry
|
struct TORRENT_EXPORT peer_list_entry
|
||||||
|
|
|
@ -123,8 +123,12 @@ namespace libtorrent
|
||||||
, free_torrent_hashes(true)
|
, free_torrent_hashes(true)
|
||||||
, upnp_ignore_nonrouters(false)
|
, upnp_ignore_nonrouters(false)
|
||||||
, send_buffer_watermark(100 * 1024)
|
, send_buffer_watermark(100 * 1024)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
// deprecated in 0.16
|
||||||
, auto_upload_slots(true)
|
, auto_upload_slots(true)
|
||||||
, auto_upload_slots_rate_based(true)
|
, auto_upload_slots_rate_based(true)
|
||||||
|
#endif
|
||||||
|
, choking_algorithm(rate_based_choker)
|
||||||
, use_parole_mode(true)
|
, use_parole_mode(true)
|
||||||
, cache_size(1024)
|
, cache_size(1024)
|
||||||
, cache_buffer_chunk_size(16)
|
, cache_buffer_chunk_size(16)
|
||||||
|
@ -193,6 +197,9 @@ namespace libtorrent
|
||||||
, default_cache_min_age(1)
|
, default_cache_min_age(1)
|
||||||
, num_optimistic_unchoke_slots(0)
|
, num_optimistic_unchoke_slots(0)
|
||||||
, no_atime_storage(true)
|
, no_atime_storage(true)
|
||||||
|
, default_est_reciprocation_rate(16000)
|
||||||
|
, increase_est_reciprocation_rate(20)
|
||||||
|
, decrease_est_reciprocation_rate(3)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// this is the user agent that will be sent to the tracker
|
// this is the user agent that will be sent to the tracker
|
||||||
|
@ -397,20 +404,22 @@ namespace libtorrent
|
||||||
// the upload rate is low, this is the upper limit.
|
// the upload rate is low, this is the upper limit.
|
||||||
int send_buffer_watermark;
|
int send_buffer_watermark;
|
||||||
|
|
||||||
// if auto_upload_slots is true, and a global upload
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// limit is set and the upload rate is less than 90%
|
// deprecated in 0.16
|
||||||
// of the upload limit, on new slot is opened up. If
|
|
||||||
// the upload rate is >= upload limit for an extended
|
|
||||||
// period of time, one upload slot is closed. The
|
|
||||||
// upload slots are never automatically decreased below
|
|
||||||
// the manual settings, through max_uploads.
|
|
||||||
bool auto_upload_slots;
|
bool auto_upload_slots;
|
||||||
|
|
||||||
// this only affects the auto upload slots mechanism.
|
|
||||||
// if auto_upload_slots is false, this field is not
|
|
||||||
// considered.
|
|
||||||
bool auto_upload_slots_rate_based;
|
bool auto_upload_slots_rate_based;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum choking_algorithm_t
|
||||||
|
{
|
||||||
|
fixed_slots_choker,
|
||||||
|
auto_expand_choker,
|
||||||
|
rate_based_choker,
|
||||||
|
bittyrant_choker
|
||||||
|
};
|
||||||
|
|
||||||
|
int choking_algorithm;
|
||||||
|
|
||||||
// if set to true, peers that participate in a failing
|
// if set to true, peers that participate in a failing
|
||||||
// piece is put in parole mode. i.e. They will only
|
// piece is put in parole mode. i.e. They will only
|
||||||
// download whole pieces until they either fail or pass.
|
// download whole pieces until they either fail or pass.
|
||||||
|
@ -725,6 +734,24 @@ namespace libtorrent
|
||||||
// if set to true, files won't have their atime updated
|
// if set to true, files won't have their atime updated
|
||||||
// on disk reads. This works on linux
|
// on disk reads. This works on linux
|
||||||
bool no_atime_storage;
|
bool no_atime_storage;
|
||||||
|
|
||||||
|
// === BitTyrant unchoker settings ==
|
||||||
|
|
||||||
|
// when using BitTyrant choker, this is the default
|
||||||
|
// assumed reciprocation rate. This is where each peer starts
|
||||||
|
int default_est_reciprocation_rate;
|
||||||
|
|
||||||
|
// this is the increase of the estimated reciprocation rate
|
||||||
|
// in percent. We increase by this amount once every unchoke
|
||||||
|
// interval that we are choked by the other peer and we have
|
||||||
|
// unchoked them
|
||||||
|
int increase_est_reciprocation_rate;
|
||||||
|
|
||||||
|
// each unchoke interval that we stay unchoked by the other
|
||||||
|
// peer, and we have unchoked this peer as well, we decrease
|
||||||
|
// our estimate of the reciprocation rate, since we might have
|
||||||
|
// over-estimated it
|
||||||
|
int decrease_est_reciprocation_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
|
|
@ -113,7 +113,8 @@ namespace libtorrent {
|
||||||
"upload limit too low (download rate will suffer)",
|
"upload limit too low (download rate will suffer)",
|
||||||
"download limit too low (upload rate will suffer)",
|
"download limit too low (upload rate will suffer)",
|
||||||
"send buffer watermark too low (upload rate will suffer)",
|
"send buffer watermark too low (upload rate will suffer)",
|
||||||
"too many optimistic unchoke slots"
|
"too many optimistic unchoke slots",
|
||||||
|
"using bittyrant unchoker with no upload rate limit set"
|
||||||
};
|
};
|
||||||
|
|
||||||
return torrent_alert::message() + ": performance warning: "
|
return torrent_alert::message() + ": performance warning: "
|
||||||
|
|
|
@ -180,8 +180,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
bandwidth_channel* bwc = i->channel[j];
|
bandwidth_channel* bwc = i->channel[j];
|
||||||
if (bwc->tmp == 0) channels.push_back(bwc);
|
if (bwc->tmp == 0) channels.push_back(bwc);
|
||||||
|
TORRENT_ASSERT(INT_MAX - bwc->tmp > i->priority);
|
||||||
bwc->tmp += i->priority;
|
bwc->tmp += i->priority;
|
||||||
TORRENT_ASSERT(i->priority > 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ namespace libtorrent
|
||||||
for (int j = 0; j < 5 && channel[j]; ++j)
|
for (int j = 0; j < 5 && channel[j]; ++j)
|
||||||
{
|
{
|
||||||
if (channel[j]->throttle() == 0) continue;
|
if (channel[j]->throttle() == 0) continue;
|
||||||
|
TORRENT_ASSERT(channel[j]->distribute_quota
|
||||||
|
< (std::numeric_limits<boost::uint64_t>::max)() / priority);
|
||||||
quota = (std::min)(int(boost::uint64_t(channel[j]->distribute_quota)
|
quota = (std::min)(int(boost::uint64_t(channel[j]->distribute_quota)
|
||||||
* priority / channel[j]->tmp), quota);
|
* priority / channel[j]->tmp), quota);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +67,6 @@ namespace libtorrent
|
||||||
channel[j]->use_quota(quota);
|
channel[j]->use_quota(quota);
|
||||||
TORRENT_ASSERT(assigned <= request_size);
|
TORRENT_ASSERT(assigned <= request_size);
|
||||||
--ttl;
|
--ttl;
|
||||||
TORRENT_ASSERT(assigned <= request_size);
|
|
||||||
return quota;
|
return quota;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,10 +85,10 @@ namespace libtorrent
|
||||||
, m_last_request(time_now())
|
, m_last_request(time_now())
|
||||||
, m_last_incoming_request(min_time())
|
, m_last_incoming_request(min_time())
|
||||||
, m_last_unchoke(time_now())
|
, m_last_unchoke(time_now())
|
||||||
|
, m_last_unchoked(time_now())
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
, m_requested(min_time())
|
, m_requested(min_time())
|
||||||
, m_timeout_extend(0)
|
|
||||||
, m_remote_dl_update(time_now())
|
, m_remote_dl_update(time_now())
|
||||||
, m_connect(time_now())
|
, m_connect(time_now())
|
||||||
, m_became_uninterested(time_now())
|
, m_became_uninterested(time_now())
|
||||||
|
@ -101,6 +101,7 @@ namespace libtorrent
|
||||||
, m_remote(endp)
|
, m_remote(endp)
|
||||||
, m_torrent(tor)
|
, m_torrent(tor)
|
||||||
, m_receiving_block(-1, -1)
|
, m_receiving_block(-1, -1)
|
||||||
|
, m_timeout_extend(0)
|
||||||
, m_outstanding_bytes(0)
|
, m_outstanding_bytes(0)
|
||||||
, m_queued_time_critical(0)
|
, m_queued_time_critical(0)
|
||||||
, m_num_pieces(0)
|
, m_num_pieces(0)
|
||||||
|
@ -153,6 +154,8 @@ namespace libtorrent
|
||||||
, m_received_in_piece(0)
|
, m_received_in_piece(0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
m_est_reciprocation_rate = m_ses.m_settings.default_est_reciprocation_rate;
|
||||||
|
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
if (peerinfo && peerinfo->is_i2p_addr)
|
if (peerinfo && peerinfo->is_i2p_addr)
|
||||||
{
|
{
|
||||||
|
@ -216,10 +219,10 @@ namespace libtorrent
|
||||||
, m_last_request(time_now())
|
, m_last_request(time_now())
|
||||||
, m_last_incoming_request(min_time())
|
, m_last_incoming_request(min_time())
|
||||||
, m_last_unchoke(time_now())
|
, m_last_unchoke(time_now())
|
||||||
|
, m_last_unchoked(time_now())
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
, m_requested(min_time())
|
, m_requested(min_time())
|
||||||
, m_timeout_extend(0)
|
|
||||||
, m_remote_dl_update(time_now())
|
, m_remote_dl_update(time_now())
|
||||||
, m_connect(time_now())
|
, m_connect(time_now())
|
||||||
, m_became_uninterested(time_now())
|
, m_became_uninterested(time_now())
|
||||||
|
@ -231,6 +234,7 @@ namespace libtorrent
|
||||||
, m_socket(s)
|
, m_socket(s)
|
||||||
, m_remote(endp)
|
, m_remote(endp)
|
||||||
, m_receiving_block(-1, -1)
|
, m_receiving_block(-1, -1)
|
||||||
|
, m_timeout_extend(0)
|
||||||
, m_outstanding_bytes(0)
|
, m_outstanding_bytes(0)
|
||||||
, m_queued_time_critical(0)
|
, m_queued_time_critical(0)
|
||||||
, m_num_pieces(0)
|
, m_num_pieces(0)
|
||||||
|
@ -283,6 +287,8 @@ namespace libtorrent
|
||||||
, m_received_in_piece(0)
|
, m_received_in_piece(0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
m_est_reciprocation_rate = m_ses.m_settings.default_est_reciprocation_rate;
|
||||||
|
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
if (peerinfo && peerinfo->is_i2p_addr)
|
if (peerinfo && peerinfo->is_i2p_addr)
|
||||||
{
|
{
|
||||||
|
@ -340,6 +346,62 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void peer_connection::increase_est_reciprocation_rate()
|
||||||
|
{
|
||||||
|
m_est_reciprocation_rate += m_est_reciprocation_rate
|
||||||
|
* m_ses.m_settings.increase_est_reciprocation_rate / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_connection::decrease_est_reciprocation_rate()
|
||||||
|
{
|
||||||
|
m_est_reciprocation_rate -= m_est_reciprocation_rate
|
||||||
|
* m_ses.m_settings.decrease_est_reciprocation_rate / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peer_connection::bittyrant_unchoke_compare(
|
||||||
|
boost::intrusive_ptr<peer_connection const> const& p) const
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(p);
|
||||||
|
peer_connection const& rhs = *p;
|
||||||
|
|
||||||
|
size_type d1, d2, u1, u2;
|
||||||
|
|
||||||
|
// first compare how many bytes they've sent us
|
||||||
|
d1 = m_statistics.total_payload_download() - m_downloaded_at_last_unchoke;
|
||||||
|
d2 = rhs.m_statistics.total_payload_download() - rhs.m_downloaded_at_last_unchoke;
|
||||||
|
// divided by the number of bytes we've sent them
|
||||||
|
u1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke;
|
||||||
|
u2 = rhs.m_statistics.total_payload_upload() - rhs.m_uploaded_at_last_unchoke;
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t1 = m_torrent.lock();
|
||||||
|
TORRENT_ASSERT(t1);
|
||||||
|
boost::shared_ptr<torrent> t2 = rhs.associated_torrent().lock();
|
||||||
|
TORRENT_ASSERT(t2);
|
||||||
|
|
||||||
|
// take torrent priority into account
|
||||||
|
d1 *= 1 + t1->priority();
|
||||||
|
d2 *= 1 + t2->priority();
|
||||||
|
|
||||||
|
d1 = d1 * 1000 / (std::max)(size_type(1), u1);
|
||||||
|
d2 = d2 * 1000 / (std::max)(size_type(1), u2);
|
||||||
|
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 (!c1_done && c2_done) return true;
|
||||||
|
if (c1_done && !c2_done) 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
|
||||||
|
return m_last_unchoke < rhs.m_last_unchoke;
|
||||||
|
}
|
||||||
|
|
||||||
bool peer_connection::unchoke_compare(boost::intrusive_ptr<peer_connection const> const& p) const
|
bool peer_connection::unchoke_compare(boost::intrusive_ptr<peer_connection const> const& p) const
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(p);
|
TORRENT_ASSERT(p);
|
||||||
|
@ -351,6 +413,16 @@ namespace libtorrent
|
||||||
// first compare how many bytes they've sent us
|
// first compare how many bytes they've sent us
|
||||||
c1 = m_statistics.total_payload_download() - m_downloaded_at_last_unchoke;
|
c1 = m_statistics.total_payload_download() - m_downloaded_at_last_unchoke;
|
||||||
c2 = rhs.m_statistics.total_payload_download() - rhs.m_downloaded_at_last_unchoke;
|
c2 = rhs.m_statistics.total_payload_download() - rhs.m_downloaded_at_last_unchoke;
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t1 = m_torrent.lock();
|
||||||
|
TORRENT_ASSERT(t1);
|
||||||
|
boost::shared_ptr<torrent> t2 = rhs.associated_torrent().lock();
|
||||||
|
TORRENT_ASSERT(t2);
|
||||||
|
|
||||||
|
// take torrent priority into account
|
||||||
|
c1 *= 1 + t1->priority();
|
||||||
|
c2 *= 1 + t2->priority();
|
||||||
|
|
||||||
if (c1 > c2) return true;
|
if (c1 > c2) return true;
|
||||||
if (c1 < c2) return false;
|
if (c1 < c2) return false;
|
||||||
|
|
||||||
|
@ -361,10 +433,6 @@ namespace libtorrent
|
||||||
// in order to not switch back and forth too often,
|
// in order to not switch back and forth too often,
|
||||||
// unchoked peers must be at least one piece ahead
|
// unchoked peers must be at least one piece ahead
|
||||||
// of a choked peer to be sorted at a lower unchoke-priority
|
// of a choked peer to be sorted at a lower unchoke-priority
|
||||||
boost::shared_ptr<torrent> t1 = m_torrent.lock();
|
|
||||||
TORRENT_ASSERT(t1);
|
|
||||||
boost::shared_ptr<torrent> t2 = rhs.associated_torrent().lock();
|
|
||||||
TORRENT_ASSERT(t2);
|
|
||||||
int pieces = m_ses.settings().seeding_piece_quota;
|
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 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);
|
bool c2_done = rhs.is_choked() || c2 > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024);
|
||||||
|
@ -382,9 +450,18 @@ namespace libtorrent
|
||||||
size_type c1;
|
size_type c1;
|
||||||
size_type c2;
|
size_type c2;
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t1 = m_torrent.lock();
|
||||||
|
TORRENT_ASSERT(t1);
|
||||||
|
boost::shared_ptr<torrent> t2 = p->associated_torrent().lock();
|
||||||
|
TORRENT_ASSERT(t2);
|
||||||
|
|
||||||
c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke;
|
c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke;
|
||||||
c2 = p->m_statistics.total_payload_upload() - p->m_uploaded_at_last_unchoke;
|
c2 = p->m_statistics.total_payload_upload() - p->m_uploaded_at_last_unchoke;
|
||||||
|
|
||||||
|
// take torrent priority into account
|
||||||
|
c1 *= 1 + t1->priority();
|
||||||
|
c2 *= 1 + t2->priority();
|
||||||
|
|
||||||
return c1 > c2;
|
return c1 > c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1280,6 +1357,7 @@ namespace libtorrent
|
||||||
(*m_logger) << time_now_string() << " <== UNCHOKE\n";
|
(*m_logger) << time_now_string() << " <== UNCHOKE\n";
|
||||||
#endif
|
#endif
|
||||||
m_peer_choked = false;
|
m_peer_choked = false;
|
||||||
|
m_last_unchoked = time_now();
|
||||||
if (is_disconnecting()) return;
|
if (is_disconnecting()) return;
|
||||||
|
|
||||||
if (is_interesting())
|
if (is_interesting())
|
||||||
|
@ -3343,6 +3421,11 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
p.progress_ppm = p.pieces.count() * 1000000 / p.pieces.size();
|
p.progress_ppm = p.pieces.count() * 1000000 / p.pieces.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.estimated_reciprocation_rate = m_est_reciprocation_rate;
|
||||||
|
int upload_capacity = m_ses.upload_rate_limit();
|
||||||
|
if (upload_capacity == 0)
|
||||||
|
upload_capacity = (std::max)(20000, m_ses.m_peak_up_rate + 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocates a disk buffer of size 'disk_buffer_size' and replaces the
|
// allocates a disk buffer of size 'disk_buffer_size' and replaces the
|
||||||
|
@ -4014,10 +4097,31 @@ namespace libtorrent
|
||||||
, bandwidth_channel* bwc4)
|
, bandwidth_channel* bwc4)
|
||||||
{
|
{
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
int priority = 1 + is_interesting() * 2 + m_requests_in_buffer.size();
|
int priority;
|
||||||
|
if (m_ses.m_settings.choking_algorithm == session_settings::bittyrant_choker
|
||||||
if (priority > 255) priority = 255;
|
&& !t->is_upload_only())
|
||||||
priority += t->priority() << 8;
|
{
|
||||||
|
// when we use the bittyrant choker, the priority of a peer
|
||||||
|
// is decided based on the estimated reciprocation rate and
|
||||||
|
// the share it represents of the total upload rate capacity
|
||||||
|
// the torrent priority is taken into account when unchoking peers
|
||||||
|
int upload_capacity = m_ses.upload_rate_limit();
|
||||||
|
if (upload_capacity == 0)
|
||||||
|
{
|
||||||
|
// we don't know at what rate we can upload. If we have a
|
||||||
|
// measurement of the peak, use that + 10kB/s, otherwise
|
||||||
|
// assume 20 kB/s
|
||||||
|
upload_capacity = (std::max)(20000, m_ses.m_peak_up_rate + 10000);
|
||||||
|
}
|
||||||
|
priority = (boost::uint64_t(m_est_reciprocation_rate) << 10) / upload_capacity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
priority = 1 + is_interesting() * 2 + m_requests_in_buffer.size();
|
||||||
|
if (priority > 255) priority = 255;
|
||||||
|
priority += t->priority() << 8;
|
||||||
|
}
|
||||||
|
TORRENT_ASSERT(priority < 0xffff);
|
||||||
|
|
||||||
// peers that we are not interested in are non-prioritized
|
// peers that we are not interested in are non-prioritized
|
||||||
m_channel_state[upload_channel] = peer_info::bw_limit;
|
m_channel_state[upload_channel] = peer_info::bw_limit;
|
||||||
|
|
|
@ -204,7 +204,7 @@ namespace libtorrent
|
||||||
set.active_limit = 2000;
|
set.active_limit = 2000;
|
||||||
set.active_seeds = 2000;
|
set.active_seeds = 2000;
|
||||||
|
|
||||||
set.auto_upload_slots = false;
|
set.choking_algorithm = session_settings::fixed_slots_choker;
|
||||||
|
|
||||||
// in order to be able to deliver very high
|
// in order to be able to deliver very high
|
||||||
// upload rates, this should be able to cover
|
// upload rates, this should be able to cover
|
||||||
|
|
|
@ -228,8 +228,11 @@ namespace aux {
|
||||||
TORRENT_SETTING(boolean, free_torrent_hashes)
|
TORRENT_SETTING(boolean, free_torrent_hashes)
|
||||||
TORRENT_SETTING(boolean, upnp_ignore_nonrouters)
|
TORRENT_SETTING(boolean, upnp_ignore_nonrouters)
|
||||||
TORRENT_SETTING(integer, send_buffer_watermark)
|
TORRENT_SETTING(integer, send_buffer_watermark)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
TORRENT_SETTING(boolean, auto_upload_slots)
|
TORRENT_SETTING(boolean, auto_upload_slots)
|
||||||
TORRENT_SETTING(boolean, auto_upload_slots_rate_based)
|
TORRENT_SETTING(boolean, auto_upload_slots_rate_based)
|
||||||
|
#endif
|
||||||
|
TORRENT_SETTING(integer, choking_algorithm)
|
||||||
TORRENT_SETTING(boolean, use_parole_mode)
|
TORRENT_SETTING(boolean, use_parole_mode)
|
||||||
TORRENT_SETTING(integer, cache_size)
|
TORRENT_SETTING(integer, cache_size)
|
||||||
TORRENT_SETTING(integer, cache_buffer_chunk_size)
|
TORRENT_SETTING(integer, cache_buffer_chunk_size)
|
||||||
|
@ -438,6 +441,8 @@ namespace aux {
|
||||||
, m_auto_scrape_time_scaler(180)
|
, m_auto_scrape_time_scaler(180)
|
||||||
, m_next_explicit_cache_torrent(0)
|
, m_next_explicit_cache_torrent(0)
|
||||||
, m_cache_rotation_timer(0)
|
, m_cache_rotation_timer(0)
|
||||||
|
, m_peak_up_rate(0)
|
||||||
|
, m_peak_down_rate(0)
|
||||||
, m_incoming_connection(false)
|
, m_incoming_connection(false)
|
||||||
, m_created(time_now_hires())
|
, m_created(time_now_hires())
|
||||||
, m_last_tick(m_created)
|
, m_last_tick(m_created)
|
||||||
|
@ -1052,6 +1057,17 @@ namespace aux {
|
||||||
|| m_settings.low_prio_disk != s.low_prio_disk)
|
|| m_settings.low_prio_disk != s.low_prio_disk)
|
||||||
update_disk_io_thread = true;
|
update_disk_io_thread = true;
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
// support deprecated choker settings
|
||||||
|
if (s.choking_algorithm == session_settings::rate_based_choker)
|
||||||
|
{
|
||||||
|
if (s.auto_upload_slots && !s.auto_upload_slots_rate_based)
|
||||||
|
m_settings.choking_algorithm = session_settings::auto_expand_choker;
|
||||||
|
else if (!s.auto_upload_slots)
|
||||||
|
m_settings.choking_algorithm = session_settings::fixed_slots_choker;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// safety check
|
// safety check
|
||||||
if (m_settings.volatile_read_cache
|
if (m_settings.volatile_read_cache
|
||||||
&& (m_settings.suggest_mode == session_settings::suggest_read_cache
|
&& (m_settings.suggest_mode == session_settings::suggest_read_cache
|
||||||
|
@ -1064,6 +1080,12 @@ namespace aux {
|
||||||
m_settings.volatile_read_cache = false;
|
m_settings.volatile_read_cache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_settings.choking_algorithm != s.choking_algorithm)
|
||||||
|
{
|
||||||
|
// trigger recalculation of the unchoked peers
|
||||||
|
m_unchoke_time_scaler = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// if queuing settings were changed, recalculate
|
// if queuing settings were changed, recalculate
|
||||||
// queued torrents sooner
|
// queued torrents sooner
|
||||||
if ((m_settings.active_downloads != s.active_downloads
|
if ((m_settings.active_downloads != s.active_downloads
|
||||||
|
@ -1089,7 +1111,12 @@ namespace aux {
|
||||||
, performance_alert::too_many_optimistic_unchoke_slots));
|
, performance_alert::too_many_optimistic_unchoke_slots));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s.auto_upload_slots) m_allowed_upload_slots = m_max_uploads;
|
if (s.choking_algorithm == session_settings::fixed_slots_choker)
|
||||||
|
m_allowed_upload_slots = m_max_uploads;
|
||||||
|
else if (s.choking_algorithm == session_settings::auto_expand_choker
|
||||||
|
&& m_allowed_upload_slots < m_max_uploads)
|
||||||
|
m_allowed_upload_slots = m_max_uploads;
|
||||||
|
|
||||||
// replace all occurances of '\n' with ' '.
|
// replace all occurances of '\n' with ' '.
|
||||||
std::string::iterator i = m_settings.user_agent.begin();
|
std::string::iterator i = m_settings.user_agent.begin();
|
||||||
while ((i = std::find(i, m_settings.user_agent.end(), '\n'))
|
while ((i = std::find(i, m_settings.user_agent.end(), '\n'))
|
||||||
|
@ -1915,6 +1942,9 @@ namespace aux {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_peak_up_rate = (std::max)(m_stat.upload_rate(), m_peak_up_rate);
|
||||||
|
m_peak_down_rate = (std::max)(m_stat.download_rate(), m_peak_down_rate);
|
||||||
|
|
||||||
m_stat.second_tick(tick_interval_ms);
|
m_stat.second_tick(tick_interval_ms);
|
||||||
|
|
||||||
TORRENT_ASSERT(least_recently_scraped == m_torrents.end()
|
TORRENT_ASSERT(least_recently_scraped == m_torrents.end()
|
||||||
|
@ -2394,8 +2424,29 @@ namespace aux {
|
||||||
++i;
|
++i;
|
||||||
torrent* t = p->associated_torrent().lock().get();
|
torrent* t = p->associated_torrent().lock().get();
|
||||||
policy::peer* pi = p->peer_info_struct();
|
policy::peer* pi = p->peer_info_struct();
|
||||||
|
|
||||||
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
|
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
|
||||||
|
|
||||||
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
||||||
|
{
|
||||||
|
if (!p->is_choked())
|
||||||
|
{
|
||||||
|
policy::peer* pi = p->peer_info_struct();
|
||||||
|
if (!p->has_peer_choked())
|
||||||
|
{
|
||||||
|
// we're unchoked, we may want to lower our estimated
|
||||||
|
// reciprocation rate
|
||||||
|
p->decrease_est_reciprocation_rate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we've unchoked this peer, and it hasn't reciprocated
|
||||||
|
// we may want to increase our estimated reciprocation rate
|
||||||
|
p->increase_est_reciprocation_rate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!p->is_peer_interested()
|
if (!p->is_peer_interested()
|
||||||
|| p->is_disconnecting()
|
|| p->is_disconnecting()
|
||||||
|| p->is_connecting()
|
|| p->is_connecting()
|
||||||
|
@ -2417,8 +2468,7 @@ namespace aux {
|
||||||
peers.push_back(p.get());
|
peers.push_back(p.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_settings.auto_upload_slots_rate_based
|
if (m_settings.choking_algorithm == session_settings::rate_based_choker)
|
||||||
&& m_settings.auto_upload_slots)
|
|
||||||
{
|
{
|
||||||
m_allowed_upload_slots = 0;
|
m_allowed_upload_slots = 0;
|
||||||
std::sort(peers.begin(), peers.end()
|
std::sort(peers.begin(), peers.end()
|
||||||
|
@ -2460,17 +2510,26 @@ namespace aux {
|
||||||
++m_allowed_upload_slots;
|
++m_allowed_upload_slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sorts the peers that are eligible for unchoke by download rate and secondary
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
||||||
// 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
|
// if we're using the bittyrant choker, sort peers by their return
|
||||||
// be unchoked
|
// on investment. i.e. download rate / upload rate
|
||||||
std::sort(peers.begin(), peers.end()
|
std::sort(peers.begin(), peers.end()
|
||||||
, bind(&peer_connection::unchoke_compare, _1, _2));
|
, bind(&peer_connection::bittyrant_unchoke_compare, _1, _2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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(&peer_connection::unchoke_compare, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
// auto unchoke
|
// auto unchoke
|
||||||
int upload_limit = m_bandwidth_channel[peer_connection::upload_channel]->throttle();
|
int upload_limit = m_bandwidth_channel[peer_connection::upload_channel]->throttle();
|
||||||
if (!m_settings.auto_upload_slots_rate_based
|
if (m_settings.choking_algorithm == session_settings::auto_expand_choker
|
||||||
&& m_settings.auto_upload_slots
|
|
||||||
&& upload_limit > 0)
|
&& upload_limit > 0)
|
||||||
{
|
{
|
||||||
// if our current upload rate is less than 90% of our
|
// if our current upload rate is less than 90% of our
|
||||||
|
@ -2494,9 +2553,25 @@ namespace aux {
|
||||||
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
|
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
|
||||||
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
|
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
|
||||||
|
|
||||||
// reserve one upload slot for optimistic unchokes
|
// reserve some upload slots for optimistic unchokes
|
||||||
int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
|
int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
|
||||||
|
|
||||||
|
int upload_capacity_left = 0;
|
||||||
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
||||||
|
{
|
||||||
|
upload_capacity_left = m_upload_channel.throttle();
|
||||||
|
if (upload_capacity_left == 0)
|
||||||
|
{
|
||||||
|
// we don't know at what rate we can upload. If we have a
|
||||||
|
// measurement of the peak, use that + 10kB/s, otherwise
|
||||||
|
// assume 20 kB/s
|
||||||
|
upload_capacity_left = (std::max)(20000, m_peak_up_rate + 10000);
|
||||||
|
if (m_alerts.should_post<performance_alert>())
|
||||||
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
||||||
|
, performance_alert::bittyrant_with_no_uplimit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_num_unchoked = 0;
|
m_num_unchoked = 0;
|
||||||
// go through all the peers and unchoke the first ones and choke
|
// go through all the peers and unchoke the first ones and choke
|
||||||
// all the other ones.
|
// all the other ones.
|
||||||
|
@ -2508,12 +2583,28 @@ namespace aux {
|
||||||
TORRENT_ASSERT(!p->ignore_unchoke_slots());
|
TORRENT_ASSERT(!p->ignore_unchoke_slots());
|
||||||
|
|
||||||
// this will update the m_uploaded_at_last_unchoke
|
// this will update the m_uploaded_at_last_unchoke
|
||||||
|
// #error this should be called for all peers!
|
||||||
p->reset_choke_counters();
|
p->reset_choke_counters();
|
||||||
|
|
||||||
torrent* t = p->associated_torrent().lock().get();
|
torrent* t = p->associated_torrent().lock().get();
|
||||||
TORRENT_ASSERT(t);
|
TORRENT_ASSERT(t);
|
||||||
if (unchoke_set_size > 0)
|
|
||||||
|
// if this peer should be unchoked depends on different things
|
||||||
|
// in different unchoked schemes
|
||||||
|
bool unchoke = false;
|
||||||
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
||||||
{
|
{
|
||||||
|
unchoke = p->est_reciprocation_rate() <= upload_capacity_left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unchoke = unchoke_set_size > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unchoke)
|
||||||
|
{
|
||||||
|
upload_capacity_left -= p->est_reciprocation_rate();
|
||||||
|
|
||||||
// yes, this peer should be unchoked
|
// yes, this peer should be unchoked
|
||||||
if (p->is_choked())
|
if (p->is_choked())
|
||||||
{
|
{
|
||||||
|
@ -3565,7 +3656,7 @@ namespace aux {
|
||||||
std::set<peer_connection*> unique_peers;
|
std::set<peer_connection*> unique_peers;
|
||||||
TORRENT_ASSERT(m_max_connections > 0);
|
TORRENT_ASSERT(m_max_connections > 0);
|
||||||
TORRENT_ASSERT(m_max_uploads >= 0);
|
TORRENT_ASSERT(m_max_uploads >= 0);
|
||||||
if (!m_settings.auto_upload_slots_rate_based || !m_settings.auto_upload_slots)
|
if (m_settings.choking_algorithm == session_settings::auto_expand_choker)
|
||||||
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
|
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
|
||||||
int unchokes = 0;
|
int unchokes = 0;
|
||||||
int num_optimistic = 0;
|
int num_optimistic = 0;
|
||||||
|
|
|
@ -17,10 +17,10 @@ void test_swarm()
|
||||||
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49010, 50000), "0.0.0.0", 0);
|
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49010, 50000), "0.0.0.0", 0);
|
||||||
session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50010, 51000), "0.0.0.0", 0);
|
session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50010, 51000), "0.0.0.0", 0);
|
||||||
|
|
||||||
ses1.set_severity_level(alert::debug);
|
ses1.set_alert_mask(alert::all_categories);
|
||||||
ses2.set_severity_level(alert::debug);
|
ses2.set_alert_mask(alert::all_categories);
|
||||||
ses3.set_severity_level(alert::debug);
|
ses3.set_alert_mask(alert::all_categories);
|
||||||
|
|
||||||
// this is to avoid everything finish from a single peer
|
// this is to avoid everything finish from a single peer
|
||||||
// immediately. To make the swarm actually connect all
|
// immediately. To make the swarm actually connect all
|
||||||
// three peers before finishing.
|
// three peers before finishing.
|
||||||
|
@ -35,8 +35,7 @@ void test_swarm()
|
||||||
session_settings settings;
|
session_settings settings;
|
||||||
settings.allow_multiple_connections_per_ip = true;
|
settings.allow_multiple_connections_per_ip = true;
|
||||||
settings.ignore_limits_on_local_network = false;
|
settings.ignore_limits_on_local_network = false;
|
||||||
settings.auto_upload_slots = true;
|
settings.choking_algorithm = session_settings::auto_expand_choker;
|
||||||
settings.auto_upload_slots_rate_based = false;
|
|
||||||
ses1.set_settings(settings);
|
ses1.set_settings(settings);
|
||||||
ses2.set_settings(settings);
|
ses2.set_settings(settings);
|
||||||
ses3.set_settings(settings);
|
ses3.set_settings(settings);
|
||||||
|
|
Loading…
Reference in New Issue