Skip to content

Commit 12ff937

Browse files
author
Jonathan Eagles
committed
TEZ-3912. Fetchers should be more robust to corrupted inputs (Kuhu Shukla via jeagles)
1 parent 5b75ef1 commit 12ff937

2 files changed

Lines changed: 59 additions & 3 deletions

File tree

tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/ShuffleUtils.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public static void shuffleToMemory(byte[] shuffleData,
125125
LOG.debug("Read " + shuffleData.length + " bytes from input for "
126126
+ identifier);
127127
}
128-
} catch (InternalError | IOException e) {
128+
} catch (InternalError | Exception e) {
129129
// Close the streams
130130
LOG.info("Failed to read data to memory for " + identifier + ". len=" + compressedLength +
131131
", decomp=" + decompressedLength + ". ExceptionMessage=" + e.getMessage());
@@ -135,9 +135,12 @@ public static void shuffleToMemory(byte[] shuffleData,
135135
// on decompression failures. Catching and re-throwing as IOException
136136
// to allow fetch failure logic to be processed.
137137
throw new IOException(e);
138+
} else if (e instanceof IOException) {
139+
throw e;
140+
} else {
141+
// Re-throw as an IOException
142+
throw new IOException(e);
138143
}
139-
// Re-throw
140-
throw e;
141144
}
142145
}
143146

tez-runtime-library/src/test/java/org/apache/tez/runtime/library/common/shuffle/TestShuffleUtils.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.io.IOException;
4242
import java.io.InputStream;
4343
import java.io.OutputStream;
44+
import java.net.SocketTimeoutException;
4445
import java.nio.ByteBuffer;
4546
import java.util.Arrays;
4647
import java.util.BitSet;
@@ -300,6 +301,58 @@ public void testInternalErrorTranslation() throws Exception {
300301
}
301302
}
302303

304+
@Test
305+
public void testExceptionTranslation() throws Exception {
306+
String codecErrorMsg = "codec failure";
307+
CompressionInputStream mockCodecStream = mock(CompressionInputStream.class);
308+
when(mockCodecStream.read(any(byte[].class), anyInt(), anyInt()))
309+
.thenThrow(new IllegalArgumentException(codecErrorMsg));
310+
Decompressor mockDecoder = mock(Decompressor.class);
311+
CompressionCodec mockCodec = mock(CompressionCodec.class);
312+
when(mockCodec.createDecompressor()).thenReturn(mockDecoder);
313+
when(mockCodec.createInputStream(any(InputStream.class), any(Decompressor.class)))
314+
.thenReturn(mockCodecStream);
315+
byte[] header = new byte[] { (byte) 'T', (byte) 'I', (byte) 'F', (byte) 1};
316+
try {
317+
ShuffleUtils.shuffleToMemory(new byte[1024], new ByteArrayInputStream(header),
318+
1024, 128, mockCodec, false, 0, mock(Logger.class), null);
319+
Assert.fail("shuffle was supposed to throw!");
320+
} catch (IOException e) {
321+
Assert.assertTrue(e.getCause() instanceof IllegalArgumentException);
322+
Assert.assertTrue(e.getMessage().contains(codecErrorMsg));
323+
}
324+
CompressionInputStream mockCodecStream1 = mock(CompressionInputStream.class);
325+
when(mockCodecStream1.read(any(byte[].class), anyInt(), anyInt()))
326+
.thenThrow(new SocketTimeoutException(codecErrorMsg));
327+
CompressionCodec mockCodec1 = mock(CompressionCodec.class);
328+
when(mockCodec1.createDecompressor()).thenReturn(mockDecoder);
329+
when(mockCodec1.createInputStream(any(InputStream.class), any(Decompressor.class)))
330+
.thenReturn(mockCodecStream1);
331+
try {
332+
ShuffleUtils.shuffleToMemory(new byte[1024], new ByteArrayInputStream(header),
333+
1024, 128, mockCodec1, false, 0, mock(Logger.class), null);
334+
Assert.fail("shuffle was supposed to throw!");
335+
} catch (IOException e) {
336+
Assert.assertTrue(e instanceof SocketTimeoutException);
337+
Assert.assertTrue(e.getMessage().contains(codecErrorMsg));
338+
}
339+
CompressionInputStream mockCodecStream2 = mock(CompressionInputStream.class);
340+
when(mockCodecStream2.read(any(byte[].class), anyInt(), anyInt()))
341+
.thenThrow(new InternalError(codecErrorMsg));
342+
CompressionCodec mockCodec2 = mock(CompressionCodec.class);
343+
when(mockCodec2.createDecompressor()).thenReturn(mockDecoder);
344+
when(mockCodec2.createInputStream(any(InputStream.class), any(Decompressor.class)))
345+
.thenReturn(mockCodecStream2);
346+
try {
347+
ShuffleUtils.shuffleToMemory(new byte[1024], new ByteArrayInputStream(header),
348+
1024, 128, mockCodec2, false, 0, mock(Logger.class), null);
349+
Assert.fail("shuffle was supposed to throw!");
350+
} catch (IOException e) {
351+
Assert.assertTrue(e.getCause() instanceof InternalError);
352+
Assert.assertTrue(e.getMessage().contains(codecErrorMsg));
353+
}
354+
}
355+
303356
@Test
304357
public void testShuffleToDiskChecksum() throws Exception {
305358
// verify sending a stream of zeroes without checksum validation

0 commit comments

Comments
 (0)