blob: 455a74eee976692890831243f5edbe671c75ea49 [file] [log] [blame]
/**
* 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.hdfs.server.namenode;
import org.apache.hadoop.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
import org.apache.hadoop.hdfs.util.ConstEnumCounters;
import org.apache.hadoop.hdfs.util.EnumCounters;
import java.util.function.Consumer;
/**
* Counters for namespace, storage space and storage type space quota and usage.
*/
public class QuotaCounts {
/**
* We pre-define 4 most common used EnumCounters objects. When the nsSsCounts
* and tsCounts are set to the 4 most common used value, we just point them to
* the pre-defined const EnumCounters objects instead of constructing many
* objects with the same value. See HDFS-14547.
*/
final static EnumCounters<Quota> QUOTA_RESET =
new ConstEnumCounters<>(Quota.class, HdfsConstants.QUOTA_RESET);
final static EnumCounters<Quota> QUOTA_DEFAULT =
new ConstEnumCounters<>(Quota.class, 0);
final static EnumCounters<StorageType> STORAGE_TYPE_RESET =
new ConstEnumCounters<>(StorageType.class, HdfsConstants.QUOTA_RESET);
final static EnumCounters<StorageType> STORAGE_TYPE_DEFAULT =
new ConstEnumCounters<>(StorageType.class, 0);
/**
* Modify counter with action. If the counter is ConstEnumCounters, copy all
* the values of it to a new EnumCounters object, and modify the new obj.
*
* @param counter the EnumCounters to be modified.
* @param action the modifying action on counter.
* @return the modified counter.
*/
static <T extends Enum<T>> EnumCounters<T> modify(EnumCounters<T> counter,
Consumer<EnumCounters<T>> action) {
if (counter instanceof ConstEnumCounters) {
counter = counter.deepCopyEnumCounter();
}
action.accept(counter);
return counter;
}
// Name space and storage space counts (HDFS-7775 refactors the original disk
// space count to storage space counts)
@VisibleForTesting
EnumCounters<Quota> nsSsCounts;
// Storage type space counts
@VisibleForTesting
EnumCounters<StorageType> tsCounts;
public static class Builder {
private EnumCounters<Quota> nsSsCounts;
private EnumCounters<StorageType> tsCounts;
public Builder() {
this.nsSsCounts = QUOTA_DEFAULT;
this.tsCounts = STORAGE_TYPE_DEFAULT;
}
public Builder nameSpace(long val) {
nsSsCounts =
setQuotaCounter(nsSsCounts, Quota.NAMESPACE, Quota.STORAGESPACE, val);
return this;
}
public Builder storageSpace(long val) {
nsSsCounts =
setQuotaCounter(nsSsCounts, Quota.STORAGESPACE, Quota.NAMESPACE, val);
return this;
}
public Builder typeSpaces(EnumCounters<StorageType> val) {
if (val != null) {
if (val == STORAGE_TYPE_DEFAULT || val == STORAGE_TYPE_RESET) {
tsCounts = val;
} else {
tsCounts = modify(tsCounts, ec -> ec.set(val));
}
}
return this;
}
public Builder typeSpaces(long val) {
if (val == HdfsConstants.QUOTA_RESET) {
tsCounts = STORAGE_TYPE_RESET;
} else if (val == 0) {
tsCounts = STORAGE_TYPE_DEFAULT;
} else {
tsCounts = modify(tsCounts, ec -> ec.reset(val));
}
return this;
}
public Builder quotaCount(QuotaCounts that) {
if (that.nsSsCounts == QUOTA_DEFAULT || that.nsSsCounts == QUOTA_RESET) {
nsSsCounts = that.nsSsCounts;
} else {
nsSsCounts = modify(nsSsCounts, ec -> ec.set(that.nsSsCounts));
}
if (that.tsCounts == STORAGE_TYPE_DEFAULT
|| that.tsCounts == STORAGE_TYPE_RESET) {
tsCounts = that.tsCounts;
} else {
tsCounts = modify(tsCounts, ec -> ec.set(that.tsCounts));
}
return this;
}
public QuotaCounts build() {
return new QuotaCounts(this);
}
}
private QuotaCounts(Builder builder) {
this.nsSsCounts = builder.nsSsCounts;
this.tsCounts = builder.tsCounts;
}
public QuotaCounts add(QuotaCounts that) {
nsSsCounts = modify(nsSsCounts, ec -> ec.add(that.nsSsCounts));
tsCounts = modify(tsCounts, ec -> ec.add(that.tsCounts));
return this;
}
public QuotaCounts subtract(QuotaCounts that) {
nsSsCounts = modify(nsSsCounts, ec -> ec.subtract(that.nsSsCounts));
tsCounts = modify(tsCounts, ec -> ec.subtract(that.tsCounts));
return this;
}
/**
* Returns a QuotaCounts whose value is {@code (-this)}.
*
* @return {@code -this}
*/
public QuotaCounts negation() {
QuotaCounts ret = new QuotaCounts.Builder().quotaCount(this).build();
ret.nsSsCounts = modify(ret.nsSsCounts, ec -> ec.negation());
ret.tsCounts = modify(ret.tsCounts, ec -> ec.negation());
return ret;
}
public long getNameSpace(){
return nsSsCounts.get(Quota.NAMESPACE);
}
public void setNameSpace(long nameSpaceCount) {
nsSsCounts =
setQuotaCounter(nsSsCounts, Quota.NAMESPACE, Quota.STORAGESPACE,
nameSpaceCount);
}
public void addNameSpace(long nsDelta) {
nsSsCounts = modify(nsSsCounts, ec -> ec.add(Quota.NAMESPACE, nsDelta));
}
public long getStorageSpace(){
return nsSsCounts.get(Quota.STORAGESPACE);
}
public void setStorageSpace(long spaceCount) {
nsSsCounts =
setQuotaCounter(nsSsCounts, Quota.STORAGESPACE, Quota.NAMESPACE,
spaceCount);
}
public void addStorageSpace(long dsDelta) {
nsSsCounts = modify(nsSsCounts, ec -> ec.add(Quota.STORAGESPACE, dsDelta));
}
public EnumCounters<StorageType> getTypeSpaces() {
EnumCounters<StorageType> ret =
new EnumCounters<StorageType>(StorageType.class);
ret.set(tsCounts);
return ret;
}
void setTypeSpaces(EnumCounters<StorageType> that) {
if (that == STORAGE_TYPE_DEFAULT || that == STORAGE_TYPE_RESET) {
tsCounts = that;
} else if (that != null) {
tsCounts = modify(tsCounts, ec -> ec.set(that));
}
}
long getTypeSpace(StorageType type) {
return this.tsCounts.get(type);
}
void setTypeSpace(StorageType type, long spaceCount) {
tsCounts = modify(tsCounts, ec -> ec.set(type, spaceCount));
}
public void addTypeSpace(StorageType type, long delta) {
tsCounts = modify(tsCounts, ec -> ec.add(type, delta));
}
public boolean anyNsSsCountGreaterOrEqual(long val) {
if (nsSsCounts == QUOTA_DEFAULT) {
return val <= 0;
} else if (nsSsCounts == QUOTA_RESET) {
return val <= HdfsConstants.QUOTA_RESET;
}
return nsSsCounts.anyGreaterOrEqual(val);
}
public boolean anyTypeSpaceCountGreaterOrEqual(long val) {
if (tsCounts == STORAGE_TYPE_DEFAULT) {
return val <= 0;
} else if (tsCounts == STORAGE_TYPE_RESET) {
return val <= HdfsConstants.QUOTA_RESET;
}
return tsCounts.anyGreaterOrEqual(val);
}
/**
* Set inputCounts' value of Quota type quotaToSet to val.
* inputCounts should be the left side value of this method.
*
* @param inputCounts the EnumCounters instance.
* @param quotaToSet the quota type to be set.
* @param otherQuota the other quota type besides quotaToSet.
* @param val the value to be set.
* @return the modified inputCounts.
*/
private static EnumCounters<Quota> setQuotaCounter(
EnumCounters<Quota> inputCounts, Quota quotaToSet, Quota otherQuota,
long val) {
if (val == HdfsConstants.QUOTA_RESET
&& inputCounts.get(otherQuota) == HdfsConstants.QUOTA_RESET) {
return QUOTA_RESET;
} else if (val == 0 && inputCounts.get(otherQuota) == 0) {
return QUOTA_DEFAULT;
} else {
return modify(inputCounts, ec -> ec.set(quotaToSet, val));
}
}
@Override
public String toString() {
return "name space=" + getNameSpace() +
"\nstorage space=" + getStorageSpace() +
"\nstorage types=" + getTypeSpaces();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (!(obj instanceof QuotaCounts)) {
return false;
}
final QuotaCounts that = (QuotaCounts)obj;
return this.nsSsCounts.equals(that.nsSsCounts)
&& this.tsCounts.equals(that.tsCounts);
}
@Override
public int hashCode() {
assert false : "hashCode not designed";
return 42; // any arbitrary constant will do
}
}