HDFS-8986. Add option to -du to calculate directory space usage excluding snapshots. Contributed by Xiao Chen.

This commit is contained in:
Wei-Chiu Chuang 2016-08-24 08:49:02 -07:00
parent 00c8ab91ba
commit bd729af8a8
12 changed files with 423 additions and 45 deletions

View File

@ -34,6 +34,11 @@ public class ContentSummary extends QuotaUsage implements Writable{
private long length; private long length;
private long fileCount; private long fileCount;
private long directoryCount; private long directoryCount;
// These fields are to track the snapshot-related portion of the values.
private long snapshotLength;
private long snapshotFileCount;
private long snapshotDirectoryCount;
private long snapshotSpaceConsumed;
/** We don't use generics. Instead override spaceConsumed and other methods /** We don't use generics. Instead override spaceConsumed and other methods
in order to keep backward compatibility. */ in order to keep backward compatibility. */
@ -56,6 +61,26 @@ public class ContentSummary extends QuotaUsage implements Writable{
return this; return this;
} }
public Builder snapshotLength(long snapshotLength) {
this.snapshotLength = snapshotLength;
return this;
}
public Builder snapshotFileCount(long snapshotFileCount) {
this.snapshotFileCount = snapshotFileCount;
return this;
}
public Builder snapshotDirectoryCount(long snapshotDirectoryCount) {
this.snapshotDirectoryCount = snapshotDirectoryCount;
return this;
}
public Builder snapshotSpaceConsumed(long snapshotSpaceConsumed) {
this.snapshotSpaceConsumed = snapshotSpaceConsumed;
return this;
}
@Override @Override
public Builder quota(long quota){ public Builder quota(long quota){
super.quota(quota); super.quota(quota);
@ -107,6 +132,10 @@ public class ContentSummary extends QuotaUsage implements Writable{
private long length; private long length;
private long fileCount; private long fileCount;
private long directoryCount; private long directoryCount;
private long snapshotLength;
private long snapshotFileCount;
private long snapshotDirectoryCount;
private long snapshotSpaceConsumed;
} }
/** Constructor deprecated by ContentSummary.Builder*/ /** Constructor deprecated by ContentSummary.Builder*/
@ -142,17 +171,37 @@ public class ContentSummary extends QuotaUsage implements Writable{
this.length = builder.length; this.length = builder.length;
this.fileCount = builder.fileCount; this.fileCount = builder.fileCount;
this.directoryCount = builder.directoryCount; this.directoryCount = builder.directoryCount;
this.snapshotLength = builder.snapshotLength;
this.snapshotFileCount = builder.snapshotFileCount;
this.snapshotDirectoryCount = builder.snapshotDirectoryCount;
this.snapshotSpaceConsumed = builder.snapshotSpaceConsumed;
} }
/** @return the length */ /** @return the length */
public long getLength() {return length;} public long getLength() {return length;}
public long getSnapshotLength() {
return snapshotLength;
}
/** @return the directory count */ /** @return the directory count */
public long getDirectoryCount() {return directoryCount;} public long getDirectoryCount() {return directoryCount;}
public long getSnapshotDirectoryCount() {
return snapshotDirectoryCount;
}
/** @return the file count */ /** @return the file count */
public long getFileCount() {return fileCount;} public long getFileCount() {return fileCount;}
public long getSnapshotFileCount() {
return snapshotFileCount;
}
public long getSnapshotSpaceConsumed() {
return snapshotSpaceConsumed;
}
@Override @Override
@InterfaceAudience.Private @InterfaceAudience.Private
public void write(DataOutput out) throws IOException { public void write(DataOutput out) throws IOException {
@ -180,9 +229,14 @@ public class ContentSummary extends QuotaUsage implements Writable{
if (this == to) { if (this == to) {
return true; return true;
} else if (to instanceof ContentSummary) { } else if (to instanceof ContentSummary) {
return getLength() == ((ContentSummary) to).getLength() && ContentSummary right = (ContentSummary) to;
getFileCount() == ((ContentSummary) to).getFileCount() && return getLength() == right.getLength() &&
getDirectoryCount() == ((ContentSummary) to).getDirectoryCount() && getFileCount() == right.getFileCount() &&
getDirectoryCount() == right.getDirectoryCount() &&
getSnapshotLength() == right.getSnapshotLength() &&
getSnapshotFileCount() == right.getSnapshotFileCount() &&
getSnapshotDirectoryCount() == right.getSnapshotDirectoryCount() &&
getSnapshotSpaceConsumed() == right.getSnapshotSpaceConsumed() &&
super.equals(to); super.equals(to);
} else { } else {
return super.equals(to); return super.equals(to);
@ -191,7 +245,9 @@ public class ContentSummary extends QuotaUsage implements Writable{
@Override @Override
public int hashCode() { public int hashCode() {
long result = getLength() ^ getFileCount() ^ getDirectoryCount(); long result = getLength() ^ getFileCount() ^ getDirectoryCount()
^ getSnapshotLength() ^ getSnapshotFileCount()
^ getSnapshotDirectoryCount() ^ getSnapshotSpaceConsumed();
return ((int) result) ^ super.hashCode(); return ((int) result) ^ super.hashCode();
} }
@ -255,15 +311,14 @@ public class ContentSummary extends QuotaUsage implements Writable{
* @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
*/ */
@Override
public String toString(boolean qOption) { public String toString(boolean qOption) {
return toString(qOption, false); return toString(qOption, false);
} }
/** 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; * For description of the options,
* if qOption is true, output quota and remaining quota as well. * @see #toString(boolean, boolean, boolean, boolean, List)
* 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 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 * @param hOption a flag indicating if human readable output if to be used
@ -273,10 +328,24 @@ public class ContentSummary extends QuotaUsage implements Writable{
return toString(qOption, hOption, false, null); return toString(qOption, hOption, false, null);
} }
/** Return the string representation of the object in the output format.
* For description of the options,
* @see #toString(boolean, boolean, boolean, boolean, List)
*
* @param qOption a flag indicating if quota needs to be printed or not
* @param hOption a flag indicating if human readable output is to be used
* @param xOption a flag indicating if calculation from snapshots is to be
* included in the output
* @return the string representation of the object
*/
public String toString(boolean qOption, boolean hOption, boolean xOption) {
return toString(qOption, hOption, false, xOption, null);
}
/** /**
* Return the string representation of the object in the output format. * Return the string representation of the object in the output format.
* if tOption is true, display the quota by storage types, * For description of the options,
* Otherwise, same logic with #toString(boolean,boolean) * @see #toString(boolean, boolean, boolean, boolean, List)
* *
* @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
* @param hOption a flag indicating if human readable output if to be used * @param hOption a flag indicating if human readable output if to be used
@ -286,6 +355,29 @@ public class ContentSummary extends QuotaUsage implements Writable{
*/ */
public String toString(boolean qOption, boolean hOption, public String toString(boolean qOption, boolean hOption,
boolean tOption, List<StorageType> types) { boolean tOption, List<StorageType> types) {
return toString(qOption, hOption, tOption, false, types);
}
/** 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
* if tOption is true, display the quota by storage types
* if tOption is false, same logic with #toString(boolean,boolean)
* if xOption is false, output includes the calculation from snapshots
* if xOption is true, output excludes the calculation from snapshots
*
* @param qOption a flag indicating if quota needs to be printed or not
* @param hOption a flag indicating if human readable output is to be used
* @param tOption a flag indicating if display quota by storage types
* @param xOption a flag indicating if calculation from snapshots is to be
* included in the output
* @param types Storage types to display
* @return the string representation of the object
*/
public String toString(boolean qOption, boolean hOption, boolean tOption,
boolean xOption, List<StorageType> types) {
String prefix = ""; String prefix = "";
if (tOption) { if (tOption) {
@ -296,11 +388,18 @@ public class ContentSummary extends QuotaUsage implements Writable{
prefix = getQuotaUsage(hOption); prefix = getQuotaUsage(hOption);
} }
if (xOption) {
return prefix + String.format(SUMMARY_FORMAT,
formatSize(directoryCount - snapshotDirectoryCount, hOption),
formatSize(fileCount - snapshotFileCount, hOption),
formatSize(length - snapshotLength, hOption));
} else {
return prefix + String.format(SUMMARY_FORMAT, return prefix + String.format(SUMMARY_FORMAT,
formatSize(directoryCount, hOption), formatSize(directoryCount, hOption),
formatSize(fileCount, hOption), formatSize(fileCount, hOption),
formatSize(length, hOption)); formatSize(length, hOption));
} }
}
/** /**
* Formats a size to be human readable or in bytes * Formats a size to be human readable or in bytes

View File

@ -51,6 +51,8 @@ public class Count extends FsCommand {
private static final String OPTION_HUMAN = "h"; private static final String OPTION_HUMAN = "h";
private static final String OPTION_HEADER = "v"; private static final String OPTION_HEADER = "v";
private static final String OPTION_TYPE = "t"; private static final String OPTION_TYPE = "t";
// exclude snapshots from calculation. Only work on default columns.
private static final String OPTION_EXCLUDE_SNAPSHOT = "x";
//return the quota, namespace count and disk space usage. //return the quota, namespace count and disk space usage.
private static final String OPTION_QUOTA_AND_USAGE = "u"; private static final String OPTION_QUOTA_AND_USAGE = "u";
@ -58,7 +60,8 @@ public class Count extends FsCommand {
public static final String USAGE = public static final String USAGE =
"[-" + OPTION_QUOTA + "] [-" + OPTION_HUMAN + "] [-" + OPTION_HEADER "[-" + OPTION_QUOTA + "] [-" + OPTION_HUMAN + "] [-" + OPTION_HEADER
+ "] [-" + OPTION_TYPE + " [<storage type>]] [-" + + "] [-" + OPTION_TYPE + " [<storage type>]] [-" +
OPTION_QUOTA_AND_USAGE + "] <path> ..."; OPTION_QUOTA_AND_USAGE + "] [-" + OPTION_EXCLUDE_SNAPSHOT
+ "] <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" +
@ -72,6 +75,8 @@ public class Count extends FsCommand {
"The -" + OPTION_HUMAN + "The -" + OPTION_HUMAN +
" option shows file sizes in human readable format.\n" + " option shows file sizes in human readable format.\n" +
"The -" + OPTION_HEADER + " option displays a header line.\n" + "The -" + OPTION_HEADER + " option displays a header line.\n" +
"The -" + OPTION_EXCLUDE_SNAPSHOT + " option excludes snapshots " +
"from being calculated. \n" +
"The -" + OPTION_TYPE + " option displays quota by storage types.\n" + "The -" + OPTION_TYPE + " option displays quota by storage types.\n" +
"It must be used with -" + OPTION_QUOTA + " option.\n" + "It must be used with -" + OPTION_QUOTA + " option.\n" +
"If a comma-separated list of storage types is given after the -" + "If a comma-separated list of storage types is given after the -" +
@ -87,6 +92,7 @@ public class Count extends FsCommand {
private boolean showQuotabyType; private boolean showQuotabyType;
private List<StorageType> storageTypes = null; private List<StorageType> storageTypes = null;
private boolean showQuotasAndUsageOnly; private boolean showQuotasAndUsageOnly;
private boolean excludeSnapshots;
/** Constructor */ /** Constructor */
public Count() {} public Count() {}
@ -106,7 +112,8 @@ public class Count extends FsCommand {
@Override @Override
protected void processOptions(LinkedList<String> args) { protected void processOptions(LinkedList<String> args) {
CommandFormat cf = new CommandFormat(1, Integer.MAX_VALUE, CommandFormat cf = new CommandFormat(1, Integer.MAX_VALUE,
OPTION_QUOTA, OPTION_HUMAN, OPTION_HEADER, OPTION_QUOTA_AND_USAGE); OPTION_QUOTA, OPTION_HUMAN, OPTION_HEADER, OPTION_QUOTA_AND_USAGE,
OPTION_EXCLUDE_SNAPSHOT);
cf.addOptionWithValue(OPTION_TYPE); cf.addOptionWithValue(OPTION_TYPE);
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
@ -115,6 +122,7 @@ public class Count extends FsCommand {
showQuotas = cf.getOpt(OPTION_QUOTA); showQuotas = cf.getOpt(OPTION_QUOTA);
humanReadable = cf.getOpt(OPTION_HUMAN); humanReadable = cf.getOpt(OPTION_HUMAN);
showQuotasAndUsageOnly = cf.getOpt(OPTION_QUOTA_AND_USAGE); showQuotasAndUsageOnly = cf.getOpt(OPTION_QUOTA_AND_USAGE);
excludeSnapshots = cf.getOpt(OPTION_EXCLUDE_SNAPSHOT);
if (showQuotas || showQuotasAndUsageOnly) { if (showQuotas || showQuotasAndUsageOnly) {
String types = cf.getOptValue(OPTION_TYPE); String types = cf.getOptValue(OPTION_TYPE);
@ -125,6 +133,11 @@ public class Count extends FsCommand {
} else { } else {
showQuotabyType = false; showQuotabyType = false;
} }
if (excludeSnapshots) {
out.println(OPTION_QUOTA + " or " + OPTION_QUOTA_AND_USAGE + " option "
+ "is given, the -x option is ignored.");
excludeSnapshots = false;
}
} }
if (cf.getOpt(OPTION_HEADER)) { if (cf.getOpt(OPTION_HEADER)) {
@ -163,7 +176,8 @@ public class Count extends FsCommand {
storageTypes) + src); storageTypes) + src);
} else { } else {
ContentSummary summary = src.fs.getContentSummary(src.path); ContentSummary summary = src.fs.getContentSummary(src.path);
out.println(summary.toString(showQuotas, isHumanReadable()) + src); out.println(summary.
toString(showQuotas, isHumanReadable(), excludeSnapshots) + src);
} }
} }

View File

@ -26,6 +26,7 @@ import java.util.List;
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.fs.ContentSummary;
import org.apache.hadoop.fs.FsStatus; import org.apache.hadoop.fs.FsStatus;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.util.StringUtils;
@ -106,27 +107,30 @@ class FsUsage extends FsCommand {
/** show disk usage */ /** show disk usage */
public static class Du extends FsUsage { public static class Du extends FsUsage {
public static final String NAME = "du"; public static final String NAME = "du";
public static final String USAGE = "[-s] [-h] <path> ..."; public static final String USAGE = "[-s] [-h] [-x] <path> ...";
public static final String DESCRIPTION = public static final String DESCRIPTION =
"Show the amount of space, in bytes, used by the files that " + "Show the amount of space, in bytes, used by the files that match " +
"match the specified file pattern. The following flags are optional:\n" + "the specified file pattern. The following flags are optional:\n" +
"-s: Rather than showing the size of each individual file that" + "-s: Rather than showing the size of each individual file that" +
" matches the pattern, shows the total (summary) size.\n" + " matches the pattern, shows the total (summary) size.\n" +
"-h: Formats the sizes of files in a human-readable fashion" + "-h: Formats the sizes of files in a human-readable fashion" +
" rather than a number of bytes.\n\n" + " rather than a number of bytes.\n" +
"Note that, even without the -s option, this only shows size summaries " + "-x: Excludes snapshots from being counted.\n\n" +
"one level deep into a directory.\n\n" + "Note that, even without the -s option, this only shows size " +
"summaries one level deep into a directory.\n\n" +
"The output is in the form \n" + "The output is in the form \n" +
"\tsize\tname(full path)\n"; "\tsize\tname(full path)\n";
protected boolean summary = false; protected boolean summary = false;
private boolean excludeSnapshots = false;
@Override @Override
protected void processOptions(LinkedList<String> args) throws IOException { protected void processOptions(LinkedList<String> args) throws IOException {
CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "h", "s"); CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "h", "s", "x");
cf.parse(args); cf.parse(args);
humanReadable = cf.getOpt("h"); humanReadable = cf.getOpt("h");
summary = cf.getOpt("s"); summary = cf.getOpt("s");
excludeSnapshots = cf.getOpt("x");
if (args.isEmpty()) args.add(Path.CUR_DIR); if (args.isEmpty()) args.add(Path.CUR_DIR);
} }
@ -144,11 +148,10 @@ class FsUsage extends FsCommand {
@Override @Override
protected void processPath(PathData item) throws IOException { protected void processPath(PathData item) throws IOException {
long length; ContentSummary contentSummary = item.fs.getContentSummary(item.path);
if (item.stat.isDirectory()) { long length = contentSummary.getLength();
length = item.fs.getContentSummary(item.path).getLength(); if (excludeSnapshots) {
} else { length -= contentSummary.getSnapshotLength();
length = item.stat.getLen();
} }
usagesTable.addRow(formatSize(length), item); usagesTable.addRow(formatSize(length), item);
} }

View File

@ -132,10 +132,12 @@ Similar to get command, except that the destination is restricted to a local fil
count count
----- -----
Usage: `hadoop fs -count [-q] [-h] [-v] [-t [<storage type>]] [-u] <paths> ` Usage: `hadoop fs -count [-q] [-h] [-v] [-x] [-t [<storage type>]] [-u] <paths> `
Count the number of directories, files and bytes under the paths that match the specified file pattern. Get the quota and the usage. The output columns with -count are: DIR\_COUNT, FILE\_COUNT, CONTENT\_SIZE, PATHNAME Count the number of directories, files and bytes under the paths that match the specified file pattern. Get the quota and the usage. The output columns with -count are: DIR\_COUNT, FILE\_COUNT, CONTENT\_SIZE, PATHNAME
The -u and -q options control what columns the output contains. -q means show quotas, -u limits the output to show quotas and usage only.
The output columns with -count -q are: QUOTA, REMAINING\_QUOTA, SPACE\_QUOTA, REMAINING\_SPACE\_QUOTA, DIR\_COUNT, FILE\_COUNT, CONTENT\_SIZE, PATHNAME The output columns with -count -q are: QUOTA, REMAINING\_QUOTA, SPACE\_QUOTA, REMAINING\_SPACE\_QUOTA, DIR\_COUNT, FILE\_COUNT, CONTENT\_SIZE, PATHNAME
The output columns with -count -u are: QUOTA, REMAINING\_QUOTA, SPACE\_QUOTA, REMAINING\_SPACE\_QUOTA The output columns with -count -u are: QUOTA, REMAINING\_QUOTA, SPACE\_QUOTA, REMAINING\_SPACE\_QUOTA
@ -146,6 +148,8 @@ The -h option shows sizes in human readable format.
The -v option displays a header line. The -v option displays a header line.
The -x option excludes snapshots from the result calculation. Without the -x option (default), the result is always calculated from all INodes, including all snapshots under the given path. The -x option is ignored if -u or -q option is given.
Example: Example:
* `hadoop fs -count hdfs://nn1.example.com/file1 hdfs://nn2.example.com/file2` * `hadoop fs -count hdfs://nn1.example.com/file1 hdfs://nn2.example.com/file2`
@ -211,14 +215,15 @@ Example:
du du
---- ----
Usage: `hadoop fs -du [-s] [-h] URI [URI ...]` Usage: `hadoop fs -du [-s] [-h] [-x] URI [URI ...]`
Displays sizes of files and directories contained in the given directory or the length of a file in case its just a file. Displays sizes of files and directories contained in the given directory or the length of a file in case its just a file.
Options: Options:
* The -s option will result in an aggregate summary of file lengths being displayed, rather than the individual files. * The -s option will result in an aggregate summary of file lengths being displayed, rather than the individual files. Without the -s option, calculation is done by going 1-level deep from the given path.
* The -h option will format file sizes in a "human-readable" fashion (e.g 64.0m instead of 67108864) * The -h option will format file sizes in a "human-readable" fashion (e.g 64.0m instead of 67108864)
* The -x option will exclude snapshots from the result calculation. Without the -x option (default), the result is always calculated from all INodes, including all snapshots under the given path.
The du returns three columns with the following format: The du returns three columns with the following format:

View File

@ -447,7 +447,7 @@ public class TestCount {
Count count = new Count(); Count count = new Count();
String actual = count.getUsage(); String actual = count.getUsage();
String expected = String expected =
"-count [-q] [-h] [-v] [-t [<storage type>]] [-u] <path> ..."; "-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] <path> ...";
assertEquals("Count.getUsage", expected, actual); assertEquals("Count.getUsage", expected, actual);
} }
@ -465,6 +465,7 @@ public class TestCount {
+ " DIR_COUNT FILE_COUNT CONTENT_SIZE PATHNAME\n" + " DIR_COUNT FILE_COUNT CONTENT_SIZE PATHNAME\n"
+ "The -h option shows file sizes in human readable format.\n" + "The -h option shows file sizes in human readable format.\n"
+ "The -v option displays a header line.\n" + "The -v option displays a header line.\n"
+ "The -x option excludes snapshots from being calculated. \n"
+ "The -t option displays quota by storage types.\n" + "The -t option displays quota by storage types.\n"
+ "It must be used with -q option.\n" + "It must be used with -q option.\n"
+ "If a comma-separated list of storage types is given after the -t option, \n" + "If a comma-separated list of storage types is given after the -t option, \n"
@ -520,7 +521,7 @@ public class TestCount {
} }
@Override @Override
public String toString(boolean qOption, boolean hOption) { public String toString(boolean qOption, boolean hOption, boolean xOption) {
if (qOption) { if (qOption) {
if (hOption) { if (hOption) {
return (HUMAN + WITH_QUOTAS); return (HUMAN + WITH_QUOTAS);

View File

@ -200,7 +200,7 @@
<comparators> <comparators>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^-du \[-s\] \[-h\] &lt;path&gt; \.\.\. :\s*</expected-output> <expected-output>^-du \[-s\] \[-h\] \[-x\] &lt;path&gt; \.\.\. :\s*</expected-output>
</comparator> </comparator>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
@ -226,6 +226,10 @@
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>\s*of bytes.\s*</expected-output> <expected-output>\s*of bytes.\s*</expected-output>
</comparator> </comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^\s*-x\s*Excludes snapshots from being counted.\s*</expected-output>
</comparator>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^\s*Note that, even without the -s option, this only shows size summaries one level\s*</expected-output> <expected-output>^\s*Note that, even without the -s option, this only shows size summaries one level\s*</expected-output>
@ -274,7 +278,7 @@
<comparators> <comparators>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^-count \[-q\] \[-h\] \[-v\] \[-t \[&lt;storage type&gt;\]\] \[-u\] &lt;path&gt; \.\.\. :( )*</expected-output> <expected-output>^-count \[-q\] \[-h\] \[-v\] \[-t \[&lt;storage type&gt;\]\] \[-u\] \[-x\] &lt;path&gt; \.\.\. :( )*</expected-output>
</comparator> </comparator>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
@ -308,6 +312,10 @@
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^( |\t)*The -v option displays a header line.( )*</expected-output> <expected-output>^( |\t)*The -v option displays a header line.( )*</expected-output>
</comparator> </comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^( |\t)*The -x option excludes snapshots from being calculated.( )*</expected-output>
</comparator>
</comparators> </comparators>
</test> </test>

View File

@ -1364,6 +1364,10 @@ public class PBHelperClient {
builder.length(cs.getLength()). builder.length(cs.getLength()).
fileCount(cs.getFileCount()). fileCount(cs.getFileCount()).
directoryCount(cs.getDirectoryCount()). directoryCount(cs.getDirectoryCount()).
snapshotLength(cs.getSnapshotLength()).
snapshotFileCount(cs.getSnapshotFileCount()).
snapshotDirectoryCount(cs.getSnapshotDirectoryCount()).
snapshotSpaceConsumed(cs.getSnapshotSpaceConsumed()).
quota(cs.getQuota()). quota(cs.getQuota()).
spaceConsumed(cs.getSpaceConsumed()). spaceConsumed(cs.getSpaceConsumed()).
spaceQuota(cs.getSpaceQuota()); spaceQuota(cs.getSpaceQuota());
@ -1958,6 +1962,10 @@ public class PBHelperClient {
builder.setLength(cs.getLength()). builder.setLength(cs.getLength()).
setFileCount(cs.getFileCount()). setFileCount(cs.getFileCount()).
setDirectoryCount(cs.getDirectoryCount()). setDirectoryCount(cs.getDirectoryCount()).
setSnapshotLength(cs.getSnapshotLength()).
setSnapshotFileCount(cs.getSnapshotFileCount()).
setSnapshotDirectoryCount(cs.getSnapshotDirectoryCount()).
setSnapshotSpaceConsumed(cs.getSnapshotSpaceConsumed()).
setQuota(cs.getQuota()). setQuota(cs.getQuota()).
setSpaceConsumed(cs.getSpaceConsumed()). setSpaceConsumed(cs.getSpaceConsumed()).
setSpaceQuota(cs.getSpaceQuota()); setSpaceQuota(cs.getSpaceQuota());

View File

@ -136,6 +136,10 @@ message ContentSummaryProto {
required uint64 spaceConsumed = 5; required uint64 spaceConsumed = 5;
required uint64 spaceQuota = 6; required uint64 spaceQuota = 6;
optional StorageTypeQuotaInfosProto typeQuotaInfos = 7; optional StorageTypeQuotaInfosProto typeQuotaInfos = 7;
optional uint64 snapshotLength = 8;
optional uint64 snapshotFileCount = 9;
optional uint64 snapshotDirectoryCount = 10;
optional uint64 snapshotSpaceConsumed = 11;
} }
/** /**

View File

@ -29,6 +29,7 @@ public class ContentSummaryComputationContext {
private FSNamesystem fsn = null; private FSNamesystem fsn = null;
private BlockStoragePolicySuite bsps = null; private BlockStoragePolicySuite bsps = null;
private ContentCounts counts = null; private ContentCounts counts = null;
private ContentCounts snapshotCounts = null;
private long nextCountLimit = 0; private long nextCountLimit = 0;
private long limitPerRun = 0; private long limitPerRun = 0;
private long yieldCount = 0; private long yieldCount = 0;
@ -51,6 +52,7 @@ public class ContentSummaryComputationContext {
this.limitPerRun = limitPerRun; this.limitPerRun = limitPerRun;
this.nextCountLimit = limitPerRun; this.nextCountLimit = limitPerRun;
this.counts = new ContentCounts.Builder().build(); this.counts = new ContentCounts.Builder().build();
this.snapshotCounts = new ContentCounts.Builder().build();
this.sleepMilliSec = sleepMicroSec/1000; this.sleepMilliSec = sleepMicroSec/1000;
this.sleepNanoSec = (int)((sleepMicroSec%1000)*1000); this.sleepNanoSec = (int)((sleepMicroSec%1000)*1000);
} }
@ -125,6 +127,10 @@ public class ContentSummaryComputationContext {
return counts; return counts;
} }
public ContentCounts getSnapshotCounts() {
return snapshotCounts;
}
public BlockStoragePolicySuite getBlockStoragePolicySuite() { public BlockStoragePolicySuite getBlockStoragePolicySuite() {
Preconditions.checkState((bsps != null || fsn != null), Preconditions.checkState((bsps != null || fsn != null),
"BlockStoragePolicySuite must be either initialized or available via" + "BlockStoragePolicySuite must be either initialized or available via" +

View File

@ -428,8 +428,9 @@ public abstract class INode implements INodeAttributes, Diff.Element<byte[]> {
*/ */
public final ContentSummary computeAndConvertContentSummary(int snapshotId, public final ContentSummary computeAndConvertContentSummary(int snapshotId,
ContentSummaryComputationContext summary) { ContentSummaryComputationContext summary) {
ContentCounts counts = computeContentSummary(snapshotId, summary) computeContentSummary(snapshotId, summary);
.getCounts(); final ContentCounts counts = summary.getCounts();
final ContentCounts snapshotCounts = summary.getSnapshotCounts();
final QuotaCounts q = getQuotaCounts(); final QuotaCounts q = getQuotaCounts();
return new ContentSummary.Builder(). return new ContentSummary.Builder().
length(counts.getLength()). length(counts.getLength()).
@ -440,6 +441,10 @@ public abstract class INode implements INodeAttributes, Diff.Element<byte[]> {
spaceQuota(q.getStorageSpace()). spaceQuota(q.getStorageSpace()).
typeConsumed(counts.getTypeSpaces()). typeConsumed(counts.getTypeSpaces()).
typeQuota(q.getTypeSpaces().asArray()). typeQuota(q.getTypeSpaces().asArray()).
snapshotLength(snapshotCounts.getLength()).
snapshotFileCount(snapshotCounts.getFileCount()).
snapshotDirectoryCount(snapshotCounts.getDirectoryCount()).
snapshotSpaceConsumed(snapshotCounts.getStoragespace()).
build(); build();
} }

View File

@ -634,6 +634,10 @@ public class INodeDirectory extends INodeWithAdditionalFields
// computation should include all the deleted files/directories // computation should include all the deleted files/directories
sf.computeContentSummary4Snapshot(summary.getBlockStoragePolicySuite(), sf.computeContentSummary4Snapshot(summary.getBlockStoragePolicySuite(),
summary.getCounts()); summary.getCounts());
// Also compute ContentSummary for snapshotCounts (So we can extract it
// later from the ContentSummary of all).
sf.computeContentSummary4Snapshot(summary.getBlockStoragePolicySuite(),
summary.getSnapshotCounts());
} }
final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature(); final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature();
if (q != null && snapshotId == Snapshot.CURRENT_STATE_ID) { if (q != null && snapshotId == Snapshot.CURRENT_STATE_ID) {

View File

@ -105,6 +105,11 @@ public class TestDFSShell {
return p; return p;
} }
static void rmr(FileSystem fs, Path p) throws IOException {
assertTrue(fs.delete(p, true));
assertFalse(fs.exists(p));
}
static File createLocalFile(File f) throws IOException { static File createLocalFile(File f) throws IOException {
assertTrue(!f.exists()); assertTrue(!f.exists());
PrintWriter out = new PrintWriter(f); PrintWriter out = new PrintWriter(f);
@ -214,6 +219,7 @@ public class TestDFSShell {
shell.setConf(conf); shell.setConf(conf);
try { try {
cluster.waitActive();
Path myPath = new Path("/test/dir"); Path myPath = new Path("/test/dir");
assertTrue(fs.mkdirs(myPath)); assertTrue(fs.mkdirs(myPath));
assertTrue(fs.exists(myPath)); assertTrue(fs.exists(myPath));
@ -239,7 +245,7 @@ public class TestDFSShell {
assertTrue(val == 0); assertTrue(val == 0);
String returnString = out.toString(); String returnString = out.toString();
out.reset(); out.reset();
// Check if size matchs as expected // Check if size matches as expected
assertThat(returnString, containsString(myFileLength.toString())); assertThat(returnString, containsString(myFileLength.toString()));
assertThat(returnString, containsString(myFile2Length.toString())); assertThat(returnString, containsString(myFile2Length.toString()));
@ -274,6 +280,221 @@ public class TestDFSShell {
} }
@Test (timeout = 180000)
public void testDuSnapshots() throws IOException {
final int replication = 2;
final Configuration conf = new HdfsConfiguration();
final MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf)
.numDataNodes(replication).build();
final DistributedFileSystem dfs = cluster.getFileSystem();
final PrintStream psBackup = System.out;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream psOut = new PrintStream(out);
final FsShell shell = new FsShell();
shell.setConf(conf);
try {
System.setOut(psOut);
cluster.waitActive();
final Path parent = new Path("/test");
final Path dir = new Path(parent, "dir");
mkdir(dfs, dir);
final Path file = new Path(dir, "file");
writeFile(dfs, file);
final Path file2 = new Path(dir, "file2");
writeFile(dfs, file2);
final Long fileLength = dfs.getFileStatus(file).getLen();
final Long file2Length = dfs.getFileStatus(file2).getLen();
/*
* Construct dir as follows:
* /test/dir/file <- this will later be deleted after snapshot taken.
* /test/dir/newfile <- this will be created after snapshot taken.
* /test/dir/file2
* Snapshot enabled on /test
*/
// test -du on /test/dir
int ret = -1;
try {
ret = shell.run(new String[] {"-du", dir.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, ret);
String returnString = out.toString();
LOG.info("-du return is:\n" + returnString);
// Check if size matches as expected
assertTrue(returnString.contains(fileLength.toString()));
assertTrue(returnString.contains(file2Length.toString()));
out.reset();
// take a snapshot, then remove file and add newFile
final String snapshotName = "ss1";
final Path snapshotPath = new Path(parent, ".snapshot/" + snapshotName);
dfs.allowSnapshot(parent);
assertThat(dfs.createSnapshot(parent, snapshotName), is(snapshotPath));
rmr(dfs, file);
final Path newFile = new Path(dir, "newfile");
writeFile(dfs, newFile);
final Long newFileLength = dfs.getFileStatus(newFile).getLen();
// test -du -s on /test
ret = -1;
try {
ret = shell.run(new String[] {"-du", "-s", parent.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, ret);
returnString = out.toString();
LOG.info("-du -s return is:\n" + returnString);
Long combinedLength = fileLength + file2Length + newFileLength;
assertTrue(returnString.contains(combinedLength.toString()));
out.reset();
// test -du on /test
ret = -1;
try {
ret = shell.run(new String[] {"-du", parent.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, ret);
returnString = out.toString();
LOG.info("-du return is:\n" + returnString);
assertTrue(returnString.contains(combinedLength.toString()));
out.reset();
// test -du -s -x on /test
ret = -1;
try {
ret = shell.run(new String[] {"-du", "-s", "-x", parent.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, ret);
returnString = out.toString();
LOG.info("-du -s -x return is:\n" + returnString);
Long exludeSnapshotLength = file2Length + newFileLength;
assertTrue(returnString.contains(exludeSnapshotLength.toString()));
out.reset();
// test -du -x on /test
ret = -1;
try {
ret = shell.run(new String[] {"-du", "-x", parent.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, ret);
returnString = out.toString();
LOG.info("-du -x return is:\n" + returnString);
assertTrue(returnString.contains(exludeSnapshotLength.toString()));
out.reset();
} finally {
System.setOut(psBackup);
cluster.shutdown();
}
}
@Test (timeout = 180000)
public void testCountSnapshots() throws IOException {
final int replication = 2;
final Configuration conf = new HdfsConfiguration();
final MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf)
.numDataNodes(replication).build();
final DistributedFileSystem dfs = cluster.getFileSystem();
final PrintStream psBackup = System.out;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream psOut = new PrintStream(out);
System.setOut(psOut);
final FsShell shell = new FsShell();
shell.setConf(conf);
try {
cluster.waitActive();
final Path parent = new Path("/test");
final Path dir = new Path(parent, "dir");
mkdir(dfs, dir);
final Path file = new Path(dir, "file");
writeFile(dfs, file);
final Path file2 = new Path(dir, "file2");
writeFile(dfs, file2);
final long fileLength = dfs.getFileStatus(file).getLen();
final long file2Length = dfs.getFileStatus(file2).getLen();
final Path dir2 = new Path(parent, "dir2");
mkdir(dfs, dir2);
/*
* Construct dir as follows:
* /test/dir/file <- this will later be deleted after snapshot taken.
* /test/dir/newfile <- this will be created after snapshot taken.
* /test/dir/file2
* /test/dir2 <- this will later be deleted after snapshot taken.
* Snapshot enabled on /test
*/
// take a snapshot
// then create /test/dir/newfile and remove /test/dir/file, /test/dir2
final String snapshotName = "s1";
final Path snapshotPath = new Path(parent, ".snapshot/" + snapshotName);
dfs.allowSnapshot(parent);
assertThat(dfs.createSnapshot(parent, snapshotName), is(snapshotPath));
rmr(dfs, file);
rmr(dfs, dir2);
final Path newFile = new Path(dir, "new file");
writeFile(dfs, newFile);
final Long newFileLength = dfs.getFileStatus(newFile).getLen();
// test -count on /test. Include header for easier debugging.
int val = -1;
try {
val = shell.run(new String[] {"-count", "-v", parent.toString() });
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, val);
String returnString = out.toString();
LOG.info("-count return is:\n" + returnString);
Scanner in = new Scanner(returnString);
in.nextLine();
assertEquals(3, in.nextLong()); //DIR_COUNT
assertEquals(3, in.nextLong()); //FILE_COUNT
assertEquals(fileLength + file2Length + newFileLength,
in.nextLong()); //CONTENT_SIZE
out.reset();
// test -count -x on /test. Include header for easier debugging.
val = -1;
try {
val =
shell.run(new String[] {"-count", "-x", "-v", parent.toString()});
} catch (Exception e) {
System.err.println("Exception raised from DFSShell.run " +
e.getLocalizedMessage());
}
assertEquals(0, val);
returnString = out.toString();
LOG.info("-count -x return is:\n" + returnString);
in = new Scanner(returnString);
in.nextLine();
assertEquals(2, in.nextLong()); //DIR_COUNT
assertEquals(2, in.nextLong()); //FILE_COUNT
assertEquals(file2Length + newFileLength, in.nextLong()); //CONTENT_SIZE
out.reset();
} finally {
System.setOut(psBackup);
cluster.shutdown();
}
}
@Test (timeout = 30000) @Test (timeout = 30000)
public void testPut() throws IOException { public void testPut() throws IOException {
Configuration conf = new HdfsConfiguration(); Configuration conf = new HdfsConfiguration();