/* */ #include "BtSeederStateChoke.h" #include #include "Peer.h" #include "Logger.h" #include "LogFactory.h" #include "SimpleRandomizer.h" namespace aria2 { BtSeederStateChoke::BtSeederStateChoke(): _round(0), _lastRound(0), _logger(LogFactory::getInstance()) {} BtSeederStateChoke::~BtSeederStateChoke() {} BtSeederStateChoke::PeerEntry::PeerEntry (const SharedHandle& peer, const struct timeval& now): _peer(peer), _outstandingUpload(peer->countOutstandingUpload()), _lastAmUnchoking(peer->getLastAmUnchoking()), _recentUnchoking(!_lastAmUnchoking.elapsed(TIME_FRAME)), _uploadSpeed(peer->calculateUploadSpeed(now)) {} 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.isNewer(rhs._lastAmUnchoking)) { return true; } else if(rhs._recentUnchoking) { return false; } else { return this->_uploadSpeed > rhs._uploadSpeed; } } SharedHandle BtSeederStateChoke::PeerEntry::getPeer() const { return _peer; } unsigned int BtSeederStateChoke::PeerEntry::getUploadSpeed() const { return _uploadSpeed; } void BtSeederStateChoke::unchoke (std::deque& peers) { int count = (_round == 2) ? 4 : 3; std::sort(peers.begin(), peers.end()); std::deque::iterator r = peers.begin(); for(; r != peers.end() && count; ++r, --count) { (*r).getPeer()->chokingRequired(false); _logger->info("RU: %s, ulspd=%u", (*r).getPeer()->ipaddr.c_str(), (*r).getUploadSpeed()); } if(_round == 2 && r != peers.end()) { std::random_shuffle(r, peers.end(), *(SimpleRandomizer::getInstance().get())); (*r).getPeer()->optUnchoking(true); _logger->info("POU: %s", (*r).getPeer()->ipaddr.c_str()); } } class ChokingRequired { public: void operator()(const SharedHandle& peer) const { peer->chokingRequired(true); } }; class GenPeerEntry { private: struct timeval _now; public: GenPeerEntry() { gettimeofday(&_now, 0); } BtSeederStateChoke::PeerEntry operator()(const SharedHandle& peer) const { return BtSeederStateChoke::PeerEntry(peer, _now); } }; class NotInterestedPeer { public: bool operator()(const BtSeederStateChoke::PeerEntry& peerEntry) const { return !peerEntry.getPeer()->peerInterested(); } }; void BtSeederStateChoke::executeChoke(const std::deque >& peerSet) { _logger->info("Seeder state, %d choke round started", _round); _lastRound.reset(); std::deque peerEntries; std::for_each(peerSet.begin(), peerSet.end(), ChokingRequired()); std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peerEntries), GenPeerEntry()); peerEntries.erase(std::remove_if(peerEntries.begin(), peerEntries.end(), NotInterestedPeer()), peerEntries.end()); unchoke(peerEntries); if(++_round == 3) { _round = 0; } } const Time& BtSeederStateChoke::getLastRound() const { return _lastRound; } } // namespace aria2