|
@@ -20,6 +20,11 @@ class BlockAlignedReadableFile extends DelegatingReadableFile {
|
|
|
private final int blockSize;
|
|
|
private final ByteBuffer currentBlockBuffer;
|
|
|
private boolean eofReached = false;
|
|
|
+ private Mode mode = Mode.PASSTHROUGH;
|
|
|
+
|
|
|
+ private enum Mode {
|
|
|
+ BLOCK_ALIGNED, PASSTHROUGH;
|
|
|
+ }
|
|
|
|
|
|
public BlockAlignedReadableFile(ReadableFile delegate, int blockSize) {
|
|
|
super(delegate);
|
|
@@ -28,11 +33,12 @@ class BlockAlignedReadableFile extends DelegatingReadableFile {
|
|
|
}
|
|
|
this.blockSize = blockSize;
|
|
|
this.currentBlockBuffer = ByteBuffer.allocate(blockSize);
|
|
|
- this.currentBlockBuffer.flip(); // so the next attempt will read from source.
|
|
|
+ this.currentBlockBuffer.flip(); // so remaining() is 0 -> next read will read from physical source.
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void position(long logicalPosition) throws UncheckedIOException {
|
|
|
+ switchToBlockAlignedMode();
|
|
|
long blockNumber = logicalPosition / blockSize;
|
|
|
long physicalPosition = blockNumber * blockSize;
|
|
|
assert physicalPosition <= logicalPosition;
|
|
@@ -45,8 +51,24 @@ class BlockAlignedReadableFile extends DelegatingReadableFile {
|
|
|
currentBlockBuffer.position(diff);
|
|
|
}
|
|
|
|
|
|
+ // visible for testing
|
|
|
+ void switchToBlockAlignedMode() {
|
|
|
+ mode = Mode.BLOCK_ALIGNED;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public int read(ByteBuffer target) throws UncheckedIOException {
|
|
|
+ switch (mode) {
|
|
|
+ case PASSTHROUGH:
|
|
|
+ return super.read(target);
|
|
|
+ case BLOCK_ALIGNED:
|
|
|
+ return readBlockAligned(target);
|
|
|
+ default:
|
|
|
+ throw new IllegalStateException("Unsupported mode " + mode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int readBlockAligned(ByteBuffer target) {
|
|
|
int read = -1;
|
|
|
while (!eofReached && target.hasRemaining()) {
|
|
|
read += ByteBuffers.copy(currentBlockBuffer, target);
|