HADOOP-8944. Shell command fs -count should include human readable option (Jonathan Allen via aw)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1617775 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Allen Wittenauer 2014-08-13 17:30:26 +00:00
parent 5197f8c3c5
commit a34dafe325
6 changed files with 126 additions and 17 deletions

View File

@ -202,6 +202,9 @@ Trunk (Unreleased)
HADOOP-10224. JavaKeyStoreProvider has to protect against corrupting HADOOP-10224. JavaKeyStoreProvider has to protect against corrupting
underlying store. (asuresh via tucu) underlying store. (asuresh via tucu)
HADOOP-8944. Shell command fs -count should include human readable option
(Jonathan Allen via aw)
BUG FIXES BUG FIXES
HADOOP-9451. Fault single-layer config if node group topology is enabled. HADOOP-9451. Fault single-layer config if node group topology is enabled.

View File

@ -24,6 +24,7 @@
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.StringUtils;
/** Store the summary of a content (a directory or a file). */ /** Store the summary of a content (a directory or a file). */
@InterfaceAudience.Public @InterfaceAudience.Public
@ -102,7 +103,7 @@ public void readFields(DataInput in) throws IOException {
* <----12----> <----12----> <-------18-------> * <----12----> <----12----> <-------18------->
* DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME * DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME
*/ */
private static final String STRING_FORMAT = "%12d %12d %18d "; private static final String STRING_FORMAT = "%12s %12s %18s ";
/** /**
* Output format: * Output format:
* <----12----> <----15----> <----15----> <----15----> <----12----> <----12----> <-------18-------> * <----12----> <----15----> <----15----> <----15----> <----12----> <----12----> <-------18------->
@ -117,7 +118,7 @@ public void readFields(DataInput in) throws IOException {
private static final String QUOTA_HEADER = String.format( private static final String QUOTA_HEADER = String.format(
QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT,
"quota", "remaining quota", "space quota", "reamaining quota") + "name quota", "rem name quota", "space quota", "rem space quota") +
HEADER; HEADER;
/** Return the header of the output. /** Return the header of the output.
@ -139,11 +140,25 @@ public String toString() {
/** Return the string representation of the object in the output format. /** Return the string representation of the object in the output format.
* if qOption is false, output directory count, file count, and content size; * if qOption is false, output directory count, file count, and content size;
* if qOption is true, output quota and remaining quota as well. * if qOption is true, output quota and remaining quota as well.
* *
* @param qOption a flag indicating if quota needs to be printed or not * @param qOption a flag indicating if quota needs to be printed or not
* @return the string representation of the object * @return the string representation of the object
*/ */
public String toString(boolean qOption) { public String toString(boolean qOption) {
return toString(qOption, false);
}
/** Return the string representation of the object in the output format.
* if qOption is false, output directory count, file count, and content size;
* if qOption is true, output quota and remaining quota as well.
* if hOption is false file sizes are returned in bytes
* if hOption is true file sizes are returned in human readable
*
* @param qOption a flag indicating if quota needs to be printed or not
* @param hOption a flag indicating if human readable output if to be used
* @return the string representation of the object
*/
public String toString(boolean qOption, boolean hOption) {
String prefix = ""; String prefix = "";
if (qOption) { if (qOption) {
String quotaStr = "none"; String quotaStr = "none";
@ -152,19 +167,32 @@ public String toString(boolean qOption) {
String spaceQuotaRem = "inf"; String spaceQuotaRem = "inf";
if (quota>0) { if (quota>0) {
quotaStr = Long.toString(quota); quotaStr = formatSize(quota, hOption);
quotaRem = Long.toString(quota-(directoryCount+fileCount)); quotaRem = formatSize(quota-(directoryCount+fileCount), hOption);
} }
if (spaceQuota>0) { if (spaceQuota>0) {
spaceQuotaStr = Long.toString(spaceQuota); spaceQuotaStr = formatSize(spaceQuota, hOption);
spaceQuotaRem = Long.toString(spaceQuota - spaceConsumed); spaceQuotaRem = formatSize(spaceQuota - spaceConsumed, hOption);
} }
prefix = String.format(QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, prefix = String.format(QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT,
quotaStr, quotaRem, spaceQuotaStr, spaceQuotaRem); quotaStr, quotaRem, spaceQuotaStr, spaceQuotaRem);
} }
return prefix + String.format(STRING_FORMAT, directoryCount, return prefix + String.format(STRING_FORMAT,
fileCount, length); formatSize(directoryCount, hOption),
formatSize(fileCount, hOption),
formatSize(length, hOption));
}
/**
* Formats a size to be human readable or in bytes
* @param size value to be formatted
* @param humanReadable flag indicating human readable or not
* @return String representation of the size
*/
private String formatSize(long size, boolean humanReadable) {
return humanReadable
? StringUtils.TraditionalBinaryPrefix.long2String(size, "", 1)
: String.valueOf(size);
} }
} }

