diff --git a/ChangeLog b/ChangeLog index cc8a41b5..ac8f5c0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2010-09-26 Tatsuhiro Tsujikawa + + Sort usedHosts by least used and faster download speed. + * src/Makefile.am + * src/RequestGroupMan.cc + * src/Triplet.h + * test/Makefile.am + * test/TripletTest.cc + 2010-09-23 Tatsuhiro Tsujikawa Made small optimization. diff --git a/src/Makefile.am b/src/Makefile.am index bce6f9f8..553b19e4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -210,7 +210,8 @@ SRCS = Socket.h\ SinkStreamFilter.cc SinkStreamFilter.h\ ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h\ NullSinkStreamFilter.cc NullSinkStreamFilter.h\ - uri.cc uri.h + uri.cc uri.h\ + Triplet.h if ENABLE_XML_RPC SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\ diff --git a/src/Makefile.in b/src/Makefile.in index a1b55ad9..74731720 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -447,7 +447,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \ ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \ NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \ - XmlRpcRequestParserController.cc \ + Triplet.h XmlRpcRequestParserController.cc \ XmlRpcRequestParserController.h \ XmlRpcRequestParserStateMachine.cc \ XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \ @@ -1241,7 +1241,7 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \ StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \ ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \ NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \ - $(am__append_1) $(am__append_2) $(am__append_3) \ + Triplet.h $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) \ diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 695d69ed..f55b07e2 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -72,6 +72,7 @@ #include "Segment.h" #include "DlAbortEx.h" #include "uri.h" +#include "Triplet.h" namespace aria2 { @@ -898,6 +899,11 @@ bool RequestGroupMan::doesOverallUploadSpeedExceed() void RequestGroupMan::getUsedHosts (std::vector >& usedHosts) { + // vector of triplet which consists of use count, -download speed, + // hostname. We want to sort by least used and faster download + // speed. We use -download speed so that we can sort them using + // operator<(). + std::vector > tempHosts; for(std::deque >::const_iterator i = requestGroups_.begin(), eoi = requestGroups_.end(); i != eoi; ++i) { const std::deque >& inFlightReqs = @@ -906,22 +912,27 @@ void RequestGroupMan::getUsedHosts inFlightReqs.begin(), eoj = inFlightReqs.end(); j != eoj; ++j) { uri::UriStruct us; if(uri::parse(us, (*j)->getUri())) { - std::vector >::iterator k; - std::vector >::iterator eok = - usedHosts.end(); - for(k = usedHosts.begin(); k != eok; ++k) { - if((*k).second == us.host) { + std::vector >::iterator k; + std::vector >::iterator eok = + tempHosts.end(); + for(k = tempHosts.begin(); k != eok; ++k) { + if((*k).third == us.host) { ++(*k).first; break; } } if(k == eok) { - usedHosts.push_back(std::make_pair(1, us.host)); + SharedHandle ss = findServerStat(us.host, us.protocol); + int invDlSpeed = !ss.isNull() && ss->isOK()? + -(static_cast(ss->getDownloadSpeed())):0; + tempHosts.push_back(makeTriplet(1, invDlSpeed, us.host)); } } } } - std::sort(usedHosts.begin(), usedHosts.end()); + std::sort(tempHosts.begin(), tempHosts.end()); + std::transform(tempHosts.begin(), tempHosts.end(), + std::back_inserter(usedHosts), Triplet2Pair<1, 3>()); } } // namespace aria2 diff --git a/src/Triplet.h b/src/Triplet.h new file mode 100644 index 00000000..303f55ab --- /dev/null +++ b/src/Triplet.h @@ -0,0 +1,151 @@ +/* */ +#ifndef D_TRIPLET_H +#define D_TRIPLET_H + +#include + +namespace aria2 { + +template +struct Triplet { + typedef T1 first_type; + typedef T2 second_type; + typedef T3 third_type; + + T1 first; + T2 second; + T3 third; + + Triplet() {} + + Triplet(const T1& t1, const T2& t2, const T3& t3): + first(t1), second(t2), third(t3) {} + + template + Triplet(const Triplet& t): + first(t.first), second(t.second), third(t.third) {} + + Triplet& operator=(const Triplet& tri) + { + if(this != &tri) { + first = tri.first; + second = tri.second; + third = tri.third; + } + return *this; + } +}; + +template +bool operator<(const Triplet& lhs, const Triplet& rhs) +{ + return lhs.first < rhs.first || + (!(rhs.first < lhs.first) && (lhs.second < rhs.second || + (!(rhs.second < lhs.second) && + lhs.third < rhs.third))); +} + +template +Triplet makeTriplet(const T1& t1, const T2& t2, const T3& t3) +{ + return Triplet(t1, t2, t3); +} + +template +struct TripletNthType; + +template +struct TripletNthType { + typedef T1 type; +}; + +template +struct TripletNthType { + typedef T2 type; +}; + +template +struct TripletNthType { + typedef T3 type; +}; + +template +struct TripletGet; + +template<> +struct TripletGet<1> { + template + static T1 get(const Triplet& tri) + { + return tri.first; + } +}; + +template<> +struct TripletGet<2> { + template + static T2 get(const Triplet& tri) + { + return tri.second; + } +}; + +template<> +struct TripletGet<3> { + template + static T3 get(const Triplet& tri) + { + return tri.third; + } +}; + +template +class Triplet2Pair { +public: + template + std::pair::type, + typename TripletNthType::type> + operator()(const Triplet& tri) const + { + return std::make_pair::type, + typename TripletNthType::type> + (TripletGet::get(tri), TripletGet::get(tri)); + } +}; + +} // namespace aria2 + +#endif // D_TRIPLET_H diff --git a/test/Makefile.am b/test/Makefile.am index 61789980..6c68f0ab 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -74,7 +74,8 @@ aria2c_SOURCES = AllTest.cc\ ValueBaseTest.cc\ ChunkedDecodingStreamFilterTest.cc\ UriTest.cc\ - MockSegment.h + MockSegment.h\ + TripletTest.cc if ENABLE_XML_RPC aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index d9836a42..b1f9638d 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -215,7 +215,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ bitfieldTest.cc DownloadContextTest.cc \ SessionSerializerTest.cc ValueBaseTest.cc \ ChunkedDecodingStreamFilterTest.cc UriTest.cc MockSegment.h \ - XmlRpcRequestParserControllerTest.cc \ + TripletTest.cc XmlRpcRequestParserControllerTest.cc \ XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \ FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \ GZipEncoderTest.cc GZipDecodingStreamFilterTest.cc \ @@ -409,9 +409,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \ DownloadContextTest.$(OBJEXT) SessionSerializerTest.$(OBJEXT) \ ValueBaseTest.$(OBJEXT) \ ChunkedDecodingStreamFilterTest.$(OBJEXT) UriTest.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) \ - $(am__objects_7) + TripletTest.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) @@ -646,7 +646,7 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \ bitfieldTest.cc DownloadContextTest.cc \ SessionSerializerTest.cc ValueBaseTest.cc \ ChunkedDecodingStreamFilterTest.cc UriTest.cc MockSegment.h \ - $(am__append_1) $(am__append_2) $(am__append_3) \ + TripletTest.cc $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) @@ -892,6 +892,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestUtil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TripletTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataDataExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataPostDownloadHandlerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRejectExtensionMessageTest.Po@am__quote@ diff --git a/test/TripletTest.cc b/test/TripletTest.cc new file mode 100644 index 00000000..ef99c795 --- /dev/null +++ b/test/TripletTest.cc @@ -0,0 +1,77 @@ +#include "Triplet.h" + +#include + +namespace aria2 { + +class TripletTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(TripletTest); + CPPUNIT_TEST(testLess); + CPPUNIT_TEST(testTripletGet); + CPPUNIT_TEST(testTripletNthType); + CPPUNIT_TEST(testTriplet2Pair); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp() {} + + void tearDown() {} + + void testLess(); + void testTripletGet(); + void testTripletNthType(); + void testTriplet2Pair(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TripletTest); + +void TripletTest::testLess() +{ + Triplet tri1(0, 1, 1); + Triplet tri2(1, 0, 0); + CPPUNIT_ASSERT(!(tri1 < tri1)); + CPPUNIT_ASSERT(tri1 < tri2); + CPPUNIT_ASSERT(!(tri2 < tri1)); + + Triplet tri3(0, 0, 1); + Triplet tri4(0, 1, 0); + CPPUNIT_ASSERT(tri3 < tri4); + CPPUNIT_ASSERT(!(tri4 < tri3)); + + Triplet tri5(0, 0, 0); + Triplet tri6(0, 0, 1); + CPPUNIT_ASSERT(tri5 < tri6); + CPPUNIT_ASSERT(!(tri6 < tri5)); +} + +void TripletTest::testTripletGet() +{ + Triplet x(1, 3.14, "foo"); + CPPUNIT_ASSERT_EQUAL(1, (TripletGet<1>::get(x))); + CPPUNIT_ASSERT_EQUAL((double)3.14, (TripletGet<2>::get(x))); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), (TripletGet<3>::get(x))); +} + +void TripletTest::testTripletNthType() +{ + TripletNthType::type x = 1; + CPPUNIT_ASSERT_EQUAL(1, x); + TripletNthType::type y = 3.14; + CPPUNIT_ASSERT_EQUAL((double)3.14, y); + TripletNthType::type z = "foo"; + CPPUNIT_ASSERT_EQUAL(std::string("foo"), z); +} + +void TripletTest::testTriplet2Pair() +{ + Triplet x(1, 3.14, "foo"); + std::pair p1 = Triplet2Pair<1, 2>()(x); + CPPUNIT_ASSERT_EQUAL(1, p1.first); + CPPUNIT_ASSERT_EQUAL((double)3.14, p1.second); + + std::pair p2 = Triplet2Pair<2, 3>()(x); + CPPUNIT_ASSERT_EQUAL((double)3.14, p2.first); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), p2.second); +} + +} // namespace aria2