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