Просмотр исходного кода

Merge branch 'dynamic-select-file'

Tatsuhiro Tsujikawa 9 лет назад
Родитель
Сommit
c7d242e27d
10 измененных файлов с 132 добавлено и 25 удалено
  1. 13 10
      doc/manual-src/en/aria2c.rst
  2. 6 0
      src/Option.cc
  3. 2 0
      src/Option.h
  4. 7 0
      src/RequestGroup.cc
  5. 18 0
      src/RequestGroup.h
  6. 23 5
      src/RequestGroupMan.cc
  7. 46 5
      src/RpcMethod.cc
  8. 2 1
      src/RpcMethod.h
  9. 14 2
      src/RpcMethodImpl.cc
  10. 1 2
      src/bitfield.h

+ 13 - 10
doc/manual-src/en/aria2c.rst

@@ -3159,7 +3159,19 @@ For information on the *secret* parameter, see :ref:`rpc_auth`.
 
   This method changes options of the download denoted by *gid* (string)
   dynamically.  *options* is a struct.
-  The following options are available for active downloads:
+  The options listed in `Input File`_ subsection are available,
+  **except** for following options:
+
+  * :option:`dry-run <--dry-run>`
+  * :option:`metalink-base-uri <--metalink-base-uri>`
+  * :option:`parameterized-uri <-P>`
+  * :option:`pause <--pause>`
+  * :option:`piece-length <--piece-length>`
+  * :option:`rpc-save-upload-metadata <--rpc-save-upload-metadata>`
+
+  Except for the following options, changing the other options of
+  active download makes it restart (restart itself is managed by
+  aria2, and no user intervention is required):
 
   * :option:`bt-max-peers <--bt-max-peers>`
   * :option:`bt-request-peer-speed-limit <--bt-request-peer-speed-limit>`
@@ -3168,15 +3180,6 @@ For information on the *secret* parameter, see :ref:`rpc_auth`.
   * :option:`max-download-limit <--max-download-limit>`
   * :option:`max-upload-limit <-u>`
 
