diff --git a/ChangeLog b/ChangeLog index a1c086c9..dfa1be09 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-07-04 Tatsuhiro Tsujikawa + + Made URI reusing function work. + * src/CreateRequestCommand.cc + * src/FileEntry.cc + * src/FileEntry.h + * test/FileEntryTest.cc + 2009-07-04 Tatsuhiro Tsujikawa Add formerly fastest PeerStat's sessionDownloadLength to new diff --git a/src/CreateRequestCommand.cc b/src/CreateRequestCommand.cc index adfd625e..311cc8b9 100644 --- a/src/CreateRequestCommand.cc +++ b/src/CreateRequestCommand.cc @@ -67,6 +67,10 @@ bool CreateRequestCommand::executeInternal() _fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset (_segments.front()->getPositionToWrite()); } + if(_fileEntry->getRemainingUris().empty() && + getOption()->getAsBool(PREF_REUSE_URI)) { + _fileEntry->reuseUri(_requestGroup->getNumConcurrentCommand()); + } req = _fileEntry->getRequest(_requestGroup->getURISelector(), getOption()->get(PREF_REFERER), // Don't use HEAD request when file diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 87203e7c..25d195e2 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -278,4 +278,39 @@ void FileEntry::extractURIResult _uriResults.erase(_uriResults.begin(), i); } +void FileEntry::reuseUri(size_t num) +{ + std::deque uris = _spentUris; + std::sort(uris.begin(), uris.end()); + uris.erase(std::unique(uris.begin(), uris.end()), uris.end()); + + std::deque errorUris(_uriResults.size()); + std::transform(_uriResults.begin(), _uriResults.end(), + errorUris.begin(), std::mem_fun_ref(&URIResult::getURI)); + std::sort(errorUris.begin(), errorUris.end()); + errorUris.erase(std::unique(errorUris.begin(), errorUris.end()), + errorUris.end()); + + std::deque reusableURIs; + std::set_difference(uris.begin(), uris.end(), + errorUris.begin(), errorUris.end(), + std::back_inserter(reusableURIs)); + size_t ininum = reusableURIs.size(); + _logger->debug("Found %u reusable URIs", + static_cast(ininum)); + // Reuse at least num URIs here to avoid to + // run this process repeatedly. + if(ininum > 0 && ininum < num) { + _logger->debug("fewer than num=%u", + num); + for(size_t i = 0; i < num/ininum; ++i) { + _uris.insert(_uris.end(), reusableURIs.begin(), reusableURIs.end()); + } + _uris.insert(_uris.end(), reusableURIs.begin(), + reusableURIs.begin()+(num%ininum)); + _logger->debug("Duplication complete: now %u URIs for reuse", + static_cast(_uris.size())); + } +} + } // namespace aria2 diff --git a/src/FileEntry.h b/src/FileEntry.h index 6d351ac7..a52b2f02 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -225,6 +225,12 @@ public: { return _singleHostMultiConnection; } + + // Reuse URIs which have not emitted error so far. Thie method + // tries to reuse at least num URIs. If less than num URIs found to + // reuse, those URIs are used more than once so that num URIs total + // are available to reuse. + void reuseUri(size_t num); }; typedef SharedHandle FileEntryHandle; diff --git a/test/FileEntryTest.cc b/test/FileEntryTest.cc index f60ae625..3963e44e 100644 --- a/test/FileEntryTest.cc +++ b/test/FileEntryTest.cc @@ -14,6 +14,7 @@ class FileEntryTest : public CppUnit::TestFixture { CPPUNIT_TEST(testExtractURIResult); CPPUNIT_TEST(testGetRequest); CPPUNIT_TEST(testGetRequest_disableSingleHostMultiConnection); + CPPUNIT_TEST(testReuseUri); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} @@ -23,6 +24,7 @@ public: void testExtractURIResult(); void testGetRequest(); void testGetRequest_disableSingleHostMultiConnection(); + void testReuseUri(); }; @@ -128,4 +130,23 @@ void FileEntryTest::testGetRequest_disableSingleHostMultiConnection() CPPUNIT_ASSERT(req3rd.isNull()); } +void FileEntryTest::testReuseUri() +{ + SharedHandle selector(new InOrderURISelector()); + SharedHandle fileEntry = createFileEntry(); + size_t numUris = fileEntry->getRemainingUris().size(); + for(size_t i = 0; i < numUris; ++i) { + fileEntry->getRequest(selector); + } + CPPUNIT_ASSERT_EQUAL((size_t)0, fileEntry->getRemainingUris().size()); + fileEntry->addURIResult("http://localhost/aria2.zip", + downloadresultcode::UNKNOWN_ERROR); + fileEntry->reuseUri(3); + CPPUNIT_ASSERT_EQUAL((size_t)3, fileEntry->getRemainingUris().size()); + const std::deque& uris = fileEntry->getRemainingUris(); + CPPUNIT_ASSERT_EQUAL(std::string("ftp://localhost/aria2.zip"), uris[0]); + CPPUNIT_ASSERT_EQUAL(std::string("http://mirror/aria2.zip"), uris[1]); + CPPUNIT_ASSERT_EQUAL(std::string("ftp://localhost/aria2.zip"), uris[2]); +} + } // namespace aria2