Add parameter to limit read ahead to maximum length. Allows to use mu… (#724)

* Add parameter to limit read ahead to maximum length. Allows to use multiple concurrent threads reading from the same file with an offset without reading too much ahead for a single segment.

* Review and add tests.

Signed-off-by: David Kocher <dkocher@iterate.ch>

Co-authored-by: Yves Langisch <yves@langisch.ch>
This commit is contained in:
David Kocher
2021-12-23 22:24:52 +01:00
committed by GitHub
parent cab7731928
commit 8cf63a96a9
2 changed files with 109 additions and 4 deletions

View File

@@ -224,6 +224,7 @@ public class RemoteFile
private final byte[] b = new byte[1];
private final int maxUnconfirmedReads;
private final long readAheadLimit;
private final Queue<Promise<Response, SFTPException>> unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
private final Queue<Long> unconfirmedReadOffsets = new LinkedList<Long>();
@@ -232,17 +233,22 @@ public class RemoteFile
private boolean eof;
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads) {
assert 0 <= maxUnconfirmedReads;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this(maxUnconfirmedReads, 0L, -1L);
}
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads, long fileOffset) {
/**
*
* @param maxUnconfirmedReads Maximum number of unconfirmed requests to send
* @param fileOffset Initial offset in file to read from
* @param readAheadLimit Read ahead is disabled after this limit has been reached
*/
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads, long fileOffset, long readAheadLimit) {
assert 0 <= maxUnconfirmedReads;
assert 0 <= fileOffset;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this.requestOffset = this.responseOffset = fileOffset;
this.readAheadLimit = readAheadLimit > 0 ? fileOffset + readAheadLimit : Long.MAX_VALUE;
}
private ByteArrayInputStream pending = new ByteArrayInputStream(new byte[0]);
@@ -293,9 +299,18 @@ public class RemoteFile
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.max(1024, len); // don't be shy!
if (readAheadLimit > requestOffset) {
long remaining = readAheadLimit - requestOffset;
if (reqLen > remaining) {
reqLen = (int) remaining;
}
}
unconfirmedReads.add(RemoteFile.this.asyncRead(requestOffset, reqLen));
unconfirmedReadOffsets.add(requestOffset);
requestOffset += reqLen;
if (requestOffset >= readAheadLimit) {
break;
}
}
long nextOffset = unconfirmedReadOffsets.peek();