Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions fluss-common/src/main/java/org/apache/fluss/utils/IOUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,23 @@ private static long copyBytes(
return totalBytes;
} finally {
if (close) {
out.close();
in.close();
Throwable closeException = null;
try {
out.close();
} catch (Throwable t) {
closeException = t;
}
try {
in.close();
} catch (Throwable t) {
closeException = ExceptionUtils.firstOrSuppressed(t, closeException);
}
if (closeException != null) {
if (closeException instanceof IOException) {
throw (IOException) closeException;
}
ExceptionUtils.rethrow(closeException);
}
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions fluss-common/src/test/java/org/apache/fluss/utils/IOUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -74,6 +75,17 @@ void testCopyBytes() throws IOException {
assertThat(buf).isEqualTo(new byte[] {'h', 'e', 'l', 'l', 'o'});
}

@Test
void testCopyBytesClosesInputWhenOutputCloseFails() {
TrackingInputStream in = new TrackingInputStream("hello".getBytes());
OutputStream out = new CloseFailingOutputStream();

assertThatThrownBy(() -> IOUtils.copyBytes(in, out, true))
.isInstanceOf(IOException.class)
.hasMessage("Fail to close output");
assertThat(in.closed).isTrue();
}

@Test
void testReadFully() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Expand Down Expand Up @@ -108,4 +120,30 @@ public void close() throws Exception {
closed = true;
}
}

private static class TrackingInputStream extends ByteArrayInputStream {

private boolean closed;

private TrackingInputStream(byte[] buf) {
super(buf);
}

@Override
public void close() throws IOException {
closed = true;
super.close();
}
}

private static class CloseFailingOutputStream extends OutputStream {

@Override
public void write(int b) {}

@Override
public void close() throws IOException {
throw new IOException("Fail to close output");
}
}
}