SegmentMan.cc 14 KB

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