소스 검색

Save options directly specified for download in --save-session

This change makes --save-session save only options specified for
download, more specifically, options in command-line, -i file and via
RPC. The other options from conf file and default values are not
saved.  This will drastically decrease the size of session file.
Tatsuhiro Tsujikawa 12 년 전
부모
커밋
4070113ef0
6개의 변경된 파일119개의 추가작업 그리고 34개의 파일을 삭제
  1. 31 3
      src/Option.cc
  2. 22 7
      src/Option.h
  3. 1 1
      src/SessionSerializer.cc
  4. 10 8
      src/main.cc
  5. 25 15
      src/option_processing.cc
  6. 30 0
      test/OptionTest.cc

+ 31 - 3
src/Option.cc

@@ -51,7 +51,8 @@ Option::~Option() {}
 
 Option::Option(const Option& option)
   : table_(option.table_),
-    use_(option.use_)
+    use_(option.use_),
+    parent_(option.parent_)
 {}
 
 Option& Option::operator=(const Option& option)
@@ -59,6 +60,7 @@ Option& Option::operator=(const Option& option)
   if(this != &option) {
     table_ = option.table_;
     use_ = option.use_;
+    parent_ = option.parent_;
   }
   return *this;
 }
@@ -85,18 +87,34 @@ void Option::put(const Pref* pref, const std::string& value) {
 }
 
 bool Option::defined(const Pref* pref) const
+{
+  return bitfield::test(use_, use_.size()*8, pref->i) ||
+    (parent_ && parent_->defined(pref));
+}
+
+bool Option::definedLocal(const Pref* pref) const
 {
   return bitfield::test(use_, use_.size()*8, pref->i);
 }
 
 bool Option::blank(const Pref* pref) const
 {
-  return !defined(pref) || table_[pref->i].empty();
+  if(bitfield::test(use_, use_.size()*8, pref->i)) {
+    return table_[pref->i].empty();
+  } else {
+    return !parent_ || parent_->blank(pref);
+  }
 }
 
 const std::string& Option::get(const Pref* pref) const
 {
-  return table_[pref->i];
+  if(bitfield::test(use_, use_.size()*8, pref->i)) {
+    return table_[pref->i];
+  } else if(parent_) {
+    return parent_->get(pref);
+  } else {
+    return A2STR::NIL;
+  }
 }
 
 int32_t Option::getAsInt(const Pref* pref) const {
@@ -153,4 +171,14 @@ void Option::merge(const Option& option)
   }
 }
 
+void Option::setParent(const SharedHandle<Option>& parent)
+{
+  parent_ = parent;
+}
+
+const SharedHandle<Option>& Option::getParent() const
+{
+  return parent_;
+}
+
 } // namespace aria2

+ 22 - 7
src/Option.h

@@ -40,6 +40,8 @@
 #include <string>
 #include <vector>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 struct Pref;
@@ -48,6 +50,7 @@ class Option {
 private:
   std::vector<std::string> table_;
   std::vector<unsigned char> use_;
+  SharedHandle<Option> parent_;
 public:
   Option();
   ~Option();
@@ -55,29 +58,41 @@ public:
   Option& operator=(const Option& option);
 
   void put(const Pref* pref, const std::string& value);
-  // Returns true if name is defined. Otherwise returns false.
-  // Note that even if the value is a empty string, this method returns true.
+  // Returns true if name is defined. Otherwise returns false.  Note
+  // that even if the value is a empty string, this method returns
+  // true.  If option is not defined in this object and parent_ is not
+  // NULL, lookup parent_ to check |pref| is defined.
   bool defined(const Pref* pref) const;
+  // Just like defined(), but this function does not lookup parent_.
+  bool definedLocal(const Pref* pref) const;
   // Returns true if name is not defined or the value is a empty string.
   // Otherwise returns false.
   bool blank(const Pref* pref) const;
+  // Returns option value for |pref|. If the |pref| is not defined in
+  // this object, parent_ is looked up.
   const std::string& get(const Pref* pref) const;
   int32_t getAsInt(const Pref* pref) const;
   int64_t getAsLLInt(const Pref* pref) const;
   bool getAsBool(const Pref* pref) const;
   double getAsDouble(const Pref* pref) const;
-
+  // Removes |pref| from this object. This function does not modify
+  // parent_.
   void remove(const Pref* pref);
-
+  // Removes all option values from this object. This function does
+  // not modify parent_.
   void clear();
-
+  // Returns the option value table of this object. It does not
+  // contain option values in parent_ and so forth.
   const std::vector<std::string>& getTable() const
   {
     return table_;
   }
-
-  // Copy option values defined in option to this option.
+  // Copy option values defined in option to this option. parent_ is
+  // left unmodified for this object.
   void merge(const Option& option);
+  // Sets parent Option object for this object.
+  void setParent(const SharedHandle<Option>& parent);
+  const SharedHandle<Option>& getParent() const;
 };
 
 } // namespace aria2

