From ffaeb271f9f2e746c702650e26709db35ec7f158 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 2 Jul 2009 16:26:04 +0000 Subject: [PATCH] 2009-07-03 Tatsuhiro Tsujikawa Rewritten PeerStats handling in SegmentMan.cc. Now we have 2 list of PeerStat in SegmentMan. peerStats is used for calculating download speed. Therefore all active PeerStats should be in there. Another one is _fastestPeerStats and it only contains fastest PeerStat for each hostname/protocol pair. They are used for updating ServerStat. * src/DownloadCommand.cc * src/Request.h * src/RequestGroupMan.cc * src/SegmentMan.cc * src/SegmentMan.h * test/SegmentManTest.cc --- ChangeLog | 15 ++++++++++++++ src/DownloadCommand.cc | 11 ++++------- src/Request.h | 2 -- src/RequestGroupMan.cc | 44 ++++++------------------------------------ src/SegmentMan.cc | 33 +++++++++++++++++++++++++++++++ src/SegmentMan.h | 23 ++++++++++++++++++---- test/SegmentManTest.cc | 20 +++++++++++++++++++ 7 files changed, 97 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index af9bc00f..5a906ae6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-07-03 Tatsuhiro Tsujikawa + + Rewritten PeerStats handling in SegmentMan.cc. Now we have 2 list + of PeerStat in SegmentMan. peerStats is used for calculating + download speed. Therefore all active PeerStats should be in + there. Another one is _fastestPeerStats and it only contains + fastest PeerStat for each hostname/protocol pair. They are used + for updating ServerStat. + * src/DownloadCommand.cc + * src/Request.h + * src/RequestGroupMan.cc + * src/SegmentMan.cc + * src/SegmentMan.h + * test/SegmentManTest.cc + 2009-07-03 Tatsuhiro Tsujikawa Try all available addresses returned by DNS until it gets diff --git a/src/DownloadCommand.cc b/src/DownloadCommand.cc index bd6af440..c72ca3fc 100644 --- a/src/DownloadCommand.cc +++ b/src/DownloadCommand.cc @@ -89,18 +89,15 @@ DownloadCommand::DownloadCommand(int cuid, } } #endif // ENABLE_MESSAGE_DIGEST - peerStat = req->getPeerStat(); - if(peerStat.isNull()) { - peerStat = req->initPeerStat(); - _requestGroup->getSegmentMan()->registerPeerStat(peerStat); - } + + peerStat = req->initPeerStat(); peerStat->downloadStart(); + _requestGroup->getSegmentMan()->registerPeerStat(peerStat); } DownloadCommand::~DownloadCommand() { - assert(peerStat.get()); peerStat->downloadStop(); - req->purgePeerStat(); + _requestGroup->getSegmentMan()->updateFastestPeerStat(peerStat); } bool DownloadCommand::executeInternal() { diff --git a/src/Request.h b/src/Request.h index a3552229..cab16999 100644 --- a/src/Request.h +++ b/src/Request.h @@ -185,8 +185,6 @@ public: const SharedHandle& initPeerStat(); - void purgePeerStat() { _peerStat.reset(); } - static const std::string METHOD_GET; static const std::string METHOD_HEAD; diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index b2a08421..2d568553 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -329,34 +329,6 @@ public: } }; -class PeerStatFaster { -public: - bool operator()(const SharedHandle& lhs, - const SharedHandle& rhs) const - { - int r; - r = lhs->getHostname().compare(rhs->getHostname()); - if(r != 0) { - return r < 0; - } - r = lhs->getProtocol().compare(rhs->getProtocol()); - if(r != 0) { - return r < 0; - } - return lhs->getAvgDownloadSpeed() > rhs->getAvgDownloadSpeed(); - } -}; - -class PeerStatHostProtoEqual { -public: - bool operator()(const SharedHandle& lhs, - const SharedHandle& rhs) const - { - return lhs->getHostname() == rhs->getHostname() && - lhs->getProtocol() == rhs->getProtocol(); - } -}; - class CollectServerStat { private: RequestGroupMan* _requestGroupMan; @@ -370,16 +342,12 @@ public: // Collect statistics during download in PeerStats and update/register // ServerStatMan if(!group->getSegmentMan().isNull()) { - - std::deque > peerStats = - group->getSegmentMan()->getPeerStats(); - std::sort(peerStats.begin(), peerStats.end(), PeerStatFaster()); - // Use fastest PeerStat for each hostname/protocol pair. + bool singleConnection = + group->getSegmentMan()->getPeerStats().size() == 1; + const std::deque >& peerStats = + group->getSegmentMan()->getFastestPeerStats(); for(std::deque >::const_iterator i = - peerStats.begin(), - last = std::unique(peerStats.begin(), peerStats.end(), - PeerStatHostProtoEqual()); - i != last; ++i) { + peerStats.begin(); i != peerStats.end(); ++i) { if((*i)->getHostname().empty() || (*i)->getProtocol().empty()) { continue; } @@ -391,7 +359,7 @@ public: (*i)->getProtocol()); ss->increaseCounter(); ss->updateDownloadSpeed(speed); - if(peerStats.size() == 1) { + if(singleConnection) { ss->updateSingleConnectionAvgSpeed(speed); } else { diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index a321adab..0433868b 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -282,9 +282,42 @@ uint64_t SegmentMan::getDownloadLength() const { void SegmentMan::registerPeerStat(const SharedHandle& peerStat) { + for(std::deque >::iterator i = peerStats.begin(); + i != peerStats.end(); ++i) { + if((*i)->getStatus() == PeerStat::IDLE) { + *i = peerStat; + return; + } + } peerStats.push_back(peerStat); } +class PeerStatHostProtoEqual { +private: + const SharedHandle& _peerStat; +public: + PeerStatHostProtoEqual(const SharedHandle& peerStat): + _peerStat(peerStat) {} + + bool operator()(const SharedHandle& p) const + { + return _peerStat->getHostname() == p->getHostname() && + _peerStat->getProtocol() == p->getProtocol(); + } +}; + +void SegmentMan::updateFastestPeerStat(const SharedHandle& peerStat) +{ + std::deque >::iterator i = + std::find_if(_fastestPeerStats.begin(), _fastestPeerStats.end(), + PeerStatHostProtoEqual(peerStat)); + if(i == _fastestPeerStats.end()) { + _fastestPeerStats.push_back(peerStat); + } else if((*i)->getAvgDownloadSpeed() < peerStat->getAvgDownloadSpeed()) { + *i = peerStat; + } +} + unsigned int SegmentMan::calculateDownloadSpeed() { unsigned int speed = 0; diff --git a/src/SegmentMan.h b/src/SegmentMan.h index bd449ffc..3f71cb78 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -88,8 +88,12 @@ private: // segment. The value is writtenLength for that segment. std::map _segmentWrittenLengthMemo; + // Used for calculating download speed. std::deque > peerStats; + // Keep track of fastest PeerStat for each server + std::deque > _fastestPeerStats; + // key: PeerStat's cuid, value: its download speed std::map _peerStatDlspdMap; @@ -188,10 +192,10 @@ public: */ uint64_t getDownloadLength() const; - /** - * Registers given peerStat if it has not been registerd and returns true. - * Otherwise does nothing and returns false. - */ + + // If there is inactive PeerStat in peerStats, it is replaced with + // given peerStat. If no such PeerStat exist, the given peerStat is + // inserted. void registerPeerStat(const SharedHandle& peerStat); const std::deque >& getPeerStats() const @@ -199,6 +203,17 @@ public: return peerStats; } + // If there is slower PeerStat than given peerStat for the same + // hostname and protocol in _fastestPeerStats, the former is + // replaced with latter. If there are no PeerStat with same hostname + // and protocol with given peerStat, given peerStat is inserted. + void updateFastestPeerStat(const SharedHandle& peerStat); + + const std::deque >& getFastestPeerStats() const + { + return _fastestPeerStats; + } + /** * Returns current download speed in bytes per sec. */ diff --git a/test/SegmentManTest.cc b/test/SegmentManTest.cc index aac84893..90c562b2 100644 --- a/test/SegmentManTest.cc +++ b/test/SegmentManTest.cc @@ -17,6 +17,7 @@ class SegmentManTest:public CppUnit::TestFixture { CPPUNIT_TEST(testNullBitfield); CPPUNIT_TEST(testCompleteSegment); CPPUNIT_TEST(testGetSegment_sameFileEntry); + CPPUNIT_TEST(testRegisterPeerStat); CPPUNIT_TEST_SUITE_END(); private: @@ -28,6 +29,7 @@ public: void testCompleteSegment(); void testGetPeerStat(); void testGetSegment_sameFileEntry(); + void testRegisterPeerStat(); }; @@ -124,4 +126,22 @@ void SegmentManTest::testGetSegment_sameFileEntry() CPPUNIT_ASSERT_EQUAL((size_t)3, segments.size()); } +void SegmentManTest::testRegisterPeerStat() +{ + Option op; + SharedHandle dctx(new DownloadContext()); + SharedHandle ps(new DefaultPieceStorage(dctx, &op)); + SegmentMan segman(&op, dctx, ps); + + SharedHandle p1(new PeerStat(0, "host1", "http")); + segman.registerPeerStat(p1); + CPPUNIT_ASSERT_EQUAL((size_t)1, segman.getPeerStats().size()); + SharedHandle p2(new PeerStat(0, "host2", "http")); + segman.registerPeerStat(p2); + CPPUNIT_ASSERT_EQUAL((size_t)1, segman.getPeerStats().size()); + p2->downloadStart(); + segman.registerPeerStat(p1); + CPPUNIT_ASSERT_EQUAL((size_t)2, segman.getPeerStats().size()); +} + } // namespace aria2