Added --deferred-input option.

If true is given to --deferred-input option, aria2 does not read all
URIs and options from file specified by -i option at startup, but it
reads one by one when it needs later. This may reduce memory usage if
input file contains a lot of URIs to download. If false is given,
aria2 reads all URIs and options at startup. This option defaults to
false.
pull/9/head
Tatsuhiro Tsujikawa 2012-02-05 18:57:16 +09:00
parent b8121faf93
commit f2d55f0edc
12 changed files with 141 additions and 27 deletions

View File

@ -42,6 +42,7 @@ Basic Options
URI. This optional line must start with one or more white spaces and have URI. This optional line must start with one or more white spaces and have
one option per single line. one option per single line.
See *<<_input_file, Input File>>* subsection for details. See *<<_input_file, Input File>>* subsection for details.
See also *<<aria2_optref_deferred_input, --deferred-input>>* option.
[[aria2_optref_log]]*-l*, *--log*=LOG:: [[aria2_optref_log]]*-l*, *--log*=LOG::
The file name of the log file. If '-' is specified, log is written to The file name of the log file. If '-' is specified, log is written to
@ -916,6 +917,16 @@ Advanced Options
and standard input, standard output and standard error will be and standard input, standard output and standard error will be
redirected to '/dev/null'. Default: 'false' redirected to '/dev/null'. Default: 'false'
[[aria2_optref_deferred_input]]*--deferred-input*[='true'|'false']::
If 'true' is given, aria2 does not read all URIs and options from file
specified by *<<aria2_optref_input_file, -i>>* option at startup,
but it reads one by one when it
needs later. This may reduce memory usage if input file contains a
lot of URIs to download. If 'false' is given, aria2 reads all URIs
and options at startup.
Default: 'false'
[[aria2_optref_disable_ipv6]]*--disable-ipv6*[='true'|'false']:: [[aria2_optref_disable_ipv6]]*--disable-ipv6*[='true'|'false']::
Disable IPv6. This is useful if you have to use broken DNS and want Disable IPv6. This is useful if you have to use broken DNS and want

View File

@ -60,6 +60,7 @@
#include "fmt.h" #include "fmt.h"
#include "SocketCore.h" #include "SocketCore.h"
#include "OutputFile.h" #include "OutputFile.h"
#include "UriListParser.h"
#ifdef ENABLE_SSL #ifdef ENABLE_SSL
# include "TLSContext.h" # include "TLSContext.h"
#endif // ENABLE_SSL #endif // ENABLE_SSL
@ -143,11 +144,13 @@ MultiUrlRequestInfo::MultiUrlRequestInfo
(const std::vector<SharedHandle<RequestGroup> >& requestGroups, (const std::vector<SharedHandle<RequestGroup> >& requestGroups,
const SharedHandle<Option>& op, const SharedHandle<Option>& op,
const SharedHandle<StatCalc>& statCalc, const SharedHandle<StatCalc>& statCalc,
const SharedHandle<OutputFile>& summaryOut) const SharedHandle<OutputFile>& summaryOut,
const SharedHandle<UriListParser>& uriListParser)
: requestGroups_(requestGroups), : requestGroups_(requestGroups),
option_(op), option_(op),
statCalc_(statCalc), statCalc_(statCalc),
summaryOut_(summaryOut) summaryOut_(summaryOut),
uriListParser_(uriListParser)
{} {}
MultiUrlRequestInfo::~MultiUrlRequestInfo() {} MultiUrlRequestInfo::~MultiUrlRequestInfo() {}
@ -235,6 +238,9 @@ error_code::Value MultiUrlRequestInfo::execute()
(option_->getAsInt(PREF_SERVER_STAT_TIMEOUT)); (option_->getAsInt(PREF_SERVER_STAT_TIMEOUT));
} }
e->setStatCalc(statCalc_); e->setStatCalc(statCalc_);
if(uriListParser_) {
e->getRequestGroupMan()->setUriListParser(uriListParser_);
}
#ifdef SIGHUP #ifdef SIGHUP
util::setGlobalSignalHandler(SIGHUP, handler, 0); util::setGlobalSignalHandler(SIGHUP, handler, 0);
#endif // SIGHUP #endif // SIGHUP

