/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs; import java.util.Arrays; import java.util.List; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.util.StringUtils; /** Store the quota usage of a directory. */ @InterfaceAudience.Public @InterfaceStability.Evolving public class QuotaUsage { private long fileAndDirectoryCount; // Make the followings protected so that // deprecated ContentSummary constructor can use them. private long quota; private long spaceConsumed; private long spaceQuota; private long[] typeConsumed; private long[] typeQuota; /** Builder class for QuotaUsage. */ public static class Builder { public Builder() { this.quota = -1; this.spaceQuota = -1; typeConsumed = new long[StorageType.values().length]; typeQuota = new long[StorageType.values().length]; for (int i = 0; i < typeQuota.length; i++) { typeQuota[i] = -1; } } public Builder fileAndDirectoryCount(long count) { this.fileAndDirectoryCount = count; return this; } public Builder quota(long quota){ this.quota = quota; return this; } public Builder spaceConsumed(long spaceConsumed) { this.spaceConsumed = spaceConsumed; return this; } public Builder spaceQuota(long spaceQuota) { this.spaceQuota = spaceQuota; return this; } public Builder typeConsumed(long[] typeConsumed) { for (int i = 0; i < typeConsumed.length; i++) { this.typeConsumed[i] = typeConsumed[i]; } return this; } public Builder typeQuota(StorageType type, long quota) { this.typeQuota[type.ordinal()] = quota; return this; } public Builder typeConsumed(StorageType type, long consumed) { this.typeConsumed[type.ordinal()] = consumed; return this; } public Builder typeQuota(long[] typeQuota) { for (int i = 0; i < typeQuota.length; i++) { this.typeQuota[i] = typeQuota[i]; } return this; } public QuotaUsage build() { return new QuotaUsage(this); } private long fileAndDirectoryCount; private long quota; private long spaceConsumed; private long spaceQuota; private long[] typeConsumed; private long[] typeQuota; } // Make it protected for the deprecated ContentSummary constructor. protected QuotaUsage() { } /** Build the instance based on the builder. */ protected QuotaUsage(Builder builder) { this.fileAndDirectoryCount = builder.fileAndDirectoryCount; this.quota = builder.quota; this.spaceConsumed = builder.spaceConsumed; this.spaceQuota = builder.spaceQuota; this.typeConsumed = builder.typeConsumed; this.typeQuota = builder.typeQuota; } protected void setQuota(long quota) { this.quota = quota; } protected void setSpaceConsumed(long spaceConsumed) { this.spaceConsumed = spaceConsumed; } protected void setSpaceQuota(long spaceQuota) { this.spaceQuota = spaceQuota; } /** Return the directory count. */ public long getFileAndDirectoryCount() { return fileAndDirectoryCount; } /** Return the directory quota. */ public long getQuota() { return quota; } /** Return (disk) space consumed. */ public long getSpaceConsumed() { return spaceConsumed; } /** Return (disk) space quota. */ public long getSpaceQuota() { return spaceQuota; } /** Return storage type quota. */ public long getTypeQuota(StorageType type) { return (typeQuota != null) ? typeQuota[type.ordinal()] : -1; } /** Return storage type consumed. */ public long getTypeConsumed(StorageType type) { return (typeConsumed != null) ? typeConsumed[type.ordinal()] : 0; } /** Return storage type quota. */ private long[] getTypesQuota() { return typeQuota; } /** Return storage type quota. */ private long[] getTypesConsumed() { return typeConsumed; } /** Return true if any storage type quota has been set. */ public boolean isTypeQuotaSet() { if (typeQuota == null) { return false; } for (StorageType t : StorageType.getTypesSupportingQuota()) { if (typeQuota[t.ordinal()] > 0) { return true; } } return false; } /** Return true if any storage type consumption information is available. */ public boolean isTypeConsumedAvailable() { if (typeConsumed == null) { return false; } for (StorageType t : StorageType.getTypesSupportingQuota()) { if (typeConsumed[t.ordinal()] > 0) { return true; } } return false; } @Override public boolean equals(Object to) { return (this == to || (to instanceof QuotaUsage && getFileAndDirectoryCount() == ((QuotaUsage) to).getFileAndDirectoryCount() && getQuota() == ((QuotaUsage) to).getQuota() && getSpaceConsumed() == ((QuotaUsage) to).getSpaceConsumed() && getSpaceQuota() == ((QuotaUsage) to).getSpaceQuota() && Arrays.equals(getTypesQuota(), ((QuotaUsage) to).getTypesQuota()) && Arrays.equals(getTypesConsumed(), ((QuotaUsage) to).getTypesConsumed()))); } @Override public int hashCode() { long result = (getFileAndDirectoryCount() ^ getQuota() ^ getSpaceConsumed() ^ getSpaceQuota()); if (getTypesQuota() != null) { for (long quota : getTypesQuota()) { result ^= quota; } } if (getTypesConsumed() != null) { for (long consumed : getTypesConsumed()) { result ^= consumed; } } return (int)result; } /** * Output format: * <----12----> <----15----> <----15----> <----15----> <-------18-------> * QUOTA REMAINING_QUATA SPACE_QUOTA SPACE_QUOTA_REM FILE_NAME */ protected static final String QUOTA_STRING_FORMAT = "%12s %15s "; protected static final String SPACE_QUOTA_STRING_FORMAT = "%15s %15s "; protected static final String[] QUOTA_HEADER_FIELDS = new String[] {"QUOTA", "REM_QUOTA", "SPACE_QUOTA", "REM_SPACE_QUOTA"}; protected static final String QUOTA_HEADER = String.format( QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, (Object[]) QUOTA_HEADER_FIELDS); /** * Output format: * <----12----> <------15-----> <------15-----> <------15-----> * QUOTA REM_QUOTA SPACE_QUOTA REM_SPACE_QUOTA * <----12----> <----12----> <-------18-------> * DIR_COUNT FILE_COUNT CONTENT_SIZE */ private static final String STORAGE_TYPE_SUMMARY_FORMAT = "%13s %17s "; /** Return the header of the output. * @return the header of the output */ public static String getHeader() { return QUOTA_HEADER; } /** default quota display string */ private static final String QUOTA_NONE = "none"; private static final String QUOTA_INF = "inf"; @Override public String toString() { return toString(false); } public String toString(boolean hOption) { return toString(hOption, false, null); } /** Return the string representation of the object in the output format. * if hOption is false file sizes are returned in bytes * if hOption is true file sizes are returned in human readable * * @param hOption a flag indicating if human readable output if to be used * @return the string representation of the object */ public String toString(boolean hOption, boolean tOption, List<StorageType> types) { if (tOption) { return getTypesQuotaUsage(hOption, types); } return getQuotaUsage(hOption); } protected String getQuotaUsage(boolean hOption) { String quotaStr = QUOTA_NONE; String quotaRem = QUOTA_INF; String spaceQuotaStr = QUOTA_NONE; String spaceQuotaRem = QUOTA_INF; if (quota > 0) { quotaStr = formatSize(quota, hOption); quotaRem = formatSize(quota-fileAndDirectoryCount, hOption); } if (spaceQuota >= 0) { spaceQuotaStr = formatSize(spaceQuota, hOption); spaceQuotaRem = formatSize(spaceQuota - spaceConsumed, hOption); } return String.format(QUOTA_STRING_FORMAT + SPACE_QUOTA_STRING_FORMAT, quotaStr, quotaRem, spaceQuotaStr, spaceQuotaRem); } protected String getTypesQuotaUsage(boolean hOption, List<StorageType> types) { StringBuffer content = new StringBuffer(); for (StorageType st : types) { long typeQuota = getTypeQuota(st); long typeConsumed = getTypeConsumed(st); String quotaStr = QUOTA_NONE; String quotaRem = QUOTA_INF; if (typeQuota >= 0) { quotaStr = formatSize(typeQuota, hOption); quotaRem = formatSize(typeQuota - typeConsumed, hOption); } content.append(String.format(STORAGE_TYPE_SUMMARY_FORMAT, quotaStr, quotaRem)); } return content.toString(); } /** * return the header of with the StorageTypes. * * @param storageTypes * @return storage header string */ public static String getStorageTypeHeader(List<StorageType> storageTypes) { StringBuffer header = new StringBuffer(); for (StorageType st : storageTypes) { /* the field length is 13/17 for quota and remain quota * as the max length for quota name is ARCHIVE_QUOTA * and remain quota name REM_ARCHIVE_QUOTA */ String storageName = st.toString(); header.append(String.format(STORAGE_TYPE_SUMMARY_FORMAT, storageName + "_QUOTA", "REM_" + storageName + "_QUOTA")); } return header.toString(); } /** * 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); } }