/* */ #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" #include "fmt.h" namespace aria2 { FeedbackURISelector::FeedbackURISelector (const SharedHandle& serverStatMan) : serverStatMan_(serverStatMan) {} FeedbackURISelector::~FeedbackURISelector() {} std::string FeedbackURISelector::select (FileEntry* fileEntry, const std::vector >& usedHosts) { if(A2_LOG_DEBUG_ENABLED) { for(std::vector >::const_iterator i = usedHosts.begin(), eoi = usedHosts.end(); i != eoi; ++i) { A2_LOG_DEBUG(fmt("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()) { A2_LOG_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)); } A2_LOG_DEBUG(fmt("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_split_result us; if(uri_split(&us, (*i).c_str()) == -1) { continue; } std::string host = uri::getFieldString(us, USR_HOST, (*i).c_str()); std::string protocol = uri::getFieldString(us, USR_SCHEME, (*i).c_str()); SharedHandle ss = serverStatMan_->find(host, protocol); if(ss && ss->isError()) { A2_LOG_DEBUG(fmt("Error not considered: %s", (*i).c_str())); continue; } cands.push_back(std::make_pair(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 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_split_result us; if(uri_split(&us, (*i).c_str()) == -1) { continue; } std::string host = uri::getFieldString(us, USR_HOST, (*i).c_str()); if(findSecond(usedHosts.begin(), usedHosts.end(), host) != usedHosts.end()) { A2_LOG_DEBUG(fmt("%s is in usedHosts, not considered", (*i).c_str())); continue; } std::string protocol = uri::getFieldString(us, USR_SCHEME, (*i).c_str()); SharedHandle ss = serverStatMan_->find(host, protocol); if(!ss) { 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 { A2_LOG_DEBUG("Selected from normCands"); return normCands.front(); } } else { A2_LOG_DEBUG("Selected from fastCands"); std::sort(fastCands.begin(), fastCands.end(), ServerStatFaster()); return fastCands.front().second; } } } // namespace aria2