SegmentMan.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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 "SegmentMan.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include <numeric>
  39. #include "util.h"
  40. #include "message.h"
  41. #include "prefs.h"
  42. #include "PiecedSegment.h"
  43. #include "GrowSegment.h"
  44. #include "LogFactory.h"
  45. #include "Logger.h"
  46. #include "PieceStorage.h"
  47. #include "PeerStat.h"
  48. #include "Option.h"
  49. #include "DownloadContext.h"
  50. #include "Piece.h"
  51. #include "FileEntry.h"
  52. #include "wallclock.h"
  53. #include "fmt.h"
  54. namespace aria2 {
  55. SegmentEntry::SegmentEntry(cuid_t cuid, const SharedHandle<Segment>& segment)
  56. : cuid(cuid), segment(segment)
  57. {}
  58. SegmentEntry::~SegmentEntry() {}
  59. SegmentMan::SegmentMan
  60. (const Option* option,
  61. const SharedHandle<DownloadContext>& downloadContext,
  62. const PieceStorageHandle& pieceStorage)
  63. : option_(option),
  64. downloadContext_(downloadContext),
  65. pieceStorage_(pieceStorage),
  66. lastPeerStatDlspdMapUpdated_(0),
  67. cachedDlspd_(0),
  68. ignoreBitfield_(downloadContext->getPieceLength(),
  69. downloadContext->getTotalLength())
  70. {
  71. ignoreBitfield_.enableFilter();
  72. }
  73. SegmentMan::~SegmentMan() {}
  74. bool SegmentMan::downloadFinished() const
  75. {
  76. if(!pieceStorage_) {
  77. return false;
  78. } else {
  79. return pieceStorage_->downloadFinished();
  80. }
  81. }
  82. void SegmentMan::init()
  83. {
  84. // TODO Do we have to do something about DownloadContext and
  85. // PieceStorage here?
  86. }
  87. uint64_t SegmentMan::getTotalLength() const
  88. {
  89. if(!pieceStorage_) {
  90. return 0;
  91. } else {
  92. return pieceStorage_->getTotalLength();
  93. }
  94. }
  95. void SegmentMan::setPieceStorage(const PieceStorageHandle& pieceStorage)
  96. {
  97. pieceStorage_ = pieceStorage;
  98. }
  99. void SegmentMan::setDownloadContext
  100. (const SharedHandle<DownloadContext>& downloadContext)
  101. {
  102. downloadContext_ = downloadContext;
  103. }
  104. SharedHandle<Segment> SegmentMan::checkoutSegment
  105. (cuid_t cuid, const SharedHandle<Piece>& piece)
  106. {
  107. if(!piece) {
  108. return SharedHandle<Segment>();
  109. }
  110. A2_LOG_DEBUG(fmt("Attach segment#%lu to CUID#%lld.",
  111. static_cast<unsigned long>(piece->getIndex()),
  112. cuid));
  113. piece->setUsedBySegment(true);
  114. SharedHandle<Segment> segment;
  115. if(piece->getLength() == 0) {
  116. segment.reset(new GrowSegment(piece));
  117. } else {
  118. segment.reset(new PiecedSegment(downloadContext_->getPieceLength(), piece));
  119. }
  120. SegmentEntryHandle entry(new SegmentEntry(cuid, segment));
  121. usedSegmentEntries_.push_back(entry);
  122. A2_LOG_DEBUG(fmt("index=%lu, length=%lu, segmentLength=%lu,"
  123. " writtenLength=%lu",
  124. static_cast<unsigned long>(segment->getIndex()),
  125. static_cast<unsigned long>(segment->getLength()),
  126. static_cast<unsigned long>(segment->getSegmentLength()),
  127. static_cast<unsigned long>(segment->getWrittenLength())));
  128. if(piece->getLength() > 0) {
  129. std::map<size_t, size_t>::iterator positr =
  130. segmentWrittenLengthMemo_.find(segment->getIndex());
  131. if(positr != segmentWrittenLengthMemo_.end()) {
  132. const size_t writtenLength = (*positr).second;
  133. A2_LOG_DEBUG(fmt("writtenLength(in memo)=%lu, writtenLength=%lu",
  134. static_cast<unsigned long>(writtenLength),
  135. static_cast<unsigned long>(segment->getWrittenLength()))
  136. );
  137. // If the difference between cached writtenLength and segment's
  138. // writtenLength is less than one block, we assume that these
  139. // missing bytes are already downloaded.
  140. if(segment->getWrittenLength() < writtenLength &&
  141. writtenLength-segment->getWrittenLength() < piece->getBlockLength()) {
  142. segment->updateWrittenLength(writtenLength-segment->getWrittenLength());
  143. }
  144. }
  145. }
  146. return segment;
  147. }
  148. void SegmentMan::getInFlightSegment
  149. (std::vector<SharedHandle<Segment> >& segments, cuid_t cuid)
  150. {
  151. for(SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
  152. eoi = usedSegmentEntries_.end(); itr != eoi; ++itr) {
  153. const SegmentEntryHandle& segmentEntry = *itr;
  154. if(segmentEntry->cuid == cuid) {
  155. segments.push_back(segmentEntry->segment);
  156. }
  157. }
  158. }
  159. SharedHandle<Segment> SegmentMan::getSegment(cuid_t cuid, size_t minSplitSize)
  160. {
  161. SharedHandle<Piece> piece =
  162. pieceStorage_->getMissingPiece
  163. (minSplitSize,
  164. ignoreBitfield_.getFilterBitfield(), ignoreBitfield_.getBitfieldLength(),
  165. cuid);
  166. return checkoutSegment(cuid, piece);
  167. }
  168. void SegmentMan::getSegment
  169. (std::vector<SharedHandle<Segment> >& segments,
  170. cuid_t cuid,
  171. size_t minSplitSize,
  172. const SharedHandle<FileEntry>& fileEntry,
  173. size_t maxSegments)
  174. {
  175. BitfieldMan filter(ignoreBitfield_);
  176. filter.enableFilter();
  177. filter.addNotFilter(fileEntry->getOffset(), fileEntry->getLength());
  178. std::vector<SharedHandle<Segment> > pending;
  179. while(segments.size() < maxSegments) {
  180. SharedHandle<Segment> segment =
  181. checkoutSegment(cuid,
  182. pieceStorage_->getMissingPiece
  183. (minSplitSize,
  184. filter.getFilterBitfield(), filter.getBitfieldLength(),
  185. cuid));
  186. if(!segment) {
  187. break;
  188. }
  189. if(segment->getPositionToWrite() < fileEntry->getOffset() ||
  190. fileEntry->getLastOffset() <= segment->getPositionToWrite()) {
  191. pending.push_back(segment);
  192. } else {
  193. segments.push_back(segment);
  194. }
  195. }
  196. for(std::vector<SharedHandle<Segment> >::const_iterator i = pending.begin(),
  197. eoi = pending.end(); i != eoi; ++i) {
  198. cancelSegment(cuid, *i);
  199. }
  200. }
  201. SharedHandle<Segment> SegmentMan::getSegmentWithIndex
  202. (cuid_t cuid, size_t index) {
  203. if(index > 0 && downloadContext_->getNumPieces() <= index) {
  204. return SharedHandle<Segment>();
  205. }
  206. return checkoutSegment(cuid, pieceStorage_->getMissingPiece(index, cuid));
  207. }
  208. SharedHandle<Segment> SegmentMan::getCleanSegmentIfOwnerIsIdle
  209. (cuid_t cuid, size_t index)
  210. {
  211. if(index > 0 && downloadContext_->getNumPieces() <= index) {
  212. return SharedHandle<Segment>();
  213. }
  214. for(SegmentEntries::const_iterator itr = usedSegmentEntries_.begin(),
  215. eoi = usedSegmentEntries_.end(); itr != eoi; ++itr) {
  216. const SharedHandle<SegmentEntry>& segmentEntry = *itr;
  217. if(segmentEntry->segment->getIndex() == index) {
  218. if(segmentEntry->segment->getWrittenLength() > 0) {
  219. return SharedHandle<Segment>();
  220. }
  221. if(segmentEntry->cuid == cuid) {
  222. return segmentEntry->segment;
  223. }
  224. cuid_t owner = segmentEntry->cuid;
  225. SharedHandle<PeerStat> ps = getPeerStat(owner);
  226. if(!ps || ps->getStatus() == PeerStat::IDLE) {
  227. cancelSegment(owner);
  228. return getSegmentWithIndex(cuid, index);
  229. } else {
  230. return SharedHandle<Segment>();
  231. }
  232. }
  233. }
  234. return SharedHandle<Segment>();
  235. }
  236. void SegmentMan::cancelSegmentInternal
  237. (cuid_t cuid,
  238. const SharedHandle<Segment>& segment)
  239. {
  240. A2_LOG_DEBUG(fmt("Canceling segment#%lu",
  241. static_cast<unsigned long>(segment->getIndex())));
  242. segment->getPiece()->setUsedBySegment(false);
  243. pieceStorage_->cancelPiece(segment->getPiece(), cuid);
  244. segmentWrittenLengthMemo_[segment->getIndex()] = segment->getWrittenLength();
  245. A2_LOG_DEBUG(fmt("Memorized segment index=%lu, writtenLength=%lu",
  246. static_cast<unsigned long>(segment->getIndex()),
  247. static_cast<unsigned long>(segment->getWrittenLength())));
  248. }
  249. void SegmentMan::cancelSegment(cuid_t cuid) {
  250. for(SegmentEntries::iterator itr = usedSegmentEntries_.begin(),
  251. eoi = usedSegmentEntries_.end(); itr != eoi;) {
  252. if((*itr)->cuid == cuid) {
  253. cancelSegmentInternal(cuid, (*itr)->segment);
  254. itr = usedSegmentEntries_.erase(itr);
  255. eoi = usedSegmentEntries_.end();
  256. } else {
  257. ++itr;
  258. }
  259. }
  260. }
  261. void SegmentMan::cancelSegment
  262. (cuid_t cuid, const SharedHandle<Segment>& segment)
  263. {
  264. for(SegmentEntries::iterator itr = usedSegmentEntries_.begin(),
  265. eoi = usedSegmentEntries_.end(); itr != eoi;) {
  266. if((*itr)->cuid == cuid && *(*itr)->segment == *segment) {
  267. cancelSegmentInternal(cuid, (*itr)->segment);
  268. itr = usedSegmentEntries_.erase(itr);
  269. break;
  270. } else {
  271. ++itr;
  272. }
  273. }
  274. }
  275. void SegmentMan::cancelAllSegments()
  276. {
  277. for(std::deque<SharedHandle<SegmentEntry> >::iterator itr =
  278. usedSegmentEntries_.begin(), eoi = usedSegmentEntries_.end();
  279. itr != eoi; ++itr) {
  280. cancelSegmentInternal((*itr)->cuid, (*itr)->segment);
  281. }
  282. usedSegmentEntries_.clear();
  283. }
  284. void SegmentMan::eraseSegmentWrittenLengthMemo()
  285. {
  286. segmentWrittenLengthMemo_.clear();
  287. }
  288. namespace {
  289. class FindSegmentEntry {
  290. private:
  291. SharedHandle<Segment> segment_;
  292. public:
  293. FindSegmentEntry(const SharedHandle<Segment>& segment):segment_(segment) {}
  294. bool operator()(const SegmentEntryHandle& segmentEntry) const
  295. {
  296. return segmentEntry->segment->getIndex() == segment_->getIndex();
  297. }
  298. };
  299. } // namespace
  300. bool SegmentMan::completeSegment
  301. (cuid_t cuid, const SharedHandle<Segment>& segment) {
  302. pieceStorage_->completePiece(segment->getPiece());
  303. pieceStorage_->advertisePiece(cuid, segment->getPiece()->getIndex());
  304. SegmentEntries::iterator itr = std::find_if(usedSegmentEntries_.begin(),
  305. usedSegmentEntries_.end(),
  306. FindSegmentEntry(segment));
  307. if(itr == usedSegmentEntries_.end()) {
  308. return false;
  309. } else {
  310. usedSegmentEntries_.erase(itr);
  311. return true;
  312. }
  313. }
  314. bool SegmentMan::hasSegment(size_t index) const {
  315. return pieceStorage_->hasPiece(index);
  316. }
  317. uint64_t SegmentMan::getDownloadLength() const {
  318. if(!pieceStorage_) {
  319. return 0;
  320. } else {
  321. return pieceStorage_->getCompletedLength();
  322. }
  323. }
  324. void SegmentMan::registerPeerStat(const SharedHandle<PeerStat>& peerStat)
  325. {
  326. for(std::vector<SharedHandle<PeerStat> >::iterator i = peerStats_.begin(),
  327. eoi = peerStats_.end(); i != eoi; ++i) {
  328. if((*i)->getStatus() == PeerStat::IDLE) {
  329. *i = peerStat;
  330. return;
  331. }
  332. }
  333. peerStats_.push_back(peerStat);
  334. }
  335. SharedHandle<PeerStat> SegmentMan::getPeerStat(cuid_t cuid) const
  336. {
  337. for(std::vector<SharedHandle<PeerStat> >::const_iterator i =
  338. peerStats_.begin(), eoi = peerStats_.end(); i != eoi; ++i) {
  339. if((*i)->getCuid() == cuid) {
  340. return *i;
  341. }
  342. }
  343. return SharedHandle<PeerStat>();
  344. }
  345. namespace {
  346. class PeerStatHostProtoEqual {
  347. private:
  348. const SharedHandle<PeerStat>& peerStat_;
  349. public:
  350. PeerStatHostProtoEqual(const SharedHandle<PeerStat>& peerStat):
  351. peerStat_(peerStat) {}
  352. bool operator()(const SharedHandle<PeerStat>& p) const
  353. {
  354. return peerStat_->getHostname() == p->getHostname() &&
  355. peerStat_->getProtocol() == p->getProtocol();
  356. }
  357. };
  358. } // namespace
  359. void SegmentMan::updateFastestPeerStat(const SharedHandle<PeerStat>& peerStat)
  360. {
  361. std::vector<SharedHandle<PeerStat> >::iterator i =
  362. std::find_if(fastestPeerStats_.begin(), fastestPeerStats_.end(),
  363. PeerStatHostProtoEqual(peerStat));
  364. if(i == fastestPeerStats_.end()) {
  365. fastestPeerStats_.push_back(peerStat);
  366. } else if((*i)->getAvgDownloadSpeed() < peerStat->getAvgDownloadSpeed()) {
  367. // *i's SessionDownloadLength must be added to peerStat
  368. peerStat->addSessionDownloadLength((*i)->getSessionDownloadLength());
  369. *i = peerStat;
  370. } else {
  371. // peerStat's SessionDownloadLength must be added to *i
  372. (*i)->addSessionDownloadLength(peerStat->getSessionDownloadLength());
  373. }
  374. }
  375. unsigned int SegmentMan::calculateDownloadSpeed()
  376. {
  377. unsigned int speed = 0;
  378. if(lastPeerStatDlspdMapUpdated_.differenceInMillis(global::wallclock())+
  379. A2_DELTA_MILLIS >= 250){
  380. lastPeerStatDlspdMapUpdated_ = global::wallclock();
  381. peerStatDlspdMap_.clear();
  382. for(std::vector<SharedHandle<PeerStat> >::const_iterator i =
  383. peerStats_.begin(), eoi = peerStats_.end(); i != eoi; ++i) {
  384. if((*i)->getStatus() == PeerStat::ACTIVE) {
  385. unsigned int s = (*i)->calculateDownloadSpeed();
  386. peerStatDlspdMap_[(*i)->getCuid()] = s;
  387. speed += s;
  388. }
  389. }
  390. cachedDlspd_ = speed;
  391. } else {
  392. speed = cachedDlspd_;
  393. }
  394. return speed;
  395. }
  396. void SegmentMan::updateDownloadSpeedFor(const SharedHandle<PeerStat>& pstat)
  397. {
  398. unsigned int newspd = pstat->calculateDownloadSpeed();
  399. unsigned int oldSpd = peerStatDlspdMap_[pstat->getCuid()];
  400. if(cachedDlspd_ > oldSpd) {
  401. cachedDlspd_ -= oldSpd;
  402. cachedDlspd_ += newspd;
  403. } else {
  404. cachedDlspd_ = newspd;
  405. }
  406. peerStatDlspdMap_[pstat->getCuid()] = newspd;
  407. }
  408. namespace {
  409. class PeerStatDownloadLengthOperator {
  410. public:
  411. uint64_t operator()(uint64_t total, const SharedHandle<PeerStat>& ps)
  412. {
  413. return ps->getSessionDownloadLength()+total;
  414. }
  415. };
  416. } // namespace
  417. uint64_t SegmentMan::calculateSessionDownloadLength() const
  418. {
  419. return std::accumulate(fastestPeerStats_.begin(), fastestPeerStats_.end(),
  420. 0LL, PeerStatDownloadLengthOperator());
  421. }
  422. size_t SegmentMan::countFreePieceFrom(size_t index) const
  423. {
  424. size_t numPieces = downloadContext_->getNumPieces();
  425. for(size_t i = index; i < numPieces; ++i) {
  426. if(pieceStorage_->hasPiece(i) || pieceStorage_->isPieceUsed(i)) {
  427. return i-index;
  428. }
  429. }
  430. return downloadContext_->getNumPieces()-index;
  431. }
  432. void SegmentMan::ignoreSegmentFor(const SharedHandle<FileEntry>& fileEntry)
  433. {
  434. A2_LOG_DEBUG(fmt("ignoring segment for path=%s, offset=%s, length=%s",
  435. fileEntry->getPath().c_str(),
  436. util::itos(fileEntry->getOffset()).c_str(),
  437. util::uitos(fileEntry->getLength()).c_str()));
  438. ignoreBitfield_.addFilter(fileEntry->getOffset(), fileEntry->getLength());
  439. }
  440. void SegmentMan::recognizeSegmentFor(const SharedHandle<FileEntry>& fileEntry)
  441. {
  442. ignoreBitfield_.removeFilter(fileEntry->getOffset(), fileEntry->getLength());
  443. }
  444. bool SegmentMan::allSegmentsIgnored() const
  445. {
  446. return ignoreBitfield_.isAllFilterBitSet();
  447. }
  448. } // namespace aria2