/* */ #include "FeedbackURISelector.h" #include #include "ServerStatMan.h" #include "ServerStat.h" #include "Request.h" #include "A2STR.h" #include "FileEntry.h" namespace aria2 { FeedbackURISelector::FeedbackURISelector (const SharedHandle& serverStatMan): serverStatMan_(serverStatMan) {} FeedbackURISelector::~FeedbackURISelector() {} 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(); } }; std::string FeedbackURISelector::select (FileEntry* fileEntry, const std::vector& usedHosts) { if(fileEntry->getRemainingUris().empty()) { return A2STR::NIL; } // Select URI with usedHosts first. If no URI is selected, then do // it again without usedHosts. std::string uri = selectInternal(fileEntry->getRemainingUris(), usedHosts); if(uri.empty()) { uri = selectInternal (fileEntry->getRemainingUris(), std::vector()); } if(!uri.empty()) { std::deque& uris = fileEntry->getRemainingUris(); uris.erase(std::find(uris.begin(), uris.end(), uri)); } return uri; } std::string FeedbackURISelector::selectInternal (const std::deque& uris, const std::vector& usedHosts) { // Use first 10 good URIs to introduce some randomness. const size_t NUM_URI = 10; // Ignore low speed server const unsigned int SPEED_THRESHOLD = 20*1024; 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) { Request r; r.setUri(*i); if(std::find(usedHosts.begin(), usedHosts.end(), r.getHost()) != usedHosts.end()) { continue; } SharedHandle ss = serverStatMan_->find(r.getHost(), r.getProtocol()); if(!ss.isNull() && ss->isOK() && ss->getDownloadSpeed() > SPEED_THRESHOLD) { fastCands.push_back(std::make_pair(ss, *i)); } if(ss.isNull() || ss->isOK()) { normCands.push_back(*i); } } if(fastCands.empty()) { if(normCands.empty()) { if(usedHosts.empty()) { // All URIs are inspected but aria2 cannot find usable one. // Return first URI anyway in this case. return uris.front(); } else { // If usedHosts is not empty, there is a possibility it // includes usable host. return A2STR::NIL; } } else { return normCands.front(); } } else { std::sort(fastCands.begin(), fastCands.end(), ServerStatFaster()); return fastCands.front().second; } } } // namespace aria2