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:
@@ -19,9 +19,11 @@ package org.springframework.boot.loader.zip;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -74,6 +76,28 @@ class FileChannelDataBlockTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void readReadsFileWhenAnotherThreadHasBeenInterrupted() throws IOException, InterruptedException {
|
||||
try (FileChannelDataBlock block = createAndOpenBlock()) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);
|
||||
AtomicReference<IOException> failure = new AtomicReference<>();
|
||||
Thread thread = new Thread(() -> {
|
||||
Thread.currentThread().interrupt();
|
||||
try {
|
||||
block.read(ByteBuffer.allocate(CONTENT.length), 0);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
failure.set(ex);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
thread.join();
|
||||
assertThat(failure.get()).isInstanceOf(ClosedByInterruptException.class);
|
||||
assertThat(block.read(buffer, 0)).isEqualTo(6);
|
||||
assertThat(buffer.array()).containsExactly(CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void readDoesNotReadPastEndOfFile() throws IOException {
|
||||
try (FileChannelDataBlock block = createAndOpenBlock()) {
|
||||
|
||||
Reference in New Issue
Block a user