diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index b7f246b5..d85d7ac1 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -92,7 +92,8 @@ AbstractCommand::AbstractCommand socketRecvBuffer_(socketRecvBuffer), checkSocketIsReadable_(false), checkSocketIsWritable_(false), nameResolverCheck_(false), - incNumConnection_(incNumConnection) + incNumConnection_(incNumConnection), + serverStatTimer_(global::wallclock) { if(socket_ && socket_->isOpen()) { setReadCheckSocket(socket_); @@ -117,6 +118,22 @@ AbstractCommand::~AbstractCommand() { } } +void AbstractCommand::useFasterRequest +(const SharedHandle& fasterRequest) +{ + A2_LOG_INFO(fmt("CUID#%lld - Use faster Request hostname=%s, port=%u", + getCuid(), + fasterRequest->getHost().c_str(), + fasterRequest->getPort())); + // Cancel current Request object and use faster one. + fileEntry_->removeRequest(req_); + Command* command = + InitiateConnectionCommandFactory::createInitiateConnectionCommand + (getCuid(), fasterRequest, fileEntry_, requestGroup_, e_); + e_->setNoWait(true); + e_->addCommand(command); +} + bool AbstractCommand::execute() { A2_LOG_DEBUG(fmt("CUID#%lld - socket: read:%d, write:%d, hup:%d, err:%d", getCuid(), @@ -158,17 +175,25 @@ bool AbstractCommand::execute() { !getPieceStorage()->hasMissingUnusedPiece()) { SharedHandle fasterRequest = fileEntry_->findFasterRequest(req_); if(fasterRequest) { - A2_LOG_INFO(fmt("CUID#%lld - Use faster Request hostname=%s, port=%u", - getCuid(), - fasterRequest->getHost().c_str(), - fasterRequest->getPort())); - // Cancel current Request object and use faster one. - fileEntry_->removeRequest(req_); - Command* command = - InitiateConnectionCommandFactory::createInitiateConnectionCommand - (getCuid(), fasterRequest, fileEntry_, requestGroup_, e_); - e_->setNoWait(true); - e_->addCommand(command); + useFasterRequest(fasterRequest); + return true; + } + } + // Don't use this feature if PREF_MAX_{OVERALL_}DOWNLOAD_LIMIT + // is used + if(e_->getRequestGroupMan()->getMaxOverallDownloadSpeedLimit() == 0 && + requestGroup_->getMaxDownloadSpeedLimit() == 0 && + serverStatTimer_.difference(global::wallclock) >= 10) { + serverStatTimer_ = global::wallclock; + std::vector > usedHosts; + if(getOption()->getAsBool(PREF_SELECT_LEAST_USED_HOST)) { + getDownloadEngine()->getRequestGroupMan()->getUsedHosts(usedHosts); + } + SharedHandle fasterRequest = + fileEntry_->findFasterRequest + (req_, usedHosts, e_->getRequestGroupMan()->getServerStatMan()); + if(fasterRequest) { + useFasterRequest(fasterRequest); return true; } } diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h index d612fada..8d9fbf08 100644 --- a/src/AbstractCommand.h +++ b/src/AbstractCommand.h @@ -85,9 +85,10 @@ private: bool nameResolverCheck_; bool incNumConnection_; + Timer serverStatTimer_; size_t calculateMinSplitSize() const; - + void useFasterRequest(const SharedHandle& fasterRequest); #ifdef ENABLE_ASYNC_DNS void setNameResolverCheck(const SharedHandle& resolver); diff --git a/src/FeedbackURISelector.cc b/src/FeedbackURISelector.cc index cb9ad199..e93af40c 100644 --- a/src/FeedbackURISelector.cc +++ b/src/FeedbackURISelector.cc @@ -56,18 +56,6 @@ FeedbackURISelector::FeedbackURISelector FeedbackURISelector::~FeedbackURISelector() {} -namespace { -class ServerStatFaster { -public: - bool operator()(const std::pair, std::string> lhs, - const std::pair, std::string> rhs) - const - { - return lhs.first->getDownloadSpeed() > rhs.first->getDownloadSpeed(); - } -}; -} // namespace - std::string FeedbackURISelector::select (FileEntry* fileEntry, const std::vector >& usedHosts) diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 262ae890..f69466b8 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -46,6 +46,8 @@ #include "uri.h" #include "PeerStat.h" #include "fmt.h" +#include "ServerStatMan.h" +#include "ServerStat.h" namespace aria2 { @@ -221,6 +223,57 @@ FileEntry::findFasterRequest(const SharedHandle& base) return SharedHandle(); } +SharedHandle +FileEntry::findFasterRequest +(const SharedHandle& base, + const std::vector >& usedHosts, + const SharedHandle& serverStatMan) +{ + const int startupIdleTime = 10; + const unsigned int SPEED_THRESHOLD = 20*1024; + if(lastFasterReplace_.difference(global::wallclock) < startupIdleTime) { + return SharedHandle(); + } + const SharedHandle& basestat = base->getPeerStat(); + A2_LOG_DEBUG("Search faster server using ServerStat."); + // Use first 10 good URIs to introduce some randomness. + const size_t NUM_URI = 10; + std::vector, std::string> > fastCands; + std::vector normCands; + for(std::deque::const_iterator i = uris_.begin(), + eoi = uris_.end(); i != eoi && fastCands.size() < NUM_URI; ++i) { + uri::UriStruct us; + if(!uri::parse(us, *i)) { + continue; + } + if(findSecond(usedHosts.begin(), usedHosts.end(), us.host) != + usedHosts.end()) { + A2_LOG_DEBUG(fmt("%s is in usedHosts, not considered", (*i).c_str())); + continue; + } + SharedHandle ss = serverStatMan->find(us.host, us.protocol); + if(ss && ss->isOK()) { + if((basestat && + ss->getDownloadSpeed() > basestat->calculateDownloadSpeed()*1.5) || + (!basestat && ss->getDownloadSpeed() > SPEED_THRESHOLD)) { + fastCands.push_back(std::make_pair(ss, *i)); + } + } + } + if(!fastCands.empty()) { + A2_LOG_DEBUG("Selected from fastCands"); + std::sort(fastCands.begin(), fastCands.end(), ServerStatFaster()); + SharedHandle fastestRequest(new Request()); + fastestRequest->setUri(fastCands.front().second); + fastestRequest->setReferer(base->getReferer()); + inFlightRequests_.push_back(fastestRequest); + lastFasterReplace_ = global::wallclock; + return fastestRequest; + } + A2_LOG_DEBUG("No faster server found."); + return SharedHandle(); +} + namespace { class RequestFaster { public: diff --git a/src/FileEntry.h b/src/FileEntry.h index 0a40ef49..1a321683 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -53,6 +53,7 @@ namespace aria2 { class URISelector; +class ServerStatMan; class FileEntry { private: @@ -169,6 +170,13 @@ public: // removed from the pool and returned. SharedHandle findFasterRequest(const SharedHandle& base); + // Finds faster server using ServerStatMan. + SharedHandle + findFasterRequest + (const SharedHandle& base, + const std::vector >& usedHosts, + const SharedHandle& serverStatMan); + void poolRequest(const SharedHandle& request); bool removeRequest(const SharedHandle& request); diff --git a/src/RequestGroupMan.h b/src/RequestGroupMan.h index f4107d74..ab3da333 100644 --- a/src/RequestGroupMan.h +++ b/src/RequestGroupMan.h @@ -294,6 +294,11 @@ public: // Returns currently used hosts and its use count. void getUsedHosts(std::vector >& usedHosts); + + const SharedHandle& getServerStatMan() const + { + return serverStatMan_; + } }; typedef SharedHandle RequestGroupManHandle; diff --git a/src/ServerStat.h b/src/ServerStat.h index f572997a..361d5e9e 100644 --- a/src/ServerStat.h +++ b/src/ServerStat.h @@ -39,6 +39,7 @@ #include #include +#include "SharedHandle.h" #include "TimeA2.h" namespace aria2 { @@ -167,6 +168,16 @@ private: std::ostream& operator<<(std::ostream& o, const ServerStat& serverStat); +class ServerStatFaster { +public: + bool operator() + (const std::pair, std::string> lhs, + const std::pair, std::string> rhs) const + { + return lhs.first->getDownloadSpeed() > rhs.first->getDownloadSpeed(); + } +}; + } // namespace aria2 #endif // D_SERVER_STAT_H