View File

@ -48,6 +48,7 @@ class RequestGroup;
class Option; class Option;
class StatCalc; class StatCalc;
class OutputFile; class OutputFile;
class UriListParser;
class MultiUrlRequestInfo { class MultiUrlRequestInfo {
private: private:
@ -59,13 +60,16 @@ private:
SharedHandle<OutputFile> summaryOut_; SharedHandle<OutputFile> summaryOut_;
SharedHandle<UriListParser> uriListParser_;
void printMessageForContinue(); void printMessageForContinue();
public: public:
MultiUrlRequestInfo MultiUrlRequestInfo
(const std::vector<SharedHandle<RequestGroup> >& requestGroups, (const std::vector<SharedHandle<RequestGroup> >& requestGroups,
const SharedHandle<Option>& op, const SharedHandle<Option>& op,
const SharedHandle<StatCalc>& statCalc, const SharedHandle<StatCalc>& statCalc,
const SharedHandle<OutputFile>& summaryOut); const SharedHandle<OutputFile>& summaryOut,
const SharedHandle<UriListParser>& uriListParser);
virtual ~MultiUrlRequestInfo(); virtual ~MultiUrlRequestInfo();

View File

@ -201,6 +201,15 @@ OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_ADVANCED); op->addTag(TAG_ADVANCED);
handlers.push_back(op); handlers.push_back(op);
} }
{
SharedHandle<OptionHandler> op(new BooleanOptionHandler
(PREF_DEFERRED_INPUT,
TEXT_DEFERRED_INPUT,
A2_V_FALSE,
OptionHandler::OPT_ARG));
op->addTag(TAG_ADVANCED);
handlers.push_back(op);
}
{ {
SharedHandle<OptionHandler> op(new DefaultOptionHandler SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DIR, (PREF_DIR,

View File

@ -74,6 +74,8 @@
#include "Triplet.h" #include "Triplet.h"
#include "Signature.h" #include "Signature.h"
#include "OutputFile.h" #include "OutputFile.h"
#include "download_helper.h"
#include "UriListParser.h"
namespace aria2 { namespace aria2 {
@ -485,7 +487,21 @@ void RequestGroupMan::fillRequestGroupFromReserver(DownloadEngine* e)
std::vector<SharedHandle<RequestGroup> > temp; std::vector<SharedHandle<RequestGroup> > temp;
int count = 0; int count = 0;
int num = maxSimultaneousDownloads_-requestGroups_.size(); int num = maxSimultaneousDownloads_-requestGroups_.size();
while(count < num && !reservedGroups_.empty()) { while(count < num && (uriListParser_ || !reservedGroups_.empty())) {
if(uriListParser_ && reservedGroups_.empty()) {
std::vector<SharedHandle<RequestGroup> > groups;
bool ok = createRequestGroupFromUriListParser(groups, option_,
uriListParser_.get());
if(ok) {
reservedGroups_.insert(reservedGroups_.end(), groups.begin(),
groups.end());
} else {
uriListParser_.reset();
if(reservedGroups_.empty()) {
break;
}
}
}
SharedHandle<RequestGroup> groupToAdd = reservedGroups_.front(); SharedHandle<RequestGroup> groupToAdd = reservedGroups_.front();
reservedGroups_.pop_front(); reservedGroups_.pop_front();
std::vector<Command*> commands; std::vector<Command*> commands;
@ -962,4 +978,10 @@ void RequestGroupMan::getUsedHosts
std::back_inserter(usedHosts), Tuple2Pair<1, 3>()); std::back_inserter(usedHosts), Tuple2Pair<1, 3>());
} }
void RequestGroupMan::setUriListParser
(const SharedHandle<UriListParser>& uriListParser)
{
uriListParser_ = uriListParser;
}
} // namespace aria2 } // namespace aria2

View File

@ -55,6 +55,7 @@ class ServerStatMan;
class ServerStat; class ServerStat;
class Option; class Option;
class OutputFile; class OutputFile;
class UriListParser;
class RequestGroupMan { class RequestGroupMan {
private: private:
@ -85,6 +86,9 @@ private:
int maxDownloadResult_; int maxDownloadResult_;
// UriListParser for deferred input.
SharedHandle<UriListParser> uriListParser_;
void formatDownloadResultFull void formatDownloadResultFull
(OutputFile& out, (OutputFile& out,
const std::string& status, const std::string& status,
@ -309,6 +313,8 @@ public:
{ {
maxDownloadResult_ = v; maxDownloadResult_ = v;
} }
void setUriListParser(const SharedHandle<UriListParser>& uriListParser);
}; };
typedef SharedHandle<RequestGroupMan> RequestGroupManHandle; typedef SharedHandle<RequestGroupMan> RequestGroupManHandle;

View File

@ -412,21 +412,23 @@ void createRequestGroupForUri
} }
} }
namespace { bool createRequestGroupFromUriListParser
void createRequestGroupForUriList
(std::vector<SharedHandle<RequestGroup> >& result, (std::vector<SharedHandle<RequestGroup> >& result,
const SharedHandle<Option>& option, const Option* option,
const std::string& filename) UriListParser* uriListParser)
{ {
UriListParser p(filename); // Since result already contains some entries, we cache the size of
while(p.hasNext()) { // it. Later, we use this value to determine RequestGroup is
// actually created.
size_t num = result.size();
while(uriListParser->hasNext()) {
std::vector<std::string> uris; std::vector<std::string> uris;
Option tempOption; Option tempOption;
p.parseNext(uris, tempOption); uriListParser->parseNext(uris, tempOption);
if(uris.empty()) { if(uris.empty()) {
continue; continue;
} }
SharedHandle<Option> requestOption(new Option(*option.get())); SharedHandle<Option> requestOption(new Option(*option));
requestOption->remove(PREF_OUT); requestOption->remove(PREF_OUT);
const SharedHandle<OptionParser>& oparser = OptionParser::getInstance(); const SharedHandle<OptionParser>& oparser = OptionParser::getInstance();
for(size_t i = 1, len = option::countOption(); i < len; ++i) { for(size_t i = 1, len = option::countOption(); i < len; ++i) {
@ -436,25 +438,38 @@ void createRequestGroupForUriList
requestOption->put(pref, tempOption.get(pref)); requestOption->put(pref, tempOption.get(pref));
} }
} }
// This does not throw exception because throwOnError = false.
createRequestGroupForUri(result, requestOption, uris); createRequestGroupForUri(result, requestOption, uris);
if(num < result.size()) {
return true;
} }
} }
} // namespace return false;
}
SharedHandle<UriListParser> openUriListParser(const std::string& filename)
{
std::string listPath;
if(filename == "-") {
listPath = DEV_STDIN;
} else {
if(!File(filename).isFile()) {
throw DL_ABORT_EX
(fmt(EX_FILE_OPEN, filename.c_str(), "No such file"));
}
listPath = filename;
}
return SharedHandle<UriListParser>(new UriListParser(listPath));
}
void createRequestGroupForUriList void createRequestGroupForUriList
(std::vector<SharedHandle<RequestGroup> >& result, (std::vector<SharedHandle<RequestGroup> >& result,
const SharedHandle<Option>& option) const SharedHandle<Option>& option)
{ {
if(option->get(PREF_INPUT_FILE) == "-") { SharedHandle<UriListParser> uriListParser = openUriListParser
createRequestGroupForUriList(result, option, DEV_STDIN); (option->get(PREF_INPUT_FILE));
} else { while(createRequestGroupFromUriListParser(result, option.get(),
if(!File(option->get(PREF_INPUT_FILE)).isFile()) { uriListParser.get()));
throw DL_ABORT_EX
(fmt(EX_FILE_OPEN, option->get(PREF_INPUT_FILE).c_str(),
"No such file"));
}
createRequestGroupForUriList(result, option, option->get(PREF_INPUT_FILE));
}
} }
SharedHandle<MetadataInfo> SharedHandle<MetadataInfo>

