forked from premiere/premiere-libtorrent
some more refactoring in choker
This commit is contained in:
parent
d9388f9898
commit
9338aa6c60
|
@ -1348,10 +1348,7 @@ int main(int argc, char* argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
settings.set_str(settings_pack::user_agent, "client_test/" LIBTORRENT_VERSION);
|
settings.set_str(settings_pack::user_agent, "client_test/" LIBTORRENT_VERSION);
|
||||||
settings.set_int(settings_pack::choking_algorithm, settings_pack::auto_expand_choker);
|
settings.set_int(settings_pack::choking_algorithm, settings_pack::rate_based_choker);
|
||||||
settings.set_bool(settings_pack::volatile_read_cache, false);
|
|
||||||
settings.set_int(settings_pack::disk_io_write_mode, settings_pack::disable_os_cache);
|
|
||||||
settings.set_int(settings_pack::disk_io_read_mode, settings_pack::disable_os_cache);
|
|
||||||
|
|
||||||
ses.apply_settings(settings);
|
ses.apply_settings(settings);
|
||||||
|
|
||||||
|
|
244
src/choker.cpp
244
src/choker.cpp
|
@ -41,12 +41,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
// return true if 'lhs' peer should be preferred to be unchoke over 'rhs'
|
// return true if 'lhs' peer should be preferred to be unchoke over 'rhs'
|
||||||
|
bool unchoke_compare_rr(peer_connection const* lhs
|
||||||
// TODO: 3 split this funcion up into multiple functions, one for each
|
, peer_connection const* rhs, int pieces)
|
||||||
// seed_choking_algorithm, and pick which one to use when calling
|
|
||||||
// the sort function
|
|
||||||
bool unchoke_compare(peer_connection const* lhs
|
|
||||||
, peer_connection const* rhs, aux::session_settings const& sett)
|
|
||||||
{
|
{
|
||||||
// if one peer belongs to a higher priority torrent than the other one
|
// if one peer belongs to a higher priority torrent than the other one
|
||||||
// that one should be unchoked.
|
// that one should be unchoked.
|
||||||
|
@ -69,88 +65,139 @@ namespace libtorrent
|
||||||
|
|
||||||
if (c1 != c2) return c1 > c2;
|
if (c1 != c2) return c1 > c2;
|
||||||
|
|
||||||
if (sett.get_int(settings_pack::seed_choking_algorithm)
|
// when seeding, rotate which peer is unchoked in a round-robin fasion
|
||||||
== settings_pack::round_robin)
|
|
||||||
{
|
|
||||||
// the amount uploaded since unchoked (not just in the last round)
|
|
||||||
c1 = lhs->uploaded_since_unchoked();
|
|
||||||
c2 = rhs->uploaded_since_unchoked();
|
|
||||||
|
|
||||||
// the way the round-robin unchoker works is that it,
|
// the amount uploaded since unchoked (not just in the last round)
|
||||||
// by default, prioritizes any peer that is already unchoked.
|
c1 = lhs->uploaded_since_unchoked();
|
||||||
// this maintain the status quo across unchoke rounds. However,
|
c2 = rhs->uploaded_since_unchoked();
|
||||||
// peers that are unchoked, but have sent more than one quota
|
|
||||||
// since they were unchoked, they get de-prioritized.
|
|
||||||
|
|
||||||
int pieces = sett.get_int(settings_pack::seeding_piece_quota);
|
// the way the round-robin unchoker works is that it,
|
||||||
// if a peer is already unchoked, and the number of bytes sent since it was unchoked
|
// by default, prioritizes any peer that is already unchoked.
|
||||||
// is greater than the send quanta, then it's done with it' upload slot, and we
|
// this maintain the status quo across unchoke rounds. However,
|
||||||
// can de-prioritize it
|
// peers that are unchoked, but have sent more than one quota
|
||||||
bool c1_quota_complete = !lhs->is_choked() && c1
|
// since they were unchoked, they get de-prioritized.
|
||||||
> (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024);
|
|
||||||
bool c2_quota_complete = !rhs->is_choked() && c2
|
|
||||||
> (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024);
|
|
||||||
|
|
||||||
// if c2 has completed a quanta, it shuold be de-prioritized
|
// if a peer is already unchoked, and the number of bytes sent since it was unchoked
|
||||||
// and vice versa
|
// is greater than the send quanta, then it's done with it' upload slot, and we
|
||||||
if (c1_quota_complete < c2_quota_complete) return true;
|
// can de-prioritize it
|
||||||
if (c1_quota_complete > c2_quota_complete) return false;
|
bool c1_quota_complete = !lhs->is_choked() && c1
|
||||||
|
> (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024);
|
||||||
|
bool c2_quota_complete = !rhs->is_choked() && c2
|
||||||
|
> (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024);
|
||||||
|
|
||||||
// if both peers have either completed a quanta, or not.
|
// if c2 has completed a quanta, it shuold be de-prioritized
|
||||||
// keep unchoked peers prioritized over choked ones, to let
|
// and vice versa
|
||||||
// peers keep working on uploading a full quanta
|
if (c1_quota_complete < c2_quota_complete) return true;
|
||||||
if (lhs->is_choked() < rhs->is_choked()) return true;
|
if (c1_quota_complete > c2_quota_complete) return false;
|
||||||
if (lhs->is_choked() > rhs->is_choked()) return false;
|
|
||||||
|
|
||||||
// if the peers are still identical (say, they're both waiting to be unchoked)
|
// if both peers have either completed a quanta, or not.
|
||||||
// fall through and rely on the logic to prioritize peers who have waited
|
// keep unchoked peers prioritized over choked ones, to let
|
||||||
// the longest to be unchoked
|
// peers keep working on uploading a full quanta
|
||||||
}
|
if (lhs->is_choked() < rhs->is_choked()) return true;
|
||||||
else if (sett.get_int(settings_pack::seed_choking_algorithm)
|
if (lhs->is_choked() > rhs->is_choked()) return false;
|
||||||
== settings_pack::fastest_upload)
|
|
||||||
{
|
// if the peers are still identical (say, they're both waiting to be unchoked)
|
||||||
c1 = lhs->uploaded_in_last_round();
|
// prioritize the one that has waited the longest to be unchoked
|
||||||
c2 = rhs->uploaded_in_last_round();
|
// the round-robin unchoker relies on this logic. Don't change it
|
||||||
|
// without moving this into that unchoker logic
|
||||||
|
return lhs->time_of_last_unchoke() < rhs->time_of_last_unchoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if 'lhs' peer should be preferred to be unchoke over 'rhs'
|
||||||
|
bool unchoke_compare_fastest_upload(peer_connection const* lhs
|
||||||
|
, peer_connection const* rhs)
|
||||||
|
{
|
||||||
|
// if one peer belongs to a higher priority torrent than the other one
|
||||||
|
// that one should be unchoked.
|
||||||
|
boost::shared_ptr<torrent> t1 = lhs->associated_torrent().lock();
|
||||||
|
TORRENT_ASSERT(t1);
|
||||||
|
boost::shared_ptr<torrent> t2 = rhs->associated_torrent().lock();
|
||||||
|
TORRENT_ASSERT(t2);
|
||||||
|
|
||||||
|
int prio1 = lhs->get_priority(peer_connection::upload_channel);
|
||||||
|
int prio2 = rhs->get_priority(peer_connection::upload_channel);
|
||||||
|
|
||||||
|
if (prio1 != prio2)
|
||||||
|
return prio1 > prio2;
|
||||||
|
|
||||||
|
// compare how many bytes they've sent us
|
||||||
|
size_type c1;
|
||||||
|
size_type c2;
|
||||||
|
c1 = lhs->downloaded_in_last_round();
|
||||||
|
c2 = rhs->downloaded_in_last_round();
|
||||||
|
|
||||||
|
if (c1 != c2) return c1 > c2;
|
||||||
|
|
||||||
|
// when seeding, prefer the peer we're uploading the fastest to
|
||||||
|
c1 = lhs->uploaded_in_last_round();
|
||||||
|
c2 = rhs->uploaded_in_last_round();
|
||||||
|
|
||||||
|
// take torrent priority into account
|
||||||
|
c1 *= prio1;
|
||||||
|
c2 *= prio2;
|
||||||
|
|
||||||
|
if (c1 > c2) return true;
|
||||||
|
if (c2 > c1) return false;
|
||||||
|
|
||||||
// take torrent priority into account
|
// prioritize the one that has waited the longest to be unchoked
|
||||||
c1 *= prio1;
|
// the round-robin unchoker relies on this logic. Don't change it
|
||||||
c2 *= prio2;
|
// without moving this into that unchoker logic
|
||||||
|
return lhs->time_of_last_unchoke() < rhs->time_of_last_unchoke();
|
||||||
|
}
|
||||||
|
|
||||||
if (c1 > c2) return true;
|
// return true if 'lhs' peer should be preferred to be unchoke over 'rhs'
|
||||||
if (c2 > c1) return false;
|
bool unchoke_compare_anti_leech(peer_connection const* lhs
|
||||||
}
|
, peer_connection const* rhs)
|
||||||
else if (sett.get_int(settings_pack::seed_choking_algorithm)
|
{
|
||||||
== settings_pack::anti_leech)
|
// if one peer belongs to a higher priority torrent than the other one
|
||||||
{
|
// that one should be unchoked.
|
||||||
// the anti-leech seeding algorithm is based on the paper "Improving
|
boost::shared_ptr<torrent> t1 = lhs->associated_torrent().lock();
|
||||||
// BitTorrent: A Simple Approach" from Chow et. al. and ranks peers based
|
TORRENT_ASSERT(t1);
|
||||||
// on how many pieces they have, prefering to unchoke peers that just
|
boost::shared_ptr<torrent> t2 = rhs->associated_torrent().lock();
|
||||||
// started and peers that are close to completing. Like this:
|
TORRENT_ASSERT(t2);
|
||||||
// ^
|
|
||||||
// | \ / |
|
int prio1 = lhs->get_priority(peer_connection::upload_channel);
|
||||||
// | \ / |
|
int prio2 = rhs->get_priority(peer_connection::upload_channel);
|
||||||
// | \ / |
|
|
||||||
// s | \ / |
|
if (prio1 != prio2)
|
||||||
// c | \ / |
|
return prio1 > prio2;
|
||||||
// o | \ / |
|
|
||||||
// r | \ / |
|
// compare how many bytes they've sent us
|
||||||
// e | \ / |
|
size_type c1;
|
||||||
// | \ / |
|
size_type c2;
|
||||||
// | \ / |
|
c1 = lhs->downloaded_in_last_round();
|
||||||
// | \ / |
|
c2 = rhs->downloaded_in_last_round();
|
||||||
// | \ / |
|
|
||||||
// | V |
|
if (c1 != c2) return c1 > c2;
|
||||||
// +---------------------------+
|
|
||||||
// 0% num have pieces 100%
|
// the anti-leech seeding algorithm is based on the paper "Improving
|
||||||
int t1_total = t1->torrent_file().num_pieces();
|
// BitTorrent: A Simple Approach" from Chow et. al. and ranks peers based
|
||||||
int t2_total = t2->torrent_file().num_pieces();
|
// on how many pieces they have, prefering to unchoke peers that just
|
||||||
int score1 = (lhs->num_have_pieces() < t1_total / 2
|
// started and peers that are close to completing. Like this:
|
||||||
? t1_total - lhs->num_have_pieces() : lhs->num_have_pieces()) * 1000 / t1_total;
|
// ^
|
||||||
int score2 = (rhs->num_have_pieces() < t2_total / 2
|
// | \ / |
|
||||||
? t2_total - rhs->num_have_pieces() : rhs->num_have_pieces()) * 1000 / t2_total;
|
// | \ / |
|
||||||
if (score1 > score2) return true;
|
// | \ / |
|
||||||
if (score2 > score1) return false;
|
// s | \ / |
|
||||||
}
|
// c | \ / |
|
||||||
|
// o | \ / |
|
||||||
|
// r | \ / |
|
||||||
|
// e | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | V |
|
||||||
|
// +---------------------------+
|
||||||
|
// 0% num have pieces 100%
|
||||||
|
int t1_total = t1->torrent_file().num_pieces();
|
||||||
|
int t2_total = t2->torrent_file().num_pieces();
|
||||||
|
int score1 = (lhs->num_have_pieces() < t1_total / 2
|
||||||
|
? t1_total - lhs->num_have_pieces() : lhs->num_have_pieces()) * 1000 / t1_total;
|
||||||
|
int score2 = (rhs->num_have_pieces() < t2_total / 2
|
||||||
|
? t2_total - rhs->num_have_pieces() : rhs->num_have_pieces()) * 1000 / t2_total;
|
||||||
|
if (score1 > score2) return true;
|
||||||
|
if (score2 > score1) return false;
|
||||||
|
|
||||||
// prioritize the one that has waited the longest to be unchoked
|
// prioritize the one that has waited the longest to be unchoked
|
||||||
// the round-robin unchoker relies on this logic. Don't change it
|
// the round-robin unchoker relies on this logic. Don't change it
|
||||||
|
@ -318,9 +365,38 @@ namespace libtorrent
|
||||||
// we use partial sort here, because we only care about the top
|
// we use partial sort here, because we only care about the top
|
||||||
// upload_slots peers.
|
// upload_slots peers.
|
||||||
|
|
||||||
std::partial_sort(peers.begin(), peers.begin()
|
if (sett.get_int(settings_pack::seed_choking_algorithm)
|
||||||
+ (std::min)(upload_slots, int(peers.size())), peers.end()
|
== settings_pack::round_robin)
|
||||||
, boost::bind(&unchoke_compare, _1, _2, boost::cref(sett)));
|
{
|
||||||
|
int pieces = sett.get_int(settings_pack::seeding_piece_quota);
|
||||||
|
|
||||||
|
std::partial_sort(peers.begin(), peers.begin()
|
||||||
|
+ (std::min)(upload_slots, int(peers.size())), peers.end()
|
||||||
|
, boost::bind(&unchoke_compare_rr, _1, _2, pieces));
|
||||||
|
}
|
||||||
|
else if (sett.get_int(settings_pack::seed_choking_algorithm)
|
||||||
|
== settings_pack::fastest_upload)
|
||||||
|
{
|
||||||
|
std::partial_sort(peers.begin(), peers.begin()
|
||||||
|
+ (std::min)(upload_slots, int(peers.size())), peers.end()
|
||||||
|
, boost::bind(&unchoke_compare_fastest_upload, _1, _2));
|
||||||
|
}
|
||||||
|
else if (sett.get_int(settings_pack::seed_choking_algorithm)
|
||||||
|
== settings_pack::anti_leech)
|
||||||
|
{
|
||||||
|
std::partial_sort(peers.begin(), peers.begin()
|
||||||
|
+ (std::min)(upload_slots, int(peers.size())), peers.end()
|
||||||
|
, boost::bind(&unchoke_compare_anti_leech, _1, _2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(false && "unknown seed choking algorithm");
|
||||||
|
|
||||||
|
int pieces = sett.get_int(settings_pack::seeding_piece_quota);
|
||||||
|
std::partial_sort(peers.begin(), peers.begin()
|
||||||
|
+ (std::min)(upload_slots, int(peers.size())), peers.end()
|
||||||
|
, boost::bind(&unchoke_compare_rr, _1, _2, pieces));
|
||||||
|
}
|
||||||
|
|
||||||
return upload_slots;
|
return upload_slots;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue