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    /** Returns {@code true} if the quota is being violated, {@code false} otherwise. */
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().append(quotaStatus.hashCode()).append(usage).append(limit)
164      .toHashCode();
165  }
166
167  @Override
168  public boolean equals(Object o) {
169    if (o instanceof SpaceQuotaSnapshot) {
170      SpaceQuotaSnapshot other = (SpaceQuotaSnapshot) o;
171      return quotaStatus.equals(other.quotaStatus) && usage == other.usage && limit == other.limit;
172    }
173    return false;
174  }
175
176  @Override
177  public String toString() {
178    StringBuilder sb = new StringBuilder(32);
179    sb.append("SpaceQuotaSnapshot[policy=").append(quotaStatus).append(", use=");
180    sb.append(StringUtils.byteDesc(usage)).append("/");
181    sb.append(StringUtils.byteDesc(limit)).append("]");
182    return sb.toString();
183  }
184
185  // ProtobufUtil is in hbase-client, and this doesn't need to be public.
186  public static SpaceQuotaSnapshot toSpaceQuotaSnapshot(QuotaProtos.SpaceQuotaSnapshot proto) {
187    return new SpaceQuotaSnapshot(SpaceQuotaStatus.toStatus(proto.getQuotaStatus()),
188      proto.getQuotaUsage(), proto.getQuotaLimit());
189  }
190
191  public static QuotaProtos.SpaceQuotaSnapshot toProtoSnapshot(SpaceQuotaSnapshot snapshot) {
192    return QuotaProtos.SpaceQuotaSnapshot.newBuilder()
193      .setQuotaStatus(SpaceQuotaStatus.toProto(snapshot.getQuotaStatus()))
194      .setQuotaUsage(snapshot.getUsage()).setQuotaLimit(snapshot.getLimit()).build();
195  }
196
197  /**
198   * Returns a singleton that corresponds to no snapshot information.
199   */
200  public static SpaceQuotaSnapshot getNoSuchSnapshot() {
201    return NO_SUCH_SNAPSHOT;
202  }
203}