From e2216a96d7995f522647f773f784162ca2d5bf14 Mon Sep 17 00:00:00 2001 From: Harsh J Date: Sat, 22 Sep 2012 20:34:16 +0000 Subject: [PATCH] HADOOP-7256. Resource leak during failure scenario of closing of resources. Contributed by Ramkrishna S. Vasudevan. (harsh) git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1388893 13f79535-47bb-0310-9956-ffa450edef68 (cherry picked from commit 28023b77595991fe3be590a929b7d162556f1d4a) --- .../java/org/apache/hadoop/io/IOUtils.java | 5 ++- .../org/apache/hadoop/io/TestIOUtils.java | 37 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java index 70e407b2bf8..451163cc140 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/IOUtils.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; @@ -43,6 +44,7 @@ import org.apache.hadoop.util.ChunkedArrayList; @InterfaceAudience.Public @InterfaceStability.Evolving public class IOUtils { + public static final Log LOG = LogFactory.getLog(IOUtils.class); /** * Copies from one stream to another. @@ -243,7 +245,7 @@ public class IOUtils { if (c != null) { try { c.close(); - } catch(IOException e) { + } catch(Throwable e) { if (log != null && log.isDebugEnabled()) { log.debug("Exception in closing " + c, e); } @@ -272,6 +274,7 @@ public class IOUtils { try { sock.close(); } catch (IOException ignored) { + LOG.debug("Ignoring exception while closing socket", ignored); } } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java index e485f9fe177..ac4fb483f67 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/io/TestIOUtils.java @@ -73,6 +73,36 @@ public class TestIOUtils { Mockito.verify(outputStream, Mockito.atLeastOnce()).close(); } + @Test + public void testCopyBytesShouldCloseInputSteamWhenOutputStreamCloseThrowsRunTimeException() + throws Exception { + InputStream inputStream = Mockito.mock(InputStream.class); + OutputStream outputStream = Mockito.mock(OutputStream.class); + Mockito.doReturn(-1).when(inputStream).read(new byte[1]); + Mockito.doThrow(new RuntimeException()).when(outputStream).close(); + try { + IOUtils.copyBytes(inputStream, outputStream, 1, true); + fail("Didn't throw exception"); + } catch (RuntimeException e) { + } + Mockito.verify(outputStream, Mockito.atLeastOnce()).close(); + } + + @Test + public void testCopyBytesShouldCloseInputSteamWhenInputStreamCloseThrowsRunTimeException() + throws Exception { + InputStream inputStream = Mockito.mock(InputStream.class); + OutputStream outputStream = Mockito.mock(OutputStream.class); + Mockito.doReturn(-1).when(inputStream).read(new byte[1]); + Mockito.doThrow(new RuntimeException()).when(inputStream).close(); + try { + IOUtils.copyBytes(inputStream, outputStream, 1, true); + fail("Didn't throw exception"); + } catch (RuntimeException e) { + } + Mockito.verify(inputStream, Mockito.atLeastOnce()).close(); + } + @Test public void testCopyBytesShouldNotCloseStreamsWhenCloseIsFalse() throws Exception { @@ -83,7 +113,7 @@ public class TestIOUtils { Mockito.verify(inputStream, Mockito.atMost(0)).close(); Mockito.verify(outputStream, Mockito.atMost(0)).close(); } - + @Test public void testCopyBytesWithCountShouldCloseStreamsWhenCloseIsTrue() throws Exception { @@ -124,7 +154,7 @@ public class TestIOUtils { Mockito.verify(inputStream, Mockito.atLeastOnce()).close(); Mockito.verify(outputStream, Mockito.atLeastOnce()).close(); } - + @Test public void testWriteFully() throws IOException { final int INPUT_BUFFER_LEN = 10000; @@ -155,6 +185,7 @@ public class TestIOUtils { for (int i = HALFWAY; i < input.length; i++) { assertEquals(input[i - HALFWAY], output[i]); } + raf.close(); } finally { File f = new File(TEST_FILE_NAME); if (f.exists()) { @@ -184,7 +215,7 @@ public class TestIOUtils { "Error while reading compressed data", ioe); } } - + @Test public void testSkipFully() throws IOException { byte inArray[] = new byte[] {0, 1, 2, 3, 4};