You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by at...@apache.org on 2013/02/26 02:43:44 UTC
svn commit: r1449994 - in
/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common:
CHANGES.txt src/main/java/org/apache/hadoop/fs/DF.java
src/test/java/org/apache/hadoop/fs/TestDFVariations.java
Author: atm
Date: Tue Feb 26 01:43:44 2013
New Revision: 1449994
URL: http://svn.apache.org/r1449994
Log:
HADOOP-7487. DF should throw a more reasonable exception when mount cannot be determined. Contributed by Andrew Wang.
Modified:
hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt
hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/DF.java
hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestDFVariations.java
Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1449994&r1=1449993&r2=1449994&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt Tue Feb 26 01:43:44 2013
@@ -50,6 +50,9 @@ Release 2.0.4-beta - UNRELEASED
HADOOP-9323. Fix typos in API documentation. (suresh)
+ HADOOP-7487. DF should throw a more reasonable exception when mount cannot
+ be determined. (Andrew Wang via atm)
+
Release 2.0.3-alpha - 2013-02-06
INCOMPATIBLE CHANGES
Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/DF.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/DF.java?rev=1449994&r1=1449993&r2=1449994&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/DF.java (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/DF.java Tue Feb 26 01:43:44 2013
@@ -17,19 +17,22 @@
*/
package org.apache.hadoop.fs;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.BufferedReader;
-
+import java.util.ArrayList;
import java.util.EnumSet;
+import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.util.Shell;
+import com.google.common.annotations.VisibleForTesting;
+
/** Filesystem disk space usage statistics.
* Uses the unix 'df' program to get mount points, and java.io.File for
* space utilization. Tested on Linux, FreeBSD, Cygwin. */
@@ -44,6 +47,8 @@ public class DF extends Shell {
private final File dirFile;
private String filesystem;
private String mount;
+
+ private ArrayList<String> output;
enum OSType {
OS_TYPE_UNIX("UNIX"),
@@ -84,6 +89,7 @@ public class DF extends Shell {
super(dfInterval);
this.dirPath = path.getCanonicalPath();
this.dirFile = new File(this.dirPath);
+ this.output = new ArrayList<String>();
}
protected OSType getOSType() {
@@ -127,7 +133,21 @@ public class DF extends Shell {
/** @return the filesystem mount point for the indicated volume */
public String getMount() throws IOException {
+ // Abort early if specified path does not exist
+ if (!dirFile.exists()) {
+ throw new FileNotFoundException("Specified path " + dirFile.getPath()
+ + "does not exist");
+ }
run();
+ // Skip parsing if df was not successful
+ if (getExitCode() != 0) {
+ StringBuffer sb = new StringBuffer("df could not be run successfully: ");
+ for (String line: output) {
+ sb.append(line);
+ }
+ throw new IOException(sb.toString());
+ }
+ parseOutput();
return mount;
}
@@ -152,46 +172,71 @@ public class DF extends Shell {
@Override
protected void parseExecResult(BufferedReader lines) throws IOException {
- lines.readLine(); // skip headings
-
+ output.clear();
String line = lines.readLine();
- if (line == null) {
- throw new IOException( "Expecting a line not the end of stream" );
+ while (line != null) {
+ output.add(line);
+ line = lines.readLine();
+ }
+ }
+
+ @VisibleForTesting
+ protected void parseOutput() throws IOException {
+ if (output.size() < 2) {
+ StringBuffer sb = new StringBuffer("Fewer lines of output than expected");
+ if (output.size() > 0) {
+ sb.append(": " + output.get(0));
+ }
+ throw new IOException(sb.toString());
}
+
+ String line = output.get(1);
StringTokenizer tokens =
new StringTokenizer(line, " \t\n\r\f%");
- this.filesystem = tokens.nextToken();
+ try {
+ this.filesystem = tokens.nextToken();
+ } catch (NoSuchElementException e) {
+ throw new IOException("Unexpected empty line");
+ }
if (!tokens.hasMoreTokens()) { // for long filesystem name
- line = lines.readLine();
- if (line == null) {
- throw new IOException( "Expecting a line not the end of stream" );
+ if (output.size() > 2) {
+ line = output.get(2);
+ } else {
+ throw new IOException("Expecting additional output after line: "
+ + line);
}
tokens = new StringTokenizer(line, " \t\n\r\f%");
}
- switch(getOSType()) {
- case OS_TYPE_AIX:
- Long.parseLong(tokens.nextToken()); // capacity
- Long.parseLong(tokens.nextToken()); // available
- Integer.parseInt(tokens.nextToken()); // pct used
- tokens.nextToken();
- tokens.nextToken();
- this.mount = tokens.nextToken();
- break;
-
- case OS_TYPE_WIN:
- case OS_TYPE_SOLARIS:
- case OS_TYPE_MAC:
- case OS_TYPE_UNIX:
- default:
- Long.parseLong(tokens.nextToken()); // capacity
- Long.parseLong(tokens.nextToken()); // used
- Long.parseLong(tokens.nextToken()); // available
- Integer.parseInt(tokens.nextToken()); // pct used
- this.mount = tokens.nextToken();
- break;
- }
+ try {
+ switch(getOSType()) {
+ case OS_TYPE_AIX:
+ Long.parseLong(tokens.nextToken()); // capacity
+ Long.parseLong(tokens.nextToken()); // available
+ Integer.parseInt(tokens.nextToken()); // pct used
+ tokens.nextToken();
+ tokens.nextToken();
+ this.mount = tokens.nextToken();
+ break;
+
+ case OS_TYPE_WIN:
+ case OS_TYPE_SOLARIS:
+ case OS_TYPE_MAC:
+ case OS_TYPE_UNIX:
+ default:
+ Long.parseLong(tokens.nextToken()); // capacity
+ Long.parseLong(tokens.nextToken()); // used
+ Long.parseLong(tokens.nextToken()); // available
+ Integer.parseInt(tokens.nextToken()); // pct used
+ this.mount = tokens.nextToken();
+ break;
+ }
+ } catch (NoSuchElementException e) {
+ throw new IOException("Could not parse line: " + line);
+ } catch (NumberFormatException e) {
+ throw new IOException("Could not parse line: " + line);
+ }
}
public static void main(String[] args) throws Exception {
Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestDFVariations.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestDFVariations.java?rev=1449994&r1=1449993&r2=1449994&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestDFVariations.java (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestDFVariations.java Tue Feb 26 01:43:44 2013
@@ -17,13 +17,21 @@
*/
package org.apache.hadoop.fs;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.StringReader;
import java.util.EnumSet;
+import java.util.Random;
-public class TestDFVariations extends TestCase {
+import org.apache.hadoop.test.GenericTestUtils;
+import org.junit.Test;
+
+public class TestDFVariations {
public static class XXDF extends DF {
private final String osName;
@@ -48,12 +56,81 @@ public class TestDFVariations extends Te
}
}
+ @Test(timeout=5000)
public void testOSParsing() throws Exception {
for (DF.OSType ost : EnumSet.allOf(DF.OSType.class)) {
XXDF df = new XXDF(ost.getId());
assertEquals(ost.getId() + " mount", "/foo/bar", df.getMount());
}
}
-
+
+ @Test(timeout=5000)
+ public void testDFInvalidPath() throws Exception {
+ // Generate a path that doesn't exist
+ Random random = new Random(0xDEADBEEFl);
+ File file = null;
+ byte[] bytes = new byte[64];
+ while (file == null) {
+ random.nextBytes(bytes);
+ final String invalid = new String("/" + bytes);
+ final File invalidFile = new File(invalid);
+ if (!invalidFile.exists()) {
+ file = invalidFile;
+ }
+ }
+ DF df = new DF(file, 0l);
+ try {
+ df.getMount();
+ } catch (FileNotFoundException e) {
+ // expected, since path does not exist
+ GenericTestUtils.assertExceptionContains(file.getName(), e);
+ }
+ }
+
+ @Test(timeout=5000)
+ public void testDFMalformedOutput() throws Exception {
+ DF df = new DF(new File("/"), 0l);
+ BufferedReader reader = new BufferedReader(new StringReader(
+ "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
+ "/dev/sda5 19222656 10597036 7649060 59% /"));
+ df.parseExecResult(reader);
+ df.parseOutput();
+
+ reader = new BufferedReader(new StringReader(
+ "Filesystem 1K-blocks Used Available Use% Mounted on"));
+ df.parseExecResult(reader);
+ try {
+ df.parseOutput();
+ fail("Expected exception with missing line!");
+ } catch (IOException e) {
+ GenericTestUtils.assertExceptionContains(
+ "Fewer lines of output than expected", e);
+ System.out.println(e.toString());
+ }
+
+ reader = new BufferedReader(new StringReader(
+ "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
+ " "));
+ df.parseExecResult(reader);
+ try {
+ df.parseOutput();
+ fail("Expected exception with empty line!");
+ } catch (IOException e) {
+ GenericTestUtils.assertExceptionContains("Unexpected empty line", e);
+ System.out.println(e.toString());
+ }
+
+ reader = new BufferedReader(new StringReader(
+ "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
+ " 19222656 10597036 7649060 59% /"));
+ df.parseExecResult(reader);
+ try {
+ df.parseOutput();
+ fail("Expected exception with missing field!");
+ } catch (IOException e) {
+ GenericTestUtils.assertExceptionContains("Could not parse line: ", e);
+ System.out.println(e.toString());
+ }
+ }
}