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;
023
024import org.apache.hadoop.fs.StorageType;
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 implements Writable{
034  private long length;
035  private long fileCount;
036  private long directoryCount;
037  private long quota;
038  private long spaceConsumed;
039  private long spaceQuota;
040  private long typeConsumed[];
041  private long typeQuota[];
042
043  public static class Builder{
044    public Builder() {
045      this.quota = -1;
046      this.spaceQuota = -1;
047
048      typeConsumed = new long[StorageType.values().length];
049      typeQuota = new long[StorageType.values().length];
050      for (int i = 0; i < typeQuota.length; i++) {
051        typeQuota[i] = -1;
052      }
053    }
054
055    public Builder length(long length) {
056      this.length = length;
057      return this;
058    }
059
060    public Builder fileCount(long fileCount) {
061      this.fileCount = fileCount;
062      return this;
063    }
064
065    public Builder directoryCount(long directoryCount) {
066      this.directoryCount = directoryCount;
067      return this;
068    }
069
070    public Builder quota(long quota){
071      this.quota = quota;
072      return this;
073    }
074
075    public Builder spaceConsumed(long spaceConsumed) {
076      this.spaceConsumed = spaceConsumed;
077      return this;
078    }
079
080    public Builder spaceQuota(long spaceQuota) {
081      this.spaceQuota = spaceQuota;
082      return this;
083    }
084
085    public Builder typeConsumed(long typeConsumed[]) {
086      for (int i = 0; i < typeConsumed.length; i++) {
087        this.typeConsumed[i] = typeConsumed[i];
088      }
089      return this;
090    }
091
092    public Builder typeQuota(StorageType type, long quota) {
093      this.typeQuota[type.ordinal()] = quota;
094      return this;
095    }
096
097    public Builder typeConsumed(StorageType type, long consumed) {
098      this.typeConsumed[type.ordinal()] = consumed;
099      return this;
100    }
101
102    public Builder typeQuota(long typeQuota[]) {
103      for (int i = 0; i < typeQuota.length; i++) {
104        this.typeQuota[i] = typeQuota[i];
105      }
106      return this;
107    }
108
109    public ContentSummary build() {
110      return new ContentSummary(length, fileCount, directoryCount, quota,
111          spaceConsumed, spaceQuota, typeConsumed, typeQuota);
112    }
113
114    private long length;
115    private long fileCount;
116    private long directoryCount;
117    private long quota;
118    private long spaceConsumed;
119    private long spaceQuota;
120    private long typeConsumed[];
121    private long typeQuota[];
122  }
123
124  /** Constructor deprecated by ContentSummary.Builder*/
125  @Deprecated
126  public ContentSummary() {}
127  
128  /** Constructor, deprecated by ContentSummary.Builder
129   *  This constructor implicitly set spaceConsumed the same as length.
130   *  spaceConsumed and length must be set explicitly with
131   *  ContentSummary.Builder
132   * */
133  @Deprecated
134  public ContentSummary(long length, long fileCount, long directoryCount) {
135    this(length, fileCount, directoryCount, -1L, length, -1L);
136  }
137
138  /** Constructor, deprecated by ContentSummary.Builder */
139  @Deprecated
140  public ContentSummary(
141      long length, long fileCount, long directoryCount, long quota,
142      long spaceConsumed, long spaceQuota) {
143    this.length = length;
144    this.fileCount = fileCount;
145    this.directoryCount = directoryCount;
146    this.quota = quota;
147    this.spaceConsumed = spaceConsumed;
148    this.spaceQuota = spaceQuota;
149  }
150
151  /** Constructor for ContentSummary.Builder*/
152  private ContentSummary(
153      long length, long fileCount, long directoryCount, long quota,
154      long spaceConsumed, long spaceQuota, long typeConsumed[],
155      long typeQuota[]) {
156    this.length = length;
157    this.fileCount = fileCount;
158    this.directoryCount = directoryCount;
159    this.quota = quota;
160    this.spaceConsumed = spaceConsumed;
161    this.spaceQuota = spaceQuota;
162    this.typeConsumed = typeConsumed;
163    this.typeQuota = typeQuota;
164  }
165
166  /** @return the length */
167  public long getLength() {return length;}
168
169  /** @return the directory count */
170  public long getDirectoryCount() {return directoryCount;}
171
172  /** @return the file count */
173  public long getFileCount() {return fileCount;}
174  
175  /** Return the directory quota */
176  public long getQuota() {return quota;}
177  
178  /** Retuns storage space consumed */
179  public long getSpaceConsumed() {return spaceConsumed;}
180
181  /** Returns storage space quota */
182  public long getSpaceQuota() {return spaceQuota;}
183
184  /** Returns storage type quota */
185  public long getTypeQuota(StorageType type) {
186    return (typeQuota != null) ? typeQuota[type.ordinal()] : -1;
187  }
188
189  /** Returns storage type consumed*/
190  public long getTypeConsumed(StorageType type) {
191    return (typeConsumed != null) ? typeConsumed[type.ordinal()] : 0;
192  }
193
194  /** Returns true if any storage type quota has been set*/
195  public boolean isTypeQuotaSet() {
196    if (typeQuota == null) {
197      return false;
198    }
199    for (StorageType t : StorageType.getTypesSupportingQuota()) {
200      if (typeQuota[t.ordinal()] > 0) {
201        return true;
202      }
203    }
204    return false;
205  }
206
207  /** Returns true if any storage type consumption information is available*/
208  public boolean isTypeConsumedAvailable() {
209    if (typeConsumed == null) {
210      return false;
211    }
212    for (StorageType t : StorageType.getTypesSupportingQuota()) {
213      if (typeConsumed[t.ordinal()] > 0) {
214        return true;
215      }
216    }
217    return false;
218  }
219
220  @Override
221  @InterfaceAudience.Private
222  public void write(DataOutput out) throws IOException {
223    out.writeLong(length);
224    out.writeLong(fileCount);
225    out.writeLong(directoryCount);
226    out.writeLong(quota);
227    out.writeLong(spaceConsumed);
228    out.writeLong(spaceQuota);
229  }
230
231  @Override
232  @InterfaceAudience.Private
233  public void readFields(DataInput in) throws IOException {
234    this.length = in.readLong();
235    this.fileCount = in.readLong();
236    this.directoryCount = in.readLong();
237    this.quota = in.readLong();
238    this.spaceConsumed = in.readLong();
239    this.spaceQuota = in.readLong();
240  }
241  
242  /** 
243   * Output format:
244   * <----12----> <----12----> <-------18------->
245   *    DIR_COUNT   FILE_COUNT       CONTENT_SIZE FILE_NAME    
246   */
247  private static final String STRING_FORMAT = "%12s %12s %18s ";
248  /** 
249   * Output format:
250   * <----12----> <----15----> <----15----> <----15----> <----12----> <----12----> <-------18------->
251   *    QUOTA   REMAINING_QUATA SPACE_QUOTA SPACE_QUOTA_REM DIR_COUNT   FILE_COUNT   CONTENT_SIZE     FILE_NAME    
252   */
253  private static final String QUOTA_STRING_FORMAT = "%12s %15s ";
254  private static final String SPACE_QUOTA_STRING_FORMAT = "%15s %15s ";
255  
256  /** The header string */
257  private static final String HEADER = String.format(
258      STRING_FORMAT.replace('d', 's'), "directories", "files", "bytes");
259
260  private static final String QUOTA_HEADER = String.format(
261      QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, 
262      "name quota", "rem name quota", "space quota", "rem space quota") +
263      HEADER;
264  
265  /** Return the header of the output.
266   * if qOption is false, output directory count, file count, and content size;
267   * if qOption is true, output quota and remaining quota as well.
268   * 
269   * @param qOption a flag indicating if quota needs to be printed or not
270   * @return the header of the output
271   */
272  public static String getHeader(boolean qOption) {
273    return qOption ? QUOTA_HEADER : HEADER;
274  }
275  
276  @Override
277  public String toString() {
278    return toString(true);
279  }
280
281  /** Return the string representation of the object in the output format.
282   * if qOption is false, output directory count, file count, and content size;
283   * if qOption is true, output quota and remaining quota as well.
284   *
285   * @param qOption a flag indicating if quota needs to be printed or not
286   * @return the string representation of the object
287  */
288  public String toString(boolean qOption) {
289    return toString(qOption, false);
290  }
291
292  /** Return the string representation of the object in the output format.
293   * if qOption is false, output directory count, file count, and content size;
294   * if qOption is true, output quota and remaining quota as well.
295   * if hOption is false file sizes are returned in bytes
296   * if hOption is true file sizes are returned in human readable 
297   * 
298   * @param qOption a flag indicating if quota needs to be printed or not
299   * @param hOption a flag indicating if human readable output if to be used
300   * @return the string representation of the object
301   */
302  public String toString(boolean qOption, boolean hOption) {
303    String prefix = "";
304    if (qOption) {
305      String quotaStr = "none";
306      String quotaRem = "inf";
307      String spaceQuotaStr = "none";
308      String spaceQuotaRem = "inf";
309      
310      if (quota>0) {
311        quotaStr = formatSize(quota, hOption);
312        quotaRem = formatSize(quota-(directoryCount+fileCount), hOption);
313      }
314      if (spaceQuota>0) {
315        spaceQuotaStr = formatSize(spaceQuota, hOption);
316        spaceQuotaRem = formatSize(spaceQuota - spaceConsumed, hOption);
317      }
318      
319      prefix = String.format(QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, 
320                             quotaStr, quotaRem, spaceQuotaStr, spaceQuotaRem);
321    }
322    
323    return prefix + String.format(STRING_FORMAT,
324     formatSize(directoryCount, hOption),
325     formatSize(fileCount, hOption),
326     formatSize(length, hOption));
327  }
328  /**
329   * Formats a size to be human readable or in bytes
330   * @param size value to be formatted
331   * @param humanReadable flag indicating human readable or not
332   * @return String representation of the size
333  */
334  private String formatSize(long size, boolean humanReadable) {
335    return humanReadable
336      ? StringUtils.TraditionalBinaryPrefix.long2String(size, "", 1)
337      : String.valueOf(size);
338  }
339}