diff --git a/ChangeLog b/ChangeLog index bb33268e..af9e9d28 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-07-20 Tatsuhiro Tsujikawa + + Now SegmentMan::findSlowerSegmentEntry() picks up the segment for which + the transfer has not yet started. + Rewritten SegmentMan::registerPeerStat() and SegmentMan::getPeerStat(). + * src/SegmentMan.cc + * src/SegmentMan.h + * test/SegmentManTest.cc + 2008-07-20 Tatsuhiro Tsujikawa Cache last calculated average download/upload speed. diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 0fbc4cf5..a2f4442b 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -123,25 +123,36 @@ SegmentHandle SegmentMan::checkoutSegment(int32_t cuid, return segment; } -SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peerStat) const { +SegmentEntryHandle SegmentMan::findSlowerSegmentEntry +(const PeerStatHandle& peerStat) +{ unsigned int speed = peerStat->getAvgDownloadSpeed()*0.8; SegmentEntryHandle slowSegmentEntry; - for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); ++itr) { - const SegmentEntryHandle& segmentEntry = *itr; + int startupIdleTime = _option->getAsInt(PREF_STARTUP_IDLE_TIME); + for(std::deque >::const_iterator itr = + usedSegmentEntries.begin(); itr != usedSegmentEntries.end(); ++itr) { + const SharedHandle& segmentEntry = *itr; if(segmentEntry->cuid == 0) { continue; } - PeerStatHandle p = getPeerStat(segmentEntry->cuid); - if(!p.get() || p->getCuid() == peerStat->getCuid() || - p->getStatus() != PeerStat::ACTIVE || - !p->getDownloadStartTime().elapsed(_option->getAsInt(PREF_STARTUP_IDLE_TIME))) { - continue; - } - unsigned int pSpeed = p->calculateDownloadSpeed(); - if(pSpeed < speed) { - speed = pSpeed; + SharedHandle p = getPeerStat(segmentEntry->cuid); + if(p.isNull()) { + // "p is null" means that it hasn't used DownloadCommand yet, i.e. waiting + // response from HTTP server after sending HTTP request. + p.reset(new PeerStat(segmentEntry->cuid)); + registerPeerStat(p); slowSegmentEntry = segmentEntry; + } else { + if(p->getCuid() == peerStat->getCuid() || + (p->getStatus() == PeerStat::ACTIVE && + !p->getDownloadStartTime().elapsed(startupIdleTime))) { + continue; + } + unsigned int pSpeed = p->calculateDownloadSpeed(); + if(pSpeed < speed) { + speed = pSpeed; + slowSegmentEntry = segmentEntry; + } } } return slowSegmentEntry; @@ -241,22 +252,36 @@ uint64_t SegmentMan::getDownloadLength() const { } } -void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) { - PeerStatHandle temp = getPeerStat(peerStat->getCuid()); - if(!temp.get()) { - peerStats.push_back(peerStat); +class FindPeerStat { +public: + bool operator()(const SharedHandle& peerStat, int32_t cuid) const + { + return peerStat->getCuid() < cuid; + } +}; + +bool SegmentMan::registerPeerStat(const SharedHandle& peerStat) +{ + std::deque >::iterator i = + std::lower_bound(peerStats.begin(), peerStats.end(),peerStat->getCuid(), + FindPeerStat()); + if(i == peerStats.end() || (*i)->getCuid() != peerStat->getCuid()) { + peerStats.insert(i, peerStat); + return true ; + } else { + return false; } } PeerStatHandle SegmentMan::getPeerStat(int32_t cuid) const { - for(std::deque >::const_iterator itr = peerStats.begin(); itr != peerStats.end(); ++itr) { - const PeerStatHandle& peerStat = *itr; - if(peerStat->getCuid() == cuid) { - return peerStat; - } + std::deque >::const_iterator i = + std::lower_bound(peerStats.begin(), peerStats.end(), cuid, FindPeerStat()); + if(i != peerStats.end() && (*i)->getCuid() == cuid) { + return *i; + } else { + return SharedHandle(); } - return SharedHandle(); } unsigned int SegmentMan::calculateDownloadSpeed() const { diff --git a/src/SegmentMan.h b/src/SegmentMan.h index fcc9c743..8d8be720 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -82,7 +82,8 @@ private: SharedHandle checkoutSegment(int32_t cuid, const SharedHandle& piece); - SegmentEntryHandle findSlowerSegmentEntry(const SharedHandle& peerStat) const; + SharedHandle findSlowerSegmentEntry + (const SharedHandle& peerStat); public: SegmentMan(const Option* option, const SharedHandle& downloadContext, @@ -159,10 +160,10 @@ public: uint64_t getDownloadLength() const; /** - * Registers given peerStat if it has not been registerd. - * Otherwise does nothing. + * Registers given peerStat if it has not been registerd and returns true. + * Otherwise does nothing and returns false. */ - void registerPeerStat(const SharedHandle& peerStat); + bool registerPeerStat(const SharedHandle& peerStat); /** * Returns peerStat whose cuid is given cuid. If it is not found, returns diff --git a/test/SegmentManTest.cc b/test/SegmentManTest.cc index d7a8a562..be4d8f89 100644 --- a/test/SegmentManTest.cc +++ b/test/SegmentManTest.cc @@ -8,6 +8,8 @@ #include "Segment.h" #include "Option.h" #include "FileEntry.h" +#include "MockPieceStorage.h" +#include "PeerStat.h" #include namespace aria2 { @@ -17,7 +19,7 @@ class SegmentManTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SegmentManTest); CPPUNIT_TEST(testNullBitfield); CPPUNIT_TEST(testCompleteSegment); - CPPUNIT_TEST(testMarkPieceDone_usedSegment); + CPPUNIT_TEST(testGetPeerStat); CPPUNIT_TEST_SUITE_END(); private: @@ -27,7 +29,7 @@ public: void testNullBitfield(); void testCompleteSegment(); - void testMarkPieceDone_usedSegment(); + void testGetPeerStat(); }; @@ -82,30 +84,38 @@ void SegmentManTest::testCompleteSegment() CPPUNIT_ASSERT_EQUAL((size_t)2, segments[1]->getIndex()); } -void SegmentManTest::testMarkPieceDone_usedSegment() +void SegmentManTest::testGetPeerStat() { - // TODO implement this later - /* - SegmentMan segmentMan; - int32_t pieceLength = 1024*1024; - int64_t totalLength = 10*pieceLength; - segmentMan.initBitfield(pieceLength, totalLength); - segmentMan.markPieceDone(5*pieceLength+100); + Option op; + size_t pieceLength = 1; + uint64_t totalLength = 1; + SharedHandle dctx + (new SingleFileDownloadContext(pieceLength, totalLength, "aria2.tar.bz2")); + SharedHandle ps(new MockPieceStorage()); + SegmentMan segmentMan(&op, dctx, ps); - for(int32_t i = 0; i < 5; ++i) { - CPPUNIT_ASSERT(segmentMan.hasSegment(i)); + CPPUNIT_ASSERT(segmentMan.getPeerStat(1).isNull()); + SharedHandle ps1(new PeerStat(1)); + CPPUNIT_ASSERT(segmentMan.registerPeerStat(ps1)); + { + SharedHandle ps = segmentMan.getPeerStat(1); + CPPUNIT_ASSERT(!ps.isNull()); + CPPUNIT_ASSERT_EQUAL(1, ps->getCuid()); } - for(int32_t i = 5; i < 10; ++i) { - CPPUNIT_ASSERT(!segmentMan.hasSegment(i)); + // Duplicate registering is not allowed. + SharedHandle ps1d(new PeerStat(1)); + CPPUNIT_ASSERT(!segmentMan.registerPeerStat(ps1d)); + + // See whether it can work on several entries. + SharedHandle ps2(new PeerStat(2)); + SharedHandle ps3(new PeerStat(3)); + CPPUNIT_ASSERT(segmentMan.registerPeerStat(ps3)); + CPPUNIT_ASSERT(segmentMan.registerPeerStat(ps2)); + { + SharedHandle ps = segmentMan.getPeerStat(2); + CPPUNIT_ASSERT(!ps.isNull()); + CPPUNIT_ASSERT_EQUAL(2, ps->getCuid()); } - - SharedHandle segment = segmentMan.getSegment(0, 5); - CPPUNIT_ASSERT(!segment.isNull()); - CPPUNIT_ASSERT_EQUAL((int32_t)5, segment->index); - CPPUNIT_ASSERT_EQUAL(pieceLength, (int32_t) segment->length); - CPPUNIT_ASSERT_EQUAL(pieceLength, (int32_t) segment->segmentLength); - CPPUNIT_ASSERT_EQUAL((int32_t)100, segment->writtenLength); - */ } } // namespace aria2