Added --retry-wait option.

This option was once existed in aria2 but erased on 2009-09-20.  Now
it is resurrected once again.  We choose 2 as default value, but there
is no good theory behind it.  Now we retry HTTP download when remote
server returns 503 Service Unavailable if --retry-wait > 0. We also
added error code 29: HTTP_SERVICE_UNAVAILABLE.
pull/1/head
Tatsuhiro Tsujikawa 2011-01-17 21:19:45 +09:00
parent 4824b09237
commit f2a63fa06a
13 changed files with 77 additions and 7 deletions

View File

@ -306,6 +306,9 @@ bool AbstractCommand::execute() {
tryReserved();
return true;
} else {
Timer wakeTime(global::wallclock);
wakeTime.advance(getOption()->getAsInt(PREF_RETRY_WAIT));
req_->setWakeTime(wakeTime);
return prepareForRetry(0);
}
} catch(DownloadFailureException& err) {

View File

@ -46,6 +46,8 @@
#include "RequestGroupMan.h"
#include "FileEntry.h"
#include "SocketRecvBuffer.h"
#include "LogFactory.h"
#include "wallclock.h"
namespace aria2 {
@ -93,6 +95,11 @@ bool CreateRequestCommand::executeInternal()
getSegmentMan()->ignoreSegmentFor(getFileEntry());
}
throw DL_ABORT_EX("No URI available.");
} else if(getRequest()->getWakeTime() > global::wallclock) {
A2_LOG_DEBUG("This request object is still sleeping.");
getFileEntry()->poolRequest(getRequest());
getDownloadEngine()->addCommand(this);
return false;
}
Command* command =

View File

@ -170,9 +170,23 @@ FileEntry::getRequest
break;
}
}
} else {
req = requestPool_.front();
requestPool_.pop_front();
} else {
// Skip Request object if it is still
// sleeping(Request::getWakeTime() < global::wallclock). If all
// pooled objects are sleeping, return first one. Caller should
// inspect returned object's getWakeTime().
std::deque<SharedHandle<Request> >::iterator i = requestPool_.begin();
std::deque<SharedHandle<Request> >::iterator eoi = requestPool_.end();
for(; i != eoi; ++i) {
if((*i)->getWakeTime() <= global::wallclock) {
break;
}
}
if(i == eoi) {
i = requestPool_.begin();
}
req = *i;
requestPool_.erase(i);
inFlightRequests_.push_back(req);
A2_LOG_DEBUG(fmt("Picked up from pool: %s", req->getUri().c_str()));
}

View File

@ -207,6 +207,16 @@ bool HttpSkipResponseCommand::processResponse()
} else if(statusCode == 404) {
throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
error_code::RESOURCE_NOT_FOUND);
} else if(statusCode == 503) {
// Only retry if pretry-wait > 0. Hammering 'busy' server is not
// a good idea.
if(getOption()->getAsInt(PREF_RETRY_WAIT) > 0) {
throw DL_RETRY_EX2(fmt(EX_BAD_STATUS, statusCode),
error_code::HTTP_SERVICE_UNAVAILABLE);
} else {
throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, statusCode),
error_code::HTTP_SERVICE_UNAVAILABLE);
}
} else {
throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, statusCode),
error_code::HTTP_PROTOCOL_ERROR);

View File

@ -689,6 +689,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_HTTP);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new NumberOptionHandler
(PREF_RETRY_WAIT,
TEXT_RETRY_WAIT,
"2",
0, 600));
op->addTag(TAG_FTP);
op->addTag(TAG_HTTP);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new BooleanOptionHandler
(PREF_REUSE_URI,

View File

@ -42,6 +42,7 @@
#include "A2STR.h"
#include "uri.h"
#include "PeerStat.h"
#include "wallclock.h"
namespace aria2 {
@ -66,7 +67,8 @@ Request::Request():
hasPassword_(false),
ipv6LiteralAddress_(false),
removalRequested_(false),
connectedPort_(0)
connectedPort_(0),
wakeTime_(global::wallclock)
{}
Request::~Request() {}

View File

@ -39,6 +39,7 @@
#include <string>
#include "SharedHandle.h"
#include "TimerA2.h"
namespace aria2 {
@ -96,6 +97,8 @@ private:
uint16_t connectedPort_;
Timer wakeTime_;
bool parseUri(const std::string& uri);
public:
Request();
@ -229,6 +232,16 @@ public:
return connectedPort_;
}
void setWakeTime(Timer timer)
{
wakeTime_ = timer;
}
const Timer& getWakeTime()
{
return wakeTime_;
}
static const std::string METHOD_GET;
static const std::string METHOD_HEAD;

View File

@ -75,6 +75,11 @@ bool Timer::operator<(const Timer& timer) const
return util::difftv(timer.tv_, tv_) > 0;
}
bool Timer::operator<=(const Timer& timer) const
{
return util::difftv(timer.tv_, tv_) >= 0;
}
bool Timer::operator>(const Timer& timer) const
{
return util::difftv(tv_, timer.tv_) > 0;

View File

@ -59,6 +59,8 @@ public:
bool operator<(const Timer& timer) const;
bool operator<=(const Timer& timer) const;
bool operator>(const Timer& timer) const;
void reset();

View File

@ -71,7 +71,8 @@ enum Value {
BENCODE_PARSE_ERROR = 25,
BITTORRENT_PARSE_ERROR = 26,
MAGNET_PARSE_ERROR = 27,
OPTION_ERROR = 28
OPTION_ERROR = 28,
HTTP_SERVICE_UNAVAILABLE = 29
};
} // namespace error_code

View File

@ -202,6 +202,8 @@ const std::string PREF_SELECT_LEAST_USED_HOST("select-least-used-host");
const std::string PREF_ENABLE_ASYNC_DNS6("enable-async-dns6");
// value: 1*digit
const std::string PREF_MAX_DOWNLOAD_RESULT("max-download-result");
// value: 1*digit
const std::string PREF_RETRY_WAIT("retry-wait");
/**
* FTP related preferences

View File

@ -206,6 +206,8 @@ extern const std::string PREF_SELECT_LEAST_USED_HOST;
extern const std::string PREF_ENABLE_ASYNC_DNS6;
// value: 1*digit
extern const std::string PREF_MAX_DOWNLOAD_RESULT;
// value: 1*digit
extern const std::string PREF_RETRY_WAIT;
/**
* FTP related preferences

View File

@ -59,8 +59,7 @@
" Please note that in Metalink download, this\n" \
" option has no effect and use -C option instead.")
#define TEXT_RETRY_WAIT \
_(" --retry-wait=SEC Set the seconds to wait to retry after an error\n" \
" has occured.")
_(" --retry-wait=SEC Set the seconds to wait between retries.")
#define TEXT_TIMEOUT \
_(" -t, --timeout=SEC Set timeout in seconds.")
#define TEXT_MAX_TRIES \