View File

@ -49,6 +49,7 @@ class RequestGroup;
class Option; class Option;
class MetadataInfo; class MetadataInfo;
class DownloadContext; class DownloadContext;
class UriListParser;
#ifdef ENABLE_BITTORRENT #ifdef ENABLE_BITTORRENT
// Create RequestGroup object using torrent file specified by // Create RequestGroup object using torrent file specified by
@ -75,6 +76,26 @@ void createRequestGroupForMetalink
const std::string& metalinkData = ""); const std::string& metalinkData = "");
#endif // ENABLE_METALINK #endif // ENABLE_METALINK
// Reads one entry from uriListParser and creates RequestGroups from
// it and store them in result. If the bad entry is found, this
// function just skips it and reads next entry. If at least one
// RequestGroup is created successfully, this function returns true
// and created RequestGroups are stored in result. If no RequestGroup
// is created and uriListParser reads all input, this function returns
// false. The option is used as a option template.
bool createRequestGroupFromUriListParser
(std::vector<SharedHandle<RequestGroup> >& result,
const Option* option,
UriListParser* uriListParser);
// Creates UriListParser using given filename. If filename is "-",
// then UriListParser is configured to read from standard input.
// Otherwise, this function first checks file denoted by filename
// exists. If it does not exist, this function throws exception.
// This function returns SharedHandle<UriListParser> object if it
// succeeds.
SharedHandle<UriListParser> openUriListParser(const std::string& filename);
// Create RequestGroup objects from reading file specified by input-file option. // Create RequestGroup objects from reading file specified by input-file option.
// If the value of input-file option is "-", stdin is used as a input source. // If the value of input-file option is "-", stdin is used as a input source.
// Each line is treated as if it is provided in command-line argument. // Each line is treated as if it is provided in command-line argument.

