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  // These fields are to track the snapshot-related portion of the values.
038  private long snapshotLength;
039  private long snapshotFileCount;
040  private long snapshotDirectoryCount;
041  private long snapshotSpaceConsumed;
042
043  /** We don't use generics. Instead override spaceConsumed and other methods
044      in order to keep backward compatibility. */
045  public static class Builder extends QuotaUsage.Builder {
046    public Builder() {
047    }
048
049    public Builder length(long length) {
050      this.length = length;
051      return this;
052    }
053
054    public Builder fileCount(long fileCount) {
055      this.fileCount = fileCount;
056      return this;
057    }
058
059    public Builder directoryCount(long directoryCount) {
060      this.directoryCount = directoryCount;
061      return this;
062    }
063
064    public Builder snapshotLength(long snapshotLength) {
065      this.snapshotLength = snapshotLength;
066      return this;
067    }
068
069    public Builder snapshotFileCount(long snapshotFileCount) {
070      this.snapshotFileCount = snapshotFileCount;
071      return this;
072    }
073
074    public Builder snapshotDirectoryCount(long snapshotDirectoryCount) {
075      this.snapshotDirectoryCount = snapshotDirectoryCount;
076      return this;
077    }
078
079    public Builder snapshotSpaceConsumed(long snapshotSpaceConsumed) {
080      this.snapshotSpaceConsumed = snapshotSpaceConsumed;
081      return this;
082    }
083
084    @Override
085    public Builder quota(long quota){
086      super.quota(quota);
087      return this;
088    }
089
090    @Override
091    public Builder spaceConsumed(long spaceConsumed) {
092      super.spaceConsumed(spaceConsumed);
093      return this;
094    }
095
096    @Override
097    public Builder spaceQuota(long spaceQuota) {
098      super.spaceQuota(spaceQuota);
099      return this;
100    }
101
102    @Override
103    public Builder typeConsumed(long typeConsumed[]) {
104      super.typeConsumed(typeConsumed);
105      return this;
106    }
107
108    @Override
109    public Builder typeQuota(StorageType type, long quota) {
110      super.typeQuota(type, quota);
111      return this;
112    }
113
114    @Override
115    public Builder typeConsumed(StorageType type, long consumed) {
116      super.typeConsumed(type, consumed);
117      return this;
118    }
119
120    @Override
121    public Builder typeQuota(long typeQuota[]) {
122      super.typeQuota(typeQuota);
123      return this;
124    }
125
126    public ContentSummary build() {
127      // Set it in case applications call QuotaUsage#getFileAndDirectoryCount.
128      super.fileAndDirectoryCount(this.fileCount + this.directoryCount);
129      return new ContentSummary(this);
130    }
131
132    private long length;
133    private long fileCount;
134    private long directoryCount;
135    private long snapshotLength;
136    private long snapshotFileCount;
137    private long snapshotDirectoryCount;
138    private long snapshotSpaceConsumed;
139  }
140
141  /** Constructor deprecated by ContentSummary.Builder*/
142  @Deprecated
143  public ContentSummary() {}
144  
145  /** Constructor, deprecated by ContentSummary.Builder
146   *  This constructor implicitly set spaceConsumed the same as length.
147   *  spaceConsumed and length must be set explicitly with
148   *  ContentSummary.Builder
149   * */
150  @Deprecated
151  public ContentSummary(long length, long fileCount, long directoryCount) {
152    this(length, fileCount, directoryCount, -1L, length, -1L);
153  }
154
155  /** Constructor, deprecated by ContentSummary.Builder */
156  @Deprecated
157  public ContentSummary(
158      long length, long fileCount, long directoryCount, long quota,
159      long spaceConsumed, long spaceQuota) {
160    this.length = length;
161    this.fileCount = fileCount;
162    this.directoryCount = directoryCount;
163    setQuota(quota);
164    setSpaceConsumed(spaceConsumed);
165    setSpaceQuota(spaceQuota);
166  }
167
168  /** Constructor for ContentSummary.Builder*/
169  private ContentSummary(Builder builder) {
170    super(builder);
171    this.length = builder.length;
172    this.fileCount = builder.fileCount;
173    this.directoryCount = builder.directoryCount;
174    this.snapshotLength = builder.snapshotLength;
175    this.snapshotFileCount = builder.snapshotFileCount;
176    this.snapshotDirectoryCount = builder.snapshotDirectoryCount;
177    this.snapshotSpaceConsumed = builder.snapshotSpaceConsumed;
178  }
179
180  /** @return the length */
181  public long getLength() {return length;}
182
183  public long getSnapshotLength() {
184    return snapshotLength;
185  }
186
187  /** @return the directory count */
188  public long getDirectoryCount() {return directoryCount;}
189
190  public long getSnapshotDirectoryCount() {
191    return snapshotDirectoryCount;
192  }
193
194  /** @return the file count */
195  public long getFileCount() {return fileCount;}
196
197  public long getSnapshotFileCount() {
198    return snapshotFileCount;
199  }
200
201  public long getSnapshotSpaceConsumed() {
202    return snapshotSpaceConsumed;
203  }
204
205  @Override
206  @InterfaceAudience.Private
207  public void write(DataOutput out) throws IOException {
208    out.writeLong(length);
209    out.writeLong(fileCount);
210    out.writeLong(directoryCount);
211    out.writeLong(getQuota());
212    out.writeLong(getSpaceConsumed());
213    out.writeLong(getSpaceQuota());
214  }
215
216  @Override
217  @InterfaceAudience.Private
218  public void readFields(DataInput in) throws IOException {
219    this.length = in.readLong();
220    this.fileCount = in.readLong();
221    this.directoryCount = in.readLong();
222    setQuota(in.readLong());
223    setSpaceConsumed(in.readLong());
224    setSpaceQuota(in.readLong());
225  }
226
227  @Override
228  public boolean equals(Object to) {
229    if (this == to) {
230      return true;
231    } else if (to instanceof ContentSummary) {
232      ContentSummary right = (ContentSummary) to;
233      return getLength() == right.getLength() &&
234          getFileCount() == right.getFileCount() &&
235          getDirectoryCount() == right.getDirectoryCount() &&
236          getSnapshotLength() == right.getSnapshotLength() &&
237          getSnapshotFileCount() == right.getSnapshotFileCount() &&
238          getSnapshotDirectoryCount() == right.getSnapshotDirectoryCount() &&
239          getSnapshotSpaceConsumed() == right.getSnapshotSpaceConsumed() &&
240          super.equals(to);
241    } else {
242      return super.equals(to);
243    }
244  }
245
246  @Override
247  public int hashCode() {
248    long result = getLength() ^ getFileCount() ^ getDirectoryCount()
249        ^ getSnapshotLength() ^ getSnapshotFileCount()
250        ^ getSnapshotDirectoryCount() ^ getSnapshotSpaceConsumed();
251    return ((int) result) ^ super.hashCode();
252  }
253
254  /**
255   * Output format:
256   * <----12----> <----12----> <-------18------->
257   *    DIR_COUNT   FILE_COUNT       CONTENT_SIZE
258   */
259  private static final String SUMMARY_FORMAT = "%12s %12s %18s ";
260
261  private static final String[] SUMMARY_HEADER_FIELDS =
262      new String[] {"DIR_COUNT", "FILE_COUNT", "CONTENT_SIZE"};
263
264  /** The header string */
265  private static final String SUMMARY_HEADER = String.format(
266      SUMMARY_FORMAT, (Object[]) SUMMARY_HEADER_FIELDS);
267
268  private static final String ALL_HEADER = QUOTA_HEADER + SUMMARY_HEADER;
269
270
271  /** Return the header of the output.
272   * if qOption is false, output directory count, file count, and content size;
273   * if qOption is true, output quota and remaining quota as well.
274   * 
275   * @param qOption a flag indicating if quota needs to be printed or not
276   * @return the header of the output
277   */
278  public static String getHeader(boolean qOption) {
279    return qOption ? ALL_HEADER : SUMMARY_HEADER;
280  }
281
282
283
284  /**
285   * Returns the names of the fields from the summary header.
286   * 
287   * @return names of fields as displayed in the header
288   */
289  public static String[] getHeaderFields() {
290    return SUMMARY_HEADER_FIELDS;
291  }
292
293  /**
294   * Returns the names of the fields used in the quota summary.
295   * 
296   * @return names of quota fields as displayed in the header
297   */
298  public static String[] getQuotaHeaderFields() {
299    return QUOTA_HEADER_FIELDS;
300  }
301
302  @Override
303  public String toString() {
304    return toString(true);
305  }
306
307  /** Return the string representation of the object in the output format.
308   * if qOption is false, output directory count, file count, and content size;
309   * if qOption is true, output quota and remaining quota as well.
310   *
311   * @param qOption a flag indicating if quota needs to be printed or not
312   * @return the string representation of the object
313  */
314  @Override
315  public String toString(boolean qOption) {
316    return toString(qOption, false);
317  }
318
319  /** Return the string representation of the object in the output format.
320   * For description of the options,
321   * @see #toString(boolean, boolean, boolean, boolean, List)
322   * 
323   * @param qOption a flag indicating if quota needs to be printed or not
324   * @param hOption a flag indicating if human readable output if to be used
325   * @return the string representation of the object
326   */
327  public String toString(boolean qOption, boolean hOption) {
328    return toString(qOption, hOption, false, null);
329  }
330
331  /** Return the string representation of the object in the output format.
332   * For description of the options,
333   * @see #toString(boolean, boolean, boolean, boolean, List)
334   *
335   * @param qOption a flag indicating if quota needs to be printed or not
336   * @param hOption a flag indicating if human readable output is to be used
337   * @param xOption a flag indicating if calculation from snapshots is to be
338   *                included in the output
339   * @return the string representation of the object
340   */
341  public String toString(boolean qOption, boolean hOption, boolean xOption) {
342    return toString(qOption, hOption, false, xOption, null);
343  }
344
345  /**
346   * Return the string representation of the object in the output format.
347   * For description of the options,
348   * @see #toString(boolean, boolean, boolean, boolean, List)
349   *
350   * @param qOption a flag indicating if quota needs to be printed or not
351   * @param hOption a flag indicating if human readable output if to be used
352   * @param tOption a flag indicating if display quota by storage types
353   * @param types Storage types to display
354   * @return the string representation of the object
355   */
356  public String toString(boolean qOption, boolean hOption,
357                         boolean tOption, List<StorageType> types) {
358    return toString(qOption, hOption, tOption, false, types);
359  }
360
361  /** Return the string representation of the object in the output format.
362   * if qOption is false, output directory count, file count, and content size;
363   * if qOption is true, output quota and remaining quota as well.
364   * if hOption is false, file sizes are returned in bytes
365   * if hOption is true, file sizes are returned in human readable
366   * if tOption is true, display the quota by storage types
367   * if tOption is false, same logic with #toString(boolean,boolean)
368   * if xOption is false, output includes the calculation from snapshots
369   * if xOption is true, output excludes the calculation from snapshots
370   *
371   * @param qOption a flag indicating if quota needs to be printed or not
372   * @param hOption a flag indicating if human readable output is to be used
373   * @param tOption a flag indicating if display quota by storage types
374   * @param xOption a flag indicating if calculation from snapshots is to be
375   *                included in the output
376   * @param types Storage types to display
377   * @return the string representation of the object
378   */
379  public String toString(boolean qOption, boolean hOption, boolean tOption,
380      boolean xOption, List<StorageType> types) {
381    String prefix = "";
382
383    if (tOption) {
384      return getTypesQuotaUsage(hOption, types);
385    }
386
387    if (qOption) {
388      prefix = getQuotaUsage(hOption);
389    }
390
391    if (xOption) {
392      return prefix + String.format(SUMMARY_FORMAT,
393          formatSize(directoryCount - snapshotDirectoryCount, hOption),
394          formatSize(fileCount - snapshotFileCount, hOption),
395          formatSize(length - snapshotLength, hOption));
396    } else {
397      return prefix + String.format(SUMMARY_FORMAT,
398          formatSize(directoryCount, hOption),
399          formatSize(fileCount, hOption),
400          formatSize(length, hOption));
401    }
402  }
403
404  /**
405   * Formats a size to be human readable or in bytes
406   * @param size value to be formatted
407   * @param humanReadable flag indicating human readable or not
408   * @return String representation of the size
409  */
410  private String formatSize(long size, boolean humanReadable) {
411    return humanReadable
412      ? StringUtils.TraditionalBinaryPrefix.long2String(size, "", 1)
413      : String.valueOf(size);
414  }
415}