+ 1 - 1
src/SessionSerializer.cc

@@ -112,7 +112,7 @@ bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op)
   for(size_t i = 1, len = option::countOption(); i < len; ++i) {
     const Pref* pref = option::i2p(i);
     const OptionHandler* h = oparser->find(pref);
-    if(h && h->getInitialOption() && op->defined(pref)) {
+    if(h && h->getInitialOption() && op->definedLocal(pref)) {
       if(h->getCumulative()) {
         const std::string& val = op->get(pref);
         std::vector<std::string> v;

+ 10 - 8
src/main.cc

@@ -272,14 +272,16 @@ error_code::Value main(int argc, char* argv[])
   // command-line. If they are left, because op is used as a template
   // for new RequestGroup(such as created in RPC command), they causes
   // unintentional effect.
-  op->remove(PREF_OUT);
-  op->remove(PREF_FORCE_SEQUENTIAL);
-  op->remove(PREF_INPUT_FILE);
-  op->remove(PREF_INDEX_OUT);
-  op->remove(PREF_SELECT_FILE);
-  op->remove(PREF_PAUSE);
-  op->remove(PREF_CHECKSUM);
-  op->remove(PREF_GID);
+  for(SharedHandle<Option> i = op; i; i = i->getParent()) {
+    i->remove(PREF_OUT);
+    i->remove(PREF_FORCE_SEQUENTIAL);
+    i->remove(PREF_INPUT_FILE);
+    i->remove(PREF_INDEX_OUT);
+    i->remove(PREF_SELECT_FILE);
+    i->remove(PREF_PAUSE);
+    i->remove(PREF_CHECKSUM);
+    i->remove(PREF_GID);
+  }
   if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() &&
      !uriListParser) {
     global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD);

+ 25 - 15
src/option_processing.cc

@@ -175,6 +175,20 @@ void showCandidates
 
 } // namespace
 
+#ifdef __MINGW32__
+namespace {
+void optionNativeToUtf8(Option& op)
+{
+  for(size_t i = 1, len = option::countOption(); i < len; ++i) {
+    const Pref* pref = option::i2p(i);
+    if(op.definedLocal(pref) && !util::isUtf8(op.get(pref))) {
+      op.put(pref, nativeToUtf8(op.get(pref)));
+    }
+  }
+}
+} // namespace
+#endif // __MINGW32__
+
 void option_processing(Option& op, std::vector<std::string>& uris,
                        int argc, char* argv[])
 {
@@ -213,9 +227,8 @@ void option_processing(Option& op, std::vector<std::string>& uris,
         exit(error_code::FINISHED);
       }
     }
-
-    oparser->parseDefaultValues(op);
-
+    SharedHandle<Option> confOption(new Option());
+    oparser->parseDefaultValues(*confOption);
     if(!noConf) {
       std::string cfname =
         ucfname.empty() ?
@@ -230,7 +243,7 @@ void option_processing(Option& op, std::vector<std::string>& uris,
           }
         }
         try {
-          oparser->parse(op, ss);
+          oparser->parse(*confOption, ss);
         } catch(OptionHandlerException& e) {
           global::cerr()->printf(_("Parse error in %s"), cfname.c_str());
           global::cerr()->printf("\n%s", e.stackTrace().c_str());
@@ -254,24 +267,21 @@ void option_processing(Option& op, std::vector<std::string>& uris,
       }
     }
     // Override configuration with environment variables.
-    overrideWithEnv(op, oparser, PREF_HTTP_PROXY, "http_proxy");
-    overrideWithEnv(op, oparser, PREF_HTTPS_PROXY, "https_proxy");
-    overrideWithEnv(op, oparser, PREF_FTP_PROXY, "ftp_proxy");
-    overrideWithEnv(op, oparser, PREF_ALL_PROXY, "all_proxy");
-    overrideWithEnv(op, oparser, PREF_NO_PROXY, "no_proxy");
+    overrideWithEnv(*confOption, oparser, PREF_HTTP_PROXY, "http_proxy");
+    overrideWithEnv(*confOption, oparser, PREF_HTTPS_PROXY, "https_proxy");
+    overrideWithEnv(*confOption, oparser, PREF_FTP_PROXY, "ftp_proxy");
+    overrideWithEnv(*confOption, oparser, PREF_ALL_PROXY, "all_proxy");
+    overrideWithEnv(*confOption, oparser, PREF_NO_PROXY, "no_proxy");
 
     // we must clear eof bit and seek to the beginning of the buffer.
     cmdstream.clear();
     cmdstream.seekg(0, std::ios::beg);
     // finaly let's parse and store command-iine options.
+    op.setParent(confOption);
     oparser->parse(op, cmdstream);
 #ifdef __MINGW32__
-    for(size_t i = 1, len = option::countOption(); i < len; ++i) {
-      const Pref* pref = option::i2p(i);
-      if(op.defined(pref) && !util::isUtf8(op.get(pref))) {
-        op.put(pref, nativeToUtf8(op.get(pref)));
-      }
-    }
+    optionNativeToUtf8(op);
+    optionNativeToUtf8(*confOption);
 #endif // __MINGW32__
   } catch(OptionHandlerException& e) {
     global::cerr()->printf("%s", e.stackTrace().c_str());

+ 30 - 0
test/OptionTest.cc

@@ -17,6 +17,7 @@ class OptionTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testDefined);
   CPPUNIT_TEST(testBlank);
   CPPUNIT_TEST(testMerge);
+  CPPUNIT_TEST(testParent);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -30,6 +31,7 @@ public:
   void testDefined();
   void testBlank();
   void testMerge();
+  void testParent();
 };
 
 
