RequestGroupMan.cc 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "RequestGroupMan.h"
  36. #include <unistd.h>
  37. #include <cstring>
  38. #include <iomanip>
  39. #include <sstream>
  40. #include <numeric>
  41. #include <algorithm>
  42. #include <utility>
  43. #include "BtProgressInfoFile.h"
  44. #include "RecoverableException.h"
  45. #include "RequestGroup.h"
  46. #include "LogFactory.h"
  47. #include "Logger.h"
  48. #include "DownloadEngine.h"
  49. #include "message.h"
  50. #include "a2functional.h"
  51. #include "DownloadResult.h"
  52. #include "DownloadContext.h"
  53. #include "ServerStatMan.h"
  54. #include "ServerStat.h"
  55. #include "SegmentMan.h"
  56. #include "FeedbackURISelector.h"
  57. #include "InorderURISelector.h"
  58. #include "AdaptiveURISelector.h"
  59. #include "Option.h"
  60. #include "prefs.h"
  61. #include "File.h"
  62. #include "util.h"
  63. #include "Command.h"
  64. #include "FileEntry.h"
  65. #include "fmt.h"
  66. #include "FileAllocationEntry.h"
  67. #include "CheckIntegrityEntry.h"
  68. #include "Segment.h"
  69. #include "DlAbortEx.h"
  70. #include "uri.h"
  71. #include "Triplet.h"
  72. #include "Signature.h"
  73. #include "OutputFile.h"
  74. #include "download_helper.h"
  75. #include "UriListParser.h"
  76. #include "SingletonHolder.h"
  77. #include "Notifier.h"
  78. #include "PeerStat.h"
  79. #include "WrDiskCache.h"
  80. #ifdef ENABLE_BITTORRENT
  81. # include "bittorrent_helper.h"
  82. #endif // ENABLE_BITTORRENT
  83. namespace aria2 {
  84. namespace {
  85. template<typename InputIterator>
  86. void appendReservedGroup(RequestGroupList& list,
  87. InputIterator first, InputIterator last)
  88. {
  89. for(; first != last; ++first) {
  90. list.push_back((*first)->getGID(), *first);
  91. }
  92. }
  93. } // namespace
  94. RequestGroupMan::RequestGroupMan
  95. (const std::vector<SharedHandle<RequestGroup> >& requestGroups,
  96. int maxSimultaneousDownloads,
  97. const Option* option)
  98. : maxSimultaneousDownloads_(maxSimultaneousDownloads),
  99. option_(option),
  100. serverStatMan_(new ServerStatMan()),
  101. maxOverallDownloadSpeedLimit_
  102. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)),
  103. maxOverallUploadSpeedLimit_(option->getAsInt
  104. (PREF_MAX_OVERALL_UPLOAD_LIMIT)),
  105. rpc_(option->getAsBool(PREF_ENABLE_RPC)),
  106. queueCheck_(true),
  107. removedErrorResult_(0),
  108. removedLastErrorResult_(error_code::FINISHED),
  109. maxDownloadResult_(option->getAsInt(PREF_MAX_DOWNLOAD_RESULT)),
  110. wrDiskCache_(0)
  111. {
  112. appendReservedGroup(reservedGroups_,
  113. requestGroups.begin(), requestGroups.end());
  114. }
  115. RequestGroupMan::~RequestGroupMan()
  116. {
  117. delete wrDiskCache_;
  118. }
  119. bool RequestGroupMan::downloadFinished()
  120. {
  121. if(rpc_) {
  122. return false;
  123. }
  124. return requestGroups_.empty() && reservedGroups_.empty();
  125. }
  126. void RequestGroupMan::addRequestGroup
  127. (const SharedHandle<RequestGroup>& group)
  128. {
  129. requestGroups_.push_back(group->getGID(), group);
  130. }
  131. void RequestGroupMan::addReservedGroup
  132. (const std::vector<SharedHandle<RequestGroup> >& groups)
  133. {
  134. requestQueueCheck();
  135. appendReservedGroup(reservedGroups_, groups.begin(), groups.end());
  136. }
  137. void RequestGroupMan::addReservedGroup
  138. (const SharedHandle<RequestGroup>& group)
  139. {
  140. requestQueueCheck();
  141. reservedGroups_.push_back(group->getGID(), group);
  142. }
  143. namespace {
  144. struct RequestGroupKeyFunc {
  145. a2_gid_t operator()(const SharedHandle<RequestGroup>& rg) const
  146. {
  147. return rg->getGID();
  148. }
  149. };
  150. } // namespace
  151. void RequestGroupMan::insertReservedGroup
  152. (size_t pos, const std::vector<SharedHandle<RequestGroup> >& groups)
  153. {
  154. requestQueueCheck();
  155. pos = std::min(reservedGroups_.size(), pos);
  156. RequestGroupList::SeqType::iterator dest = reservedGroups_.begin();
  157. std::advance(dest, pos);
  158. reservedGroups_.insert(dest, RequestGroupKeyFunc(),
  159. groups.begin(), groups.end());
  160. }
  161. void RequestGroupMan::insertReservedGroup
  162. (size_t pos, const SharedHandle<RequestGroup>& group)
  163. {
  164. requestQueueCheck();
  165. pos = std::min(reservedGroups_.size(), pos);
  166. reservedGroups_.insert(pos, group->getGID(), group);
  167. }
  168. size_t RequestGroupMan::countRequestGroup() const
  169. {
  170. return requestGroups_.size();
  171. }
  172. SharedHandle<RequestGroup> RequestGroupMan::findGroup(a2_gid_t gid) const
  173. {
  174. SharedHandle<RequestGroup> rg = requestGroups_.get(gid);
  175. if(!rg) {
  176. rg = reservedGroups_.get(gid);
  177. }
  178. return rg;
  179. }
  180. size_t RequestGroupMan::changeReservedGroupPosition
  181. (a2_gid_t gid, int pos, A2_HOW how)
  182. {
  183. ssize_t dest = reservedGroups_.move(gid, pos, how);
  184. if(dest == -1) {
  185. throw DL_ABORT_EX(fmt("GID#%s not found in the waiting queue.",
  186. GroupId::toHex(gid).c_str()));
  187. } else {
  188. return dest;
  189. }
  190. }
  191. bool RequestGroupMan::removeReservedGroup(a2_gid_t gid)
  192. {
  193. return reservedGroups_.remove(gid);
  194. }
  195. namespace {
  196. void notifyDownloadEvent
  197. (const std::string& event, const SharedHandle<RequestGroup>& group)
  198. {
  199. // Check NULL to make unit test easier.
  200. Notifier* notifier = SingletonHolder<Notifier>::instance();
  201. if(notifier) {
  202. notifier->notifyDownloadEvent(event, group);
  203. }
  204. }
  205. } // namespace
  206. namespace {
  207. void executeStopHook
  208. (const SharedHandle<RequestGroup>& group,
  209. const Option* option,
  210. error_code::Value result)
  211. {
  212. if(result == error_code::FINISHED &&
  213. !option->blank(PREF_ON_DOWNLOAD_COMPLETE)) {
  214. util::executeHookByOptName(group, option, PREF_ON_DOWNLOAD_COMPLETE);
  215. } else if(result != error_code::IN_PROGRESS &&
  216. result != error_code::REMOVED &&
  217. !option->blank(PREF_ON_DOWNLOAD_ERROR)) {
  218. util::executeHookByOptName(group, option, PREF_ON_DOWNLOAD_ERROR);
  219. } else if(!option->blank(PREF_ON_DOWNLOAD_STOP)) {
  220. util::executeHookByOptName(group, option, PREF_ON_DOWNLOAD_STOP);
  221. }
  222. if(result == error_code::FINISHED) {
  223. notifyDownloadEvent(Notifier::ON_DOWNLOAD_COMPLETE, group);
  224. } else if(result != error_code::IN_PROGRESS &&
  225. result != error_code::REMOVED) {
  226. notifyDownloadEvent(Notifier::ON_DOWNLOAD_ERROR, group);
  227. } else {
  228. notifyDownloadEvent(Notifier::ON_DOWNLOAD_STOP, group);
  229. }
  230. }
  231. } // namespace
  232. namespace {
  233. class ProcessStoppedRequestGroup {
  234. private:
  235. DownloadEngine* e_;
  236. RequestGroupList& reservedGroups_;
  237. void saveSignature(const SharedHandle<RequestGroup>& group)
  238. {
  239. SharedHandle<Signature> sig =
  240. group->getDownloadContext()->getSignature();
  241. if(sig && !sig->getBody().empty()) {
  242. // filename of signature file is the path to download file followed by
  243. // ".sig".
  244. std::string signatureFile = group->getFirstFilePath()+".sig";
  245. if(sig->save(signatureFile)) {
  246. A2_LOG_NOTICE(fmt(MSG_SIGNATURE_SAVED, signatureFile.c_str()));
  247. } else {
  248. A2_LOG_NOTICE(fmt(MSG_SIGNATURE_NOT_SAVED, signatureFile.c_str()));
  249. }
  250. }
  251. }
  252. public:
  253. ProcessStoppedRequestGroup
  254. (DownloadEngine* e,
  255. RequestGroupList& reservedGroups)
  256. : e_(e),
  257. reservedGroups_(reservedGroups)
  258. {}
  259. void operator()(const RequestGroupList::SeqType::value_type& val)
  260. {
  261. const SharedHandle<RequestGroup>& group = val.second;
  262. if(group->getNumCommand() == 0) {
  263. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  264. // DownloadContext::resetDownloadStopTime() is only called when
  265. // download completed. If
  266. // DownloadContext::getDownloadStopTime().isZero() is true, then
  267. // there is a possibility that the download is error or
  268. // in-progress and resetDownloadStopTime() is not called. So
  269. // call it here.
  270. if(dctx->getDownloadStopTime().isZero()) {
  271. dctx->resetDownloadStopTime();
  272. }
  273. try {
  274. group->closeFile();
  275. if(group->isPauseRequested()) {
  276. A2_LOG_NOTICE
  277. (fmt(_("Download GID#%s paused"),
  278. GroupId::toHex(group->getGID()).c_str()));
  279. group->saveControlFile();
  280. } else if(group->downloadFinished() &&
  281. !group->getDownloadContext()->isChecksumVerificationNeeded()) {
  282. group->applyLastModifiedTimeToLocalFiles();
  283. group->reportDownloadFinished();
  284. if(group->allDownloadFinished()) {
  285. group->removeControlFile();
  286. saveSignature(group);
  287. } else {
  288. group->saveControlFile();
  289. }
  290. std::vector<SharedHandle<RequestGroup> > nextGroups;
  291. group->postDownloadProcessing(nextGroups);
  292. if(!nextGroups.empty()) {
  293. A2_LOG_DEBUG
  294. (fmt("Adding %lu RequestGroups as a result of"
  295. " PostDownloadHandler.",
  296. static_cast<unsigned long>(nextGroups.size())));
  297. e_->getRequestGroupMan()->insertReservedGroup(0, nextGroups);
  298. }
  299. #ifdef ENABLE_BITTORRENT
  300. // For in-memory download (e.g., Magnet URI), the
  301. // FileEntry::getPath() does not return actual file path, so
  302. // we don't remove it.
  303. if(group->getOption()->getAsBool(PREF_BT_REMOVE_UNSELECTED_FILE) &&
  304. !group->inMemoryDownload() &&
  305. dctx->hasAttribute(CTX_ATTR_BT)) {
  306. A2_LOG_INFO(fmt(MSG_REMOVING_UNSELECTED_FILE,
  307. GroupId::toHex(group->getGID()).c_str()));
  308. const std::vector<SharedHandle<FileEntry> >& files =
  309. dctx->getFileEntries();
  310. for(std::vector<SharedHandle<FileEntry> >::const_iterator i =
  311. files.begin(), eoi = files.end(); i != eoi; ++i) {
  312. if(!(*i)->isRequested()) {
  313. if(File((*i)->getPath()).remove()) {
  314. A2_LOG_INFO(fmt(MSG_FILE_REMOVED, (*i)->getPath().c_str()));
  315. } else {
  316. A2_LOG_INFO(fmt(MSG_FILE_COULD_NOT_REMOVED,
  317. (*i)->getPath().c_str()));
  318. }
  319. }
  320. }
  321. }
  322. #endif // ENABLE_BITTORRENT
  323. } else {
  324. A2_LOG_NOTICE
  325. (fmt(_("Download GID#%s not complete: %s"),
  326. GroupId::toHex(group->getGID()).c_str(),
  327. group->getDownloadContext()->getBasePath().c_str()));
  328. group->saveControlFile();
  329. }
  330. } catch(RecoverableException& ex) {
  331. A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, ex);
  332. }
  333. if(group->isPauseRequested()) {
  334. group->setState(RequestGroup::STATE_WAITING);
  335. reservedGroups_.push_front(group->getGID(), group);
  336. group->releaseRuntimeResource(e_);
  337. group->setForceHaltRequested(false);
  338. util::executeHookByOptName(group, e_->getOption(),
  339. PREF_ON_DOWNLOAD_PAUSE);
  340. notifyDownloadEvent(Notifier::ON_DOWNLOAD_PAUSE, group);
  341. // TODO Should we have to prepend spend uris to remaining uris
  342. // in case PREF_REUSE_URI is disabed?
  343. } else {
  344. SharedHandle<DownloadResult> dr = group->createDownloadResult();
  345. e_->getRequestGroupMan()->addDownloadResult(dr);
  346. executeStopHook(group, e_->getOption(), dr->result);
  347. group->releaseRuntimeResource(e_);
  348. }
  349. }
  350. }
  351. };
  352. } // namespace
  353. namespace {
  354. class CollectServerStat {
  355. private:
  356. RequestGroupMan* requestGroupMan_;
  357. public:
  358. CollectServerStat(RequestGroupMan* requestGroupMan):
  359. requestGroupMan_(requestGroupMan) {}
  360. void operator()(const RequestGroupList::SeqType::value_type& val)
  361. {
  362. const SharedHandle<RequestGroup>& group = val.second;
  363. if(group->getNumCommand() == 0) {
  364. // Collect statistics during download in PeerStats and update/register
  365. // ServerStatMan
  366. if(group->getSegmentMan()) {
  367. bool singleConnection =
  368. group->getSegmentMan()->getPeerStats().size() == 1;
  369. const std::vector<SharedHandle<PeerStat> >& peerStats =
  370. group->getSegmentMan()->getFastestPeerStats();
  371. for(std::vector<SharedHandle<PeerStat> >::const_iterator i =
  372. peerStats.begin(), eoi = peerStats.end(); i != eoi; ++i) {
  373. if((*i)->getHostname().empty() || (*i)->getProtocol().empty()) {
  374. continue;
  375. }
  376. int speed = (*i)->getAvgDownloadSpeed();
  377. if (speed == 0) continue;
  378. SharedHandle<ServerStat> ss =
  379. requestGroupMan_->getOrCreateServerStat((*i)->getHostname(),
  380. (*i)->getProtocol());
  381. ss->increaseCounter();
  382. ss->updateDownloadSpeed(speed);
  383. if(singleConnection) {
  384. ss->updateSingleConnectionAvgSpeed(speed);
  385. }
  386. else {
  387. ss->updateMultiConnectionAvgSpeed(speed);
  388. }
  389. }
  390. }
  391. }
  392. }
  393. };
  394. } // namespace
  395. void RequestGroupMan::updateServerStat()
  396. {
  397. std::for_each(requestGroups_.begin(), requestGroups_.end(),
  398. CollectServerStat(this));
  399. }
  400. void RequestGroupMan::removeStoppedGroup(DownloadEngine* e)
  401. {
  402. size_t numPrev = requestGroups_.size();
  403. updateServerStat();
  404. std::for_each(requestGroups_.begin(), requestGroups_.end(),
  405. ProcessStoppedRequestGroup(e, reservedGroups_));
  406. for(RequestGroupList::SeqType::iterator i = requestGroups_.begin(),
  407. eoi = requestGroups_.end(); i != eoi;) {
  408. const SharedHandle<RequestGroup>& rg = (*i).second;
  409. if(rg->getNumCommand() == 0) {
  410. i = requestGroups_.erase(i);
  411. eoi = requestGroups_.end();
  412. } else {
  413. ++i;
  414. }
  415. }
  416. size_t numRemoved = numPrev-requestGroups_.size();
  417. if(numRemoved > 0) {
  418. A2_LOG_DEBUG(fmt("%lu RequestGroup(s) deleted.",
  419. static_cast<unsigned long>(numRemoved)));
  420. }
  421. }
  422. void RequestGroupMan::configureRequestGroup
  423. (const SharedHandle<RequestGroup>& requestGroup) const
  424. {
  425. const std::string& uriSelectorValue =
  426. requestGroup->getOption()->get(PREF_URI_SELECTOR);
  427. SharedHandle<URISelector> sel;
  428. if(uriSelectorValue == V_FEEDBACK) {
  429. sel.reset(new FeedbackURISelector(serverStatMan_));
  430. } else if(uriSelectorValue == V_INORDER) {
  431. sel.reset(new InorderURISelector());
  432. } else if(uriSelectorValue == V_ADAPTIVE) {
  433. sel.reset(new AdaptiveURISelector(serverStatMan_, requestGroup.get()));
  434. }
  435. if(sel) {
  436. requestGroup->setURISelector(sel);
  437. }
  438. }
  439. namespace {
  440. void createInitialCommand(const SharedHandle<RequestGroup>& requestGroup,
  441. std::vector<Command*>& commands,
  442. DownloadEngine* e)
  443. {
  444. requestGroup->createInitialCommand(commands, e);
  445. }
  446. } // namespace
  447. void RequestGroupMan::fillRequestGroupFromReserver(DownloadEngine* e)
  448. {
  449. removeStoppedGroup(e);
  450. if(static_cast<size_t>(maxSimultaneousDownloads_) <= requestGroups_.size()) {
  451. return;
  452. }
  453. int count = 0;
  454. int num = maxSimultaneousDownloads_-requestGroups_.size();
  455. std::vector<SharedHandle<RequestGroup> > pending;
  456. while(count < num && (uriListParser_ || !reservedGroups_.empty())) {
  457. if(uriListParser_ && reservedGroups_.empty()) {
  458. std::vector<SharedHandle<RequestGroup> > groups;
  459. // May throw exception
  460. bool ok = createRequestGroupFromUriListParser(groups, option_,
  461. uriListParser_.get());
  462. if(ok) {
  463. appendReservedGroup(reservedGroups_, groups.begin(), groups.end());
  464. } else {
  465. uriListParser_.reset();
  466. if(reservedGroups_.empty()) {
  467. break;
  468. }
  469. }
  470. }
  471. SharedHandle<RequestGroup> groupToAdd = (*reservedGroups_.begin()).second;
  472. reservedGroups_.pop_front();
  473. if((rpc_ && groupToAdd->isPauseRequested()) ||
  474. !groupToAdd->isDependencyResolved()) {
  475. pending.push_back(groupToAdd);
  476. continue;
  477. }
  478. // Drop pieceStorage here because paused download holds its
  479. // reference.
  480. groupToAdd->dropPieceStorage();
  481. configureRequestGroup(groupToAdd);
  482. groupToAdd->setRequestGroupMan(this);
  483. std::vector<Command*> commands;
  484. try {
  485. createInitialCommand(groupToAdd, commands, e);
  486. ++count;
  487. } catch(RecoverableException& ex) {
  488. A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, ex);
  489. A2_LOG_DEBUG("Deleting temporal commands.");
  490. std::for_each(commands.begin(), commands.end(), Deleter());
  491. commands.clear();
  492. A2_LOG_DEBUG("Commands deleted");
  493. groupToAdd->setLastErrorCode(ex.getErrorCode());
  494. // We add groupToAdd to e later in order to it is processed in
  495. // removeStoppedGroup().
  496. }
  497. if(commands.empty()) {
  498. requestQueueCheck();
  499. } else {
  500. e->addCommand(commands);
  501. }
  502. groupToAdd->setState(RequestGroup::STATE_ACTIVE);
  503. requestGroups_.push_back(groupToAdd->getGID(), groupToAdd);
  504. util::executeHookByOptName(groupToAdd, e->getOption(),
  505. PREF_ON_DOWNLOAD_START);
  506. notifyDownloadEvent(Notifier::ON_DOWNLOAD_START, groupToAdd);
  507. }
  508. if(!pending.empty()) {
  509. reservedGroups_.insert(reservedGroups_.begin(), RequestGroupKeyFunc(),
  510. pending.begin(), pending.end());
  511. }
  512. if(count > 0) {
  513. e->setNoWait(true);
  514. e->setRefreshInterval(0);
  515. A2_LOG_DEBUG(fmt("%d RequestGroup(s) added.", count));
  516. }
  517. }
  518. void RequestGroupMan::save()
  519. {
  520. for(RequestGroupList::SeqType::iterator itr = requestGroups_.begin(),
  521. eoi = requestGroups_.end(); itr != eoi; ++itr) {
  522. const SharedHandle<RequestGroup>& rg = (*itr).second;
  523. if(rg->allDownloadFinished() &&
  524. !rg->getDownloadContext()->isChecksumVerificationNeeded()) {
  525. rg->removeControlFile();
  526. } else {
  527. try {
  528. rg->saveControlFile();
  529. } catch(RecoverableException& e) {
  530. A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, e);
  531. }
  532. }
  533. }
  534. }
  535. void RequestGroupMan::closeFile()
  536. {
  537. for(RequestGroupList::SeqType::iterator itr = requestGroups_.begin(),
  538. eoi = requestGroups_.end(); itr != eoi; ++itr) {
  539. (*itr).second->closeFile();
  540. }
  541. }
  542. RequestGroupMan::DownloadStat RequestGroupMan::getDownloadStat() const
  543. {
  544. int finished = 0;
  545. int error = removedErrorResult_;
  546. int inprogress = 0;
  547. int removed = 0;
  548. error_code::Value lastError = removedLastErrorResult_;
  549. for(DownloadResultList::SeqType::const_iterator itr =
  550. downloadResults_.begin(), eoi = downloadResults_.end(); itr != eoi;
  551. ++itr) {
  552. const SharedHandle<DownloadResult>& dr = (*itr).second;
  553. if(dr->belongsTo != 0) {
  554. continue;
  555. }
  556. if(dr->result == error_code::FINISHED) {
  557. ++finished;
  558. } else if(dr->result == error_code::IN_PROGRESS) {
  559. ++inprogress;
  560. } else if(dr->result == error_code::REMOVED) {
  561. ++removed;
  562. } else {
  563. ++error;
  564. lastError = dr->result;
  565. }
  566. }
  567. return DownloadStat(finished, error, inprogress, removed,
  568. reservedGroups_.size(),
  569. lastError);
  570. }
  571. enum DownloadStatus {
  572. A2_STATUS_OK,
  573. A2_STATUS_INPR,
  574. A2_STATUS_RM,
  575. A2_STATUS_ERR
  576. };
  577. namespace {
  578. const char* getStatusStr(DownloadStatus status, bool useColor)
  579. {
  580. // status string is formatted in 4 characters wide.
  581. switch(status) {
  582. case(A2_STATUS_OK):
  583. if(useColor) {
  584. return "\033[1;32mOK\033[0m ";
  585. } else {
  586. return "OK ";
  587. }
  588. case(A2_STATUS_INPR):
  589. if(useColor) {
  590. return "\033[1;34mINPR\033[0m";
  591. } else {
  592. return "INPR";
  593. }
  594. case(A2_STATUS_RM):
  595. if(useColor) {
  596. return "\033[1mRM\033[0m ";
  597. } else {
  598. return "RM ";
  599. }
  600. case(A2_STATUS_ERR):
  601. if(useColor) {
  602. return "\033[1;31mERR\033[0m ";
  603. } else {
  604. return "ERR ";
  605. }
  606. default:
  607. return "";
  608. }
  609. }
  610. } // namespace
  611. void RequestGroupMan::showDownloadResults(OutputFile& o, bool full) const
  612. {
  613. int pathRowSize = 55;
  614. // Download Results:
  615. // idx|stat|path/length
  616. // ===+====+=======================================================================
  617. o.printf("\n%s"
  618. "\ngid |stat|avg speed |",
  619. _("Download Results:"));
  620. if(full) {
  621. o.write(" %|path/URI"
  622. "\n======+====+===========+===+");
  623. pathRowSize -= 4;
  624. } else {
  625. o.write("path/URI"
  626. "\n======+====+===========+");
  627. }
  628. std::string line(pathRowSize, '=');
  629. o.printf("%s\n", line.c_str());
  630. bool useColor = o.supportsColor();
  631. int ok = 0;
  632. int err = 0;
  633. int inpr = 0;
  634. int rm = 0;
  635. for(DownloadResultList::SeqType::const_iterator itr =
  636. downloadResults_.begin(), eoi = downloadResults_.end(); itr != eoi;
  637. ++itr) {
  638. const SharedHandle<DownloadResult>& dr = (*itr).second;
  639. if(dr->belongsTo != 0) {
  640. continue;
  641. }
  642. const char* status;
  643. switch(dr->result) {
  644. case error_code::FINISHED:
  645. status = getStatusStr(A2_STATUS_OK, useColor);
  646. ++ok;
  647. break;
  648. case error_code::IN_PROGRESS:
  649. status = getStatusStr(A2_STATUS_INPR, useColor);
  650. ++inpr;
  651. break;
  652. case error_code::REMOVED:
  653. status = getStatusStr(A2_STATUS_RM, useColor);
  654. ++rm;
  655. break;
  656. default:
  657. status = getStatusStr(A2_STATUS_ERR, useColor);
  658. ++err;
  659. }
  660. if(full) {
  661. formatDownloadResultFull(o, status, dr);
  662. } else {
  663. o.write(formatDownloadResult(status, dr).c_str());
  664. o.write("\n");
  665. }
  666. }
  667. if(ok > 0 || err > 0 || inpr > 0 || rm > 0) {
  668. o.printf("\n%s\n", _("Status Legend:"));
  669. if(ok > 0) {
  670. o.write(_("(OK):download completed."));
  671. }
  672. if(err > 0) {
  673. o.write(_("(ERR):error occurred."));
  674. }
  675. if(inpr > 0) {
  676. o.write(_("(INPR):download in-progress."));
  677. }
  678. if(rm > 0) {
  679. o.write(_("(RM):download removed."));
  680. }
  681. o.write("\n");
  682. }
  683. }
  684. namespace {
  685. void formatDownloadResultCommon
  686. (std::ostream& o,
  687. const char* status,
  688. const SharedHandle<DownloadResult>& downloadResult)
  689. {
  690. o << std::setw(3) << downloadResult->gid->toAbbrevHex() << "|"
  691. << std::setw(4) << status << "|"
  692. << std::setw(11);
  693. if(downloadResult->sessionTime > 0) {
  694. o << util::abbrevSize
  695. (downloadResult->sessionDownloadLength*1000/downloadResult->sessionTime)+
  696. "B/s";
  697. } else {
  698. o << "n/a";
  699. }
  700. o << "|";
  701. }
  702. } // namespace
  703. void RequestGroupMan::formatDownloadResultFull
  704. (OutputFile& out,
  705. const char* status,
  706. const SharedHandle<DownloadResult>& downloadResult) const
  707. {
  708. BitfieldMan bt(downloadResult->pieceLength, downloadResult->totalLength);
  709. bt.setBitfield(reinterpret_cast<const unsigned char*>
  710. (downloadResult->bitfield.data()),
  711. downloadResult->bitfield.size());
  712. bool head = true;
  713. const std::vector<SharedHandle<FileEntry> >& fileEntries =
  714. downloadResult->fileEntries;
  715. for(std::vector<SharedHandle<FileEntry> >::const_iterator i =
  716. fileEntries.begin(), eoi = fileEntries.end(); i != eoi; ++i) {
  717. if(!(*i)->isRequested()) {
  718. continue;
  719. }
  720. std::stringstream o;
  721. if(head) {
  722. formatDownloadResultCommon(o, status, downloadResult);
  723. head = false;
  724. } else {
  725. o << " | | |";
  726. }
  727. if((*i)->getLength() == 0 || downloadResult->bitfield.empty()) {
  728. o << " -|";
  729. } else {
  730. int64_t completedLength =
  731. bt.getOffsetCompletedLength((*i)->getOffset(), (*i)->getLength());
  732. o << std::setw(3) << 100*completedLength/(*i)->getLength() << "|";
  733. }
  734. writeFilePath(o, *i, downloadResult->inMemoryDownload);
  735. o << "\n";
  736. out.write(o.str().c_str());
  737. }
  738. if(head) {
  739. std::stringstream o;
  740. formatDownloadResultCommon(o, status, downloadResult);
  741. o << " -|n/a\n";
  742. out.write(o.str().c_str());
  743. }
  744. }
  745. std::string RequestGroupMan::formatDownloadResult
  746. (const char* status,
  747. const SharedHandle<DownloadResult>& downloadResult) const
  748. {
  749. std::stringstream o;
  750. formatDownloadResultCommon(o, status, downloadResult);
  751. const std::vector<SharedHandle<FileEntry> >& fileEntries =
  752. downloadResult->fileEntries;
  753. writeFilePath(fileEntries.begin(), fileEntries.end(), o,
  754. downloadResult->inMemoryDownload);
  755. return o.str();
  756. }
  757. namespace {
  758. template<typename StringInputIterator, typename FileEntryInputIterator>
  759. bool sameFilePathExists(StringInputIterator sfirst,
  760. StringInputIterator slast,
  761. FileEntryInputIterator ffirst,
  762. FileEntryInputIterator flast)
  763. {
  764. for(; ffirst != flast; ++ffirst) {
  765. if(std::binary_search(sfirst, slast, (*ffirst)->getPath())) {
  766. return true;
  767. }
  768. }
  769. return false;
  770. }
  771. } // namespace
  772. bool RequestGroupMan::isSameFileBeingDownloaded(RequestGroup* requestGroup) const
  773. {
  774. // TODO it may be good to use dedicated method rather than use
  775. // isPreLocalFileCheckEnabled
  776. if(!requestGroup->isPreLocalFileCheckEnabled()) {
  777. return false;
  778. }
  779. std::vector<std::string> files;
  780. for(RequestGroupList::SeqType::const_iterator itr = requestGroups_.begin(),
  781. eoi = requestGroups_.end(); itr != eoi; ++itr) {
  782. const SharedHandle<RequestGroup>& rg = (*itr).second;
  783. if(rg.get() != requestGroup) {
  784. const std::vector<SharedHandle<FileEntry> >& entries =
  785. rg->getDownloadContext()->getFileEntries();
  786. std::transform(entries.begin(), entries.end(),
  787. std::back_inserter(files),
  788. mem_fun_sh(&FileEntry::getPath));
  789. }
  790. }
  791. std::sort(files.begin(), files.end());
  792. const std::vector<SharedHandle<FileEntry> >& entries =
  793. requestGroup->getDownloadContext()->getFileEntries();
  794. return sameFilePathExists(files.begin(), files.end(),
  795. entries.begin(), entries.end());
  796. }
  797. void RequestGroupMan::halt()
  798. {
  799. for(RequestGroupList::SeqType::const_iterator i = requestGroups_.begin(),
  800. eoi = requestGroups_.end(); i != eoi; ++i) {
  801. (*i).second->setHaltRequested(true);
  802. }
  803. }
  804. void RequestGroupMan::forceHalt()
  805. {
  806. for(RequestGroupList::SeqType::const_iterator i = requestGroups_.begin(),
  807. eoi = requestGroups_.end(); i != eoi; ++i) {
  808. (*i).second->setForceHaltRequested(true);
  809. }
  810. }
  811. TransferStat RequestGroupMan::calculateStat()
  812. {
  813. // TODO Currently, all time upload length is not set.
  814. return netStat_.toTransferStat();
  815. }
  816. SharedHandle<DownloadResult>
  817. RequestGroupMan::findDownloadResult(a2_gid_t gid) const
  818. {
  819. return downloadResults_.get(gid);
  820. }
  821. bool RequestGroupMan::removeDownloadResult(a2_gid_t gid)
  822. {
  823. return downloadResults_.remove(gid);
  824. }
  825. void RequestGroupMan::addDownloadResult(const SharedHandle<DownloadResult>& dr)
  826. {
  827. bool rv = downloadResults_.push_back(dr->gid->getNumericId(), dr);
  828. assert(rv);
  829. while(downloadResults_.size() > maxDownloadResult_){
  830. DownloadResultList::SeqType::iterator i = downloadResults_.begin();
  831. const SharedHandle<DownloadResult>& dr = (*i).second;
  832. if(dr->belongsTo == 0 && dr->result != error_code::FINISHED) {
  833. removedLastErrorResult_ = dr->result;
  834. ++removedErrorResult_;
  835. }
  836. }
  837. }
  838. void RequestGroupMan::purgeDownloadResult()
  839. {
  840. downloadResults_.clear();
  841. }
  842. SharedHandle<ServerStat>
  843. RequestGroupMan::findServerStat(const std::string& hostname,
  844. const std::string& protocol) const
  845. {
  846. return serverStatMan_->find(hostname, protocol);
  847. }
  848. SharedHandle<ServerStat>
  849. RequestGroupMan::getOrCreateServerStat(const std::string& hostname,
  850. const std::string& protocol)
  851. {
  852. SharedHandle<ServerStat> ss = findServerStat(hostname, protocol);
  853. if(!ss) {
  854. ss.reset(new ServerStat(hostname, protocol));
  855. addServerStat(ss);
  856. }
  857. return ss;
  858. }
  859. bool RequestGroupMan::addServerStat(const SharedHandle<ServerStat>& serverStat)
  860. {
  861. return serverStatMan_->add(serverStat);
  862. }
  863. bool RequestGroupMan::loadServerStat(const std::string& filename)
  864. {
  865. return serverStatMan_->load(filename);
  866. }
  867. bool RequestGroupMan::saveServerStat(const std::string& filename) const
  868. {
  869. return serverStatMan_->save(filename);
  870. }
  871. void RequestGroupMan::removeStaleServerStat(time_t timeout)
  872. {
  873. serverStatMan_->removeStaleServerStat(timeout);
  874. }
  875. bool RequestGroupMan::doesOverallDownloadSpeedExceed()
  876. {
  877. return maxOverallDownloadSpeedLimit_ > 0 &&
  878. maxOverallDownloadSpeedLimit_ < netStat_.calculateDownloadSpeed();
  879. }
  880. bool RequestGroupMan::doesOverallUploadSpeedExceed()
  881. {
  882. return maxOverallUploadSpeedLimit_ > 0 &&
  883. maxOverallUploadSpeedLimit_ < netStat_.calculateUploadSpeed();
  884. }
  885. void RequestGroupMan::getUsedHosts
  886. (std::vector<std::pair<size_t, std::string> >& usedHosts)
  887. {
  888. // vector of triplet which consists of use count, -download speed,
  889. // hostname. We want to sort by least used and faster download
  890. // speed. We use -download speed so that we can sort them using
  891. // operator<().
  892. std::vector<Triplet<size_t, int, std::string> > tempHosts;
  893. for(RequestGroupList::SeqType::const_iterator i = requestGroups_.begin(),
  894. eoi = requestGroups_.end(); i != eoi; ++i) {
  895. const SharedHandle<RequestGroup>& rg = (*i).second;
  896. const FileEntry::InFlightRequestSet& inFlightReqs =
  897. rg->getDownloadContext()->getFirstFileEntry()->getInFlightRequests();
  898. for(FileEntry::InFlightRequestSet::iterator j =
  899. inFlightReqs.begin(), eoj = inFlightReqs.end(); j != eoj; ++j) {
  900. uri_split_result us;
  901. if(uri_split(&us, (*j)->getUri().c_str()) == 0) {
  902. std::vector<Triplet<size_t, int, std::string> >::iterator k;
  903. std::vector<Triplet<size_t, int, std::string> >::iterator eok =
  904. tempHosts.end();
  905. std::string host = uri::getFieldString(us, USR_HOST,
  906. (*j)->getUri().c_str());
  907. for(k = tempHosts.begin(); k != eok; ++k) {
  908. if((*k).third == host) {
  909. ++(*k).first;
  910. break;
  911. }
  912. }
  913. if(k == eok) {
  914. std::string protocol = uri::getFieldString(us, USR_SCHEME,
  915. (*j)->getUri().c_str());
  916. SharedHandle<ServerStat> ss = findServerStat(host, protocol);
  917. int invDlSpeed = (ss && ss->isOK()) ?
  918. -(static_cast<int>(ss->getDownloadSpeed())) : 0;
  919. tempHosts.push_back(makeTriplet(1, invDlSpeed, host));
  920. }
  921. }
  922. }
  923. }
  924. std::sort(tempHosts.begin(), tempHosts.end());
  925. std::transform(tempHosts.begin(), tempHosts.end(),
  926. std::back_inserter(usedHosts), Tuple2Pair<1, 3>());
  927. }
  928. void RequestGroupMan::setUriListParser
  929. (const SharedHandle<UriListParser>& uriListParser)
  930. {
  931. uriListParser_ = uriListParser;
  932. }
  933. void RequestGroupMan::initWrDiskCache()
  934. {
  935. assert(wrDiskCache_ == 0);
  936. size_t limit = option_->getAsInt(PREF_DISK_CACHE);
  937. if(limit > 0) {
  938. wrDiskCache_ = new WrDiskCache(limit);
  939. }
  940. }
  941. } // namespace aria2