Repair file channel when it's closed by interruption
When an interrupted that calls FileChannel.read, the channel is closed and the read fails with a ClosedByInterruptException. The closure of the channel makes it unusable by other threads. To allow other threads to read from the data block, this commit recreates the FileChannel when a read fails on an interrupted thread with a ClosedByInterruptException. The exception is then rethrown to continue the thread's interruption. Closes gh-38154
This commit is contained in:
@@ -18,6 +18,7 @@ package org.springframework.boot.loader.zip;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
@@ -179,7 +180,13 @@ class FileChannelDataBlock implements CloseableDataBlock {
|
||||
synchronized (this.lock) {
|
||||
if (position < this.bufferPosition || position >= this.bufferPosition + this.bufferSize) {
|
||||
this.buffer.clear();
|
||||
this.bufferSize = this.fileChannel.read(this.buffer, position);
|
||||
try {
|
||||
this.bufferSize = this.fileChannel.read(this.buffer, position);
|
||||
}
|
||||
catch (ClosedByInterruptException ex) {
|
||||
repairFileChannel();
|
||||
throw ex;
|
||||
}
|
||||
this.bufferPosition = position;
|
||||
}
|
||||
if (this.bufferSize <= 0) {
|
||||
@@ -193,6 +200,16 @@ class FileChannelDataBlock implements CloseableDataBlock {
|
||||
}
|
||||
}
|
||||
|
||||
private void repairFileChannel() throws IOException {
|
||||
if (tracker != null) {
|
||||
tracker.closedFileChannel(this.path, this.fileChannel);
|
||||
}
|
||||
this.fileChannel = FileChannel.open(this.path, StandardOpenOption.READ);
|
||||
if (tracker != null) {
|
||||
tracker.openedFileChannel(this.path, this.fileChannel);
|
||||
}
|
||||
}
|
||||
|
||||
void open() throws IOException {
|
||||
synchronized (this.lock) {
|
||||
if (this.referenceCount == 0) {
|
||||
@@ -231,7 +248,7 @@ class FileChannelDataBlock implements CloseableDataBlock {
|
||||
|
||||
<E extends Exception> void ensureOpen(Supplier<E> exceptionSupplier) throws E {
|
||||
synchronized (this.lock) {
|
||||
if (this.referenceCount == 0) {
|
||||
if (this.referenceCount == 0 || !this.fileChannel.isOpen()) {
|
||||
throw exceptionSupplier.get();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user