SegmentMan.cc 15 KB

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