From e20830294713c2797f669a03740768305edeab17 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 29 Nov 2009 06:43:38 +0000 Subject: [PATCH] 2009-11-29 Tatsuhiro Tsujikawa Added option --bt-prioritize-piece. This option instruct aria2 to try to download first and last pieces of each file first. The argument can contain 2 keywords:head and tail. To include both keywords, they must be separated by comma. These keywords can take one parameter, SIZE. For example , if head=SIZE is specified, pieces in the range of first SIZE bytes of each file get higher priority. tail=SIZE means the range of last SIZE bytes of each file. SIZE can include K or M(1K = 1024, 1M = 1024K). * src/DefaultPieceStorage.h * src/Makefile.am * src/OptionHandlerFactory.cc * src/OptionHandlerImpl.h * src/PriorityPieceSelector.cc * src/PriorityPieceSelector.h * src/RequestGroup.cc * src/prefs.cc * src/prefs.h * src/usage_text.h * src/util.cc * src/util.h * test/Makefile.am * test/MockPieceSelector.h * test/PriorityPieceSelectorTest.cc * test/UtilTest.cc --- ChangeLog | 27 +++++++++++++ src/DefaultPieceStorage.h | 6 +++ src/Makefile.am | 3 +- src/Makefile.in | 10 +++-- src/OptionHandlerFactory.cc | 7 ++++ src/OptionHandlerImpl.h | 27 +++++++++++++ src/PriorityPieceSelector.cc | 57 ++++++++++++++++++++++++++ src/PriorityPieceSelector.h | 67 +++++++++++++++++++++++++++++++ src/RequestGroup.cc | 37 ++++++++++++----- src/prefs.cc | 2 + src/prefs.h | 2 + src/usage_text.h | 11 +++++ src/util.cc | 64 +++++++++++++++++++++++++++++ src/util.h | 19 ++++++++- test/Makefile.am | 4 +- test/Makefile.in | 9 ++++- test/MockPieceSelector.h | 19 +++++++++ test/PriorityPieceSelectorTest.cc | 45 +++++++++++++++++++++ test/UtilTest.cc | 65 ++++++++++++++++++++++++++++++ 19 files changed, 464 insertions(+), 17 deletions(-) create mode 100644 src/PriorityPieceSelector.cc create mode 100644 src/PriorityPieceSelector.h create mode 100644 test/MockPieceSelector.h create mode 100644 test/PriorityPieceSelectorTest.cc diff --git a/ChangeLog b/ChangeLog index 5a000aeb..5e0c2ea1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2009-11-29 Tatsuhiro Tsujikawa + + Added option --bt-prioritize-piece. This option instruct aria2 to + try to download first and last pieces of each file first. The + argument can contain 2 keywords:head and tail. To include both + keywords, they must be separated by comma. These keywords can take + one parameter, SIZE. For example , if head=SIZE is specified, + pieces in the range of first SIZE bytes of each file get higher + priority. tail=SIZE means the range of last SIZE bytes of each + file. SIZE can include K or M(1K = 1024, 1M = 1024K). + * src/DefaultPieceStorage.h + * src/Makefile.am + * src/OptionHandlerFactory.cc + * src/OptionHandlerImpl.h + * src/PriorityPieceSelector.cc + * src/PriorityPieceSelector.h + * src/RequestGroup.cc + * src/prefs.cc + * src/prefs.h + * src/usage_text.h + * src/util.cc + * src/util.h + * test/Makefile.am + * test/MockPieceSelector.h + * test/PriorityPieceSelectorTest.cc + * test/UtilTest.cc + 2009-11-29 Tatsuhiro Tsujikawa Fixed typo diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index e2adf632..834026e0 100644 --- a/src/DefaultPieceStorage.h +++ b/src/DefaultPieceStorage.h @@ -239,6 +239,12 @@ public: { _pieceSelector = pieceSelector; } + + SharedHandle getPieceSelector() const + { + return _pieceSelector; + } + }; typedef SharedHandle DefaultPieceStorageHandle; diff --git a/src/Makefile.am b/src/Makefile.am index 926ed1da..93868128 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -442,7 +442,8 @@ SRCS += PeerAbstractCommand.cc PeerAbstractCommand.h\ ExtensionMessageRegistry.h\ bencode.cc bencode.h\ bittorrent_helper.cc bittorrent_helper.h\ - BtStopDownloadCommand.cc BtStopDownloadCommand.h + BtStopDownloadCommand.cc BtStopDownloadCommand.h\ + PriorityPieceSelector.cc PriorityPieceSelector.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index e9afd0a7..dd6ea663 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -240,7 +240,8 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ ExtensionMessageRegistry.h\ @ENABLE_BITTORRENT_TRUE@ bencode.cc bencode.h\ @ENABLE_BITTORRENT_TRUE@ bittorrent_helper.cc bittorrent_helper.h\ -@ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.cc BtStopDownloadCommand.h +@ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.cc BtStopDownloadCommand.h\ +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.cc PriorityPieceSelector.h @ENABLE_METALINK_TRUE@am__append_14 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -568,7 +569,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ ZeroBtMessage.h RangeBtMessageValidator.h \ IndexBtMessageValidator.h ExtensionMessageRegistry.h \ bencode.cc bencode.h bittorrent_helper.cc bittorrent_helper.h \ - BtStopDownloadCommand.cc BtStopDownloadCommand.h Metalinker.cc \ + BtStopDownloadCommand.cc BtStopDownloadCommand.h \ + PriorityPieceSelector.cc PriorityPieceSelector.h Metalinker.cc \ Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ MetalinkParserController.cc MetalinkParserController.h \ @@ -730,7 +732,8 @@ am__objects_6 = @ENABLE_BITTORRENT_TRUE@ ZeroBtMessage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ bencode.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ bittorrent_helper.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_14 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -1507,6 +1510,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceStatMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecedSegment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PriorityPieceSelector.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtocolDetector.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RangeBtMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarestPieceSelector.Po@am__quote@ diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 6a695ef9..4fc18965 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -969,6 +969,13 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_BITTORRENT); handlers.push_back(op); } + { + SharedHandle op(new PrioritizePieceOptionHandler + (PREF_BT_PRIORITIZE_PIECE, + TEXT_BT_PRIORITIZE_PIECE)); + op->addTag(TAG_BITTORRENT); + handlers.push_back(op); + } { SharedHandle op(new UnitNumberOptionHandler (PREF_BT_REQUEST_PEER_SPEED_LIMIT, diff --git a/src/OptionHandlerImpl.h b/src/OptionHandlerImpl.h index 30b75d21..3e3dd07d 100644 --- a/src/OptionHandlerImpl.h +++ b/src/OptionHandlerImpl.h @@ -55,6 +55,7 @@ #include "a2functional.h" #include "message.h" #include "File.h" +#include "FileEntry.h" namespace aria2 { @@ -601,6 +602,32 @@ public: } }; +class PrioritizePieceOptionHandler:public NameMatchOptionHandler { +public: + PrioritizePieceOptionHandler + (const std::string& optName, + const std::string& description = NO_DESCRIPTION, + const std::string& defaultValue = NO_DEFAULT_VALUE, + char shortName = 0): + NameMatchOptionHandler(optName, description, defaultValue, + OptionHandler::REQ_ARG, shortName) {} + + virtual void parseArg(Option& option, const std::string& optarg) + { + // Parse optarg against empty FileEntry list to detect syntax + // error. + std::vector result; + util::parsePrioritizePieceRange + (result, optarg, std::vector >(), 1024); + option.put(_optName, optarg); + } + + virtual std::string createPossibleValuesString() const + { + return "head[=SIZE],tail[=SIZE]"; + } +}; + } // namespace aria2 #endif // _D_OPTION_HANDLER_IMPL_H_ diff --git a/src/PriorityPieceSelector.cc b/src/PriorityPieceSelector.cc new file mode 100644 index 00000000..c11a3672 --- /dev/null +++ b/src/PriorityPieceSelector.cc @@ -0,0 +1,57 @@ +/* */ +#include "PriorityPieceSelector.h" +#include "bitfield.h" + +namespace aria2 { + +PriorityPieceSelector::PriorityPieceSelector +(const SharedHandle& selector): + _selector(selector) {} + +bool PriorityPieceSelector::select +(size_t& index, const unsigned char* bitfield, size_t nbits) const +{ + for(std::vector::const_iterator i = _prioritizedPieces.begin(); + i != _prioritizedPieces.end(); ++i) { + if(bitfield::test(bitfield, nbits, *i)) { + index = *i; + return true; + } + } + return _selector->select(index, bitfield, nbits); +} + +} // namespace aria2 diff --git a/src/PriorityPieceSelector.h b/src/PriorityPieceSelector.h new file mode 100644 index 00000000..cb305b9d --- /dev/null +++ b/src/PriorityPieceSelector.h @@ -0,0 +1,67 @@ +/* */ +#ifndef _D_PRIORITY_PIECE_SELECTOR_H_ +#define _D_PRIORITY_PIECE_SELECTOR_H_ + +#include "PieceSelector.h" + +#include + +#include "SharedHandle.h" + +namespace aria2 { + +class PriorityPieceSelector:public PieceSelector { +private: + std::vector _prioritizedPieces; + + SharedHandle _selector; +public: + PriorityPieceSelector(const SharedHandle& selector); + + virtual bool select + (size_t& index, const unsigned char* bitfield, size_t nbits) const; + + template + void setPriorityPiece(InputIterator first, InputIterator last) + { + std::vector t(first, last); + _prioritizedPieces.swap(t); + } +}; + +} // namespace aria2 + +#endif // _D_PRIORITY_PIECE_SELECTOR_H_ diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index f66da9f7..23eb8f0c 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -76,6 +76,7 @@ #include "PieceSelector.h" #include "a2functional.h" #include "SocketCore.h" +#include "SimpleRandomizer.h" #ifdef ENABLE_MESSAGE_DIGEST # include "CheckIntegrityCommand.h" #endif // ENABLE_MESSAGE_DIGEST @@ -100,6 +101,7 @@ # include "DHTPeerAnnounceStorage.h" # include "DHTEntryPointNameResolveCommand.h" # include "LongestSequencePieceSelector.h" +# include "PriorityPieceSelector.h" #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK # include "MetalinkPostDownloadHandler.h" @@ -440,15 +442,32 @@ void RequestGroup::initPieceStorage() #ifdef ENABLE_BITTORRENT SharedHandle ps (new DefaultPieceStorage(_downloadContext, _option.get())); - // Use LongestSequencePieceSelector when HTTP/FTP/BitTorrent integrated - // downloads. Currently multi-file integrated download is not supported. - if(_downloadContext->hasAttribute(bittorrent::BITTORRENT) && - isUriSuppliedForRequsetFileEntry - (_downloadContext->getFileEntries().begin(), - _downloadContext->getFileEntries().end())) { - _logger->debug("Using LongestSequencePieceSelector"); - ps->setPieceSelector - (SharedHandle(new LongestSequencePieceSelector())); + if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) { + if(isUriSuppliedForRequsetFileEntry + (_downloadContext->getFileEntries().begin(), + _downloadContext->getFileEntries().end())) { + // Use LongestSequencePieceSelector when HTTP/FTP/BitTorrent + // integrated downloads. Currently multi-file integrated + // download is not supported. + _logger->debug("Using LongestSequencePieceSelector"); + ps->setPieceSelector + (SharedHandle(new LongestSequencePieceSelector())); + } + if(_option->defined(PREF_BT_PRIORITIZE_PIECE)) { + std::vector result; + util::parsePrioritizePieceRange + (result, _option->get(PREF_BT_PRIORITIZE_PIECE), + _downloadContext->getFileEntries(), + _downloadContext->getPieceLength()); + if(!result.empty()) { + std::random_shuffle(result.begin(), result.end(), + *(SimpleRandomizer::getInstance().get())); + SharedHandle priSelector + (new PriorityPieceSelector(ps->getPieceSelector())); + priSelector->setPriorityPiece(result.begin(), result.end()); + ps->setPieceSelector(priSelector); + } + } } #else // !ENABLE_BITTORRENT SharedHandle ps diff --git a/src/prefs.cc b/src/prefs.cc index dbd9b2e4..cf56d752 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -305,6 +305,8 @@ const std::string PREF_INDEX_OUT("index-out"); const std::string PREF_BT_TRACKER_INTERVAL("bt-tracker-interval"); // values: 1*digit const std::string PREF_BT_STOP_TIMEOUT("bt-stop-timeout"); +// values: head[=SIZE]|tail[=SIZE], ... +const std::string PREF_BT_PRIORITIZE_PIECE("bt-prioritize-piece"); /** * Metalink related preferences diff --git a/src/prefs.h b/src/prefs.h index ae91b17f..79ca4c8d 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -309,6 +309,8 @@ extern const std::string PREF_INDEX_OUT; extern const std::string PREF_BT_TRACKER_INTERVAL; // values: 1*digit extern const std::string PREF_BT_STOP_TIMEOUT; +// values: head[=SIZE]|tail[=SIZE], ... +extern const std::string PREF_BT_PRIORITIZE_PIECE; /** * Metalink related preferences diff --git a/src/usage_text.h b/src/usage_text.h index ffc88c2f..1e15c305 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -567,3 +567,14 @@ _(" --bt-stop-timeout=SEC Stop BitTorrent download if download speed is 0 _(" --xml-rpc-listen-all[=true|false] Listen incoming XML-RPC requests on all\n"\ " network interfaces. If false is given, listen only\n"\ " on local loopback interface.") +#define TEXT_BT_PRIORITIZE_PIECE \ +_(" --bt-prioritize-piece=head[=SIZE],tail[=SIZE] Try to download first and last\n"\ + " pieces of each file first. The argument can\n"\ + " contain 2 keywords:head and tail. To include both\n"\ + " keywords, they must be separated by comma. These\n"\ + " keywords can take one parameter, SIZE. For example\n"\ + " , if head=SIZE is specified, pieces in the range\n"\ + " of first SIZE bytes of each file get higher\n"\ + " priority. tail=SIZE means the range of last SIZE\n"\ + " bytes of each file. SIZE can include K or M(1K =\n"\ + " 1024, 1M = 1024K).") diff --git a/src/util.cc b/src/util.cc index 308d2660..35c56158 100644 --- a/src/util.cc +++ b/src/util.cc @@ -525,6 +525,70 @@ IntSequence parseIntRange(const std::string& src) return values; } +void parsePrioritizePieceRange +(std::vector& result, const std::string& src, + const std::vector >& fileEntries, + size_t pieceLength) +{ + std::vector indexes; + std::vector parts; + split(src, std::back_inserter(parts), ",", true); + for(std::vector::const_iterator i = parts.begin(); + i != parts.end(); ++i) { + if((*i) == "head") { + for(std::vector >::const_iterator fi = + fileEntries.begin(); fi != fileEntries.end(); ++fi) { + indexes.push_back((*fi)->getOffset()/pieceLength); + } + } else if(util::startsWith(*i, "head=")) { + std::string sizestr = std::string((*i).begin()+(*i).find("=")+1, + (*i).end()); + uint64_t head = std::max((int64_t)0, getRealSize(sizestr)); + for(std::vector >::const_iterator fi = + fileEntries.begin(); fi != fileEntries.end(); ++fi) { + if((*fi)->getLength() == 0) { + continue; + } + size_t lastIndex = + ((*fi)->getOffset()+std::min(head, (*fi)->getLength())-1)/pieceLength; + for(size_t index = (*fi)->getOffset()/pieceLength; + index <= lastIndex; ++index) { + indexes.push_back(index); + } + } + } else if((*i) == "tail") { + for(std::vector >::const_iterator fi = + fileEntries.begin(); fi != fileEntries.end(); ++fi) { + indexes.push_back + (((*fi)->getOffset()+(*fi)->getLength()-1)/pieceLength); + } + } else if(util::startsWith(*i, "tail=")) { + std::string sizestr = std::string((*i).begin()+(*i).find("=")+1, + (*i).end()); + size_t tail = std::max((int64_t)0, getRealSize(sizestr)); + for(std::vector >::const_iterator fi = + fileEntries.begin(); fi != fileEntries.end(); ++fi) { + if((*fi)->getLength() == 0) { + continue; + } + uint64_t endOffset = (*fi)->getLastOffset(); + size_t fromIndex = + (endOffset-1-(std::min(tail, (*fi)->getLength())-1))/pieceLength; + for(size_t index = fromIndex; index <= (endOffset-1)/pieceLength; + ++index) { + indexes.push_back(index); + } + } + } else { + throw DL_ABORT_EX + (StringFormat("Unrecognized token %s", (*i).c_str()).str()); + } + } + std::sort(indexes.begin(), indexes.end()); + indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end()); + result.insert(result.end(), indexes.begin(), indexes.end()); +} + std::string getContentDispositionFilename(const std::string& header) { static const std::string keyName = "filename="; std::string::size_type attributesp = header.find(keyName); diff --git a/src/util.h b/src/util.h index 3db8c31a..3f3c60f6 100644 --- a/src/util.h +++ b/src/util.h @@ -48,6 +48,7 @@ #include #include #include +#include #include "SharedHandle.h" #include "IntSequence.h" @@ -193,6 +194,22 @@ uint64_t parseULLInt(const std::string& s, int base = 10); IntSequence parseIntRange(const std::string& src); +// Parses string which specifies the range of piece index for higher +// priority and appends those indexes into result. The input string +// src can contain 2 keywords "head" and "tail". To include both +// keywords, they must be separated by comma. "head" means the pieces +// where the first byte of each file sits. "tail" means the pieces +// where the last byte of each file sits. These keywords can take one +// parameter, SIZE. For example, if "head=SIZE" is specified, pieces +// in the range of first SIZE bytes of each file get higher +// priority. SIZE can include K or M(1K = 1024, 1M = 1024K). +// +// sample: head=512K,tail=512K +void parsePrioritizePieceRange +(std::vector& result, const std::string& src, + const std::vector >& fileEntries, + size_t pieceLength); + // this function temporarily put here std::string getContentDispositionFilename(const std::string& header); @@ -293,7 +310,7 @@ parseIndexPath(const std::string& line); std::map createIndexPathMap(std::istream& i); /** - * Take a string src which is a deliminated list and add its elements + * Take a string src which is a delimited list and add its elements * into result. result is stored in out. */ template diff --git a/test/Makefile.am b/test/Makefile.am index a85e0cea..f148f2d9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -187,7 +187,9 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\ MockExtensionMessageFactory.h\ MockPieceStorage.h\ BencodeTest.cc\ - BittorrentHelperTest.cc + BittorrentHelperTest.cc\ + PriorityPieceSelectorTest.cc\ + MockPieceSelector.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/test/Makefile.in b/test/Makefile.in index 3f4735c5..5d912184 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -136,7 +136,9 @@ check_PROGRAMS = $(am__EXEEXT_1) @ENABLE_BITTORRENT_TRUE@ MockExtensionMessageFactory.h\ @ENABLE_BITTORRENT_TRUE@ MockPieceStorage.h\ @ENABLE_BITTORRENT_TRUE@ BencodeTest.cc\ -@ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.cc +@ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.cc\ +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelectorTest.cc\ +@ENABLE_BITTORRENT_TRUE@ MockPieceSelector.h @ENABLE_METALINK_TRUE@am__append_7 = MetalinkerTest.cc\ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.cc\ @@ -259,6 +261,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ MockDHTTask.h MockDHTTaskFactory.h MockDHTTaskQueue.h \ MockExtensionMessage.h MockExtensionMessageFactory.h \ MockPieceStorage.h BencodeTest.cc BittorrentHelperTest.cc \ + PriorityPieceSelectorTest.cc MockPieceSelector.h \ MetalinkerTest.cc MetalinkEntryTest.cc \ Metalink2RequestGroupTest.cc \ MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc \ @@ -347,7 +350,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ @ENABLE_BITTORRENT_TRUE@ ARC4Test.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ MSEHandshakeTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BencodeTest.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelectorTest.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_7 = MetalinkerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \ @@ -840,6 +844,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceStatManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PriorityPieceSelectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtocolDetectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RarestPieceSelectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupManTest.Po@am__quote@ diff --git a/test/MockPieceSelector.h b/test/MockPieceSelector.h new file mode 100644 index 00000000..25761ad9 --- /dev/null +++ b/test/MockPieceSelector.h @@ -0,0 +1,19 @@ +#ifndef _D_MOCK_PIECE_SELECTOR_H_ +#define _D_MOCK_PIECE_SELECTOR_H_ + +#include "PieceSelector.h" + +namespace aria2 { + +class MockPieceSelector:public PieceSelector { +public: + virtual bool select + (size_t& index, const unsigned char* bitfield, size_t nbits) const + { + return false; + } +}; + +} // namespace aria2 + +#endif // _D_MOCK_PIECE_SELECTOR_H_ diff --git a/test/PriorityPieceSelectorTest.cc b/test/PriorityPieceSelectorTest.cc new file mode 100644 index 00000000..58872083 --- /dev/null +++ b/test/PriorityPieceSelectorTest.cc @@ -0,0 +1,45 @@ +#include "PriorityPieceSelector.h" + +#include + +#include "array_fun.h" +#include "BitfieldMan.h" +#include "MockPieceSelector.h" + +namespace aria2 { + +class PriorityPieceSelectorTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(PriorityPieceSelectorTest); + CPPUNIT_TEST(testSelect); + CPPUNIT_TEST_SUITE_END(); +public: + void testSelect(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(PriorityPieceSelectorTest); + +void PriorityPieceSelectorTest::testSelect() +{ + size_t pieceLength = 1024; + size_t A[] = { 1,200}; + BitfieldMan bf(pieceLength, pieceLength*256); + for(size_t i = 0; i < arrayLength(A); ++i) { + bf.setBit(A[i]); + } + PriorityPieceSelector selector + (SharedHandle(new MockPieceSelector())); + selector.setPriorityPiece(&A[0], &A[arrayLength(A)]); + + size_t index; + CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(), bf.countBlock())); + CPPUNIT_ASSERT_EQUAL((size_t)1, index); + bf.unsetBit(1); + CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(), bf.countBlock())); + CPPUNIT_ASSERT_EQUAL((size_t)200, index); + bf.unsetBit(200); + CPPUNIT_ASSERT(!selector.select(index, bf.getBitfield(), bf.countBlock())); +} + +} // namespace aria2 diff --git a/test/UtilTest.cc b/test/UtilTest.cc index bb1f958f..7845acf0 100644 --- a/test/UtilTest.cc +++ b/test/UtilTest.cc @@ -57,6 +57,7 @@ class UtilTest:public CppUnit::TestFixture { CPPUNIT_TEST(testCreateIndexPathMap); CPPUNIT_TEST(testGenerateRandomData); CPPUNIT_TEST(testFromHex); + CPPUNIT_TEST(testParsePrioritizePieceRange); CPPUNIT_TEST_SUITE_END(); private: @@ -102,6 +103,7 @@ public: void testCreateIndexPathMap(); void testGenerateRandomData(); void testFromHex(); + void testParsePrioritizePieceRange(); }; @@ -821,4 +823,67 @@ void UtilTest::testFromHex() CPPUNIT_ASSERT(util::fromHex(src).empty()); } +void UtilTest::testParsePrioritizePieceRange() +{ + // piece index + // 0 1 2 3 4 5 6 7 + // | | | | + // file1 | | | + // | | | + // file2 | | + // file3 | + // | | + // file4 | + size_t pieceLength = 1024; + std::vector > entries(4, SharedHandle()); + entries[0].reset(new FileEntry("file1", 1024, 0)); + entries[1].reset(new FileEntry("file2",2560,entries[0]->getLastOffset())); + entries[2].reset(new FileEntry("file3",0,entries[1]->getLastOffset())); + entries[3].reset(new FileEntry("file4",3584,entries[2]->getLastOffset())); + + std::vector result; + util::parsePrioritizePieceRange(result, "head", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)3, result.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, result[0]); + CPPUNIT_ASSERT_EQUAL((size_t)1, result[1]); + CPPUNIT_ASSERT_EQUAL((size_t)3, result[2]); + result.clear(); + util::parsePrioritizePieceRange(result, "tail", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)3, result.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, result[0]); + CPPUNIT_ASSERT_EQUAL((size_t)3, result[1]); + CPPUNIT_ASSERT_EQUAL((size_t)6, result[2]); + result.clear(); + util::parsePrioritizePieceRange(result, "head=1K", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)4, result.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, result[0]); + CPPUNIT_ASSERT_EQUAL((size_t)1, result[1]); + CPPUNIT_ASSERT_EQUAL((size_t)3, result[2]); + CPPUNIT_ASSERT_EQUAL((size_t)4, result[3]); + result.clear(); + util::parsePrioritizePieceRange(result, "tail=1K", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)4, result.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, result[0]); + CPPUNIT_ASSERT_EQUAL((size_t)2, result[1]); + CPPUNIT_ASSERT_EQUAL((size_t)3, result[2]); + CPPUNIT_ASSERT_EQUAL((size_t)6, result[3]); + result.clear(); + util::parsePrioritizePieceRange(result, "head,tail", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)4, result.size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, result[0]); + CPPUNIT_ASSERT_EQUAL((size_t)1, result[1]); + CPPUNIT_ASSERT_EQUAL((size_t)3, result[2]); + CPPUNIT_ASSERT_EQUAL((size_t)6, result[3]); + result.clear(); + util::parsePrioritizePieceRange + (result, "head=300M,tail=300M", entries, pieceLength); + CPPUNIT_ASSERT_EQUAL((size_t)7, result.size()); + for(size_t i = 0; i < 7; ++i) { + CPPUNIT_ASSERT_EQUAL(i, result[i]); + } + result.clear(); + util::parsePrioritizePieceRange(result, "", entries, pieceLength); + CPPUNIT_ASSERT(result.empty()); +} + } // namespace aria2