From 8ef996b4067345e103812fc93214a59231b01912 Mon Sep 17 00:00:00 2001 From: Vladimir Lagunov Date: Thu, 7 Apr 2022 18:10:02 +0700 Subject: [PATCH] Fix #777: Don't request excessive read-ahead packets in RemoteFile (#778) Due to a bug in logic introduced by #769, RemoteFile.ReadAheadRemoteFileInputStream started to send new read ahead requests for file parts that had already been requested. Every call to read() asked the server to send parts of the file from the point which is already downloaded. Instead, it should have asked to send parts after the last requested part. This commit adds exactly this logic. The bug didn't cause content corruption. It only affected performance, both on servers and on clients. --- src/main/java/net/schmizz/sshj/sftp/RemoteFile.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java b/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java index 81e95fe11..8075377e8 100644 --- a/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java +++ b/src/main/java/net/schmizz/sshj/sftp/RemoteFile.java @@ -23,6 +23,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.TimeUnit; @@ -252,7 +254,7 @@ public int getLength() { private final int maxUnconfirmedReads; private final long readAheadLimit; - private final Queue unconfirmedReads = new LinkedList<>(); + private final Deque unconfirmedReads = new ArrayDeque<>(); private long currentOffset; private int maxReadLength = Integer.MAX_VALUE; @@ -336,7 +338,14 @@ public int read(byte[] into, int off, int len) throws IOException { // we also need to go here for len <= 0, because pending may be at // EOF in which case it would return -1 instead of 0 - long requestOffset = currentOffset; + long requestOffset; + if (unconfirmedReads.isEmpty()) { + requestOffset = currentOffset; + } + else { + final UnconfirmedRead lastRequest = unconfirmedReads.getLast(); + requestOffset = lastRequest.offset + lastRequest.length; + } while (unconfirmedReads.size() <= maxUnconfirmedReads) { // Send read requests as long as there is no EOF and we have not reached the maximum parallelism int reqLen = Math.min(Math.max(1024, len), maxReadLength);