001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.fs;
019
020import java.io.DataInput;
021import java.io.DataOutput;
022import java.io.IOException;
023import java.util.List;
024
025import org.apache.hadoop.classification.InterfaceAudience;
026import org.apache.hadoop.classification.InterfaceStability;
027import org.apache.hadoop.io.Writable;
028import org.apache.hadoop.util.StringUtils;
029
030/** Store the summary of a content (a directory or a file). */
031@InterfaceAudience.Public
032@InterfaceStability.Evolving
033public class ContentSummary extends QuotaUsage implements Writable{
034  private long length;
035  private long fileCount;
036  private long directoryCount;
037
038  /** We don't use generics. Instead override spaceConsumed and other methods
039      in order to keep backward compatibility. */
040  public static class Builder extends QuotaUsage.Builder {
041    public Builder() {
042    }
043
044    public Builder length(long length) {
045      this.length = length;
046      return this;
047    }
048
049    public Builder fileCount(long fileCount) {
050      this.fileCount = fileCount;
051      return this;
052    }
053
054    public Builder directoryCount(long directoryCount) {
055      this.directoryCount = directoryCount;
056      return this;
057    }
058
059    @Override
060    public Builder quota(long quota){
061      super.quota(quota);
062      return this;
063    }
064
065    @Override
066    public Builder spaceConsumed(long spaceConsumed) {
067      super.spaceConsumed(spaceConsumed);
068      return this;
069    }
070
071    @Override
072    public Builder spaceQuota(long spaceQuota) {
073      super.spaceQuota(spaceQuota);
074      return this;
075    }
076
077    @Override
078    public Builder typeConsumed(long typeConsumed[]) {
079      super.typeConsumed(typeConsumed);
080      return this;
081    }
082
083    @Override
084    public Builder typeQuota(StorageType type, long quota) {
085      super.typeQuota(type, quota);
086      return this;
087    }
088
089    @Override
090    public Builder typeConsumed(StorageType type, long consumed) {
091      super.typeConsumed(type, consumed);
092      return this;
093    }
094
095    @Override
096    public Builder typeQuota(long typeQuota[]) {
097      super.typeQuota(typeQuota);
098      return this;
099    }
100
101    public ContentSummary build() {
102      // Set it in case applications call QuotaUsage#getFileAndDirectoryCount.
103      super.fileAndDirectoryCount(this.fileCount + this.directoryCount);
104      return new ContentSummary(this);
105    }
106
107    private long length;
108    private long fileCount;
109    private long directoryCount;
110  }
111
112  /** Constructor deprecated by ContentSummary.Builder*/
113  @Deprecated
114  public ContentSummary() {}
115  
116  /** Constructor, deprecated by ContentSummary.Builder
117   *  This constructor implicitly set spaceConsumed the same as length.
118   *  spaceConsumed and length must be set explicitly with
119   *  ContentSummary.Builder
120   * */
121  @Deprecated
122  public ContentSummary(long length, long fileCount, long directoryCount) {
123    this(length, fileCount, directoryCount, -1L, length, -1L);
124  }
125
126  /** Constructor, deprecated by ContentSummary.Builder */
127  @Deprecated
128  public ContentSummary(
129      long length, long fileCount, long directoryCount, long quota,
130      long spaceConsumed, long spaceQuota) {
131    this.length = length;
132    this.fileCount = fileCount;
133    this.directoryCount = directoryCount;
134    setQuota(quota);
135    setSpaceConsumed(spaceConsumed);
136    setSpaceQuota(spaceQuota);
137  }
138
139  /** Constructor for ContentSummary.Builder*/
140  private ContentSummary(Builder builder) {
141    super(builder);
142    this.length = builder.length;
143    this.fileCount = builder.fileCount;
144    this.directoryCount = builder.directoryCount;
145  }
146
147  /** @return the length */
148  public long getLength() {return length;}
149
150  /** @return the directory count */
151  public long getDirectoryCount() {return directoryCount;}
152
153  /** @return the file count */
154  public long getFileCount() {return fileCount;}
155
156  @Override
157  @InterfaceAudience.Private
158  public void write(DataOutput out) throws IOException {
159    out.writeLong(length);
160    out.writeLong(fileCount);
161    out.writeLong(directoryCount);
162    out.writeLong(getQuota());
163    out.writeLong(getSpaceConsumed());
164    out.writeLong(getSpaceQuota());
165  }
166
167  @Override
168  @InterfaceAudience.Private
169  public void readFields(DataInput in) throws IOException {
170    this.length = in.readLong();
171    this.fileCount = in.readLong();
172    this.directoryCount = in.readLong();
173    setQuota(in.readLong());
174    setSpaceConsumed(in.readLong());
175    setSpaceQuota(in.readLong());
176  }
177
178  @Override
179  public boolean equals(Object to) {
180    if (this == to) {
181      return true;
182    } else if (to instanceof ContentSummary) {
183      return getLength() == ((ContentSummary) to).getLength() &&
184          getFileCount() == ((ContentSummary) to).getFileCount() &&
185          getDirectoryCount() == ((ContentSummary) to).getDirectoryCount() &&
186          super.equals(to);
187    } else {
188      return super.equals(to);
189    }
190  }
191
192  @Override
193  public int hashCode() {
194    long result = getLength() ^ getFileCount() ^ getDirectoryCount();
195    return ((int) result) ^ super.hashCode();
196  }
197
198  /**
199   * Output format:
200   * <----12----> <----12----> <-------18------->
201   *    DIR_COUNT   FILE_COUNT       CONTENT_SIZE
202   */
203  private static final String SUMMARY_FORMAT = "%12s %12s %18s ";
204
205  private static final String[] SUMMARY_HEADER_FIELDS =
206      new String[] {"DIR_COUNT", "FILE_COUNT", "CONTENT_SIZE"};
207
208  /** The header string */
209  private static final String SUMMARY_HEADER = String.format(
210      SUMMARY_FORMAT, (Object[]) SUMMARY_HEADER_FIELDS);
211
212  private static final String ALL_HEADER = QUOTA_HEADER + SUMMARY_HEADER;
213
214
215  /** Return the header of the output.
216   * if qOption is false, output directory count, file count, and content size;
217   * if qOption is true, output quota and remaining quota as well.
218   * 
219   * @param qOption a flag indicating if quota needs to be printed or not
220   * @return the header of the output
221   */
222  public static String getHeader(boolean qOption) {
223    return qOption ? ALL_HEADER : SUMMARY_HEADER;
224  }
225
226
227
228  /**
229   * Returns the names of the fields from the summary header.
230   * 
231   * @return names of fields as displayed in the header
232   */
233  public static String[] getHeaderFields() {
234    return SUMMARY_HEADER_FIELDS;
235  }
236
237  /**
238   * Returns the names of the fields used in the quota summary.
239   * 
240   * @return names of quota fields as displayed in the header
241   */
242  public static String[] getQuotaHeaderFields() {
243    return QUOTA_HEADER_FIELDS;
244  }
245
246  @Override
247  public String toString() {
248    return toString(true);
249  }
250
251  /** Return the string representation of the object in the output format.
252   * if qOption is false, output directory count, file count, and content size;
253   * if qOption is true, output quota and remaining quota as well.
254   *
255   * @param qOption a flag indicating if quota needs to be printed or not
256   * @return the string representation of the object
257  */
258  public String toString(boolean qOption) {
259    return toString(qOption, false);
260  }
261
262  /** Return the string representation of the object in the output format.
263   * if qOption is false, output directory count, file count, and content size;
264   * if qOption is true, output quota and remaining quota as well.
265   * if hOption is false file sizes are returned in bytes
266   * if hOption is true file sizes are returned in human readable 
267   * 
268   * @param qOption a flag indicating if quota needs to be printed or not
269   * @param hOption a flag indicating if human readable output if to be used
270   * @return the string representation of the object
271   */
272  public String toString(boolean qOption, boolean hOption) {
273    return toString(qOption, hOption, false, null);
274  }
275
276  /**
277   * Return the string representation of the object in the output format.
278   * if tOption is true, display the quota by storage types,
279   * Otherwise, same logic with #toString(boolean,boolean)
280   *
281   * @param qOption a flag indicating if quota needs to be printed or not
282   * @param hOption a flag indicating if human readable output if to be used
283   * @param tOption a flag indicating if display quota by storage types
284   * @param types Storage types to display
285   * @return the string representation of the object
286   */
287  public String toString(boolean qOption, boolean hOption,
288                         boolean tOption, List<StorageType> types) {
289    String prefix = "";
290
291    if (tOption) {
292      return getTypesQuotaUsage(hOption, types);
293    }
294
295    if (qOption) {
296      prefix = getQuotaUsage(hOption);
297    }
298
299    return prefix + String.format(SUMMARY_FORMAT,
300        formatSize(directoryCount, hOption),
301        formatSize(fileCount, hOption),
302        formatSize(length, hOption));
303  }
304
305  /**
306   * Formats a size to be human readable or in bytes
307   * @param size value to be formatted
308   * @param humanReadable flag indicating human readable or not
309   * @return String representation of the size
310  */
311  private String formatSize(long size, boolean humanReadable) {
312    return humanReadable
313      ? StringUtils.TraditionalBinaryPrefix.long2String(size, "", 1)
314      : String.valueOf(size);
315  }
316}