You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2011/08/30 19:40:22 UTC

svn commit: r1163306 - in /mina/sshd/trunk/sshd-core/src: main/java/org/apache/sshd/server/sftp/SftpSubsystem.java test/java/org/apache/sshd/SftpTest.java

Author: gnodet
Date: Tue Aug 30 17:40:22 2011
New Revision: 1163306

URL: http://svn.apache.org/viewvc?rev=1163306&view=rev
Log:
[SSHD-135] Improve performance of SFTP transfers

Modified:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java?rev=1163306&r1=1163305&r2=1163306&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java Tue Aug 30 17:40:22 2011
@@ -23,6 +23,7 @@ import java.util.*;
 
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.IoUtils;
 import org.apache.sshd.common.util.SelectorUtils;
 import org.apache.sshd.server.*;
 import org.apache.sshd.server.FileSystemView;
@@ -266,6 +267,10 @@ public class SftpSubsystem implements Co
 
     protected static class FileHandle extends Handle {
         int flags;
+        OutputStream output;
+        long outputPos;
+        InputStream input;
+        long inputPos;
 
         public FileHandle(SshFile sshFile, int flags) {
             super(sshFile);
@@ -275,6 +280,40 @@ public class SftpSubsystem implements Co
         public int getFlags() {
             return flags;
         }
+        
+        public int read(byte[] data, long offset) throws IOException {
+            if (input != null && offset != inputPos) {
+                IoUtils.closeQuietly(input);
+                input = null;
+            }
+            if (input == null) {
+                input = file.createInputStream(offset);
+                inputPos = offset;
+            }
+            int read = input.read(data);
+            inputPos += read;
+            return read;
+        }
+
+        public void write(byte[] data, long offset) throws IOException {
+            if (output != null && offset != outputPos) {
+                IoUtils.closeQuietly(output);
+                output = null;
+            }
+            if (output == null) {
+                output = file.createOutputStream(offset);
+            }
+            output.write(data);
+            outputPos += data.length;
+        }
+
+        @Override
+        public void close() throws IOException {
+            IoUtils.closeQuietly(output, input);
+            output = null;
+            input = null;
+            super.close();
+        }
     }
 
     public SftpSubsystem() {}
@@ -519,27 +558,20 @@ public class SftpSubsystem implements Co
                     if (!(p instanceof FileHandle)) {
                         sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
                     } else {
-                        SshFile ssh = ((FileHandle) p).getFile();
-                        InputStream is = ssh.createInputStream(offset);
-                        try {
-                            byte[] b = new byte[Math.min(len, 1024 * 32)];
-                            len = is.read(b);
-                            if (len >= 0) {
-                                Buffer buf = new Buffer(len + 5);
-                                buf.putByte((byte) SSH_FXP_DATA);
-                                buf.putInt(id);
-                                buf.putBytes(b, 0, len);
-                                if (version >= 6) {
-                                    buf.putBoolean(len == 0);
-                                }
-                                send(buf);
-                            } else {
-                                sendStatus(id, SSH_FX_EOF, "");
-                            }
-                        } finally {
-                            if (is != null) {
-                                is.close();                                
+                        FileHandle fh = (FileHandle) p;
+                        byte[] b = new byte[Math.min(len, 1024 * 32)];
+                        len = fh.read(b, offset);
+                        if (len >= 0) {
+                            Buffer buf = new Buffer(len + 5);
+                            buf.putByte((byte) SSH_FXP_DATA);
+                            buf.putInt(id);
+                            buf.putBytes(b, 0, len);
+                            if (version >= 6) {
+                                buf.putBoolean(len == 0);
                             }
+                            send(buf);
+                        } else {
+                            sendStatus(id, SSH_FX_EOF, "");
                         }
                     }
                 } catch (IOException e) {
@@ -556,16 +588,9 @@ public class SftpSubsystem implements Co
                     if (!(p instanceof FileHandle)) {
                         sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
                     } else {
-                        SshFile sshFile = ((FileHandle) p).getFile();
-                        OutputStream os = sshFile.createOutputStream(offset);
-                        
-                        try {
-                            os.write(data); // TODO: handle append flags
-                        } finally {
-                            if (os != null) {
-                                os.close();                                
-                            }
-                        }
+                        FileHandle fh = (FileHandle) p;
+                        fh.write(data, offset);
+                        SshFile sshFile = fh.getFile();
 
                         sshFile.setLastModified(new Date().getTime());
                         

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java?rev=1163306&r1=1163305&r2=1163306&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java Tue Aug 30 17:40:22 2011
@@ -22,25 +22,29 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.ServerSocket;
-import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.sftp.SftpSubsystem;
-import org.junit.*;
-
 import com.jcraft.jsch.ChannelSftp;
 import com.jcraft.jsch.JSch;
 import com.jcraft.jsch.Logger;
 import com.jcraft.jsch.UserInfo;
+import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.server.Command;
 import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.sftp.SftpSubsystem;
 import org.apache.sshd.util.BogusPasswordAuthenticator;
 import org.apache.sshd.util.EchoShellFactory;
-
-import static org.junit.Assert.*;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 public class SftpTest {
 
@@ -140,6 +144,33 @@ public class SftpTest {
         root.delete();
     }
 
+    @Test
+    public void testReadWriteWithOffset() throws Exception {
+        File root = new File("target/scp");
+        File target = new File("target/scp/out.txt");
+        root.mkdirs();
+        assertTrue(root.exists());
+
+        ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+        c.connect();
+        c.put(new ByteArrayInputStream("0123456789".getBytes()), target.getPath());
+
+        assertTrue(target.exists());
+        assertEquals("0123456789", readFile("target/scp/out.txt"));
+
+        OutputStream os = c.put(target.getPath(), null, ChannelSftp.APPEND, -5);
+        os.write("a".getBytes());
+        os.close();
+        c.disconnect();
+
+        assertTrue(target.exists());
+        assertEquals("01234a", readFile("target/scp/out.txt"));
+
+        target.delete();
+        assertFalse(target.exists());
+        root.delete();
+    }
+
     protected void assertFileLength(File file, long length, long timeout) throws Exception {
         boolean ok = false;
         while (timeout > 0) {