Browse Source

Eliminate intermediate copy to read buffer.

Gert Driesen 8 years ago
parent
commit
c8373c978f
1 changed files with 41 additions and 22 deletions
  1. 41 22
      src/Renci.SshNet/Sftp/SftpFileStream.cs

+ 41 - 22
src/Renci.SshNet/Sftp/SftpFileStream.cs

@@ -329,40 +329,59 @@ namespace Renci.SshNet.Sftp
                 while (count > 0)
                 {
                     // How much data do we have available in the buffer?
-                    var tempLen = _bufferLen - _bufferPosition;
-                    if (tempLen <= 0)
+                    var bytesAvailableInBuffer = _bufferLen - _bufferPosition;
+                    if (bytesAvailableInBuffer <= 0)
                     {
                         _bufferPosition = 0;
+                        _bufferLen = 0;
 
-                        var data = _session.RequestRead(_handle, (ulong)_position, (uint)_readBufferSize);
+                        var data = _session.RequestRead(_handle, (ulong) _position, (uint) _readBufferSize);
 
-                        _bufferLen = data.Length;
-                        _serverFilePosition = (ulong)_position;
+                        // TODO: don't we need to take into account the number of bytes read (data.Length) ?
+                        _serverFilePosition = (ulong) _position;
 
-                        if (_bufferLen == 0)
+                        if (data.Length == 0)
                         {
                             break;
                         }
 
-                        Buffer.BlockCopy(data, 0, _readBuffer, 0, _bufferLen);
-                        tempLen = _bufferLen;
+                        // determine number of bytes that we can read into caller-provided buffer
+                        var bytesToWriteToCallerBuffer = Math.Min(data.Length, count);
+                        // write bytes to caller-provided buffer
+                        Buffer.BlockCopy(data, 0, buffer, offset, bytesToWriteToCallerBuffer);
+                        // advance offset to start writing bytes into caller-provided buffer
+                        offset += bytesToWriteToCallerBuffer;
+                        // update number of bytes left to read
+                        count -= bytesToWriteToCallerBuffer;
+                        // record total number of bytes read into caller-provided buffer
+                        readLen += bytesToWriteToCallerBuffer;
+                        // update stream position
+                        _position += bytesToWriteToCallerBuffer;
+
+                        if (data.Length > bytesToWriteToCallerBuffer)
+                        {
+                            // copy remaining bytes to read buffer
+                            _bufferLen = data.Length - bytesToWriteToCallerBuffer;
+                            Buffer.BlockCopy(data, count, _readBuffer, 0, _bufferLen);
+                        }
                     }
-
-                    // Don't read more than the caller wants.
-                    if (tempLen > count)
+                    else
                     {
-                        tempLen = count;
+                        // determine number of bytes that we can write from read buffer to caller-provided buffer
+                        var bytesToWriteToCallerBuffer = Math.Min(bytesAvailableInBuffer, count);
+                        // copy data from read buffer to the caller-provided buffer
+                        Buffer.BlockCopy(_readBuffer, _bufferPosition, buffer, offset, bytesToWriteToCallerBuffer);
+                        // update position in read buffer
+                        _bufferPosition += bytesToWriteToCallerBuffer;
+                        // advance offset to start writing bytes into caller-provided buffer
+                        offset += bytesAvailableInBuffer;
+                        // update number of bytes left to read
+                        count -= bytesToWriteToCallerBuffer;
+                        // record total number of bytes read into caller-provided buffer
+                        readLen += bytesToWriteToCallerBuffer;
+                        // update stream position
+                        _position += bytesToWriteToCallerBuffer;
                     }
-
-                    // Copy stream data to the caller's buffer.
-                    Buffer.BlockCopy(_readBuffer, _bufferPosition, buffer, offset, tempLen);
-
-                    // Advance to the next buffer positions.
-                    readLen += tempLen;
-                    offset += tempLen;
-                    count -= tempLen;
-                    _bufferPosition += tempLen;
-                    _position += tempLen;
                 }
             }