View File

@ -70,6 +70,7 @@
#include "fmt.h" #include "fmt.h"
#include "NullOutputFile.h" #include "NullOutputFile.h"
#include "console.h" #include "console.h"
#include "UriListParser.h"
#ifdef ENABLE_BITTORRENT #ifdef ENABLE_BITTORRENT
# include "bittorrent_helper.h" # include "bittorrent_helper.h"
#endif // ENABLE_BITTORRENT #endif // ENABLE_BITTORRENT
@ -225,6 +226,7 @@ error_code::Value main(int argc, char* argv[])
util::setGlobalSignalHandler(SIGCHLD, SIG_IGN, 0); util::setGlobalSignalHandler(SIGCHLD, SIG_IGN, 0);
#endif // SIGCHILD #endif // SIGCHILD
std::vector<SharedHandle<RequestGroup> > requestGroups; std::vector<SharedHandle<RequestGroup> > requestGroups;
SharedHandle<UriListParser> uriListParser;
#ifdef ENABLE_BITTORRENT #ifdef ENABLE_BITTORRENT
if(!op->blank(PREF_TORRENT_FILE)) { if(!op->blank(PREF_TORRENT_FILE)) {
if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) {
@ -248,7 +250,11 @@ error_code::Value main(int argc, char* argv[])
else else
#endif // ENABLE_METALINK #endif // ENABLE_METALINK
if(!op->blank(PREF_INPUT_FILE)) { if(!op->blank(PREF_INPUT_FILE)) {
if(op->getAsBool(PREF_DEFERRED_INPUT)) {
uriListParser = openUriListParser(op->get(PREF_INPUT_FILE));
} else {
createRequestGroupForUriList(requestGroups, op); createRequestGroupForUriList(requestGroups, op);
}
#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK #if defined ENABLE_BITTORRENT || defined ENABLE_METALINK
} else if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { } else if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) {
showFiles(args, op); showFiles(args, op);
@ -269,11 +275,13 @@ error_code::Value main(int argc, char* argv[])
op->remove(PREF_SELECT_FILE); op->remove(PREF_SELECT_FILE);
op->remove(PREF_PAUSE); op->remove(PREF_PAUSE);
op->remove(PREF_CHECKSUM); op->remove(PREF_CHECKSUM);
if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty()) { if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() &&
!uriListParser) {
global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD); global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD);
} else { } else {
exitStatus = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op), exitStatus = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op),
getSummaryOut(op)).execute(); getSummaryOut(op),
uriListParser).execute();
} }
return exitStatus; return exitStatus;
} }

