mirror of
https://github.com/apache/lucene.git
synced 2025-02-22 18:27:21 +00:00
LUCENE-9686: Fix read past EOF handling in DirectIODirectory (#2258)
This commit is contained in:
parent
15aaec60d9
commit
3835cb4e95
@ -359,12 +359,8 @@ public class DirectIODirectory extends FilterDirectory {
|
||||
filePos = alignedPos - buffer.capacity();
|
||||
|
||||
final int delta = (int) (pos - alignedPos);
|
||||
refill();
|
||||
try {
|
||||
buffer.position(delta);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new EOFException("read past EOF: " + this);
|
||||
}
|
||||
refill(delta);
|
||||
buffer.position(delta);
|
||||
}
|
||||
assert pos == getFilePointer();
|
||||
}
|
||||
@ -381,17 +377,18 @@ public class DirectIODirectory extends FilterDirectory {
|
||||
@Override
|
||||
public byte readByte() throws IOException {
|
||||
if (!buffer.hasRemaining()) {
|
||||
refill();
|
||||
refill(1);
|
||||
}
|
||||
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
private void refill() throws IOException {
|
||||
private void refill(int bytesToRead) throws IOException {
|
||||
filePos += buffer.capacity();
|
||||
|
||||
// BaseDirectoryTestCase#testSeekPastEOF test for consecutive read past EOF,
|
||||
// hence throwing EOFException early to maintain buffer state (position in particular)
|
||||
if (filePos > channel.size()) {
|
||||
if (filePos > channel.size() || (channel.size() - filePos < bytesToRead)) {
|
||||
throw new EOFException("read past EOF: " + this);
|
||||
}
|
||||
|
||||
@ -417,7 +414,7 @@ public class DirectIODirectory extends FilterDirectory {
|
||||
buffer.get(dst, offset, left);
|
||||
toRead -= left;
|
||||
offset += left;
|
||||
refill();
|
||||
refill(toRead);
|
||||
} else {
|
||||
buffer.get(dst, offset, toRead);
|
||||
break;
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.apache.lucene.misc.store;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.RandomizedTest;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -77,10 +79,68 @@ public class TestDirectIODirectory extends BaseDirectoryTestCase {
|
||||
o.close();
|
||||
IndexInput i = dir.openInput("out", newIOContext(random()));
|
||||
i.seek(fileSize);
|
||||
|
||||
// Seeking past EOF should always throw EOFException
|
||||
expectThrows(
|
||||
EOFException.class, () -> i.seek(fileSize + RandomizedTest.randomIntBetween(1, 2048)));
|
||||
|
||||
// Reading immediately after seeking past EOF should throw EOFException
|
||||
expectThrows(EOFException.class, () -> i.readByte());
|
||||
i.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadPastEOFShouldThrowEOFExceptionWithEmptyFile() throws Exception {
|
||||
// fileSize needs to be 0 to test this condition. Do not randomized.
|
||||
final int fileSize = 0;
|
||||
try (Directory dir = getDirectory(createTempDir("testReadPastEOF"))) {
|
||||
try (IndexOutput o = dir.createOutput("out", newIOContext(random()))) {
|
||||
o.writeBytes(new byte[fileSize], 0, fileSize);
|
||||
}
|
||||
|
||||
try (IndexInput i = dir.openInput("out", newIOContext(random()))) {
|
||||
i.seek(fileSize);
|
||||
expectThrows(EOFException.class, () -> i.readByte());
|
||||
expectThrows(EOFException.class, () -> i.readBytes(new byte[1], 0, 1));
|
||||
}
|
||||
|
||||
try (IndexInput i = dir.openInput("out", newIOContext(random()))) {
|
||||
expectThrows(
|
||||
EOFException.class, () -> i.seek(fileSize + RandomizedTest.randomIntBetween(1, 2048)));
|
||||
expectThrows(EOFException.class, () -> i.readByte());
|
||||
expectThrows(EOFException.class, () -> i.readBytes(new byte[1], 0, 1));
|
||||
}
|
||||
|
||||
try (IndexInput i = dir.openInput("out", newIOContext(random()))) {
|
||||
expectThrows(EOFException.class, () -> i.readByte());
|
||||
}
|
||||
|
||||
try (IndexInput i = dir.openInput("out", newIOContext(random()))) {
|
||||
expectThrows(EOFException.class, () -> i.readBytes(new byte[1], 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testSeekPastEOFAndRead() throws Exception {
|
||||
try (Directory dir = getDirectory(createTempDir("testSeekPastEOF"))) {
|
||||
final int len = random().nextInt(2048);
|
||||
|
||||
try (IndexOutput o = dir.createOutput("out", newIOContext(random()))) {
|
||||
byte[] b = new byte[len];
|
||||
o.writeBytes(b, 0, len);
|
||||
}
|
||||
|
||||
try (IndexInput i = dir.openInput("out", newIOContext(random()))) {
|
||||
// Seeking past EOF should always throw EOFException
|
||||
expectThrows(
|
||||
EOFException.class, () -> i.seek(len + RandomizedTest.randomIntBetween(1, 2048)));
|
||||
|
||||
// Reading immediately after seeking past EOF should throw EOFException
|
||||
expectThrows(EOFException.class, () -> i.readByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testUseDirectIODefaults() throws Exception {
|
||||
Path path = createTempDir("testUseDirectIODefaults");
|
||||
try (DirectIODirectory dir = new DirectIODirectory(FSDirectory.open(path))) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user