@@ -93,4 +95,32 @@ void OptionTest::testMerge()
   CPPUNIT_ASSERT(!dest.defined(PREF_OUT));
 }
 
+void OptionTest::testParent()
+{
+  Option child;
+  SharedHandle<Option> parent(new Option());
+  parent->put(PREF_TIMEOUT, "100");
+  child.put(PREF_DIR, "foo");
+  CPPUNIT_ASSERT(!child.defined(PREF_TIMEOUT));
+  CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
+  child.setParent(parent);
+  CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
+  CPPUNIT_ASSERT_EQUAL(std::string("100"), child.get(PREF_TIMEOUT));
+  CPPUNIT_ASSERT_EQUAL((int32_t)100, child.getAsInt(PREF_TIMEOUT));
+  CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
+  // blank
+  CPPUNIT_ASSERT(!child.blank(PREF_DIR));
+  child.put(PREF_DIR, "");
+  CPPUNIT_ASSERT(child.blank(PREF_DIR));
+  CPPUNIT_ASSERT(!child.blank(PREF_TIMEOUT));
+  // override
+  child.put(PREF_TIMEOUT, "200");
+  CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
+  CPPUNIT_ASSERT(child.definedLocal(PREF_TIMEOUT));
+  CPPUNIT_ASSERT_EQUAL(std::string("200"), child.get(PREF_TIMEOUT));
+  child.remove(PREF_TIMEOUT);
+  CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
+  CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
+}
+
 } // namespace aria2