/* */ #include "FeedbackURISelector.h" #include #include #include "ServerStatMan.h" #include "ServerStat.h" #include "A2STR.h" #include "FileEntry.h" #include "Logger.h" #include "LogFactory.h" #include "a2algo.h" #include "uri.h" namespace aria2 { FeedbackURISelector::FeedbackURISelector (const SharedHandle& serverStatMan): serverStatMan_(serverStatMan), logger_(LogFactory::getInstance()) {} 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(); } }; } std::string FeedbackURISelector::select (FileEntry* fileEntry, const std::vector >& usedHosts) { if(logger_->debug()) { for(std::vector >::const_iterator i = usedHosts.begin(), eoi = usedHosts.end(); i != eoi; ++i) { logger_->debug("UsedHost=%lu, %s", static_cast((*i).first), (*i).second.c_str()); } } 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 = selectFaster(fileEntry->getRemainingUris(), usedHosts); if(uri.empty()) { if(logger_->debug()) { logger_->debug("No URI returned from selectFaster()"); } uri = selectRarer(fileEntry->getRemainingUris(), usedHosts); } if(!uri.empty()) { std::deque& uris = fileEntry->getRemainingUris(); uris.erase(std::find(uris.begin(), uris.end(), uri)); } if(logger_->debug()) { logger_->debug("FeedbackURISelector selected %s", uri.c_str()); } return uri; } std::string FeedbackURISelector::selectRarer (const std::deque& uris, const std::vector >& usedHosts) { // pair of host and URI std::vector > cands; for(std::deque::const_iterator i = uris.begin(), eoi = uris.end(); i != eoi; ++i) { uri::UriStruct us; if(!uri::parse(us, *i)) { continue; } SharedHandle ss = serverStatMan_->find(us.host, us.protocol); if(!ss.isNull() && ss->isError()) { if(logger_->debug()) { logger_->debug("Error not considered: %s", (*i).c_str()); } continue; } cands.push_back(std::make_pair(us.host, *i)); } for(std::vector >::const_iterator i = usedHosts.begin(), eoi = usedHosts.end(); i != eoi; ++i) { for(std::vector >::const_iterator j = cands.begin(), eoj = cands.end(); j != eoj; ++j) { if((*i).second == (*j).first) { return (*j).second; } } } assert(!uris.empty()); return uris.front(); } std::string FeedbackURISelector::selectFaster (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) { uri::UriStruct us; if(!uri::parse(us, *i)) { continue; } if(findSecond(usedHosts.begin(), usedHosts.end(), us.host) != usedHosts.end()) { if(logger_->debug()) { logger_->debug("%s is in usedHosts, not considered", (*i).c_str()); } continue; } SharedHandle ss = serverStatMan_->find(us.host, us.protocol); if(ss.isNull()) { normCands.push_back(*i); } else if(ss->isOK()) { if(ss->getDownloadSpeed() > SPEED_THRESHOLD) { fastCands.push_back(std::make_pair(ss, *i)); } else { normCands.push_back(*i); } } } if(fastCands.empty()) { if(normCands.empty()) { return A2STR::NIL; } else { if(logger_->debug()) { logger_->debug("Selected from normCands"); } return normCands.front(); } } else { if(logger_->debug()) { logger_->debug("Selected from fastCands"); } std::sort(fastCands.begin(), fastCands.end(), ServerStatFaster()); return fastCands.front().second; } } } // namespace aria2