|
@@ -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 {
|