View File

@ -42,16 +42,22 @@ public static void registerCommands(CommandFactory factory) {
factory.addClass(Count.class, "-count"); factory.addClass(Count.class, "-count");
} }
private static final String OPTION_QUOTA = "q";
private static final String OPTION_HUMAN = "h";
public static final String NAME = "count"; public static final String NAME = "count";
public static final String USAGE = "[-q] <path> ..."; public static final String USAGE =
"[-" + OPTION_QUOTA + "] [-" + OPTION_HUMAN + "] <path> ...";
public static final String DESCRIPTION = public static final String DESCRIPTION =
"Count the number of directories, files and bytes under the paths\n" + "Count the number of directories, files and bytes under the paths\n" +
"that match the specified file pattern. The output columns are:\n" + "that match the specified file pattern. The output columns are:\n" +
"DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME or\n" + "DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME or\n" +
"QUOTA REMAINING_QUOTA SPACE_QUOTA REMAINING_SPACE_QUOTA \n" + "QUOTA REMAINING_QUOTA SPACE_QUOTA REMAINING_SPACE_QUOTA \n" +
" DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME"; " DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME\n" +
"The -h option shows file sizes in human readable format.";
private boolean showQuotas; private boolean showQuotas;
private boolean humanReadable;
/** Constructor */ /** Constructor */
public Count() {} public Count() {}
@ -70,17 +76,37 @@ public Count(String[] cmd, int pos, Configuration conf) {
@Override @Override
protected void processOptions(LinkedList<String> args) { protected void processOptions(LinkedList<String> args) {
CommandFormat cf = new CommandFormat(1, Integer.MAX_VALUE, "q"); CommandFormat cf = new CommandFormat(1, Integer.MAX_VALUE,
OPTION_QUOTA, OPTION_HUMAN);
cf.parse(args); cf.parse(args);
if (args.isEmpty()) { // default path is the current working directory if (args.isEmpty()) { // default path is the current working directory
args.add("."); args.add(".");
} }
showQuotas = cf.getOpt("q"); showQuotas = cf.getOpt(OPTION_QUOTA);
humanReadable = cf.getOpt(OPTION_HUMAN);
} }
@Override @Override
protected void processPath(PathData src) throws IOException { protected void processPath(PathData src) throws IOException {
ContentSummary summary = src.fs.getContentSummary(src.path); ContentSummary summary = src.fs.getContentSummary(src.path);
out.println(summary.toString(showQuotas) + src); out.println(summary.toString(showQuotas, isHumanReadable()) + src);
}
/**
* Should quotas get shown as part of the report?
* @return if quotas should be shown then true otherwise false
*/
@InterfaceAudience.Private
boolean isShowQuotas() {
return showQuotas;
}
/**
* Should sizes be shown in human readable format rather than bytes?
* @return true if human readable format
*/
@InterfaceAudience.Private
boolean isHumanReadable() {
return humanReadable;
} }
} }

View File

