BtLeecherStateChoke.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "BtLeecherStateChoke.h"
  36. #include "Peer.h"
  37. #include "Logger.h"
  38. #include "LogFactory.h"
  39. #include "a2time.h"
  40. #include <algorithm>
  41. namespace aria2 {
  42. BtLeecherStateChoke::BtLeecherStateChoke():
  43. _round(0),
  44. _lastRound(0),
  45. _logger(LogFactory::getInstance()) {}
  46. BtLeecherStateChoke::~BtLeecherStateChoke() {}
  47. class PeerFilter {
  48. private:
  49. bool _amChoking;
  50. bool _peerInterested;
  51. public:
  52. PeerFilter(bool amChoking, bool peerInterested):
  53. _amChoking(amChoking),
  54. _peerInterested(peerInterested) {}
  55. bool operator()(const Peer* peer) const
  56. {
  57. return peer->amChoking() == _amChoking &&
  58. peer->peerInterested() == _peerInterested;
  59. }
  60. };
  61. class RegularUnchoker {
  62. public:
  63. bool operator()(const Peer* peer) const
  64. {
  65. // peer must be interested to us and sent block in the last 30 seconds
  66. return peer->peerInterested() && !peer->getLastDownloadUpdate().elapsed(30);
  67. }
  68. };
  69. class DownloadFaster {
  70. private:
  71. const struct timeval _now;
  72. public:
  73. DownloadFaster(const struct timeval& now):_now(now) {}
  74. bool operator() (Peer* left, Peer* right) const
  75. {
  76. return left->calculateDownloadSpeed(_now) > right->calculateDownloadSpeed(_now);
  77. }
  78. };
  79. class SnubbedPeer {
  80. public:
  81. bool operator() (const Peer* peer) const
  82. {
  83. return peer->snubbing();
  84. }
  85. };
  86. void BtLeecherStateChoke::plannedOptimisticUnchoke(std::deque<Peer*>& peers)
  87. {
  88. std::for_each(peers.begin(), peers.end(),
  89. std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::optUnchoking), false));
  90. std::deque<Peer*>::iterator i = std::partition(peers.begin(), peers.end(), PeerFilter(true, true));
  91. if(i != peers.begin()) {
  92. std::random_shuffle(peers.begin(), i);
  93. (*peers.begin())->optUnchoking(true);
  94. _logger->info("POU: %s", (*peers.begin())->ipaddr.c_str());
  95. }
  96. }
  97. void BtLeecherStateChoke::regularUnchoke(std::deque<Peer*>& peers)
  98. {
  99. std::deque<Peer*>::iterator rest = std::partition(peers.begin(), peers.end(), RegularUnchoker());
  100. struct timeval now;
  101. gettimeofday(&now, 0);
  102. std::sort(peers.begin(), rest, DownloadFaster(now));
  103. // the number of regular unchokers
  104. int count = 3;
  105. bool fastOptUnchoker = false;
  106. std::deque<Peer*>::iterator peerIter = peers.begin();
  107. for(;peerIter != rest && count; ++peerIter, --count) {
  108. (*peerIter)->chokingRequired(false);
  109. _logger->info("RU: %s, dlspd=%u", (*peerIter)->ipaddr.c_str(), (*peerIter)->calculateDownloadSpeed(now));
  110. if((*peerIter)->optUnchoking()) {
  111. fastOptUnchoker = true;
  112. (*peerIter)->optUnchoking(false);
  113. }
  114. }
  115. if(fastOptUnchoker) {
  116. std::random_shuffle(peerIter, peers.end());
  117. for(std::deque<Peer*>::iterator i = peerIter; i != peers.end(); ++i) {
  118. if((*i)->peerInterested()) {
  119. (*i)->optUnchoking(true);
  120. _logger->info("OU: %s", (*i)->ipaddr.c_str());
  121. break;
  122. } else {
  123. (*i)->chokingRequired(false);
  124. _logger->info("OU: %s", (*i)->ipaddr.c_str());
  125. }
  126. }
  127. }
  128. }
  129. void
  130. BtLeecherStateChoke::executeChoke(const std::deque<SharedHandle<Peer> >& peerSet)
  131. {
  132. _logger->info("Leecher state, %d choke round started", _round);
  133. _lastRound.reset();
  134. std::deque<Peer*> peers;
  135. std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peers),
  136. std::mem_fun_ref(&SharedHandle<Peer>::get));
  137. peers.erase(std::remove_if(peers.begin(), peers.end(), SnubbedPeer()),
  138. peers.end());
  139. std::for_each(peers.begin(), peers.end(),
  140. std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true));
  141. // planned optimistic unchoke
  142. if(_round == 0) {
  143. plannedOptimisticUnchoke(peers);
  144. }
  145. regularUnchoke(peers);
  146. if(++_round == 3) {
  147. _round = 0;
  148. }
  149. }
  150. const Time& BtLeecherStateChoke::getLastRound() const
  151. {
  152. return _lastRound;
  153. }
  154. } // namespace aria2