From f58941f2ac6b28131f5e83396f92ae77be427c3e Mon Sep 17 00:00:00 2001 From: Eli Collins Date: Mon, 20 Aug 2012 21:10:44 +0000 Subject: [PATCH] HADOOP-8614. IOUtils#skipFully hangs forever on EOF. Contributed by Colin Patrick McCabe git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1375216 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop-common/CHANGES.txt | 3 ++ .../java/org/apache/hadoop/io/IOUtils.java | 18 ++++++--- .../org/apache/hadoop/io/TestIOUtils.java | 39 +++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index b5163cc0c0c..ae1e22a1bb7 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -405,6 +405,9 @@ Branch-2 ( Unreleased changes ) HADOOP-8654. TextInputFormat delimiter bug (Gelesh and Jason Lowe via bobby) + HADOOP-8614. IOUtils#skipFully hangs forever on EOF. + (Colin Patrick McCabe via eli) + BREAKDOWN OF HDFS-3042 SUBTASKS HADOOP-8220. ZKFailoverController doesn't handle failure to become active 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 4f30483cd96..819f075812b 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 @@ -206,12 +206,20 @@ public class IOUtils { * for any reason (including EOF) */ public static void skipFully(InputStream in, long len) throws IOException { - while (len > 0) { - long ret = in.skip(len); - if (ret < 0) { - throw new IOException( "Premature EOF from inputStream"); + long amt = len; + while (amt > 0) { + long ret = in.skip(amt); + if (ret == 0) { + // skip may return 0 even if we're not at EOF. Luckily, we can + // use the read() method to figure out if we're at the end. + int b = in.read(); + if (b == -1) { + throw new EOFException( "Premature EOF from inputStream after " + + "skipping " + (len - amt) + " byte(s)."); + } + ret = 1; } - len -= ret; + amt -= ret; } } 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 6b7ffdfcf2b..b78b1ea9f31 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 @@ -21,6 +21,8 @@ package org.apache.hadoop.io; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import java.io.ByteArrayInputStream; +import java.io.EOFException; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -175,4 +177,41 @@ public class TestIOUtils { "Error while reading compressed data", ioe); } } + + @Test + public void testSkipFully() throws IOException { + byte inArray[] = new byte[] {0, 1, 2, 3, 4}; + ByteArrayInputStream in = new ByteArrayInputStream(inArray); + try { + in.mark(inArray.length); + IOUtils.skipFully(in, 2); + IOUtils.skipFully(in, 2); + try { + IOUtils.skipFully(in, 2); + fail("expected to get a PrematureEOFException"); + } catch (EOFException e) { + assertEquals(e.getMessage(), "Premature EOF from inputStream " + + "after skipping 1 byte(s)."); + } + in.reset(); + try { + IOUtils.skipFully(in, 20); + fail("expected to get a PrematureEOFException"); + } catch (EOFException e) { + assertEquals(e.getMessage(), "Premature EOF from inputStream " + + "after skipping 5 byte(s)."); + } + in.reset(); + IOUtils.skipFully(in, 5); + try { + IOUtils.skipFully(in, 10); + fail("expected to get a PrematureEOFException"); + } catch (EOFException e) { + assertEquals(e.getMessage(), "Premature EOF from inputStream " + + "after skipping 0 byte(s)."); + } + } finally { + in.close(); + } + } }