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 org.apache.hadoop.conf.Configuration; 021import org.apache.hadoop.hbase.HBaseConfiguration; 022import org.apache.yetus.audience.InterfaceAudience; 023import org.apache.yetus.audience.InterfaceStability; 024 025import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 026import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Throttle; 027import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota; 028 029/** 030 * Simple time based limiter that checks the quota Throttle 031 */ 032@InterfaceAudience.Private 033@InterfaceStability.Evolving 034public class TimeBasedLimiter implements QuotaLimiter { 035 private static final Configuration conf = HBaseConfiguration.create(); 036 private RateLimiter reqsLimiter = null; 037 private RateLimiter reqSizeLimiter = null; 038 private RateLimiter writeReqsLimiter = null; 039 private RateLimiter writeSizeLimiter = null; 040 private RateLimiter readReqsLimiter = null; 041 private RateLimiter readSizeLimiter = null; 042 private RateLimiter reqCapacityUnitLimiter = null; 043 private RateLimiter writeCapacityUnitLimiter = null; 044 private RateLimiter readCapacityUnitLimiter = null; 045 046 private TimeBasedLimiter() { 047 if ( 048 FixedIntervalRateLimiter.class.getName().equals( 049 conf.getClass(RateLimiter.QUOTA_RATE_LIMITER_CONF_KEY, AverageIntervalRateLimiter.class) 050 .getName()) 051 ) { 052 long refillInterval = conf.getLong(FixedIntervalRateLimiter.RATE_LIMITER_REFILL_INTERVAL_MS, 053 RateLimiter.DEFAULT_TIME_UNIT); 054 reqsLimiter = new FixedIntervalRateLimiter(refillInterval); 055 reqSizeLimiter = new FixedIntervalRateLimiter(refillInterval); 056 writeReqsLimiter = new FixedIntervalRateLimiter(refillInterval); 057 writeSizeLimiter = new FixedIntervalRateLimiter(refillInterval); 058 readReqsLimiter = new FixedIntervalRateLimiter(refillInterval); 059 readSizeLimiter = new FixedIntervalRateLimiter(refillInterval); 060 reqCapacityUnitLimiter = new FixedIntervalRateLimiter(refillInterval); 061 writeCapacityUnitLimiter = new FixedIntervalRateLimiter(refillInterval); 062 readCapacityUnitLimiter = new FixedIntervalRateLimiter(refillInterval); 063 } else { 064 reqsLimiter = new AverageIntervalRateLimiter(); 065 reqSizeLimiter = new AverageIntervalRateLimiter(); 066 writeReqsLimiter = new AverageIntervalRateLimiter(); 067 writeSizeLimiter = new AverageIntervalRateLimiter(); 068 readReqsLimiter = new AverageIntervalRateLimiter(); 069 readSizeLimiter = new AverageIntervalRateLimiter(); 070 reqCapacityUnitLimiter = new AverageIntervalRateLimiter(); 071 writeCapacityUnitLimiter = new AverageIntervalRateLimiter(); 072 readCapacityUnitLimiter = new AverageIntervalRateLimiter(); 073 } 074 } 075 076 static QuotaLimiter fromThrottle(final Throttle throttle) { 077 TimeBasedLimiter limiter = new TimeBasedLimiter(); 078 boolean isBypass = true; 079 if (throttle.hasReqNum()) { 080 setFromTimedQuota(limiter.reqsLimiter, throttle.getReqNum()); 081 isBypass = false; 082 } 083 084 if (throttle.hasReqSize()) { 085 setFromTimedQuota(limiter.reqSizeLimiter, throttle.getReqSize()); 086 isBypass = false; 087 } 088 089 if (throttle.hasWriteNum()) { 090 setFromTimedQuota(limiter.writeReqsLimiter, throttle.getWriteNum()); 091 isBypass = false; 092 } 093 094 if (throttle.hasWriteSize()) { 095 setFromTimedQuota(limiter.writeSizeLimiter, throttle.getWriteSize()); 096 isBypass = false; 097 } 098 099 if (throttle.hasReadNum()) { 100 setFromTimedQuota(limiter.readReqsLimiter, throttle.getReadNum()); 101 isBypass = false; 102 } 103 104 if (throttle.hasReadSize()) { 105 setFromTimedQuota(limiter.readSizeLimiter, throttle.getReadSize()); 106 isBypass = false; 107 } 108 109 if (throttle.hasReqCapacityUnit()) { 110 setFromTimedQuota(limiter.reqCapacityUnitLimiter, throttle.getReqCapacityUnit()); 111 isBypass = false; 112 } 113 114 if (throttle.hasWriteCapacityUnit()) { 115 setFromTimedQuota(limiter.writeCapacityUnitLimiter, throttle.getWriteCapacityUnit()); 116 isBypass = false; 117 } 118 119 if (throttle.hasReadCapacityUnit()) { 120 setFromTimedQuota(limiter.readCapacityUnitLimiter, throttle.getReadCapacityUnit()); 121 isBypass = false; 122 } 123 return isBypass ? NoopQuotaLimiter.get() : limiter; 124 } 125 126 public void update(final TimeBasedLimiter other) { 127 reqsLimiter.update(other.reqsLimiter); 128 reqSizeLimiter.update(other.reqSizeLimiter); 129 writeReqsLimiter.update(other.writeReqsLimiter); 130 writeSizeLimiter.update(other.writeSizeLimiter); 131 readReqsLimiter.update(other.readReqsLimiter); 132 readSizeLimiter.update(other.readSizeLimiter); 133 reqCapacityUnitLimiter.update(other.reqCapacityUnitLimiter); 134 writeCapacityUnitLimiter.update(other.writeCapacityUnitLimiter); 135 readCapacityUnitLimiter.update(other.readCapacityUnitLimiter); 136 } 137 138 private static void setFromTimedQuota(final RateLimiter limiter, final TimedQuota timedQuota) { 139 limiter.set(timedQuota.getSoftLimit(), ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit())); 140 } 141 142 @Override 143 public void checkQuota(long writeReqs, long estimateWriteSize, long readReqs, 144 long estimateReadSize, long estimateWriteCapacityUnit, long estimateReadCapacityUnit) 145 throws RpcThrottlingException { 146 long waitInterval = reqsLimiter.getWaitIntervalMs(writeReqs + readReqs); 147 if (waitInterval > 0) { 148 RpcThrottlingException.throwNumRequestsExceeded(waitInterval); 149 } 150 waitInterval = reqSizeLimiter.getWaitIntervalMs(estimateWriteSize + estimateReadSize); 151 if (waitInterval > 0) { 152 RpcThrottlingException.throwRequestSizeExceeded(waitInterval); 153 } 154 waitInterval = reqCapacityUnitLimiter 155 .getWaitIntervalMs(estimateWriteCapacityUnit + estimateReadCapacityUnit); 156 if (waitInterval > 0) { 157 RpcThrottlingException.throwRequestCapacityUnitExceeded(waitInterval); 158 } 159 160 if (estimateWriteSize > 0) { 161 waitInterval = writeReqsLimiter.getWaitIntervalMs(writeReqs); 162 if (waitInterval > 0) { 163 RpcThrottlingException.throwNumWriteRequestsExceeded(waitInterval); 164 } 165 waitInterval = writeSizeLimiter.getWaitIntervalMs(estimateWriteSize); 166 if (waitInterval > 0) { 167 RpcThrottlingException.throwWriteSizeExceeded(waitInterval); 168 } 169 waitInterval = writeCapacityUnitLimiter.getWaitIntervalMs(estimateWriteCapacityUnit); 170 if (waitInterval > 0) { 171 RpcThrottlingException.throwWriteCapacityUnitExceeded(waitInterval); 172 } 173 } 174 175 if (estimateReadSize > 0) { 176 waitInterval = readReqsLimiter.getWaitIntervalMs(readReqs); 177 if (waitInterval > 0) { 178 RpcThrottlingException.throwNumReadRequestsExceeded(waitInterval); 179 } 180 waitInterval = readSizeLimiter.getWaitIntervalMs(estimateReadSize); 181 if (waitInterval > 0) { 182 RpcThrottlingException.throwReadSizeExceeded(waitInterval); 183 } 184 waitInterval = readCapacityUnitLimiter.getWaitIntervalMs(estimateReadCapacityUnit); 185 if (waitInterval > 0) { 186 RpcThrottlingException.throwReadCapacityUnitExceeded(waitInterval); 187 } 188 } 189 } 190 191 @Override 192 public void grabQuota(long writeReqs, long writeSize, long readReqs, long readSize, 193 long writeCapacityUnit, long readCapacityUnit) { 194 assert writeSize != 0 || readSize != 0; 195 196 reqsLimiter.consume(writeReqs + readReqs); 197 reqSizeLimiter.consume(writeSize + readSize); 198 199 if (writeSize > 0) { 200 writeReqsLimiter.consume(writeReqs); 201 writeSizeLimiter.consume(writeSize); 202 } 203 if (readSize > 0) { 204 readReqsLimiter.consume(readReqs); 205 readSizeLimiter.consume(readSize); 206 } 207 if (writeCapacityUnit > 0) { 208 reqCapacityUnitLimiter.consume(writeCapacityUnit); 209 writeCapacityUnitLimiter.consume(writeCapacityUnit); 210 } 211 if (readCapacityUnit > 0) { 212 reqCapacityUnitLimiter.consume(readCapacityUnit); 213 readCapacityUnitLimiter.consume(readCapacityUnit); 214 } 215 } 216 217 @Override 218 public void consumeWrite(final long size, long capacityUnit) { 219 reqSizeLimiter.consume(size); 220 writeSizeLimiter.consume(size); 221 reqCapacityUnitLimiter.consume(capacityUnit); 222 writeCapacityUnitLimiter.consume(capacityUnit); 223 } 224 225 @Override 226 public void consumeRead(final long size, long capacityUnit) { 227 reqSizeLimiter.consume(size); 228 readSizeLimiter.consume(size); 229 reqCapacityUnitLimiter.consume(capacityUnit); 230 readCapacityUnitLimiter.consume(capacityUnit); 231 } 232 233 @Override 234 public boolean isBypass() { 235 return false; 236 } 237 238 @Override 239 public long getWriteAvailable() { 240 return writeSizeLimiter.getAvailable(); 241 } 242 243 @Override 244 public long getRequestNumLimit() { 245 long readAndWriteLimit = readReqsLimiter.getLimit() + writeReqsLimiter.getLimit(); 246 247 if (readAndWriteLimit < 0) { // handle overflow 248 readAndWriteLimit = Long.MAX_VALUE; 249 } 250 251 return Math.min(reqsLimiter.getLimit(), readAndWriteLimit); 252 } 253 254 @Override 255 public long getReadNumLimit() { 256 return readReqsLimiter.getLimit(); 257 } 258 259 @Override 260 public long getWriteNumLimit() { 261 return writeReqsLimiter.getLimit(); 262 } 263 264 @Override 265 public long getReadAvailable() { 266 return readSizeLimiter.getAvailable(); 267 } 268 269 @Override 270 public long getReadLimit() { 271 return Math.min(readSizeLimiter.getLimit(), reqSizeLimiter.getLimit()); 272 } 273 274 @Override 275 public long getWriteLimit() { 276 return Math.min(writeSizeLimiter.getLimit(), reqSizeLimiter.getLimit()); 277 } 278 279 @Override 280 public String toString() { 281 StringBuilder builder = new StringBuilder(); 282 builder.append("TimeBasedLimiter("); 283 if (!reqsLimiter.isBypass()) { 284 builder.append("reqs=" + reqsLimiter); 285 } 286 if (!reqSizeLimiter.isBypass()) { 287 builder.append(" resSize=" + reqSizeLimiter); 288 } 289 if (!writeReqsLimiter.isBypass()) { 290 builder.append(" writeReqs=" + writeReqsLimiter); 291 } 292 if (!writeSizeLimiter.isBypass()) { 293 builder.append(" writeSize=" + writeSizeLimiter); 294 } 295 if (!readReqsLimiter.isBypass()) { 296 builder.append(" readReqs=" + readReqsLimiter); 297 } 298 if (!readSizeLimiter.isBypass()) { 299 builder.append(" readSize=" + readSizeLimiter); 300 } 301 if (!reqCapacityUnitLimiter.isBypass()) { 302 builder.append(" reqCapacityUnit=" + reqCapacityUnitLimiter); 303 } 304 if (!writeCapacityUnitLimiter.isBypass()) { 305 builder.append(" writeCapacityUnit=" + writeCapacityUnitLimiter); 306 } 307 if (!readCapacityUnitLimiter.isBypass()) { 308 builder.append(" readCapacityUnit=" + readCapacityUnitLimiter); 309 } 310 builder.append(')'); 311 return builder.toString(); 312 } 313}