mirror of https://github.com/apache/lucene.git
LUCENE-9423: Handle exc in NIOFSDirectory#openInput (#1658)
If we fail to get the size of a file in the constructor of NIOFSIndexInput, then we will leak a FileChannel opened in NIOFSDirectory#openInput.
This commit is contained in:
parent
4ae976bdf0
commit
20ec57a4fe
|
@ -25,6 +25,8 @@ import java.nio.file.Path;
|
|||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.concurrent.Future; // javadoc
|
||||
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
|
||||
/**
|
||||
* An {@link FSDirectory} implementation that uses java.nio's FileChannel's
|
||||
* positional read, which allows multiple threads to read from the same file
|
||||
|
@ -79,7 +81,16 @@ public class NIOFSDirectory extends FSDirectory {
|
|||
ensureCanRead(name);
|
||||
Path path = getDirectory().resolve(name);
|
||||
FileChannel fc = FileChannel.open(path, StandardOpenOption.READ);
|
||||
return new NIOFSIndexInput("NIOFSIndexInput(path=\"" + path + "\")", fc, context);
|
||||
boolean success = false;
|
||||
try {
|
||||
final NIOFSIndexInput indexInput = new NIOFSIndexInput("NIOFSIndexInput(path=\"" + path + "\")", fc, context);
|
||||
success = true;
|
||||
return indexInput;
|
||||
} finally {
|
||||
if (success == false) {
|
||||
IOUtils.closeWhileHandlingException(fc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,7 +18,17 @@ package org.apache.lucene.store;
|
|||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.lucene.mockfile.FilterFileChannel;
|
||||
import org.apache.lucene.mockfile.FilterPath;
|
||||
import org.apache.lucene.mockfile.LeakFS;
|
||||
|
||||
/**
|
||||
* Tests NIOFSDirectory
|
||||
|
@ -29,4 +39,29 @@ public class TestNIOFSDirectory extends BaseDirectoryTestCase {
|
|||
protected Directory getDirectory(Path path) throws IOException {
|
||||
return new NIOFSDirectory(path);
|
||||
}
|
||||
|
||||
public void testHandleExceptionInConstructor() throws Exception {
|
||||
Path path = createTempDir().toRealPath();
|
||||
final LeakFS leakFS = new LeakFS(path.getFileSystem()) {
|
||||
@Override
|
||||
public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs) throws IOException {
|
||||
return new FilterFileChannel(super.newFileChannel(path, options, attrs)) {
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
throw new IOException("simulated");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
FileSystem fs = leakFS.getFileSystem(URI.create("file:///"));
|
||||
Path wrapped = new FilterPath(path, fs);
|
||||
try (Directory dir = new NIOFSDirectory(wrapped)) {
|
||||
try (IndexOutput out = dir.createOutput("test.bin", IOContext.DEFAULT)) {
|
||||
out.writeString("hello");
|
||||
}
|
||||
final IOException error = expectThrows(IOException.class, () -> dir.openInput("test.bin", IOContext.DEFAULT));
|
||||
assertEquals("simulated", error.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue