Browse Source

sftp: Seek to the correct position to resume, fix slow start of transfer

Tatsuhiro Tsujikawa 10 years ago
parent
commit
5723f4211a

+ 4 - 2
src/InitiateConnectionCommand.cc

@@ -91,8 +91,10 @@ bool InitiateConnectionCommand::executeInternal() {
     return false;
   }
   try {
-    getDownloadEngine()->addCommand(createNextCommand(hostname, ipaddr, port,
-                                                      addrs, proxyRequest));
+    auto c = createNextCommand(hostname, ipaddr, port, addrs, proxyRequest);
+    c->setStatus(Command::STATUS_ONESHOT_REALTIME);
+    getDownloadEngine()->setNoWait(true);
+    getDownloadEngine()->addCommand(std::move(c));
     return true;
   } catch(RecoverableException& ex) {
     // Catch exception and retry another address.

+ 5 - 0
src/SSHSession.cc

@@ -227,6 +227,11 @@ int SSHSession::sftpStat(int64_t& totalLength, time_t& mtime)
   return SSH_ERR_OK;
 }
 
+void SSHSession::sftpSeek(int64_t pos)
+{
+  libssh2_sftp_seek64(sftph_, pos);
+}
+
 std::string SSHSession::getLastErrorString()
 {
   if (!ssh2_) {

+ 3 - 0
src/SSHSession.h

@@ -122,6 +122,9 @@ public:
   // blocks, or SSH_ERR_ERROR.
   int sftpStat(int64_t& totalLength, time_t& mtime);
 
+  // Moves file postion to |pos|.
+  void sftpSeek(int64_t pos);
+
   // Returns last error string
   std::string getLastErrorString();
 

+ 8 - 1
src/SftpDownloadCommand.cc

@@ -84,7 +84,14 @@ bool SftpDownloadCommand::prepareForNextSegment()
     return true;
   }
 
-  return DownloadCommand::prepareForNextSegment();
+  auto rv = DownloadCommand::prepareForNextSegment();
+  if (rv) {
+    return true;
+  }
+  // sftp may not get incoming data.  Enable write check to make this
+  // command invoke.
+  setWriteCheckSocket(getSocket());
+  return false;
 }
 
 int64_t SftpDownloadCommand::getRequestEndOffset() const

+ 17 - 5
src/SftpNegotiationCommand.cc

@@ -81,7 +81,6 @@ SftpNegotiationCommand::SftpNegotiationCommand
 
 {
   path_ = getPath();
-  disableReadCheckSocket();
   setWriteCheckSocket(getSocket());
 }
 
@@ -108,7 +107,7 @@ bool SftpNegotiationCommand::executeInternal() {
                        getCuid()));
       sequence_ = SEQ_SFTP_OPEN;
       break;
-    case SEQ_SFTP_OPEN: {
+    case SEQ_SFTP_OPEN:
       if (!getSocket()->sshSFTPOpen(path_)) {
         goto again;
       }
@@ -116,7 +115,6 @@ bool SftpNegotiationCommand::executeInternal() {
                        path_.c_str()));
       sequence_ = SEQ_SFTP_STAT;
       break;
-    }
     case SEQ_SFTP_STAT: {
       int64_t totalLength;
       time_t mtime;
@@ -134,12 +132,26 @@ bool SftpNegotiationCommand::executeInternal() {
       } else {
         getRequestGroup()->validateTotalLength(getFileEntry()->getLength(),
                                                totalLength);
-        sequence_ = SEQ_NEGOTIATION_COMPLETED;
+        sequence_ = SEQ_SFTP_SEEK;
       }
       break;
     }
-    case SEQ_FILE_PREPARATION:
+    case SEQ_SFTP_SEEK: {
       sequence_ = SEQ_NEGOTIATION_COMPLETED;
+      if (getSegments().empty()) {
+        break;
+      }
+
+      auto& segment = getSegments().front();
+
+      A2_LOG_INFO(fmt("CUID#%" PRId64 " - SFTP seek to %" PRId64,
+                      getCuid(), segment->getPositionToWrite()));
+      getSocket()->sshSFTPSeek(segment->getPositionToWrite());
+
+      break;
+    }
+    case SEQ_FILE_PREPARATION:
+      sequence_ = SEQ_SFTP_SEEK;
       disableReadCheckSocket();
       disableWriteCheckSocket();
       return false;

+ 1 - 0
src/SftpNegotiationCommand.h

@@ -49,6 +49,7 @@ public:
     SEQ_AUTH_PASSWORD,
     SEQ_SFTP_OPEN,
     SEQ_SFTP_STAT,
+    SEQ_SFTP_SEEK,
     SEQ_NEGOTIATION_COMPLETED,
     SEQ_DOWNLOAD_ALREADY_COMPLETED,
     SEQ_HEAD_OK,

+ 7 - 0
src/SocketCore.cc

@@ -1090,6 +1090,13 @@ bool SocketCore::sshSFTPStat(int64_t& totalLength, time_t& mtime,
   return true;
 }
 
+void SocketCore::sshSFTPSeek(int64_t pos)
+{
+  assert(sshSession_);
+
+  sshSession_->sftpSeek(pos);
+}
+
 bool SocketCore::sshGracefulShutdown()
 {
   assert(sshSession_);

+ 2 - 0
src/SocketCore.h

@@ -313,6 +313,8 @@ public:
   // opened.  |path| is used for logging.
   bool sshSFTPStat(int64_t& totalLength, time_t& mtime,
                    const std::string& path);
+  // Seeks file position to |pos|.
+  void sshSFTPSeek(int64_t pos);
   bool sshGracefulShutdown();
 #endif // HAVE_LIBSSH2