mirror of https://github.com/aria2/aria2
2007-11-07 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Reflect the download length of in-flight pieces. It makes the download length readout more precise. * src/DefaultPieceStorage.{h, cc} * test/DefaultPieceStorageTest.cc * src/a2functional.h * test/a2functionalTest.cc Lower CPU load when --max-download-limit is used. There is up and down in speed indicator when enabling http-pipelining but a download goes well. I think the problem is that because http-pipelining is enabled, DownloadCommand is created for each segment and in its constructor, PeerStat::downloadStart() is called. In PeerStat::downloadStart(), speed calculation object is reseted, which makes download speed zero. * src/DownloadCommand.cc Rewritten using accumulate. * src/RequestGroupMan.cc (calculateStat) Code clearnup. * src/FtpNegotiationCommand.cc * src/HttpResponseCommand.ccpull/1/head
parent
dfd40dff54
commit
b4f7588ba2
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
|||
2007-11-07 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
Reflect the download length of in-flight pieces.
|
||||
It makes the download length readout more precise.
|
||||
* src/DefaultPieceStorage.{h, cc}
|
||||
* test/DefaultPieceStorageTest.cc
|
||||
* src/a2functional.h
|
||||
* test/a2functionalTest.cc
|
||||
|
||||
Lower CPU load when --max-download-limit is used.
|
||||
There is up and down in speed indicator when enabling
|
||||
http-pipelining but a download goes well. I think the problem is that
|
||||
because http-pipelining is enabled, DownloadCommand is created for
|
||||
each segment and in its constructor, PeerStat::downloadStart() is
|
||||
called. In PeerStat::downloadStart(), speed calculation object is
|
||||
reseted, which makes download speed zero.
|
||||
* src/DownloadCommand.cc
|
||||
|
||||
Rewritten using accumulate.
|
||||
* src/RequestGroupMan.cc (calculateStat)
|
||||
|
||||
Code clearnup.
|
||||
* src/FtpNegotiationCommand.cc
|
||||
* src/HttpResponseCommand.cc
|
||||
|
||||
2007-11-06 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
Fixed: Can not resume: aria2 reports download already finished.
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#include "DefaultDiskWriterFactory.h"
|
||||
#include "DlAbortEx.h"
|
||||
#include "Util.h"
|
||||
#include "a2functional.h"
|
||||
#include <numeric>
|
||||
|
||||
DefaultPieceStorage::DefaultPieceStorage(const DownloadContextHandle& downloadContext, const Option* option):
|
||||
downloadContext(downloadContext),
|
||||
|
@ -358,12 +360,17 @@ int64_t DefaultPieceStorage::getFilteredTotalLength()
|
|||
|
||||
int64_t DefaultPieceStorage::getCompletedLength()
|
||||
{
|
||||
return bitfieldMan->getCompletedLength();
|
||||
return bitfieldMan->getCompletedLength()+getInFlightPieceCompletedLength();
|
||||
}
|
||||
|
||||
int64_t DefaultPieceStorage::getFilteredCompletedLength()
|
||||
{
|
||||
return bitfieldMan->getFilteredCompletedLength();
|
||||
return bitfieldMan->getFilteredCompletedLength()+getInFlightPieceCompletedLength();
|
||||
}
|
||||
|
||||
int32_t DefaultPieceStorage::getInFlightPieceCompletedLength() const
|
||||
{
|
||||
return accumulate(usedPieces.begin(), usedPieces.end(), 0, adopt2nd(plus<int32_t>(), mem_fun_sh(&Piece::getCompletedLength)));
|
||||
}
|
||||
|
||||
// not unittested
|
||||
|
|
|
@ -88,6 +88,9 @@ private:
|
|||
void reduceUsedPieces(int32_t delMax);
|
||||
void deleteUsedPiece(const PieceHandle& piece);
|
||||
PieceHandle findUsedPiece(int32_t index) const;
|
||||
|
||||
int32_t getInFlightPieceCompletedLength() const;
|
||||
|
||||
public:
|
||||
DefaultPieceStorage(const DownloadContextHandle& downloadContext, const Option* option);
|
||||
virtual ~DefaultPieceStorage();
|
||||
|
|
|
@ -79,10 +79,11 @@ bool DownloadCommand::executeInternal() {
|
|||
// TODO we need to specify the sum of all segmentMan's download speed here.
|
||||
if(maxDownloadSpeedLimit > 0 &&
|
||||
maxDownloadSpeedLimit < _requestGroup->getSegmentMan()->calculateDownloadSpeed()) {
|
||||
Util::usleep(1);
|
||||
e->commands.push_back(this);
|
||||
disableReadCheckSocket();
|
||||
return false;
|
||||
}
|
||||
setReadCheckSocket(socket);
|
||||
SegmentHandle segment = _segments.front();
|
||||
|
||||
int32_t BUFSIZE = 16*1024;
|
||||
|
|
|
@ -200,10 +200,11 @@ bool FtpNegotiationCommand::recvSize() {
|
|||
|
||||
initPieceStorage();
|
||||
|
||||
// TODO validate filename and totalsize against hintFilename and hintTotalSize if these are provided.
|
||||
// TODO validate totalsize against hintTotalSize if it is provided.
|
||||
_requestGroup->validateTotalLengthByHint(size);
|
||||
// TODO Is this really necessary?
|
||||
if(req->getMethod() == Request::METHOD_HEAD) {
|
||||
//_requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved.
|
||||
// TODO because we don't want segment file to be saved.
|
||||
sequence = SEQ_HEAD_OK;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -75,12 +75,6 @@ bool HttpResponseCommand::executeInternal()
|
|||
// check HTTP status number
|
||||
httpResponse->validateResponse();
|
||||
httpResponse->retrieveCookie();
|
||||
// check whether the server supports persistent connections.
|
||||
/*
|
||||
if(Util::toLower(headers.getFirst("Connection")).find("close") != string::npos) {
|
||||
req->setKeepAlive(false);
|
||||
}
|
||||
*/
|
||||
// check whether Location header exists. If it does, update request object
|
||||
// with redirected URL.
|
||||
// then establish a connection to the new host and port
|
||||
|
@ -116,18 +110,13 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe
|
|||
if(size == INT64_MAX || size < 0) {
|
||||
throw new DlAbortEx(EX_TOO_LARGE_FILE, Util::llitos(size, true).c_str());
|
||||
}
|
||||
//_requestGroup->getSegmentMan()->isSplittable = !(size == 0);
|
||||
//_requestGroup->getSegmentMan()->totalSize = size;
|
||||
//_requestGroup->getSegmentMan()->initDownloadContext(size);
|
||||
|
||||
SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setTotalLength(size);
|
||||
|
||||
initPieceStorage();
|
||||
|
||||
// quick hack for method 'head'
|
||||
// quick hack for method 'head',, is it necessary?
|
||||
if(httpRequest->getMethod() == Request::METHOD_HEAD) {
|
||||
// TODO because we don't want segment file to be saved.
|
||||
//_requestGroup->getSegmentMan()->isSplittable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -156,11 +145,9 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe
|
|||
}
|
||||
|
||||
bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResponse) {
|
||||
HttpRequestHandle httpRequest = httpResponse->getHttpRequest();
|
||||
// we ignore content-length when transfer-encoding is set
|
||||
//_requestGroup->getSegmentMan()->isSplittable = false;
|
||||
//_requestGroup->getSegmentMan()->totalSize = 0;
|
||||
// quick hack for method 'head'
|
||||
HttpRequestHandle httpRequest = httpResponse->getHttpRequest();
|
||||
// quick hack for method 'head',, is it necessary?
|
||||
if(httpRequest->getMethod() == Request::METHOD_HEAD) {
|
||||
return true;
|
||||
}
|
||||
|
@ -169,11 +156,9 @@ bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResp
|
|||
|
||||
initPieceStorage();
|
||||
|
||||
//segment = _requestGroup->getSegmentMan()->getSegment(cuid);
|
||||
|
||||
shouldCancelDownloadForSafety();
|
||||
// TODO handle file-size unknown case
|
||||
_requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();//_requestGroup->getFilePath());
|
||||
_requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
|
||||
e->commands.push_back(createHttpDownloadCommand(httpResponse));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,10 @@
|
|||
#include "LogFactory.h"
|
||||
#include "DownloadEngine.h"
|
||||
#include "message.h"
|
||||
#include "a2functional.h"
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
|
||||
RequestGroupMan::RequestGroupMan(const RequestGroups& requestGroups,
|
||||
int32_t maxSimultaneousDownloads):
|
||||
|
@ -277,10 +279,6 @@ void RequestGroupMan::halt()
|
|||
|
||||
TransferStat RequestGroupMan::calculateStat()
|
||||
{
|
||||
TransferStat stat;
|
||||
for(RequestGroups::const_iterator itr = _requestGroups.begin();
|
||||
itr != _requestGroups.end(); ++itr) {
|
||||
stat = stat+(*itr)->calculateStat();
|
||||
}
|
||||
return stat;
|
||||
return accumulate(_requestGroups.begin(), _requestGroups.end(), TransferStat(),
|
||||
adopt2nd(plus<TransferStat>(), mem_fun_sh(&RequestGroup::calculateStat)));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/* <!-- copyright */
|
||||
/*
|
||||
* aria2 - The high speed download utility
|
||||
*
|
||||
* Copyright (C) 2006 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the
|
||||
* OpenSSL library under certain conditions as described in each
|
||||
* individual source file, and distribute linked combinations
|
||||
* including the two.
|
||||
* You must obey the GNU General Public License in all respects
|
||||
* for all of the code used other than OpenSSL. If you modify
|
||||
* file(s) with this exception, you may extend this exception to your
|
||||
* version of the file(s), but you are not obligated to do so. If you
|
||||
* do not wish to do so, delete this exception statement from your
|
||||
* version. If you delete this exception statement from all source
|
||||
* files in the program, then also delete it here.
|
||||
*/
|
||||
/* copyright --> */
|
||||
#include <functional>
|
||||
#include "SharedHandle.h"
|
||||
|
||||
// mem_fun_t for SharedHandle
|
||||
template <class ReturnType, typename ClassType>
|
||||
class mem_fun_sh_t:public std::unary_function< SharedHandle<ClassType>, ReturnType>
|
||||
{
|
||||
private:
|
||||
ReturnType (ClassType::*f)();
|
||||
|
||||
public:
|
||||
mem_fun_sh_t(ReturnType (ClassType::*f)()):f(f) {}
|
||||
|
||||
ReturnType operator()(const SharedHandle<ClassType>& x) const
|
||||
{
|
||||
return (x.get()->*f)();
|
||||
}
|
||||
};
|
||||
|
||||
// const_mem_fun_t for SharedHandle
|
||||
template <class ReturnType, typename ClassType>
|
||||
class const_mem_fun_sh_t:public std::unary_function< SharedHandle<ClassType>, ReturnType>
|
||||
{
|
||||
private:
|
||||
ReturnType (ClassType::*f)() const;
|
||||
|
||||
public:
|
||||
const_mem_fun_sh_t(ReturnType (ClassType::*f)() const):f(f) {}
|
||||
|
||||
ReturnType operator()(const SharedHandle<ClassType>& x) const
|
||||
{
|
||||
return (x.get()->*f)();
|
||||
}
|
||||
};
|
||||
|
||||
template <class ReturnType, typename ClassType>
|
||||
mem_fun_sh_t<ReturnType, ClassType>
|
||||
mem_fun_sh(ReturnType (ClassType::*f)())
|
||||
{
|
||||
return mem_fun_sh_t<ReturnType, ClassType>(f);
|
||||
};
|
||||
|
||||
template <class ReturnType, typename ClassType>
|
||||
const_mem_fun_sh_t<ReturnType, ClassType>
|
||||
mem_fun_sh(ReturnType (ClassType::*f)() const)
|
||||
{
|
||||
return const_mem_fun_sh_t<ReturnType, ClassType>(f);
|
||||
};
|
||||
|
||||
template<class BinaryOp, class UnaryOp>
|
||||
class adopt2nd_t:public std::binary_function<typename BinaryOp::first_argument_type,
|
||||
typename UnaryOp::argument_type,
|
||||
typename BinaryOp::result_type> {
|
||||
private:
|
||||
BinaryOp _binaryOp;
|
||||
UnaryOp _unaryOp;
|
||||
public:
|
||||
adopt2nd_t(const BinaryOp& b, const UnaryOp& u):
|
||||
_binaryOp(b), _unaryOp(u) {}
|
||||
|
||||
typename BinaryOp::result_type
|
||||
operator()(const typename BinaryOp::first_argument_type& x,
|
||||
const typename UnaryOp::argument_type& y)
|
||||
{
|
||||
return _binaryOp(x, _unaryOp(y));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class BinaryOp, class UnaryOp>
|
||||
inline adopt2nd_t<BinaryOp, UnaryOp>
|
||||
adopt2nd(const BinaryOp& binaryOp, const UnaryOp& unaryOp)
|
||||
{
|
||||
return adopt2nd_t<BinaryOp, UnaryOp>(binaryOp, unaryOp);
|
||||
};
|
|
@ -119,20 +119,24 @@ void DefaultPieceStorageTest::testCompletePiece() {
|
|||
DefaultPieceStorage pss(btContext, option);
|
||||
pss.setEndGamePieceNum(0);
|
||||
|
||||
peer->setAllBitfield();
|
||||
peer->setAllBitfield();
|
||||
|
||||
PieceHandle piece = pss.getMissingPiece(peer);
|
||||
CPPUNIT_ASSERT_EQUAL(string("piece: index=0, length=128"),
|
||||
piece->toString());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL((long long int)0,
|
||||
CPPUNIT_ASSERT_EQUAL((int64_t)0,
|
||||
pss.getCompletedLength());
|
||||
|
||||
pss.completePiece(piece);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL((long long int)128,
|
||||
CPPUNIT_ASSERT_EQUAL((int64_t)128,
|
||||
pss.getCompletedLength());
|
||||
|
||||
PieceHandle incompletePiece = pss.getMissingPiece(peer);
|
||||
incompletePiece->completeBlock(0);
|
||||
CPPUNIT_ASSERT_EQUAL((int64_t)256,
|
||||
pss.getCompletedLength());
|
||||
}
|
||||
|
||||
void DefaultPieceStorageTest::testGetPiece() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
TESTS = aria2c
|
||||
check_PROGRAMS = $(TESTS)
|
||||
aria2c_SOURCES = AllTest.cc\
|
||||
a2functionalTest.cc\
|
||||
FileEntryTest.cc\
|
||||
PieceTest.cc\
|
||||
DefaultPieceStorageTest.cc\
|
||||
|
|
|
@ -112,8 +112,9 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
|||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
am__EXEEXT_1 = aria2c$(EXEEXT)
|
||||
am__aria2c_SOURCES_DIST = AllTest.cc FileEntryTest.cc PieceTest.cc \
|
||||
DefaultPieceStorageTest.cc SegmentTest.cc GrowSegmentTest.cc \
|
||||
am__aria2c_SOURCES_DIST = AllTest.cc a2functionalTest.cc \
|
||||
FileEntryTest.cc PieceTest.cc DefaultPieceStorageTest.cc \
|
||||
SegmentTest.cc GrowSegmentTest.cc \
|
||||
SingleFileAllocationIteratorTest.cc \
|
||||
DefaultBtProgressInfoFileTest.cc \
|
||||
SingleFileDownloadContextTest.cc RequestGroupTest.cc \
|
||||
|
@ -203,9 +204,10 @@ am__aria2c_SOURCES_DIST = AllTest.cc FileEntryTest.cc PieceTest.cc \
|
|||
@ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \
|
||||
@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandlerTest.$(OBJEXT) \
|
||||
@ENABLE_METALINK_TRUE@ MetalinkHelperTest.$(OBJEXT)
|
||||
am_aria2c_OBJECTS = AllTest.$(OBJEXT) FileEntryTest.$(OBJEXT) \
|
||||
PieceTest.$(OBJEXT) DefaultPieceStorageTest.$(OBJEXT) \
|
||||
SegmentTest.$(OBJEXT) GrowSegmentTest.$(OBJEXT) \
|
||||
am_aria2c_OBJECTS = AllTest.$(OBJEXT) a2functionalTest.$(OBJEXT) \
|
||||
FileEntryTest.$(OBJEXT) PieceTest.$(OBJEXT) \
|
||||
DefaultPieceStorageTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
|
||||
GrowSegmentTest.$(OBJEXT) \
|
||||
SingleFileAllocationIteratorTest.$(OBJEXT) \
|
||||
DefaultBtProgressInfoFileTest.$(OBJEXT) \
|
||||
SingleFileDownloadContextTest.$(OBJEXT) \
|
||||
|
@ -414,9 +416,9 @@ target_cpu = @target_cpu@
|
|||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
TESTS = aria2c
|
||||
aria2c_SOURCES = AllTest.cc FileEntryTest.cc PieceTest.cc \
|
||||
DefaultPieceStorageTest.cc SegmentTest.cc GrowSegmentTest.cc \
|
||||
SingleFileAllocationIteratorTest.cc \
|
||||
aria2c_SOURCES = AllTest.cc a2functionalTest.cc FileEntryTest.cc \
|
||||
PieceTest.cc DefaultPieceStorageTest.cc SegmentTest.cc \
|
||||
GrowSegmentTest.cc SingleFileAllocationIteratorTest.cc \
|
||||
DefaultBtProgressInfoFileTest.cc \
|
||||
SingleFileDownloadContextTest.cc RequestGroupTest.cc \
|
||||
PStringBuildVisitorTest.cc ParameterizedStringParserTest.cc \
|
||||
|
@ -584,6 +586,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2functionalTest.Po@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#include "a2functional.h"
|
||||
#include <string>
|
||||
#include <numeric>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class a2functionalTest:public CppUnit::TestFixture {
|
||||
|
||||
CPPUNIT_TEST_SUITE(a2functionalTest);
|
||||
CPPUNIT_TEST(testMemFunSh);
|
||||
CPPUNIT_TEST(testAdopt2nd);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
public:
|
||||
void testMemFunSh();
|
||||
void testAdopt2nd();
|
||||
|
||||
class Greeting {
|
||||
public:
|
||||
virtual ~Greeting() {}
|
||||
|
||||
virtual string sayGreeting() = 0;
|
||||
|
||||
virtual string sayGreetingConst() const = 0;
|
||||
};
|
||||
|
||||
typedef SharedHandle<Greeting> GreetingHandle;
|
||||
|
||||
class JapaneseGreeting:public Greeting
|
||||
{
|
||||
virtual string sayGreeting()
|
||||
{
|
||||
return "HAROO WAARUDO";
|
||||
}
|
||||
|
||||
virtual string sayGreetingConst() const
|
||||
{
|
||||
return "HAROO WAARUDO";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(a2functionalTest);
|
||||
|
||||
void a2functionalTest::testMemFunSh()
|
||||
{
|
||||
GreetingHandle greeting = new JapaneseGreeting();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(string("HAROO WAARUDO"), mem_fun_sh(&Greeting::sayGreeting)(greeting));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(string("HAROO WAARUDO"), mem_fun_sh(&Greeting::sayGreetingConst)(greeting));
|
||||
|
||||
}
|
||||
|
||||
void a2functionalTest::testAdopt2nd()
|
||||
{
|
||||
GreetingHandle greeting = new JapaneseGreeting();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(string("A Japanese said:HAROO WAARUDO"),
|
||||
adopt2nd(plus<string>(), mem_fun_sh(&Greeting::sayGreeting))("A Japanese said:", greeting));
|
||||
}
|
Loading…
Reference in New Issue