Skip to content

Commit

Permalink
Improve SFTP performance on medium/high latency connections (#866)
Browse files Browse the repository at this point in the history
* Improve SFTP performance on medium-high latency connections
- Increases maxPendingReads from 10 to 100
- Increases socket send/receive buffer to 10 SSH packets (320K)

* Fix merge

* Adjust SFTP FileReader testcases to accept new MaxPendingReads values

* Fix CreateSftpFileReader testcase, make it dependant on MaxPendingReads constant

---------

Co-authored-by: Pedro Fonseca <[email protected]>
  • Loading branch information
zybexXL and Pedro Fonseca authored Nov 13, 2023
1 parent 823bc1b commit 2eec748
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/Renci.SshNet/Connection/ConnectorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected Socket SocketConnect(string host, int port, TimeSpan timeout)
{
SocketAbstraction.Connect(socket, ep, timeout);

const int socketBufferSize = 2 * Session.MaximumSshPacketSize;
const int socketBufferSize = 10 * Session.MaximumSshPacketSize;
socket.SendBufferSize = socketBufferSize;
socket.ReceiveBufferSize = socketBufferSize;
return socket;
Expand Down
4 changes: 2 additions & 2 deletions src/Renci.SshNet/ServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public INetConfSession CreateNetConfSession(ISession session, int operationTimeo
/// </returns>
public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize)
{
const int defaultMaxPendingReads = 3;
const int defaultMaxPendingReads = 10;

// Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this
// causes a performance degradation on Sun SSH
Expand All @@ -163,7 +163,7 @@ public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSe
{
var fileAttributes = sftpSession.EndLStat(statAsyncResult);
fileSize = fileAttributes.Size;
maxPendingReads = Math.Min(10, (int) Math.Ceiling((double) fileAttributes.Size / chunkSize) + 1);
maxPendingReads = Math.Min(100, (int)Math.Ceiling((double)fileAttributes.Size / chunkSize) + 1);
}
catch (SshException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private void SetupMocks()
.Setup(p => p.EndLStat(_statAsyncResult))
.Throws(new SshException());
_sftpSessionMock.InSequence(seq)
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 3, null))
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, null))
.Returns(_sftpFileReaderMock.Object);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize
public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize
{
private ServiceFactory _serviceFactory;
private Mock<ISftpSession> _sftpSessionMock;
Expand All @@ -22,18 +22,20 @@ public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesG
private SftpFileAttributes _fileAttributes;
private long _fileSize;
private ISftpFileReader _actual;
private int _maxPendingReads;

private void SetupData()
{
var random = new Random();

_maxPendingReads = 100;
_bufferSize = (uint)random.Next(1, int.MaxValue);
_openAsyncResult = new SftpOpenAsyncResult(null, null);
_handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
_statAsyncResult = new SFtpStatAsyncResult(null, null);
_fileName = random.Next().ToString();
_chunkSize = (uint) random.Next(1000, 5000);
_fileSize = _chunkSize * random.Next(11, 50);
_fileSize = _chunkSize * random.Next(_maxPendingReads + 1, _maxPendingReads * 2);
_fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
}

Expand Down Expand Up @@ -63,7 +65,7 @@ private void SetupMocks()
.Setup(p => p.EndLStat(_statAsyncResult))
.Returns(_fileAttributes);
_sftpSessionMock.InSequence(seq)
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, _fileSize))
.Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, _maxPendingReads, _fileSize))
.Returns(_sftpFileReaderMock.Object);
}

Expand Down

0 comments on commit 2eec748

Please sign in to comment.