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.ProtobufUtil; 029import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest; 030import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos; 031import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota; 032 033@InterfaceAudience.Private 034@InterfaceStability.Evolving 035public class ThrottleSettings extends QuotaSettings { 036 final QuotaProtos.ThrottleRequest proto; 037 038 ThrottleSettings(final String userName, final TableName tableName, final String namespace, 039 final String regionServer, final QuotaProtos.ThrottleRequest proto) { 040 super(userName, tableName, namespace, regionServer); 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 public QuotaScope getQuotaScope() { 066 return proto.hasTimedQuota() ? 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 builder.append(String.format("%dreq", timedQuota.getSoftLimit())); 097 break; 098 case REQUEST_SIZE: 099 case WRITE_SIZE: 100 case READ_SIZE: 101 builder.append(sizeToString(timedQuota.getSoftLimit())); 102 break; 103 case REQUEST_CAPACITY_UNIT: 104 case READ_CAPACITY_UNIT: 105 case WRITE_CAPACITY_UNIT: 106 builder.append(String.format("%dCU", timedQuota.getSoftLimit())); 107 break; 108 default: 109 } 110 } else if (timedQuota.hasShare()) { 111 builder.append(String.format("%.2f%%", timedQuota.getShare())); 112 } 113 builder.append('/'); 114 builder.append(timeToString(ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit()))); 115 if (timedQuota.hasScope()) { 116 builder.append(", SCOPE => "); 117 builder.append(timedQuota.getScope().toString()); 118 } 119 } else { 120 builder.append(", LIMIT => NONE"); 121 } 122 return builder.toString(); 123 } 124 125 @Override 126 protected ThrottleSettings merge(QuotaSettings other) throws IOException { 127 if (other instanceof ThrottleSettings) { 128 ThrottleSettings otherThrottle = (ThrottleSettings) other; 129 130 // Make sure this and the other target the same "subject" 131 validateQuotaTarget(other); 132 133 QuotaProtos.ThrottleRequest.Builder builder = proto.toBuilder(); 134 if (!otherThrottle.proto.hasType()) { 135 return null; 136 } 137 138 QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto; 139 if (otherProto.hasTimedQuota()) { 140 if (otherProto.hasTimedQuota()) { 141 validateTimedQuota(otherProto.getTimedQuota()); 142 } 143 144 if (!proto.getType().equals(otherProto.getType())) { 145 throw new IllegalArgumentException( 146 "Cannot merge a ThrottleRequest for " + proto.getType() + " with " + 147 otherProto.getType()); 148 } 149 QuotaProtos.TimedQuota.Builder timedQuotaBuilder = proto.getTimedQuota().toBuilder(); 150 timedQuotaBuilder.mergeFrom(otherProto.getTimedQuota()); 151 152 QuotaProtos.ThrottleRequest mergedReq = builder.setTimedQuota( 153 timedQuotaBuilder.build()).build(); 154 return new ThrottleSettings(getUserName(), getTableName(), getNamespace(), 155 getRegionServer(), mergedReq); 156 } 157 } 158 return this; 159 } 160 161 private void validateTimedQuota(final TimedQuota timedQuota) throws IOException { 162 if (timedQuota.getSoftLimit() < 1) { 163 throw new DoNotRetryIOException(new UnsupportedOperationException( 164 "The throttle limit must be greater then 0, got " + timedQuota.getSoftLimit())); 165 } 166 } 167 168 static ThrottleSettings fromTimedQuota(final String userName, final TableName tableName, 169 final String namespace, final String regionServer, ThrottleType type, 170 QuotaProtos.TimedQuota timedQuota) { 171 QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder(); 172 builder.setType(ProtobufUtil.toProtoThrottleType(type)); 173 builder.setTimedQuota(timedQuota); 174 return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build()); 175 } 176}