-  For waiting or paused downloads, in addition to the above options,
-  options listed in `Input File`_ subsection are available,
-  **except** for following options:
-  :option:`dry-run <--dry-run>`,
-  :option:`metalink-base-uri <--metalink-base-uri>`,
-  :option:`parameterized-uri <-P>`,
-  :option:`pause <--pause>`,
-  :option:`piece-length <--piece-length>` and
-  :option:`rpc-save-upload-metadata <--rpc-save-upload-metadata>` option.
   This method returns ``OK`` for success.
 
   The following examples set the :option:`max-download-limit

+ 6 - 0
src/Option.cc

@@ -190,4 +190,10 @@ void Option::setParent(const std::shared_ptr<Option>& parent)
 
 const std::shared_ptr<Option>& Option::getParent() const { return parent_; }
 
+bool Option::emptyLocal() const
+{
+  size_t dst;
+  return !bitfield::getFirstSetBitIndex(dst, use_, use_.size() * 8);
+}
+
 } // namespace aria2

+ 2 - 0
src/Option.h

@@ -92,6 +92,8 @@ public:
   // Sets parent Option object for this object.
   void setParent(const std::shared_ptr<Option>& parent);
   const std::shared_ptr<Option>& getParent() const;
+  // Returns true if there is no option stored.
+  bool emptyLocal() const;
 };
 
 } // namespace aria2

+ 7 - 0
src/RequestGroup.cc

@@ -986,6 +986,8 @@ void RequestGroup::setForceHaltRequested(bool f, HaltReason haltReason)
 
 void RequestGroup::setPauseRequested(bool f) { pauseRequested_ = f; }
 
+void RequestGroup::setRestartRequested(bool f) { restartRequested_ = f; }
+
 void RequestGroup::releaseRuntimeResource(DownloadEngine* e)
 {
 #ifdef ENABLE_BITTORRENT
@@ -1308,4 +1310,9 @@ bool RequestGroup::isSeeder() const
 #endif // !ENABLE_BITTORRENT
 }
 
+void RequestGroup::setPendingOption(std::shared_ptr<Option> option)
+{
+  pendingOption_ = std::move(option);
+}
+
 } // namespace aria2

+ 18 - 0
src/RequestGroup.h

@@ -96,6 +96,9 @@ private:
 
   std::shared_ptr<Option> option_;
 
+  // options applied on restart
+  std::shared_ptr<Option> pendingOption_;
+
   std::shared_ptr<SegmentMan> segmentMan_;
 
   std::shared_ptr<DownloadContext> downloadContext_;
@@ -178,6 +181,11 @@ private:
 
   bool pauseRequested_;
 
+  // restartRequested_ indicates that this download should be
+  // restarted.  Usually, it is used with pauseRequested_ to stop
+  // download first.
+  bool restartRequested_;
+
   // This flag just indicates that the downloaded file is not saved disk but
   // just sits in memory.
   bool inMemoryDownload_;
@@ -345,6 +353,10 @@ public:
 
   bool isPauseRequested() const { return pauseRequested_; }
 
+  void setRestartRequested(bool f);
+
+  bool isRestartRequested() const { return restartRequested_; }
+
   void dependsOn(const std::shared_ptr<Dependency>& dep);
 
   bool isDependencyResolved();
@@ -500,6 +512,12 @@ public:
 
   // Returns true if this download is now seeding.
   bool isSeeder() const;
+
+  void setPendingOption(std::shared_ptr<Option> option);
+  const std::shared_ptr<Option>& getPendingOption() const
+  {
+    return pendingOption_;
+  }
 };
 
 } // namespace aria2

+ 23 - 5
src/RequestGroupMan.cc

@@ -84,6 +84,7 @@
 #include "array_fun.h"
 #include "OpenedFileCounter.h"
 #include "wallclock.h"
+#include "RpcMethodImpl.h"
 #ifdef ENABLE_BITTORRENT
 #include "bittorrent_helper.h"
 #endif // ENABLE_BITTORRENT
@@ -369,8 +370,10 @@ public:
       try {
         group->closeFile();
         if (group->isPauseRequested()) {
-          A2_LOG_NOTICE(fmt(_("Download GID#%s paused"),
-                            GroupId::toHex(group->getGID()).c_str()));
+          if (!group->isRestartRequested()) {
+            A2_LOG_NOTICE(fmt(_("Download GID#%s paused"),
+                              GroupId::toHex(group->getGID()).c_str()));
+          }
           group->saveControlFile();
         }
         else if (group->downloadFinished() &&
@@ -433,9 +436,20 @@ public:
         reservedGroups_.push_front(group->getGID(), group);
         group->releaseRuntimeResource(e_);
         group->setForceHaltRequested(false);
-        util::executeHookByOptName(group, e_->getOption(),
-                                   PREF_ON_DOWNLOAD_PAUSE);
-        notifyDownloadEvent(EVENT_ON_DOWNLOAD_PAUSE, group);
+
+        auto pendingOption = group->getPendingOption();
+        if (pendingOption) {
+          changeOption(group, *pendingOption, e_);
+        }
+
+        if (group->isRestartRequested()) {
+          group->setPauseRequested(false);
+        }
+        else {
+          util::executeHookByOptName(group, e_->getOption(),
+                                     PREF_ON_DOWNLOAD_PAUSE);
+          notifyDownloadEvent(EVENT_ON_DOWNLOAD_PAUSE, group);
+        }
         // TODO Should we have to prepend spend uris to remaining uris
         // in case PREF_REUSE_URI is disabled?
       }
@@ -445,6 +459,10 @@ public:
         executeStopHook(group, e_->getOption(), dr->result);
         group->releaseRuntimeResource(e_);
       }
+
+      group->setRestartRequested(false);
+      group->setPendingOption(nullptr);
+
       return true;
     }
     else {

+ 46 - 5
src/RpcMethod.cc

@@ -147,12 +147,53 @@ void RpcMethod::gatherRequestOption(Option* option, const Dict* optionsDict)
   }
 }
 
-void RpcMethod::gatherChangeableOption(Option* option, const Dict* optionsDict)
+void RpcMethod::gatherChangeableOption(Option* option, Option* pendingOption,
+                                       const Dict* optionsDict)
 {
-  if (optionsDict) {
-    gatherOption(optionsDict->begin(), optionsDict->end(),
-                 std::mem_fn(&OptionHandler::getChangeOption), option,
-                 optionParser_);
+  if (!optionsDict) {
+    return;
+  }
+
+  auto first = optionsDict->begin();
+  auto last = optionsDict->end();
+
+  for (; first != last; ++first) {
+    const auto& optionName = (*first).first;
+    auto pref = option::k2p(optionName);
+    auto handler = optionParser_->find(pref);
+    if (!handler) {
+      // Just ignore the unacceptable options in this context.
+      continue;
+    }
+
+    Option* dst = nullptr;
+    if (handler->getChangeOption()) {
+      dst = option;
+    }
+    else if (handler->getChangeOptionForReserved()) {
+      dst = pendingOption;
+    }
+
+    if (!dst) {
+      continue;
+    }
+
+    const auto opval = downcast<String>((*first).second);
+    if (opval) {
+      handler->parse(*dst, opval->s());
+    }
+    else if (handler->getCumulative()) {
+      // header and index-out option can take array as value
+      const auto oplist = downcast<List>((*first).second);
+      if (oplist) {
+        for (auto& elem : *oplist) {
+          const auto opval = downcast<String>(elem);
+          if (opval) {
+            handler->parse(*dst, opval->s());
+          }
+        }
+      }
+    }
   }
 }
 

+ 2 - 1
src/RpcMethod.h

@@ -75,7 +75,8 @@ protected:
 
   void gatherRequestOption(Option* option, const Dict* optionsDict);
 
-  void gatherChangeableOption(Option* option, const Dict* optionDict);
+  void gatherChangeableOption(Option* option, Option* pendingOption,
+                              const Dict* optionDict);
 
   void gatherChangeableOptionForReserved(Option* option,
                                          const Dict* optionsDict);

+ 14 - 2
src/RpcMethodImpl.cc

@@ -1113,10 +1113,22 @@ std::unique_ptr<ValueBase> ChangeOptionRpcMethod::process(const RpcRequest& req,
 
   a2_gid_t gid = str2Gid(gidParam);
   auto group = e->getRequestGroupMan()->findGroup(gid);
-  Option option;
   if (group) {
+    Option option;
+    std::shared_ptr<Option> pendingOption;
     if (group->getState() == RequestGroup::STATE_ACTIVE) {
-      gatherChangeableOption(&option, optsParam);
+      pendingOption = std::make_shared<Option>();
+      gatherChangeableOption(&option, pendingOption.get(), optsParam);
+      if (!pendingOption->emptyLocal()) {
+        group->setPendingOption(pendingOption);
+        // pauseRequestGroup() may fail if group has been told to
+        // stop/pause already.  In that case, we can still apply the
+        // pending options on pause.
+        if (pauseRequestGroup(group, false, false)) {
+          group->setRestartRequested(true);
+          e->setRefreshInterval(std::chrono::milliseconds(0));
+        }
+      }
     }
     else {
       gatherChangeableOptionForReserved(&option, optsParam);

+ 1 - 2
src/bitfield.h

@@ -143,8 +143,7 @@ size_t countSetBitSlow(const Array& bitfield, size_t nbits)
 void flipBit(unsigned char* data, size_t length, size_t bitIndex);
 
 // Stores first set bit index of bitfield to index.  bitfield contains
-// nbits. Returns true if missing bit index is found. Otherwise
-// returns false.
+// nbits. Returns true if set bit is found. Otherwise returns false.
 template <typename Array>
 bool getFirstSetBitIndex(size_t& index, const Array& bitfield, size_t nbits)
 {