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.io.IOException; 021import java.util.concurrent.TimeUnit; 022 023import org.apache.hadoop.hbase.DoNotRetryIOException; 024import org.apache.hadoop.hbase.TableName; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.yetus.audience.InterfaceStability; 027import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 028import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest; 029import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota; 030import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 031import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos; 032 033@InterfaceAudience.Private 034@InterfaceStability.Evolving 035class ThrottleSettings extends QuotaSettings { 036 final QuotaProtos.ThrottleRequest proto; 037 038 ThrottleSettings(final String userName, final TableName tableName, 039 final String namespace, final QuotaProtos.ThrottleRequest proto) { 040 super(userName, tableName, namespace); 041 this.proto = proto; 042 } 043 044 public ThrottleType getThrottleType() { 045 return ProtobufUtil.toThrottleType(proto.getType()); 046 } 047 048 public long getSoftLimit() { 049 return proto.hasTimedQuota() ? proto.getTimedQuota().getSoftLimit() : -1; 050 } 051 052 /** 053 * Returns a copy of the internal state of <code>this</code> 054 */ 055 @VisibleForTesting 056 QuotaProtos.ThrottleRequest getProto() { 057 return proto.toBuilder().build(); 058 } 059 060 public TimeUnit getTimeUnit() { 061 return proto.hasTimedQuota() ? 062 ProtobufUtil.toTimeUnit(proto.getTimedQuota().getTimeUnit()) : null; 063 } 064 065 @Override 066 public QuotaType getQuotaType() { 067 return QuotaType.THROTTLE; 068 } 069 070 @Override 071 protected void setupSetQuotaRequest(SetQuotaRequest.Builder builder) { 072 builder.setThrottle(proto); 073 } 074 075 @Override 076 public String toString() { 077 StringBuilder builder = new StringBuilder(); 078 builder.append("TYPE => THROTTLE"); 079 if (proto.hasType()) { 080 builder.append(", THROTTLE_TYPE => "); 081 builder.append(proto.getType().toString()); 082 } 083 if (proto.hasTimedQuota()) { 084 QuotaProtos.TimedQuota timedQuota = proto.getTimedQuota(); 085 builder.append(", LIMIT => "); 086 if (timedQuota.hasSoftLimit()) { 087 switch (getThrottleType()) { 088 case REQUEST_NUMBER: 089 case WRITE_NUMBER: 090 case READ_NUMBER: 091 builder.append(String.format("%dreq", timedQuota.getSoftLimit())); 092 break; 093 case REQUEST_SIZE: 094 case WRITE_SIZE: 095 case READ_SIZE: 096 builder.append(sizeToString(timedQuota.getSoftLimit())); 097 break; 098 } 099 } else if (timedQuota.hasShare()) { 100 builder.append(String.format("%.2f%%", timedQuota.getShare())); 101 } 102 builder.append('/'); 103 builder.append(timeToString(ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit()))); 104 if (timedQuota.hasScope()) { 105 builder.append(", SCOPE => "); 106 builder.append(timedQuota.getScope().toString()); 107 } 108 } else { 109 builder.append(", LIMIT => NONE"); 110 } 111 return builder.toString(); 112 } 113 114 @Override 115 protected ThrottleSettings merge(QuotaSettings other) throws IOException { 116 if (other instanceof ThrottleSettings) { 117 ThrottleSettings otherThrottle = (ThrottleSettings) other; 118 119 // Make sure this and the other target the same "subject" 120 validateQuotaTarget(other); 121 122 QuotaProtos.ThrottleRequest.Builder builder = proto.toBuilder(); 123 if (!otherThrottle.proto.hasType()) { 124 return null; 125 } 126 127 QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto; 128 if (otherProto.hasTimedQuota()) { 129 if (otherProto.hasTimedQuota()) { 130 validateTimedQuota(otherProto.getTimedQuota()); 131 } 132 133 if (!proto.getType().equals(otherProto.getType())) { 134 throw new IllegalArgumentException( 135 "Cannot merge a ThrottleRequest for " + proto.getType() + " with " + 136 otherProto.getType()); 137 } 138 QuotaProtos.TimedQuota.Builder timedQuotaBuilder = proto.getTimedQuota().toBuilder(); 139 timedQuotaBuilder.mergeFrom(otherProto.getTimedQuota()); 140 141 QuotaProtos.ThrottleRequest mergedReq = builder.setTimedQuota( 142 timedQuotaBuilder.build()).build(); 143 return new ThrottleSettings(getUserName(), getTableName(), getNamespace(), mergedReq); 144 } 145 } 146 return this; 147 } 148 149 private void validateTimedQuota(final TimedQuota timedQuota) throws IOException { 150 if (timedQuota.getSoftLimit() < 1) { 151 throw new DoNotRetryIOException(new UnsupportedOperationException( 152 "The throttle limit must be greater then 0, got " + timedQuota.getSoftLimit())); 153 } 154 } 155 156 static ThrottleSettings fromTimedQuota(final String userName, 157 final TableName tableName, final String namespace, 158 ThrottleType type, QuotaProtos.TimedQuota timedQuota) { 159 QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder(); 160 builder.setType(ProtobufUtil.toProtoThrottleType(type)); 161 builder.setTimedQuota(timedQuota); 162 return new ThrottleSettings(userName, tableName, namespace, builder.build()); 163 } 164}