SegmentMan.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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 "Util.h"
  37. #include "message.h"
  38. #include "prefs.h"
  39. #include "PiecedSegment.h"
  40. #include "GrowSegment.h"
  41. #include "LogFactory.h"
  42. #include "Logger.h"
  43. #include "PieceStorage.h"
  44. #include "PeerStat.h"
  45. #include "Option.h"
  46. #include "DownloadContext.h"
  47. #include "Piece.h"
  48. #include <algorithm>
  49. #include <numeric>
  50. #include <cassert>
  51. namespace aria2 {
  52. SegmentEntry::SegmentEntry(int32_t cuid, const SegmentHandle& segment):
  53. cuid(cuid), segment(segment) {}
  54. SegmentEntry::~SegmentEntry() {}
  55. SegmentMan::SegmentMan(const Option* option,
  56. const DownloadContextHandle& downloadContext,
  57. const PieceStorageHandle& pieceStorage):
  58. _option(option),
  59. logger(LogFactory::getInstance()),
  60. _downloadContext(downloadContext),
  61. _pieceStorage(pieceStorage)
  62. {}
  63. SegmentMan::~SegmentMan() {}
  64. bool SegmentMan::downloadFinished() const
  65. {
  66. if(_pieceStorage.isNull()) {
  67. return false;
  68. } else {
  69. return _pieceStorage->downloadFinished();
  70. }
  71. }
  72. void SegmentMan::init()
  73. {
  74. // TODO Do we have to do something about DownloadContext and PieceStorage here?
  75. }
  76. uint64_t SegmentMan::getTotalLength() const
  77. {
  78. if(_pieceStorage.isNull()) {
  79. return 0;
  80. } else {
  81. return _pieceStorage->getTotalLength();
  82. }
  83. }
  84. void SegmentMan::setPieceStorage(const PieceStorageHandle& pieceStorage)
  85. {
  86. _pieceStorage = pieceStorage;
  87. }
  88. void SegmentMan::setDownloadContext(const DownloadContextHandle& downloadContext)
  89. {
  90. _downloadContext = downloadContext;
  91. }
  92. SegmentHandle SegmentMan::checkoutSegment(int32_t cuid,
  93. const PieceHandle& piece)
  94. {
  95. if(piece.isNull()) {
  96. return SharedHandle<Segment>();
  97. }
  98. logger->debug("Attach segment#%d to CUID#%d.", piece->getIndex(), cuid);
  99. SegmentHandle segment;
  100. if(piece->getLength() == 0) {
  101. segment.reset(new GrowSegment(piece));
  102. } else {
  103. segment.reset(new PiecedSegment(_downloadContext->getPieceLength(), piece));
  104. }
  105. SegmentEntryHandle entry(new SegmentEntry(cuid, segment));
  106. usedSegmentEntries.push_back(entry);
  107. logger->debug("index=%d, length=%d, segmentLength=%d, writtenLength=%d",
  108. segment->getIndex(),
  109. segment->getLength(),
  110. segment->getSegmentLength(),
  111. segment->getWrittenLength());
  112. return segment;
  113. }
  114. SegmentEntryHandle SegmentMan::findSlowerSegmentEntry
  115. (const PeerStatHandle& peerStat)
  116. {
  117. unsigned int speed = peerStat->getAvgDownloadSpeed()*0.8;
  118. SegmentEntryHandle slowSegmentEntry;
  119. int startupIdleTime = _option->getAsInt(PREF_STARTUP_IDLE_TIME);
  120. for(std::deque<SharedHandle<SegmentEntry> >::const_iterator itr =
  121. usedSegmentEntries.begin(); itr != usedSegmentEntries.end(); ++itr) {
  122. const SharedHandle<SegmentEntry>& segmentEntry = *itr;
  123. if(segmentEntry->cuid == 0) {
  124. continue;
  125. }
  126. SharedHandle<PeerStat> p = getPeerStat(segmentEntry->cuid);
  127. if(p.isNull()) {
  128. // "p is null" means that it hasn't used DownloadCommand yet, i.e. waiting
  129. // response from HTTP server after sending HTTP request.
  130. p.reset(new PeerStat(segmentEntry->cuid));
  131. registerPeerStat(p);
  132. slowSegmentEntry = segmentEntry;
  133. } else {
  134. if(p->getCuid() == peerStat->getCuid() ||
  135. (p->getStatus() == PeerStat::ACTIVE &&
  136. !p->getDownloadStartTime().elapsed(startupIdleTime))) {
  137. continue;
  138. }
  139. unsigned int pSpeed = p->calculateDownloadSpeed();
  140. if(pSpeed < speed) {
  141. speed = pSpeed;
  142. slowSegmentEntry = segmentEntry;
  143. }
  144. }
  145. }
  146. return slowSegmentEntry;
  147. }
  148. void SegmentMan::getInFlightSegment(std::deque<SharedHandle<Segment> >& segments,
  149. int32_t cuid)
  150. {
  151. for(SegmentEntries::iterator itr = usedSegmentEntries.begin();
  152. itr != usedSegmentEntries.end(); ++itr) {
  153. const SegmentEntryHandle& segmentEntry = *itr;
  154. if(segmentEntry->cuid == cuid) {
  155. segments.push_back(segmentEntry->segment);
  156. }
  157. }
  158. }
  159. SegmentHandle SegmentMan::getSegment(int32_t cuid) {
  160. PieceHandle piece = _pieceStorage->getMissingPiece();
  161. if(piece.isNull()) {
  162. PeerStatHandle myPeerStat = getPeerStat(cuid);
  163. if(myPeerStat.isNull()) {
  164. return SharedHandle<Segment>();
  165. }
  166. SegmentEntryHandle slowSegmentEntry = findSlowerSegmentEntry(myPeerStat);
  167. if(slowSegmentEntry.get()) {
  168. logger->info(MSG_SEGMENT_FORWARDING,
  169. slowSegmentEntry->cuid,
  170. slowSegmentEntry->segment->getIndex(),
  171. cuid);
  172. PeerStatHandle slowPeerStat = getPeerStat(slowSegmentEntry->cuid);
  173. slowPeerStat->requestIdle();
  174. cancelSegment(slowSegmentEntry->cuid);
  175. SharedHandle<Piece> piece =
  176. _pieceStorage->getMissingPiece(slowSegmentEntry->segment->getIndex());
  177. assert(!piece.isNull());
  178. return checkoutSegment(cuid, piece);
  179. } else {
  180. return SharedHandle<Segment>();
  181. }
  182. } else {
  183. return checkoutSegment(cuid, piece);
  184. }
  185. }
  186. SegmentHandle SegmentMan::getSegment(int32_t cuid, size_t index) {
  187. if(_downloadContext->getNumPieces() <= index) {
  188. return SharedHandle<Segment>();
  189. }
  190. return checkoutSegment(cuid, _pieceStorage->getMissingPiece(index));
  191. }
  192. void SegmentMan::cancelSegment(int32_t cuid) {
  193. for(SegmentEntries::iterator itr = usedSegmentEntries.begin();
  194. itr != usedSegmentEntries.end();) {
  195. if((*itr)->cuid == cuid) {
  196. _pieceStorage->cancelPiece((*itr)->segment->getPiece());
  197. itr = usedSegmentEntries.erase(itr);
  198. } else {
  199. ++itr;
  200. }
  201. }
  202. }
  203. class FindSegmentEntry {
  204. private:
  205. SegmentHandle _segment;
  206. public:
  207. FindSegmentEntry(const SegmentHandle& segment):_segment(segment) {}
  208. bool operator()(const SegmentEntryHandle& segmentEntry) const
  209. {
  210. return segmentEntry->segment->getIndex() == _segment->getIndex();
  211. }
  212. };
  213. bool SegmentMan::completeSegment(int32_t cuid, const SegmentHandle& segment) {
  214. _pieceStorage->completePiece(segment->getPiece());
  215. _pieceStorage->advertisePiece(cuid, segment->getPiece()->getIndex());
  216. SegmentEntries::iterator itr = std::find_if(usedSegmentEntries.begin(),
  217. usedSegmentEntries.end(),
  218. FindSegmentEntry(segment));
  219. if(itr == usedSegmentEntries.end()) {
  220. return false;
  221. } else {
  222. usedSegmentEntries.erase(itr);
  223. return true;
  224. }
  225. }
  226. bool SegmentMan::hasSegment(size_t index) const {
  227. return _pieceStorage->hasPiece(index);
  228. }
  229. uint64_t SegmentMan::getDownloadLength() const {
  230. if(_pieceStorage.isNull()) {
  231. return 0;
  232. } else {
  233. return _pieceStorage->getCompletedLength();
  234. }
  235. }
  236. class FindPeerStat {
  237. public:
  238. bool operator()(const SharedHandle<PeerStat>& peerStat, int32_t cuid) const
  239. {
  240. return peerStat->getCuid() < cuid;
  241. }
  242. };
  243. bool SegmentMan::registerPeerStat(const SharedHandle<PeerStat>& peerStat)
  244. {
  245. std::deque<SharedHandle<PeerStat> >::iterator i =
  246. std::lower_bound(peerStats.begin(), peerStats.end(),peerStat->getCuid(),
  247. FindPeerStat());
  248. if(i == peerStats.end() || (*i)->getCuid() != peerStat->getCuid()) {
  249. peerStats.insert(i, peerStat);
  250. return true ;
  251. } else {
  252. return false;
  253. }
  254. }
  255. PeerStatHandle SegmentMan::getPeerStat(int32_t cuid) const
  256. {
  257. std::deque<SharedHandle<PeerStat> >::const_iterator i =
  258. std::lower_bound(peerStats.begin(), peerStats.end(), cuid, FindPeerStat());
  259. if(i != peerStats.end() && (*i)->getCuid() == cuid) {
  260. return *i;
  261. } else {
  262. return SharedHandle<PeerStat>();
  263. }
  264. }
  265. const std::deque<SharedHandle<PeerStat> >& SegmentMan::getPeerStats() const
  266. {
  267. return peerStats;
  268. }
  269. unsigned int SegmentMan::calculateDownloadSpeed() const {
  270. unsigned int speed = 0;
  271. for(std::deque<SharedHandle<PeerStat> >::const_iterator itr = peerStats.begin(); itr != peerStats.end(); itr++) {
  272. const PeerStatHandle& peerStat = *itr;
  273. if(peerStat->getStatus() == PeerStat::ACTIVE) {
  274. speed += peerStat->calculateDownloadSpeed();
  275. }
  276. }
  277. return speed;
  278. }
  279. class PeerStatDownloadLengthOperator {
  280. public:
  281. uint64_t operator()(uint64_t total, const SharedHandle<PeerStat>& ps)
  282. {
  283. return ps->getSessionDownloadLength()+total;
  284. }
  285. };
  286. uint64_t SegmentMan::calculateSessionDownloadLength() const
  287. {
  288. return std::accumulate(peerStats.begin(), peerStats.end(), 0LL,
  289. PeerStatDownloadLengthOperator());
  290. }
  291. size_t SegmentMan::countFreePieceFrom(size_t index) const
  292. {
  293. size_t numPieces = _downloadContext->getNumPieces();
  294. for(size_t i = index; i < numPieces; ++i) {
  295. if(_pieceStorage->hasPiece(i) || _pieceStorage->isPieceUsed(i)) {
  296. return i-index;
  297. }
  298. }
  299. return _downloadContext->getNumPieces()-index;
  300. }
  301. } // namespace aria2