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

pull/384/head
Tatsuhiro Tsujikawa 2015-05-12 22:31:14 +09:00
parent 89c1916fa5
commit 5723f4211a
8 changed files with 47 additions and 8 deletions

View File

@ -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.

View File

@ -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_) {

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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_);

View File

@ -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