diff --git a/CHANGES.txt b/CHANGES.txt index f33d02a834..d428d8a33c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -347,6 +347,9 @@ Release 0.22.0 - Unreleased HADOOP-7154. Should set MALLOC_ARENA_MAX in hadoop-env.sh (todd) + HADOOP-7187. Fix socket leak in GangliaContext. (Uma Maheswara Rao G + via szetszwo) + OPTIMIZATIONS HADOOP-6884. Add LOG.isDebugEnabled() guard for each LOG.debug(..). @@ -604,8 +607,8 @@ Release 0.21.1 - Unreleased HADOOP-7174. Null is displayed in the "fs -copyToLocal" command. (Uma Maheswara Rao G via szetszwo) - HADOOP-7187. Fix socket leak in GangliaContext. (Uma Maheswara Rao G - via szetszwo) + HADOOP-7194. Fix resource leak in IOUtils.copyBytes(..). + (Devaraj K via szetszwo) Release 0.21.0 - 2010-08-13 diff --git a/src/java/org/apache/hadoop/io/IOUtils.java b/src/java/org/apache/hadoop/io/IOUtils.java index f7d27a7aeb..ca6df1bd7e 100644 --- a/src/java/org/apache/hadoop/io/IOUtils.java +++ b/src/java/org/apache/hadoop/io/IOUtils.java @@ -47,10 +47,16 @@ public class IOUtils { try { copyBytes(in, out, buffSize); - } finally { if(close) { out.close(); + out = null; in.close(); + in = null; + } + } finally { + if(close) { + closeStream(out); + closeStream(in); } } } diff --git a/src/test/core/org/apache/hadoop/io/TestIOUtils.java b/src/test/core/org/apache/hadoop/io/TestIOUtils.java new file mode 100644 index 0000000000..44d03ea453 --- /dev/null +++ b/src/test/core/org/apache/hadoop/io/TestIOUtils.java @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.junit.Test; +import org.mockito.Mockito; + +/** + * Test cases for IOUtils.java + */ +public class TestIOUtils { + + @Test + public void testCopyBytesShouldCloseStreamsWhenCloseIsTrue() throws Exception { + InputStream inputStream = Mockito.mock(InputStream.class); + OutputStream outputStream = Mockito.mock(OutputStream.class); + Mockito.doReturn(-1).when(inputStream).read(new byte[1]); + IOUtils.copyBytes(inputStream, outputStream, 1, true); + Mockito.verify(inputStream, Mockito.atLeastOnce()).close(); + Mockito.verify(outputStream, Mockito.atLeastOnce()).close(); + } + + @Test + public void testCopyBytesShouldCloseInputSteamWhenOutputStreamCloseThrowsException() + 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 IOException()).when(outputStream).close(); + try{ + IOUtils.copyBytes(inputStream, outputStream, 1, true); + } catch (IOException e) { + } + Mockito.verify(inputStream, Mockito.atLeastOnce()).close(); + Mockito.verify(outputStream, Mockito.atLeastOnce()).close(); + } + + @Test + public void testCopyBytesShouldNotCloseStreamsWhenCloseIsFalse() + throws Exception { + InputStream inputStream = Mockito.mock(InputStream.class); + OutputStream outputStream = Mockito.mock(OutputStream.class); + Mockito.doReturn(-1).when(inputStream).read(new byte[1]); + IOUtils.copyBytes(inputStream, outputStream, 1, false); + Mockito.verify(inputStream, Mockito.atMost(0)).close(); + Mockito.verify(outputStream, Mockito.atMost(0)).close(); + } +}