/* */ #include "BtLeecherStateChoke.h" #include "Peer.h" #include "Logger.h" #include "LogFactory.h" #include "a2time.h" #include namespace aria2 { BtLeecherStateChoke::BtLeecherStateChoke(): _round(0), _lastRound(0), _logger(LogFactory::getInstance()) {} BtLeecherStateChoke::~BtLeecherStateChoke() {} class PeerFilter { private: bool _amChoking; bool _peerInterested; public: PeerFilter(bool amChoking, bool peerInterested): _amChoking(amChoking), _peerInterested(peerInterested) {} bool operator()(const Peer* peer) const { return peer->amChoking() == _amChoking && peer->peerInterested() == _peerInterested; } }; class RegularUnchoker { public: bool operator()(const Peer* peer) const { // peer must be interested to us and sent block in the last 30 seconds return peer->peerInterested() && !peer->getLastDownloadUpdate().elapsed(30); } }; class DownloadFaster { private: const struct timeval _now; public: DownloadFaster(const struct timeval& now):_now(now) {} bool operator() (Peer* left, Peer* right) const { return left->calculateDownloadSpeed(_now) > right->calculateDownloadSpeed(_now); } }; class SnubbedPeer { public: bool operator() (const Peer* peer) const { return peer->snubbing(); } }; void BtLeecherStateChoke::plannedOptimisticUnchoke(std::deque& peers) { std::for_each(peers.begin(), peers.end(), std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::optUnchoking), false)); std::deque::iterator i = std::partition(peers.begin(), peers.end(), PeerFilter(true, true)); if(i != peers.begin()) { std::random_shuffle(peers.begin(), i); (*peers.begin())->optUnchoking(true); _logger->info("POU: %s", (*peers.begin())->ipaddr.c_str()); } } void BtLeecherStateChoke::regularUnchoke(std::deque& peers) { std::deque::iterator rest = std::partition(peers.begin(), peers.end(), RegularUnchoker()); struct timeval now; gettimeofday(&now, 0); std::sort(peers.begin(), rest, DownloadFaster(now)); // the number of regular unchokers int count = 3; bool fastOptUnchoker = false; std::deque::iterator peerIter = peers.begin(); for(;peerIter != rest && count; ++peerIter, --count) { (*peerIter)->chokingRequired(false); _logger->info("RU: %s, dlspd=%u", (*peerIter)->ipaddr.c_str(), (*peerIter)->calculateDownloadSpeed(now)); if((*peerIter)->optUnchoking()) { fastOptUnchoker = true; (*peerIter)->optUnchoking(false); } } if(fastOptUnchoker) { std::random_shuffle(peerIter, peers.end()); for(std::deque::iterator i = peerIter; i != peers.end(); ++i) { if((*i)->peerInterested()) { (*i)->optUnchoking(true); _logger->info("OU: %s", (*i)->ipaddr.c_str()); break; } else { (*i)->chokingRequired(false); _logger->info("OU: %s", (*i)->ipaddr.c_str()); } } } } void BtLeecherStateChoke::executeChoke(const std::deque >& peerSet) { _logger->info("Leecher state, %d choke round started", _round); _lastRound.reset(); std::deque peers; std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peers), std::mem_fun_ref(&SharedHandle::get)); peers.erase(std::remove_if(peers.begin(), peers.end(), SnubbedPeer()), peers.end()); std::for_each(peers.begin(), peers.end(), std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true)); // planned optimistic unchoke if(_round == 0) { plannedOptimisticUnchoke(peers); } regularUnchoke(peers); if(++_round == 3) { _round = 0; } } const Time& BtLeecherStateChoke::getLastRound() const { return _lastRound; } } // namespace aria2