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