Browse Source

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 years ago
parent
commit
4070113ef0
6 changed files with 119 additions and 34 deletions
  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)
 Option::Option(const Option& option)
   : table_(option.table_),
   : table_(option.table_),
-    use_(option.use_)
+    use_(option.use_),
+    parent_(option.parent_)
 {}
 {}
 
 
 Option& Option::operator=(const Option& option)
 Option& Option::operator=(const Option& option)
@@ -59,6 +60,7 @@ Option& Option::operator=(const Option& option)
   if(this != &option) {
   if(this != &option) {
     table_ = option.table_;
     table_ = option.table_;
     use_ = option.use_;
     use_ = option.use_;
+    parent_ = option.parent_;
   }
   }
   return *this;
   return *this;
 }
 }
@@ -85,18 +87,34 @@ void Option::put(const Pref* pref, const std::string& value) {
 }
 }
 
 
 bool Option::defined(const Pref* pref) const
 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);
   return bitfield::test(use_, use_.size()*8, pref->i);
 }
 }
 
 
 bool Option::blank(const Pref* pref) const
 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
 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 {
 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
 } // namespace aria2

+ 22 - 7
src/Option.h

@@ -40,6 +40,8 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 namespace aria2 {
 
 
 struct Pref;
 struct Pref;
@@ -48,6 +50,7 @@ class Option {
 private:
 private:
   std::vector<std::string> table_;
   std::vector<std::string> table_;
   std::vector<unsigned char> use_;
   std::vector<unsigned char> use_;
+  SharedHandle<Option> parent_;
 public:
 public:
   Option();
   Option();
   ~Option();
   ~Option();
@@ -55,29 +58,41 @@ public:
   Option& operator=(const Option& option);
   Option& operator=(const Option& option);
 
 
   void put(const Pref* pref, const std::string& value);
   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;
   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.
   // Returns true if name is not defined or the value is a empty string.
   // Otherwise returns false.
   // Otherwise returns false.
   bool blank(const Pref* pref) const;
   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;
   const std::string& get(const Pref* pref) const;
   int32_t getAsInt(const Pref* pref) const;
   int32_t getAsInt(const Pref* pref) const;
   int64_t getAsLLInt(const Pref* pref) const;
   int64_t getAsLLInt(const Pref* pref) const;
   bool getAsBool(const Pref* pref) const;
   bool getAsBool(const Pref* pref) const;
   double getAsDouble(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);
   void remove(const Pref* pref);
-
+  // Removes all option values from this object. This function does
+  // not modify parent_.
   void clear();
   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
   const std::vector<std::string>& getTable() const
   {
   {
     return table_;
     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);
   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
 } // 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) {
   for(size_t i = 1, len = option::countOption(); i < len; ++i) {
     const Pref* pref = option::i2p(i);
     const Pref* pref = option::i2p(i);
     const OptionHandler* h = oparser->find(pref);
     const OptionHandler* h = oparser->find(pref);
-    if(h && h->getInitialOption() && op->defined(pref)) {
+    if(h && h->getInitialOption() && op->definedLocal(pref)) {
       if(h->getCumulative()) {
       if(h->getCumulative()) {
         const std::string& val = op->get(pref);
         const std::string& val = op->get(pref);
         std::vector<std::string> v;
         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
   // command-line. If they are left, because op is used as a template
   // for new RequestGroup(such as created in RPC command), they causes
   // for new RequestGroup(such as created in RPC command), they causes
   // unintentional effect.
   // 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() &&
   if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() &&
      !uriListParser) {
      !uriListParser) {
     global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD);
     global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD);

+ 25 - 15
src/option_processing.cc

@@ -175,6 +175,20 @@ void showCandidates
 
 
 } // namespace
 } // 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,
 void option_processing(Option& op, std::vector<std::string>& uris,
                        int argc, char* argv[])
                        int argc, char* argv[])
 {
 {
@@ -213,9 +227,8 @@ void option_processing(Option& op, std::vector<std::string>& uris,
         exit(error_code::FINISHED);
         exit(error_code::FINISHED);
       }
       }
     }
     }
-
-    oparser->parseDefaultValues(op);
-
+    SharedHandle<Option> confOption(new Option());
+    oparser->parseDefaultValues(*confOption);
     if(!noConf) {
     if(!noConf) {
       std::string cfname =
       std::string cfname =
         ucfname.empty() ?
         ucfname.empty() ?
@@ -230,7 +243,7 @@ void option_processing(Option& op, std::vector<std::string>& uris,
           }
           }
         }
         }
         try {
         try {
-          oparser->parse(op, ss);
+          oparser->parse(*confOption, ss);
         } catch(OptionHandlerException& e) {
         } catch(OptionHandlerException& e) {
           global::cerr()->printf(_("Parse error in %s"), cfname.c_str());
           global::cerr()->printf(_("Parse error in %s"), cfname.c_str());
           global::cerr()->printf("\n%s", e.stackTrace().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.
     // 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.
     // we must clear eof bit and seek to the beginning of the buffer.
     cmdstream.clear();
     cmdstream.clear();
     cmdstream.seekg(0, std::ios::beg);
     cmdstream.seekg(0, std::ios::beg);
     // finaly let's parse and store command-iine options.
     // finaly let's parse and store command-iine options.
+    op.setParent(confOption);
     oparser->parse(op, cmdstream);
     oparser->parse(op, cmdstream);
 #ifdef __MINGW32__
 #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__
 #endif // __MINGW32__
   } catch(OptionHandlerException& e) {
   } catch(OptionHandlerException& e) {
     global::cerr()->printf("%s", e.stackTrace().c_str());
     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(testDefined);
   CPPUNIT_TEST(testBlank);
   CPPUNIT_TEST(testBlank);
   CPPUNIT_TEST(testMerge);
   CPPUNIT_TEST(testMerge);
+  CPPUNIT_TEST(testParent);
   CPPUNIT_TEST_SUITE_END();
   CPPUNIT_TEST_SUITE_END();
 private:
 private:
 
 
@@ -30,6 +31,7 @@ public:
   void testDefined();
   void testDefined();
   void testBlank();
   void testBlank();
   void testMerge();
   void testMerge();
+  void testParent();
 };
 };
 
 
 
 
@@ -93,4 +95,32 @@ void OptionTest::testMerge()
   CPPUNIT_ASSERT(!dest.defined(PREF_OUT));
   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
 } // namespace aria2