View File

@ -213,6 +213,8 @@ const Pref* PREF_NO_NETRC = makePref("no-netrc");
const Pref* PREF_MAX_DOWNLOADS = makePref("max-downloads"); const Pref* PREF_MAX_DOWNLOADS = makePref("max-downloads");
// value: string that your file system recognizes as a file name. // value: string that your file system recognizes as a file name.
const Pref* PREF_INPUT_FILE = makePref("input-file"); const Pref* PREF_INPUT_FILE = makePref("input-file");
// value: true | false
const Pref* PREF_DEFERRED_INPUT = makePref("deferred-input");
// value: 1*digit // value: 1*digit
const Pref* PREF_MAX_CONCURRENT_DOWNLOADS = makePref("max-concurrent-downloads"); const Pref* PREF_MAX_CONCURRENT_DOWNLOADS = makePref("max-concurrent-downloads");
// value: true | false // value: true | false

View File

@ -156,6 +156,8 @@ extern const Pref* PREF_MAX_OVERALL_DOWNLOAD_LIMIT;
extern const Pref* PREF_MAX_DOWNLOADS; extern const Pref* PREF_MAX_DOWNLOADS;
// value: string that your file system recognizes as a file name. // value: string that your file system recognizes as a file name.
extern const Pref* PREF_INPUT_FILE; extern const Pref* PREF_INPUT_FILE;
// value: true | false
extern const Pref* PREF_DEFERRED_INPUT;
// value: 1*digit // value: 1*digit
extern const Pref* PREF_MAX_CONCURRENT_DOWNLOADS; extern const Pref* PREF_MAX_CONCURRENT_DOWNLOADS;
// value: true | false // value: true | false

View File

@ -226,7 +226,7 @@
" line of URI. This optional line must start with\n" \ " line of URI. This optional line must start with\n" \
" one or more white spaces and have one option per\n" \ " one or more white spaces and have one option per\n" \
" single line. See INPUT FILE section of man page\n" \ " single line. See INPUT FILE section of man page\n" \
" for details.") " for details. See also --deferred-input option.")
#define TEXT_MAX_CONCURRENT_DOWNLOADS \ #define TEXT_MAX_CONCURRENT_DOWNLOADS \
_(" -j, --max-concurrent-downloads=N Set maximum number of parallel downloads for\n" \ _(" -j, --max-concurrent-downloads=N Set maximum number of parallel downloads for\n" \
" every static (HTTP/FTP) URL, torrent and metalink.\n" \ " every static (HTTP/FTP) URL, torrent and metalink.\n" \
@ -859,3 +859,11 @@
" with its own pid and when parent process exits\n" \ " with its own pid and when parent process exits\n" \
" for some reason, aria2 can detect it and shutdown\n" \ " for some reason, aria2 can detect it and shutdown\n" \
" itself.") " itself.")
#define TEXT_DEFERRED_INPUT \
_(" --deferred-input[=true|false] If true is given, aria2 does not read all URIs\n" \
" and options from file specified by -i option at\n" \
" startup, but it reads one by one when it needs\n" \
" later. This may reduce memory usage if input\n" \
" file contains a lot of URIs to download.\n" \
" If false is given, aria2 reads all URIs and\n" \
" options at startup.")