001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to you under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.hadoop.hbase.quotas; 018 019import java.util.Objects; 020import java.util.Optional; 021import org.apache.commons.lang3.builder.HashCodeBuilder; 022import org.apache.yetus.audience.InterfaceAudience; 023import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 024import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos; 025import org.apache.hadoop.util.StringUtils; 026 027/** 028 * A point-in-time view of a space quota on a table. 029 */ 030@InterfaceAudience.Private 031public class SpaceQuotaSnapshot implements SpaceQuotaSnapshotView { 032 private static final SpaceQuotaSnapshot NO_SUCH_SNAPSHOT = new SpaceQuotaSnapshot( 033 SpaceQuotaStatus.notInViolation(), 0, Long.MAX_VALUE); 034 private final SpaceQuotaStatus quotaStatus; 035 private final long usage; 036 private final long limit; 037 038 /** 039 * Encapsulates the state of a quota on a table. The quota may or may not be in violation. 040 * If the quota is not in violation, the violation may be null. If the quota is in violation, 041 * there is guaranteed to be a non-null violation policy. 042 */ 043 @InterfaceAudience.Private 044 public static class SpaceQuotaStatus implements SpaceQuotaStatusView { 045 private static final SpaceQuotaStatus NOT_IN_VIOLATION = new SpaceQuotaStatus(null, false); 046 final Optional<SpaceViolationPolicy> policy; 047 final boolean inViolation; 048 049 /** 050 * Constructs a {@code SpaceQuotaSnapshot} which is in violation of the provided {@code policy}. 051 * <p/> 052 * Use {@link #notInViolation()} to obtain an instance of this class for the cases when the 053 * quota is not in violation. 054 * @param policy The non-null policy being violated. 055 */ 056 public SpaceQuotaStatus(SpaceViolationPolicy policy) { 057 // If the caller is instantiating a status, the policy must be non-null 058 this(Objects.requireNonNull(policy), true); 059 } 060 061 private SpaceQuotaStatus(SpaceViolationPolicy policy, boolean inViolation) { 062 this.policy = Optional.ofNullable(policy); 063 this.inViolation = inViolation; 064 } 065 066 /** 067 * Returns the violation policy, which may be null. It is guaranteed to be non-null if 068 * {@link #isInViolation()} is {@code true}, but may be null otherwise. 069 */ 070 @Override 071 public Optional<SpaceViolationPolicy> getPolicy() { 072 return policy; 073 } 074 075 /** 076 * @return {@code true} if the quota is being violated, {@code false} otherwise. 077 */ 078 @Override 079 public boolean isInViolation() { 080 return inViolation; 081 } 082 083 /** 084 * Returns a singleton referring to a quota which is not in violation. 085 */ 086 public static SpaceQuotaStatus notInViolation() { 087 return NOT_IN_VIOLATION; 088 } 089 090 @Override 091 public int hashCode() { 092 return new HashCodeBuilder().append(policy == null ? 0 : policy.hashCode()) 093 .append(inViolation).toHashCode(); 094 } 095 096 @Override 097 public boolean equals(Object o) { 098 if (o instanceof SpaceQuotaStatus) { 099 SpaceQuotaStatus other = (SpaceQuotaStatus) o; 100 return Objects.equals(policy, other.policy) && inViolation == other.inViolation; 101 } 102 return false; 103 } 104 105 @Override 106 public String toString() { 107 StringBuilder sb = new StringBuilder(getClass().getSimpleName()); 108 sb.append("[policy=").append(policy); 109 sb.append(", inViolation=").append(inViolation).append("]"); 110 return sb.toString(); 111 } 112 113 public static QuotaProtos.SpaceQuotaStatus toProto(SpaceQuotaStatus status) { 114 QuotaProtos.SpaceQuotaStatus.Builder builder = QuotaProtos.SpaceQuotaStatus.newBuilder(); 115 builder.setInViolation(status.inViolation); 116 if (status.isInViolation()) { 117 builder.setViolationPolicy(ProtobufUtil.toProtoViolationPolicy(status.getPolicy().get())); 118 } 119 return builder.build(); 120 } 121 122 public static SpaceQuotaStatus toStatus(QuotaProtos.SpaceQuotaStatus proto) { 123 if (proto.getInViolation()) { 124 return new SpaceQuotaStatus(ProtobufUtil.toViolationPolicy(proto.getViolationPolicy())); 125 } else { 126 return NOT_IN_VIOLATION; 127 } 128 } 129 } 130 131 public SpaceQuotaSnapshot(SpaceQuotaStatus quotaStatus, long usage, long limit) { 132 this.quotaStatus = Objects.requireNonNull(quotaStatus); 133 this.usage = usage; 134 this.limit = limit; 135 } 136 137 /** 138 * Returns the status of the quota. 139 */ 140 @Override 141 public SpaceQuotaStatus getQuotaStatus() { 142 return quotaStatus; 143 } 144 145 /** 146 * Returns the current usage, in bytes, of the target (e.g. table, namespace). 147 */ 148 @Override 149 public long getUsage() { 150 return usage; 151 } 152 153 /** 154 * Returns the limit, in bytes, of the target (e.g. table, namespace). 155 */ 156 @Override 157 public long getLimit() { 158 return limit; 159 } 160 161 @Override 162 public int hashCode() { 163 return new HashCodeBuilder() 164 .append(quotaStatus.hashCode()) 165 .append(usage) 166 .append(limit) 167 .toHashCode(); 168 } 169 170 @Override 171 public boolean equals(Object o) { 172 if (o instanceof SpaceQuotaSnapshot) { 173 SpaceQuotaSnapshot other = (SpaceQuotaSnapshot) o; 174 return quotaStatus.equals(other.quotaStatus) && usage == other.usage && limit == other.limit; 175 } 176 return false; 177 } 178 179 @Override 180 public String toString() { 181 StringBuilder sb = new StringBuilder(32); 182 sb.append("SpaceQuotaSnapshot[policy=").append(quotaStatus).append(", use="); 183 sb.append(StringUtils.byteDesc(usage)).append("/"); 184 sb.append(StringUtils.byteDesc(limit)).append("]"); 185 return sb.toString(); 186 } 187 188 // ProtobufUtil is in hbase-client, and this doesn't need to be public. 189 public static SpaceQuotaSnapshot toSpaceQuotaSnapshot(QuotaProtos.SpaceQuotaSnapshot proto) { 190 return new SpaceQuotaSnapshot(SpaceQuotaStatus.toStatus(proto.getQuotaStatus()), 191 proto.getQuotaUsage(), proto.getQuotaLimit()); 192 } 193 194 public static QuotaProtos.SpaceQuotaSnapshot toProtoSnapshot(SpaceQuotaSnapshot snapshot) { 195 return QuotaProtos.SpaceQuotaSnapshot.newBuilder() 196 .setQuotaStatus(SpaceQuotaStatus.toProto(snapshot.getQuotaStatus())) 197 .setQuotaUsage(snapshot.getUsage()).setQuotaLimit(snapshot.getLimit()).build(); 198 } 199 200 /** 201 * Returns a singleton that corresponds to no snapshot information. 202 */ 203 public static SpaceQuotaSnapshot getNoSuchSnapshot() { 204 return NO_SUCH_SNAPSHOT; 205 } 206}