/* */ #include "BtSeederStateChoke.h" #include #include "Peer.h" #include "Logger.h" #include "LogFactory.h" #include "SimpleRandomizer.h" #include "wallclock.h" #include "fmt.h" namespace aria2 { BtSeederStateChoke::BtSeederStateChoke() : round_(0), lastRound_(0) {} BtSeederStateChoke::~BtSeederStateChoke() {} BtSeederStateChoke::PeerEntry::PeerEntry (const SharedHandle& peer): peer_(peer), outstandingUpload_(peer->countOutstandingUpload()), lastAmUnchoking_(peer->getLastAmUnchoking()), recentUnchoking_(lastAmUnchoking_.difference(global::wallclock()) < TIME_FRAME), uploadSpeed_(peer->calculateUploadSpeed()) {} BtSeederStateChoke::PeerEntry::PeerEntry(const PeerEntry& c) : peer_(c.peer_), outstandingUpload_(c.outstandingUpload_), lastAmUnchoking_(c.lastAmUnchoking_), recentUnchoking_(c.recentUnchoking_), uploadSpeed_(c.uploadSpeed_) {} BtSeederStateChoke::PeerEntry::~PeerEntry() {} void BtSeederStateChoke::PeerEntry::swap(PeerEntry& c) { using std::swap; swap(peer_, c.peer_); swap(outstandingUpload_, c.outstandingUpload_); swap(lastAmUnchoking_, c.lastAmUnchoking_); swap(recentUnchoking_, c.recentUnchoking_); swap(uploadSpeed_, c.uploadSpeed_); } BtSeederStateChoke::PeerEntry& BtSeederStateChoke::PeerEntry::operator= (const PeerEntry& c) { if(this != &c) { peer_ = c.peer_; outstandingUpload_ = c.outstandingUpload_; lastAmUnchoking_ = c.lastAmUnchoking_; recentUnchoking_ = c.recentUnchoking_; uploadSpeed_ = c.uploadSpeed_; } return *this; } bool BtSeederStateChoke::PeerEntry::operator<(const PeerEntry& rhs) const { if(this->outstandingUpload_ && !rhs.outstandingUpload_) { return true; } else if(!this->outstandingUpload_ && rhs.outstandingUpload_) { return false; } if(this->recentUnchoking_ && (this->lastAmUnchoking_ > rhs.lastAmUnchoking_)) { return true; } else if(rhs.recentUnchoking_) { return false; } else { return this->uploadSpeed_ > rhs.uploadSpeed_; } } void BtSeederStateChoke::PeerEntry::disableOptUnchoking() { peer_->optUnchoking(false); } void BtSeederStateChoke::unchoke (std::vector& peers) { int count = (round_ == 2) ? 4 : 3; std::sort(peers.begin(), peers.end()); std::vector::iterator r = peers.begin(); for(std::vector::iterator eoi = peers.end(); r != eoi && count; ++r, --count) { (*r).getPeer()->chokingRequired(false); A2_LOG_INFO(fmt("RU: %s, ulspd=%d", (*r).getPeer()->getIPAddress().c_str(), (*r).getUploadSpeed())); } if(round_ < 2) { std::for_each(peers.begin(), peers.end(), std::mem_fun_ref(&PeerEntry::disableOptUnchoking)); if(r != peers.end()) { std::random_shuffle(r, peers.end(), *(SimpleRandomizer::getInstance().get())); (*r).getPeer()->optUnchoking(true); A2_LOG_INFO(fmt("POU: %s", (*r).getPeer()->getIPAddress().c_str())); } } } void BtSeederStateChoke::executeChoke(const PeerSet& peerSet) { A2_LOG_INFO(fmt("Seeder state, %d choke round started", round_)); lastRound_ = global::wallclock(); std::vector peerEntries; for(PeerSet::const_iterator i = peerSet.begin(), eoi = peerSet.end(); i != eoi; ++i) { if((*i)->isActive() && (*i)->peerInterested()) { (*i)->chokingRequired(true); peerEntries.push_back(PeerEntry(*i)); } } unchoke(peerEntries); if(++round_ == 3) { round_ = 0; } } void swap (BtSeederStateChoke::PeerEntry& a, BtSeederStateChoke::PeerEntry& b) { a.swap(b); } } // namespace aria2