/* */ #include "BtLeecherStateChoke.h" #include #include "Peer.h" #include "Logger.h" #include "LogFactory.h" #include "SimpleRandomizer.h" #include "wallclock.h" namespace aria2 { BtLeecherStateChoke::BtLeecherStateChoke(): round_(0), lastRound_(0), logger_(LogFactory::getInstance()) {} BtLeecherStateChoke::~BtLeecherStateChoke() {} BtLeecherStateChoke::PeerEntry::PeerEntry(const SharedHandle& peer): peer_(peer), downloadSpeed_(peer->calculateDownloadSpeed()), // peer must be interested to us and sent block in the last 30 seconds regularUnchoker_ (peer->peerInterested() && peer->getLastDownloadUpdate().difference(global::wallclock) < 30) {} const SharedHandle& BtLeecherStateChoke::PeerEntry::getPeer() const { return peer_; } unsigned int BtLeecherStateChoke::PeerEntry::getDownloadSpeed() const { return downloadSpeed_; } bool BtLeecherStateChoke::PeerEntry::isRegularUnchoker() const { return regularUnchoker_; } void BtLeecherStateChoke::PeerEntry::enableChokingRequired() { peer_->chokingRequired(true); } void BtLeecherStateChoke::PeerEntry::disableChokingRequired() { peer_->chokingRequired(false); } void BtLeecherStateChoke::PeerEntry::enableOptUnchoking() { peer_->optUnchoking(true); } void BtLeecherStateChoke::PeerEntry::disableOptUnchoking() { peer_->optUnchoking(false); } bool BtLeecherStateChoke::PeerEntry::isSnubbing() const { return peer_->snubbing(); } bool BtLeecherStateChoke::PeerEntry::operator<(const PeerEntry& peerEntry) const { return downloadSpeed_ > peerEntry.downloadSpeed_; } class PeerFilter { private: bool amChoking_; bool peerInterested_; public: PeerFilter(bool amChoking, bool peerInterested): amChoking_(amChoking), peerInterested_(peerInterested) {} bool operator()(const BtLeecherStateChoke::PeerEntry& peerEntry) const { return peerEntry.getPeer()->amChoking() == amChoking_ && peerEntry.getPeer()->peerInterested() == peerInterested_; } }; void BtLeecherStateChoke::plannedOptimisticUnchoke (std::vector& peerEntries) { std::for_each(peerEntries.begin(), peerEntries.end(), std::mem_fun_ref(&PeerEntry::disableOptUnchoking)); std::vector::iterator i = std::partition(peerEntries.begin(), peerEntries.end(), PeerFilter(true, true)); if(i != peerEntries.begin()) { std::random_shuffle(peerEntries.begin(), i, *(SimpleRandomizer::getInstance().get())); (*peerEntries.begin()).enableOptUnchoking(); logger_->info ("POU: %s", (*peerEntries.begin()).getPeer()->getIPAddress().c_str()); } } void BtLeecherStateChoke::regularUnchoke(std::vector& peerEntries) { std::vector::iterator rest = std::partition(peerEntries.begin(), peerEntries.end(), std::mem_fun_ref(&PeerEntry::isRegularUnchoker)); std::sort(peerEntries.begin(), rest); // the number of regular unchokers int count = 3; bool fastOptUnchoker = false; std::vector::iterator peerIter = peerEntries.begin(); for(;peerIter != rest && count; ++peerIter, --count) { (*peerIter).disableChokingRequired(); logger_->info("RU: %s, dlspd=%u", (*peerIter).getPeer()->getIPAddress().c_str(), (*peerIter).getDownloadSpeed()); if((*peerIter).getPeer()->optUnchoking()) { fastOptUnchoker = true; (*peerIter).disableOptUnchoking(); } } if(fastOptUnchoker) { std::random_shuffle(peerIter, peerEntries.end(), *(SimpleRandomizer::getInstance().get())); for(std::vector::iterator i = peerIter, eoi = peerEntries.end(); i != eoi; ++i) { if((*i).getPeer()->peerInterested()) { (*i).enableOptUnchoking(); logger_->info("OU: %s", (*i).getPeer()->getIPAddress().c_str()); break; } else { (*i).disableChokingRequired(); logger_->info("OU: %s", (*i).getPeer()->getIPAddress().c_str()); } } } } class BtLeecherStateChokeGenPeerEntry { public: BtLeecherStateChoke::PeerEntry operator() (const SharedHandle& peer) const { return BtLeecherStateChoke::PeerEntry(peer); } }; void BtLeecherStateChoke::executeChoke (const std::vector >& peerSet) { logger_->info("Leecher state, %d choke round started", round_); lastRound_ = global::wallclock; std::vector peerEntries; std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peerEntries), BtLeecherStateChokeGenPeerEntry()); peerEntries.erase(std::remove_if(peerEntries.begin(), peerEntries.end(), std::mem_fun_ref(&PeerEntry::isSnubbing)), peerEntries.end()); std::for_each(peerEntries.begin(), peerEntries.end(), std::mem_fun_ref(&PeerEntry::enableChokingRequired)); // planned optimistic unchoke if(round_ == 0) { plannedOptimisticUnchoke(peerEntries); } regularUnchoke(peerEntries); if(++round_ == 3) { round_ = 0; } } const Timer& BtLeecherStateChoke::getLastRound() const { return lastRound_; } } // namespace aria2