SegmentMan.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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 "DlAbortEx.h"
  37. #include "Util.h"
  38. #include "File.h"
  39. #include "message.h"
  40. #include "prefs.h"
  41. #include "LogFactory.h"
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <unistd.h>
  45. #include <errno.h>
  46. SegmentMan::SegmentMan():bitfield(0),
  47. totalSize(0),
  48. isSplittable(true),
  49. downloadStarted(false),
  50. dir("."),
  51. errors(0),
  52. diskWriter(0) {
  53. logger = LogFactory::getInstance();
  54. }
  55. SegmentMan::~SegmentMan() {
  56. delete bitfield;
  57. delete diskWriter;
  58. }
  59. bool SegmentMan::segmentFileExists() const {
  60. if(!isSplittable) {
  61. return false;
  62. }
  63. string segFilename = getSegmentFilePath();
  64. File f(segFilename);
  65. if(f.isFile()) {
  66. logger->info(MSG_SEGMENT_FILE_EXISTS, segFilename.c_str());
  67. return true;
  68. } else {
  69. logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, segFilename.c_str());
  70. return false;
  71. }
  72. }
  73. void SegmentMan::load() {
  74. if(!isSplittable) {
  75. return;
  76. }
  77. string segFilename = getSegmentFilePath();
  78. logger->info(MSG_LOADING_SEGMENT_FILE, segFilename.c_str());
  79. FILE* segFile = openSegFile(segFilename, "r+");
  80. try {
  81. read(segFile);
  82. fclose(segFile);
  83. } catch(string ex) {
  84. fclose(segFile);
  85. throw new DlAbortEx(EX_SEGMENT_FILE_READ,
  86. segFilename.c_str(), strerror(errno));
  87. }
  88. logger->info(MSG_LOADED_SEGMENT_FILE);
  89. }
  90. void SegmentMan::save() const {
  91. if(!isSplittable || totalSize == 0) {
  92. return;
  93. }
  94. string segFilename = getSegmentFilePath();
  95. logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str());
  96. FILE* segFile = openSegFile(segFilename, "w");
  97. try {
  98. if(fwrite(&totalSize, sizeof(totalSize), 1, segFile) < 1) {
  99. throw string("writeError");
  100. }
  101. int segmentLength = bitfield->getBlockLength();
  102. if(fwrite(&segmentLength, sizeof(segmentLength), 1, segFile) < 1) {
  103. throw string("writeError");
  104. }
  105. if(bitfield) {
  106. int bitfieldLength = bitfield->getBitfieldLength();
  107. if(fwrite(&bitfieldLength, sizeof(bitfieldLength), 1, segFile) < 1) {
  108. throw string("writeError");
  109. }
  110. if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(),
  111. 1, segFile) < 1) {
  112. throw string("writeError");
  113. }
  114. } else {
  115. int i = 0;
  116. if(fwrite(&i, sizeof(i), 1, segFile) < 1) {
  117. throw string("writeError");
  118. }
  119. }
  120. int usedSegmentCount = usedSegmentEntries.size();
  121. if(fwrite(&usedSegmentCount, sizeof(usedSegmentCount), 1, segFile) < 1) {
  122. throw string("writeError");
  123. }
  124. for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
  125. itr != usedSegmentEntries.end(); itr++) {
  126. if(fwrite(&(*itr)->segment, sizeof(Segment), 1, segFile) < 1) {
  127. throw string("writeError");
  128. }
  129. }
  130. fclose(segFile);
  131. logger->info(MSG_SAVED_SEGMENT_FILE);
  132. } catch(string ex) {
  133. fclose(segFile);
  134. throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
  135. segFilename.c_str(), strerror(errno));
  136. }
  137. }
  138. FILE* SegmentMan::openSegFile(const string& segFilename, const string& mode) const {
  139. FILE* segFile = fopen(segFilename.c_str(), mode.c_str());
  140. if(segFile == NULL) {
  141. throw new DlAbortEx(EX_SEGMENT_FILE_OPEN,
  142. segFilename.c_str(), strerror(errno));
  143. }
  144. return segFile;
  145. }
  146. void SegmentMan::read(FILE* file) {
  147. assert(file != NULL);
  148. if(fread(&totalSize, sizeof(totalSize), 1, file) < 1) {
  149. throw string("readError");
  150. }
  151. int segmentSize;
  152. if(fread(&segmentSize, sizeof(segmentSize), 1, file) < 1) {
  153. throw string("readError");
  154. }
  155. int bitfieldLength;
  156. if(fread(&bitfieldLength, sizeof(bitfieldLength), 1, file) < 1) {
  157. throw string("readError");
  158. }
  159. if(bitfieldLength > 0) {
  160. initBitfield(segmentSize, totalSize);
  161. unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()];
  162. if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) {
  163. delete [] savedBitfield;
  164. throw string("readError");
  165. } else {
  166. bitfield->setBitfield(savedBitfield, bitfield->getBitfieldLength());
  167. delete [] savedBitfield;
  168. }
  169. }
  170. int segmentCount;
  171. if(fread(&segmentCount, sizeof(segmentCount), 1, file) < 1) {
  172. throw string("readError");
  173. }
  174. while(segmentCount--) {
  175. Segment seg;
  176. if(fread(&seg, sizeof(Segment), 1, file) < 1) {
  177. throw string("readError");
  178. }
  179. usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(0, seg)));
  180. }
  181. }
  182. void SegmentMan::remove() const {
  183. if(!isSplittable) {
  184. return;
  185. }
  186. if(segmentFileExists()) {
  187. File f(getSegmentFilePath());
  188. f.remove();
  189. }
  190. }
  191. bool SegmentMan::finished() const {
  192. if(!downloadStarted) {
  193. return false;
  194. }
  195. if(!bitfield) {
  196. return false;
  197. }
  198. assert(bitfield);
  199. return bitfield->isAllBitSet();
  200. }
  201. void SegmentMan::removeIfFinished() const {
  202. if(finished()) {
  203. remove();
  204. }
  205. }
  206. void SegmentMan::init() {
  207. totalSize = 0;
  208. isSplittable = false;
  209. downloadStarted = false;
  210. errors = 0;
  211. //segments.clear();
  212. usedSegmentEntries.clear();
  213. delete bitfield;
  214. bitfield = 0;
  215. peerStats.clear();
  216. diskWriter->closeFile();
  217. }
  218. void SegmentMan::initBitfield(int segmentLength, long long int totalLength) {
  219. this->bitfield = new BitfieldMan(segmentLength, totalLength);
  220. }
  221. class FindSegmentEntryByIndex {
  222. private:
  223. int index;
  224. public:
  225. FindSegmentEntryByIndex(int index):index(index) {}
  226. bool operator()(const SegmentEntryHandle& entry) {
  227. return entry->segment.index == index;
  228. }
  229. };
  230. class FindSegmentEntryByCuid {
  231. private:
  232. int cuid;
  233. public:
  234. FindSegmentEntryByCuid(int cuid):cuid(cuid) {}
  235. bool operator()(const SegmentEntryHandle& entry) {
  236. return entry->cuid == cuid;
  237. }
  238. };
  239. Segment SegmentMan::checkoutSegment(int cuid, int index) {
  240. logger->debug("Attach segment#%d to CUID#%d.", index, cuid);
  241. bitfield->setUseBit(index);
  242. SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
  243. usedSegmentEntries.end(),
  244. FindSegmentEntryByIndex(index));
  245. Segment segment;
  246. if(itr == usedSegmentEntries.end()) {
  247. segment = Segment(index, bitfield->getBlockLength(index),
  248. bitfield->getBlockLength());
  249. SegmentEntryHandle entry =
  250. SegmentEntryHandle(new SegmentEntry(cuid, segment));
  251. usedSegmentEntries.push_back(entry);
  252. } else {
  253. (*itr)->cuid = cuid;
  254. segment = (*itr)->segment;
  255. }
  256. logger->debug("index=%d, length=%d, segmentLength=%d, writtenLength=%d",
  257. segment.index, segment.length, segment.segmentLength,
  258. segment.writtenLength);
  259. return segment;
  260. }
  261. bool SegmentMan::onNullBitfield(Segment& segment, int cuid) {
  262. if(usedSegmentEntries.size() == 0) {
  263. segment = Segment(0, 0, 0);
  264. usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(cuid, segment)));
  265. return true;
  266. } else {
  267. SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
  268. usedSegmentEntries.end(),
  269. FindSegmentEntryByCuid(cuid));
  270. if(itr == usedSegmentEntries.end()) {
  271. return false;
  272. } else {
  273. segment = (*itr)->segment;
  274. return true;
  275. }
  276. }
  277. }
  278. SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peerStat) const {
  279. int speed = (int)(peerStat->getAvgDownloadSpeed()*0.8);
  280. SegmentEntryHandle slowSegmentEntry(0);
  281. for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
  282. itr != usedSegmentEntries.end(); itr++) {
  283. const SegmentEntryHandle& segmentEntry = *itr;
  284. if(segmentEntry->cuid == 0) {
  285. continue;
  286. }
  287. PeerStatHandle p = getPeerStat(segmentEntry->cuid);
  288. if(!p.get() || p->getCuid() == peerStat->getCuid()) {
  289. continue;
  290. }
  291. int pSpeed = p->calculateDownloadSpeed();
  292. if(p->getStatus() == PeerStat::ACTIVE &&
  293. p->getDownloadStartTime().elapsed(option->getAsInt(PREF_STARTUP_IDLE_TIME)) &&
  294. pSpeed < speed) {
  295. speed = pSpeed;
  296. slowSegmentEntry = segmentEntry;
  297. }
  298. }
  299. return slowSegmentEntry;
  300. }
  301. bool SegmentMan::getSegment(Segment& segment, int cuid) {
  302. if(!bitfield) {
  303. return onNullBitfield(segment, cuid);
  304. }
  305. SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
  306. usedSegmentEntries.end(),
  307. FindSegmentEntryByCuid(cuid));
  308. if(itr != usedSegmentEntries.end()) {
  309. segment = (*itr)->segment;
  310. return true;
  311. }
  312. int index = bitfield->getSparseMissingUnusedIndex();
  313. if(index == -1) {
  314. PeerStatHandle myPeerStat = getPeerStat(cuid);
  315. if(!myPeerStat.get()) {
  316. return false;
  317. }
  318. SegmentEntryHandle slowSegmentEntry = findSlowerSegmentEntry(myPeerStat);
  319. if(slowSegmentEntry.get()) {
  320. logger->info("CUID#%d cancels segment index=%d. CUID#%d handles it instead.",
  321. slowSegmentEntry->cuid,
  322. slowSegmentEntry->segment.index,
  323. cuid);
  324. PeerStatHandle slowPeerStat = getPeerStat(slowSegmentEntry->cuid);
  325. slowPeerStat->requestIdle();
  326. cancelSegment(slowSegmentEntry->cuid);
  327. segment = checkoutSegment(cuid, slowSegmentEntry->segment.index);
  328. return true;
  329. } else {
  330. return false;
  331. }
  332. } else {
  333. segment = checkoutSegment(cuid, index);
  334. return true;
  335. }
  336. }
  337. bool SegmentMan::getSegment(Segment& segment, int cuid, int index) {
  338. if(!bitfield) {
  339. return onNullBitfield(segment, cuid);
  340. }
  341. if(index < 0 || bitfield->countBlock() <= index) {
  342. return false;
  343. }
  344. if(bitfield->isBitSet(index) || bitfield->isUseBitSet(index)) {
  345. return false;
  346. } else {
  347. segment = checkoutSegment(cuid, index);
  348. return true;
  349. }
  350. }
  351. bool SegmentMan::updateSegment(int cuid, const Segment& segment) {
  352. if(segment.isNull()) {
  353. return false;
  354. }
  355. SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
  356. usedSegmentEntries.end(),
  357. FindSegmentEntryByCuid(cuid));
  358. if(itr == usedSegmentEntries.end()) {
  359. return false;
  360. } else {
  361. (*itr)->segment = segment;
  362. return true;
  363. }
  364. }
  365. class CancelSegment {
  366. private:
  367. int cuid;
  368. BitfieldMan* bitfield;
  369. public:
  370. CancelSegment(int cuid, BitfieldMan* bitfield):cuid(cuid),
  371. bitfield(bitfield) {}
  372. void operator()(SegmentEntryHandle& entry) {
  373. if(entry->cuid == cuid) {
  374. bitfield->unsetUseBit(entry->segment.index);
  375. entry->cuid = 0;
  376. }
  377. }
  378. };
  379. void SegmentMan::cancelSegment(int cuid) {
  380. if(bitfield) {
  381. for_each(usedSegmentEntries.begin(), usedSegmentEntries.end(),
  382. CancelSegment(cuid, bitfield));
  383. } else {
  384. usedSegmentEntries.clear();
  385. }
  386. }
  387. bool SegmentMan::completeSegment(int cuid, const Segment& segment) {
  388. if(segment.isNull()) {
  389. return false;
  390. }
  391. if(bitfield) {
  392. bitfield->unsetUseBit(segment.index);
  393. bitfield->setBit(segment.index);
  394. } else {
  395. initBitfield(option->getAsInt(PREF_SEGMENT_SIZE), segment.writtenLength);
  396. bitfield->setAllBit();
  397. }
  398. SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
  399. usedSegmentEntries.end(),
  400. FindSegmentEntryByCuid(cuid));
  401. if(itr == usedSegmentEntries.end()) {
  402. return false;
  403. } else {
  404. usedSegmentEntries.erase(itr);
  405. return true;
  406. }
  407. }
  408. bool SegmentMan::hasSegment(int index) const {
  409. if(bitfield) {
  410. return bitfield->isBitSet(index);
  411. } else {
  412. return false;
  413. }
  414. }
  415. long long int SegmentMan::getDownloadLength() const {
  416. long long int dlLength = 0;
  417. if(bitfield) {
  418. dlLength += bitfield->getCompletedLength();
  419. }
  420. for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
  421. itr != usedSegmentEntries.end(); itr++) {
  422. dlLength += (*itr)->segment.writtenLength;
  423. }
  424. return dlLength;
  425. }
  426. void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) {
  427. PeerStatHandle temp = getPeerStat(peerStat->getCuid());
  428. if(!temp.get()) {
  429. peerStats.push_back(peerStat);
  430. }
  431. }
  432. int SegmentMan::calculateDownloadSpeed() const {
  433. int speed = 0;
  434. for(PeerStats::const_iterator itr = peerStats.begin();
  435. itr != peerStats.end(); itr++) {
  436. const PeerStatHandle& peerStat = *itr;
  437. if(peerStat->getStatus() == PeerStat::ACTIVE) {
  438. speed += peerStat->calculateDownloadSpeed();
  439. }
  440. }
  441. return speed;
  442. }