/* */ #include "BtSeederStateChoke.h" #include "BtContext.h" #include "Peer.h" #include "BtRegistry.h" #include "PeerObject.h" #include "BtMessageDispatcher.h" #include "BtMessageFactory.h" #include "BtRequestFactory.h" #include "BtMessageReceiver.h" #include "PeerConnection.h" #include "ExtensionMessageFactory.h" #include "Logger.h" #include "LogFactory.h" #include "a2time.h" #include namespace aria2 { BtSeederStateChoke::BtSeederStateChoke(const SharedHandle& btContext): _btContext(btContext), _round(0), _lastRound(0), _logger(LogFactory::getInstance()) {} BtSeederStateChoke::~BtSeederStateChoke() {} class RecentUnchoke { private: SharedHandle _btContext; const struct timeval _now; public: RecentUnchoke(const SharedHandle& btContext, const struct timeval& now): _btContext(btContext), _now(now) {} bool operator()(Peer* left, Peer* right) const { size_t leftUpload = BT_MESSAGE_DISPATCHER(_btContext, left)->countOutstandingRequest(); size_t rightUpload = BT_MESSAGE_DISPATCHER(_btContext, right)->countOutstandingRequest(); if(leftUpload && !rightUpload) { return true; } else if(!leftUpload && rightUpload) { return false; } const int TIME_FRAME = 20; if(!left->getLastAmUnchoking().elapsed(TIME_FRAME) && left->getLastAmUnchoking().isNewer(right->getLastAmUnchoking())) { return true; } else if(!right->getLastAmUnchoking().elapsed(TIME_FRAME) && right->getLastAmUnchoking().isNewer(left->getLastAmUnchoking())) { return false; } else { return left->calculateUploadSpeed(_now) > right->calculateUploadSpeed(_now); } } }; class NotInterestedPeer { public: bool operator()(const Peer* peer) const { return !peer->peerInterested(); } }; void BtSeederStateChoke::unchoke(std::deque& peers) { int count = (_round == 2) ? 4 : 3; struct timeval now; gettimeofday(&now, 0); std::sort(peers.begin(), peers.end(), RecentUnchoke(_btContext, now)); std::deque::iterator r = peers.begin(); for(; r != peers.end() && count; ++r, --count) { (*r)->chokingRequired(false); _logger->info("RU: %s, ulspd=%u", (*r)->ipaddr.c_str(), (*r)->calculateUploadSpeed(now)); } if(_round == 2 && r != peers.end()) { std::random_shuffle(r, peers.end()); (*r)->optUnchoking(true); _logger->info("POU: %s", (*r)->ipaddr.c_str()); } } void BtSeederStateChoke::executeChoke(const std::deque >& peerSet) { _logger->info("Seeder 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)); std::for_each(peers.begin(), peers.end(), std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true)); peers.erase(std::remove_if(peers.begin(), peers.end(), NotInterestedPeer()), peers.end()); unchoke(peers); if(++_round == 3) { _round = 0; } } const Time& BtSeederStateChoke::getLastRound() const { return _lastRound; } } // namespace aria2