@ -138,7 +138,7 @@ copyToLocal
count count
Usage: <<<hdfs dfs -count [-q] <paths> >>> Usage: <<<hdfs dfs -count [-q] [-h] <paths> >>>
Count the number of directories, files and bytes under the paths that match Count the number of directories, files and bytes under the paths that match
the specified file pattern. The output columns with -count are: DIR_COUNT, the specified file pattern. The output columns with -count are: DIR_COUNT,
@ -147,12 +147,16 @@ count
The output columns with -count -q are: QUOTA, REMAINING_QUATA, SPACE_QUOTA, The output columns with -count -q are: QUOTA, REMAINING_QUATA, SPACE_QUOTA,
REMAINING_SPACE_QUOTA, DIR_COUNT, FILE_COUNT, CONTENT_SIZE, FILE_NAME REMAINING_SPACE_QUOTA, DIR_COUNT, FILE_COUNT, CONTENT_SIZE, FILE_NAME
The -h option shows sizes in human readable format.
Example: Example:
* <<<hdfs dfs -count hdfs://nn1.example.com/file1 hdfs://nn2.example.com/file2>>> * <<<hdfs dfs -count hdfs://nn1.example.com/file1 hdfs://nn2.example.com/file2>>>
* <<<hdfs dfs -count -q hdfs://nn1.example.com/file1>>> * <<<hdfs dfs -count -q hdfs://nn1.example.com/file1>>>
* <<<hdfs dfs -count -q -h hdfs://nn1.example.com/file1>>>
Exit Code: Exit Code:
Returns 0 on success and -1 on error. Returns 0 on success and -1 on error.

View File

@ -238,7 +238,7 @@
<comparators> <comparators>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^-count \[-q\] &lt;path&gt; \.\.\. :\s*</expected-output> <expected-output>^-count \[-q\] \[-h\] &lt;path&gt; \.\.\. :( )*</expected-output>
</comparator> </comparator>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
@ -260,6 +260,10 @@
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^( |\t)*DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME( )*</expected-output> <expected-output>^( |\t)*DIR_COUNT FILE_COUNT CONTENT_SIZE FILE_NAME( )*</expected-output>
</comparator> </comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^( |\t)*The -h option shows file sizes in human readable format.( )*</expected-output>
</comparator>
</comparators> </comparators>
</test> </test>

View File

@ -8655,6 +8655,50 @@
</comparators> </comparators>
</test> </test>
<test> <!-- TESTED -->
<description>count: file using -h option</description>
<test-commands>
<command>-fs NAMENODE -mkdir -p dir</command> <!-- make sure user home dir exists -->
<command>-fs NAMENODE -put CLITEST_DATA/data15bytes file1</command>
<command>-fs NAMENODE -put CLITEST_DATA/data1k file2</command>
<command>-fs NAMENODE -count -h file1 file2</command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm file1 file2</command>
</cleanup-commands>
<comparators>
<comparator>
<type>RegexpComparator</type>
<expected-output>( |\t)*0( |\t)*1( |\t)*15 file1</expected-output>
</comparator>
</comparators>
<comparators>
<comparator>
<type>RegexpComparator</type>
<expected-output>( |\t)*0( |\t)*1( |\t)*1\.0 K file2</expected-output>
</comparator>
</comparators>
</test>
<test> <!-- TESTED -->
<description>count: directory using -q and -h options</description>
<test-commands>
<command>-fs NAMENODE -mkdir /dir1</command>
<dfs-admin-command>-fs NAMENODE -setQuota 10 /dir1 </dfs-admin-command>
<dfs-admin-command>-fs NAMENODE -setSpaceQuota 1m /dir1 </dfs-admin-command>
<command>-fs NAMENODE -count -q -h /dir1</command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /dir1</command>
</cleanup-commands>
<comparators>
<comparator>
<type>RegexpComparator</type>
<expected-output>( |\t)*10( |\t)*9( |\t)*1 M( |\t)*1 M( |\t)*1( |\t)*0( |\t)*0 /dir1</expected-output>
</comparator>
</comparators>
</test>
<!-- Tests for chmod --> <!-- Tests for chmod -->
<test> <!-- TESTED --> <test> <!-- TESTED -->
<description>chmod: change permission(octal mode) of file in absolute path</description> <description>chmod: change permission(octal mode) of file in absolute path</description>