|
@@ -36,109 +36,127 @@
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
-#include "BtContext.h"
|
|
|
#include "Peer.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 "SimpleRandomizer.h"
|
|
|
|
|
|
namespace aria2 {
|
|
|
|
|
|
-BtSeederStateChoke::BtSeederStateChoke(const SharedHandle<BtContext>& btContext):
|
|
|
- _btContext(btContext),
|
|
|
+BtSeederStateChoke::BtSeederStateChoke():
|
|
|
_round(0),
|
|
|
_lastRound(0),
|
|
|
_logger(LogFactory::getInstance()) {}
|
|
|
|
|
|
BtSeederStateChoke::~BtSeederStateChoke() {}
|
|
|
|
|
|
-class RecentUnchoke {
|
|
|
-private:
|
|
|
- SharedHandle<BtContext> _btContext;
|
|
|
-
|
|
|
- const struct timeval _now;
|
|
|
-public:
|
|
|
- RecentUnchoke(const SharedHandle<BtContext>& btContext,
|
|
|
- const struct timeval& now):
|
|
|
- _btContext(btContext), _now(now) {}
|
|
|
-
|
|
|
- bool operator()(Peer* left, Peer* right) const
|
|
|
- {
|
|
|
- size_t leftUpload = left->countOutstandingUpload();
|
|
|
- size_t rightUpload = right->countOutstandingUpload();
|
|
|
- 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)) {
|
|
|
- return false;
|
|
|
- } else {
|
|
|
- return left->calculateUploadSpeed(_now) > right->calculateUploadSpeed(_now);
|
|
|
- }
|
|
|
+BtSeederStateChoke::PeerEntry::PeerEntry
|
|
|
+(const SharedHandle<Peer>& 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;
|
|
|
}
|
|
|
-};
|
|
|
-
|
|
|
-class NotInterestedPeer {
|
|
|
-public:
|
|
|
- bool operator()(const Peer* peer) const
|
|
|
- {
|
|
|
- return !peer->peerInterested();
|
|
|
+ if(this->_recentUnchoking &&
|
|
|
+ this->_lastAmUnchoking.isNewer(rhs._lastAmUnchoking)) {
|
|
|
+ return true;
|
|
|
+ } else if(rhs._recentUnchoking) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return this->_uploadSpeed > rhs._uploadSpeed;
|
|
|
}
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-void BtSeederStateChoke::unchoke(std::deque<Peer*>& peers)
|
|
|
+SharedHandle<Peer> BtSeederStateChoke::PeerEntry::getPeer() const
|
|
|
{
|
|
|
- int count = (_round == 2) ? 4 : 3;
|
|
|
+ return _peer;
|
|
|
+}
|
|
|
|
|
|
- struct timeval now;
|
|
|
- gettimeofday(&now, 0);
|
|
|
+unsigned int BtSeederStateChoke::PeerEntry::getUploadSpeed() const
|
|
|
+{
|
|
|
+ return _uploadSpeed;
|
|
|
+}
|
|
|
|
|
|
- std::sort(peers.begin(), peers.end(), RecentUnchoke(_btContext, now));
|
|
|
+void BtSeederStateChoke::unchoke
|
|
|
+(std::deque<BtSeederStateChoke::PeerEntry>& peers)
|
|
|
+{
|
|
|
+ int count = (_round == 2) ? 4 : 3;
|
|
|
+
|
|
|
+ std::sort(peers.begin(), peers.end());
|
|
|
|
|
|
- std::deque<Peer*>::iterator r = peers.begin();
|
|
|
+ std::deque<PeerEntry>::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));
|
|
|
+ (*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()));
|
|
|
- // TODO Is r invalidated here?
|
|
|
- (*r)->optUnchoking(true);
|
|
|
- _logger->info("POU: %s", (*r)->ipaddr.c_str());
|
|
|
+ (*r).getPeer()->optUnchoking(true);
|
|
|
+ _logger->info("POU: %s", (*r).getPeer()->ipaddr.c_str());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+class ChokingRequired {
|
|
|
+public:
|
|
|
+ void operator()(const SharedHandle<Peer>& peer) const
|
|
|
+ {
|
|
|
+ peer->chokingRequired(true);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+class GenPeerEntry {
|
|
|
+private:
|
|
|
+ struct timeval _now;
|
|
|
+public:
|
|
|
+ GenPeerEntry()
|
|
|
+ {
|
|
|
+ gettimeofday(&_now, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ BtSeederStateChoke::PeerEntry operator()(const SharedHandle<Peer>& 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<SharedHandle<Peer> >& peerSet)
|
|
|
{
|
|
|
_logger->info("Seeder state, %d choke round started", _round);
|
|
|
_lastRound.reset();
|
|
|
|
|
|
- std::deque<Peer*> peers;
|
|
|
- std::transform(peerSet.begin(), peerSet.end(), std::back_inserter(peers),
|
|
|
- std::mem_fun_ref(&SharedHandle<Peer>::get));
|
|
|
-
|
|
|
- std::for_each(peers.begin(), peers.end(),
|
|
|
- std::bind2nd(std::mem_fun((void (Peer::*)(bool))&Peer::chokingRequired), true));
|
|
|
+ std::deque<PeerEntry> peerEntries;
|
|
|
|
|
|
- peers.erase(std::remove_if(peers.begin(), peers.end(), NotInterestedPeer()),
|
|
|
- peers.end());
|
|
|
+ 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(peers);
|
|
|
+ unchoke(peerEntries);
|
|
|
|
|
|
if(++_round == 3) {
|
|
|
_round = 0;
|