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.regex.Matcher; 021import java.util.regex.Pattern; 022import org.apache.hadoop.hbase.HBaseIOException; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * Describe the throttling result. TODO: At some point this will be handled on the client side to 027 * prevent operation to go on the server if the waitInterval is greater than the one got as result 028 * of this exception. 029 */ 030@InterfaceAudience.Public 031public class RpcThrottlingException extends HBaseIOException { 032 033 @InterfaceAudience.Public 034 public enum Type { 035 NumRequestsExceeded, 036 RequestSizeExceeded, 037 NumReadRequestsExceeded, 038 NumWriteRequestsExceeded, 039 WriteSizeExceeded, 040 ReadSizeExceeded, 041 RequestCapacityUnitExceeded, 042 ReadCapacityUnitExceeded, 043 WriteCapacityUnitExceeded, 044 AtomicRequestNumberExceeded, 045 AtomicReadSizeExceeded, 046 AtomicWriteSizeExceeded, 047 } 048 049 private static final String[] MSG_TYPE = new String[] { "number of requests exceeded", 050 "request size limit exceeded", "number of read requests exceeded", 051 "number of write requests exceeded", "write size limit exceeded", "read size limit exceeded", 052 "request capacity unit exceeded", "read capacity unit exceeded", "write capacity unit exceeded", 053 "atomic request number exceeded", "atomic read size exceeded", "atomic write size exceeded" }; 054 055 private static final String MSG_WAIT = " - wait "; 056 057 private long waitInterval; 058 private Type type; 059 060 public RpcThrottlingException(String msg) { 061 super(msg); 062 063 // Dirty workaround to get the information after 064 // ((RemoteException)e.getCause()).unwrapRemoteException() 065 for (int i = 0; i < MSG_TYPE.length; ++i) { 066 int index = msg.indexOf(MSG_TYPE[i]); 067 if (index >= 0) { 068 String waitTimeStr = msg.substring(index + MSG_TYPE[i].length() + MSG_WAIT.length()); 069 type = Type.values()[i]; 070 waitInterval = timeFromString(waitTimeStr); 071 break; 072 } 073 } 074 } 075 076 public RpcThrottlingException(final Type type, final long waitInterval, final String msg) { 077 super(msg); 078 this.waitInterval = waitInterval; 079 this.type = type; 080 } 081 082 public Type getType() { 083 return this.type; 084 } 085 086 public long getWaitInterval() { 087 return this.waitInterval; 088 } 089 090 public static void throwNumRequestsExceeded(final long waitInterval) 091 throws RpcThrottlingException { 092 throwThrottlingException(Type.NumRequestsExceeded, waitInterval); 093 } 094 095 public static void throwRequestSizeExceeded(final long waitInterval) 096 throws RpcThrottlingException { 097 throwThrottlingException(Type.RequestSizeExceeded, waitInterval); 098 } 099 100 public static void throwNumReadRequestsExceeded(final long waitInterval) 101 throws RpcThrottlingException { 102 throwThrottlingException(Type.NumReadRequestsExceeded, waitInterval); 103 } 104 105 public static void throwNumWriteRequestsExceeded(final long waitInterval) 106 throws RpcThrottlingException { 107 throwThrottlingException(Type.NumWriteRequestsExceeded, waitInterval); 108 } 109 110 public static void throwWriteSizeExceeded(final long waitInterval) throws RpcThrottlingException { 111 throwThrottlingException(Type.WriteSizeExceeded, waitInterval); 112 } 113 114 public static void throwReadSizeExceeded(final long waitInterval) throws RpcThrottlingException { 115 throwThrottlingException(Type.ReadSizeExceeded, waitInterval); 116 } 117 118 public static void throwRequestCapacityUnitExceeded(final long waitInterval) 119 throws RpcThrottlingException { 120 throwThrottlingException(Type.RequestCapacityUnitExceeded, waitInterval); 121 } 122 123 public static void throwReadCapacityUnitExceeded(final long waitInterval) 124 throws RpcThrottlingException { 125 throwThrottlingException(Type.ReadCapacityUnitExceeded, waitInterval); 126 } 127 128 public static void throwWriteCapacityUnitExceeded(final long waitInterval) 129 throws RpcThrottlingException { 130 throwThrottlingException(Type.WriteCapacityUnitExceeded, waitInterval); 131 } 132 133 public static void throwAtomicRequestNumberExceeded(final long waitInterval) 134 throws RpcThrottlingException { 135 throwThrottlingException(Type.AtomicRequestNumberExceeded, waitInterval); 136 } 137 138 public static void throwAtomicReadSizeExceeded(final long waitInterval) 139 throws RpcThrottlingException { 140 throwThrottlingException(Type.AtomicReadSizeExceeded, waitInterval); 141 } 142 143 public static void throwAtomicWriteSizeExceeded(final long waitInterval) 144 throws RpcThrottlingException { 145 throwThrottlingException(Type.AtomicWriteSizeExceeded, waitInterval); 146 } 147 148 private static void throwThrottlingException(final Type type, final long waitInterval) 149 throws RpcThrottlingException { 150 String msg = MSG_TYPE[type.ordinal()] + MSG_WAIT + stringFromMillis(waitInterval); 151 throw new RpcThrottlingException(type, waitInterval, msg); 152 } 153 154 // Visible for TestRpcThrottlingException 155 protected static String stringFromMillis(long millis) { 156 StringBuilder buf = new StringBuilder(); 157 long hours = millis / (60 * 60 * 1000); 158 long rem = (millis % (60 * 60 * 1000)); 159 long minutes = rem / (60 * 1000); 160 rem = rem % (60 * 1000); 161 long seconds = rem / 1000; 162 long milliseconds = rem % 1000; 163 164 if (hours != 0) { 165 buf.append(hours); 166 buf.append(hours > 1 ? "hrs, " : "hr, "); 167 } 168 if (minutes != 0) { 169 buf.append(minutes); 170 buf.append(minutes > 1 ? "mins, " : "min, "); 171 } 172 if (seconds != 0) { 173 buf.append(seconds); 174 buf.append("sec, "); 175 } 176 buf.append(milliseconds); 177 buf.append("ms"); 178 return buf.toString(); 179 } 180 181 // Visible for TestRpcThrottlingException 182 protected static long timeFromString(String timeDiff) { 183 Pattern pattern = 184 Pattern.compile("^(?:(\\d+)hrs?, )?(?:(\\d+)mins?, )?(?:(\\d+)sec[, ]{0,2})?(?:(\\d+)ms)?"); 185 long[] factors = new long[] { 60 * 60 * 1000, 60 * 1000, 1000, 1 }; 186 Matcher m = pattern.matcher(timeDiff); 187 if (m.find()) { 188 int numGroups = m.groupCount(); 189 long time = 0; 190 for (int j = 1; j <= numGroups; j++) { 191 String group = m.group(j); 192 if (group == null) { 193 continue; 194 } 195 time += Math.round(Float.parseFloat(group) * factors[j - 1]); 196 } 197 return time; 198 } 199 return -1; 200 } 201}