diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java index 386754fc2..88ef0dd04 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java @@ -516,7 +516,9 @@ private long copyPackThroughCache(PackOutputStream out, DfsReader ctx, private long copyPackBypassCache(PackOutputStream out, DfsReader ctx, MessageDigest md) throws IOException { try (ReadableChannel rc = ctx.db.openFile(packDesc, PACK)) { - ByteBuffer buf = newCopyBuffer(out, rc, ctx); + ByteBuffer buf = newCopyBuffer(out, rc); + if (ctx.getOptions().getStreamPackBufferSize() > 0) + rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize()); long position = 12; long remaining = length - (12 + 20); while (0 < remaining) { @@ -547,13 +549,8 @@ else if (n > remaining) } } - private ByteBuffer newCopyBuffer(PackOutputStream out, ReadableChannel rc, - DfsReader ctx) { + private ByteBuffer newCopyBuffer(PackOutputStream out, ReadableChannel rc) { int bs = blockSize(rc); - int bufferSize = ctx.getOptions().getStreamPackBufferSize(); - if (bufferSize > bs) - bs = (bufferSize / bs) * bs; - byte[] copyBuf = out.getCopyBuffer(); if (bs > copyBuf.length) copyBuf = new byte[bs]; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java index ae05536de..8e7af0d29 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java @@ -227,6 +227,10 @@ public long size() { public int blockSize() { return 0; } + + public void setReadAheadBytes(int b) { + // Unnecessary on a byte array. + } } private class MemRefDatabase extends DfsRefDatabase { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java index 5ec7079a8..240d552aa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReadableChannel.java @@ -100,4 +100,33 @@ public interface ReadableChannel extends ReadableByteChannel { * not need to be a power of 2. */ public int blockSize(); + + /** + * Recommend the channel maintain a read-ahead buffer. + *

+ * A read-ahead buffer of approximately {@code bufferSize} in bytes may be + * allocated and used by the channel to smooth out latency for read. + *

+ * Callers can continue to read in smaller than {@code bufferSize} chunks. + * With read-ahead buffering enabled read latency may fluctuate in a pattern + * of one slower read followed by {@code (bufferSize / readSize) - 1} fast + * reads satisfied by the read-ahead buffer. When summed up overall time to + * read the same contiguous range should be lower than if read-ahead was not + * enabled, as the implementation can combine reads to increase throughput. + *

+ * To avoid unnecessary IO callers should only enable read-ahead if the + * majority of the channel will be accessed in order. + *

+ * Implementations may chose to read-ahead using asynchronous APIs or + * background threads, or may simply aggregate reads using a buffer. + *

+ * This read ahead stays in effect until the channel is closed or the buffer + * size is set to 0. + * + * @param bufferSize + * requested size of the read ahead buffer, in bytes. + * @throws IOException + * if the read ahead cannot be adjusted. + */ + public void setReadAheadBytes(int bufferSize) throws IOException; }