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 } 045 046 private static final String[] MSG_TYPE = 047 new String[] { "number of requests exceeded", "request size limit exceeded", 048 "number of read requests exceeded", "number of write requests exceeded", 049 "write size limit exceeded", "read size limit exceeded", "request capacity unit exceeded", 050 "read capacity unit exceeded", "write capacity unit exceeded" }; 051 052 private static final String MSG_WAIT = " - wait "; 053 054 private long waitInterval; 055 private Type type; 056 057 public RpcThrottlingException(String msg) { 058 super(msg); 059 060 // Dirty workaround to get the information after 061 // ((RemoteException)e.getCause()).unwrapRemoteException() 062 for (int i = 0; i < MSG_TYPE.length; ++i) { 063 int index = msg.indexOf(MSG_TYPE[i]); 064 if (index >= 0) { 065 String waitTimeStr = msg.substring(index + MSG_TYPE[i].length() + MSG_WAIT.length()); 066 type = Type.values()[i]; 067 waitInterval = timeFromString(waitTimeStr); 068 break; 069 } 070 } 071 } 072 073 public RpcThrottlingException(final Type type, final long waitInterval, final String msg) { 074 super(msg); 075 this.waitInterval = waitInterval; 076 this.type = type; 077 } 078 079 public Type getType() { 080 return this.type; 081 } 082 083 public long getWaitInterval() { 084 return this.waitInterval; 085 } 086 087 public static void throwNumRequestsExceeded(final long waitInterval) 088 throws RpcThrottlingException { 089 throwThrottlingException(Type.NumRequestsExceeded, waitInterval); 090 } 091 092 public static void throwRequestSizeExceeded(final long waitInterval) 093 throws RpcThrottlingException { 094 throwThrottlingException(Type.RequestSizeExceeded, waitInterval); 095 } 096 097 public static void throwNumReadRequestsExceeded(final long waitInterval) 098 throws RpcThrottlingException { 099 throwThrottlingException(Type.NumReadRequestsExceeded, waitInterval); 100 } 101 102 public static void throwNumWriteRequestsExceeded(final long waitInterval) 103 throws RpcThrottlingException { 104 throwThrottlingException(Type.NumWriteRequestsExceeded, waitInterval); 105 } 106 107 public static void throwWriteSizeExceeded(final long waitInterval) throws RpcThrottlingException { 108 throwThrottlingException(Type.WriteSizeExceeded, waitInterval); 109 } 110 111 public static void throwReadSizeExceeded(final long waitInterval) throws RpcThrottlingException { 112 throwThrottlingException(Type.ReadSizeExceeded, waitInterval); 113 } 114 115 public static void throwRequestCapacityUnitExceeded(final long waitInterval) 116 throws RpcThrottlingException { 117 throwThrottlingException(Type.RequestCapacityUnitExceeded, waitInterval); 118 } 119 120 public static void throwReadCapacityUnitExceeded(final long waitInterval) 121 throws RpcThrottlingException { 122 throwThrottlingException(Type.ReadCapacityUnitExceeded, waitInterval); 123 } 124 125 public static void throwWriteCapacityUnitExceeded(final long waitInterval) 126 throws RpcThrottlingException { 127 throwThrottlingException(Type.WriteCapacityUnitExceeded, waitInterval); 128 } 129 130 private static void throwThrottlingException(final Type type, final long waitInterval) 131 throws RpcThrottlingException { 132 String msg = MSG_TYPE[type.ordinal()] + MSG_WAIT + stringFromMillis(waitInterval); 133 throw new RpcThrottlingException(type, waitInterval, msg); 134 } 135 136 // Visible for TestRpcThrottlingException 137 protected static String stringFromMillis(long millis) { 138 StringBuilder buf = new StringBuilder(); 139 long hours = millis / (60 * 60 * 1000); 140 long rem = (millis % (60 * 60 * 1000)); 141 long minutes = rem / (60 * 1000); 142 rem = rem % (60 * 1000); 143 long seconds = rem / 1000; 144 long milliseconds = rem % 1000; 145 146 if (hours != 0) { 147 buf.append(hours); 148 buf.append(hours > 1 ? "hrs, " : "hr, "); 149 } 150 if (minutes != 0) { 151 buf.append(minutes); 152 buf.append(minutes > 1 ? "mins, " : "min, "); 153 } 154 if (seconds != 0) { 155 buf.append(seconds); 156 buf.append("sec, "); 157 } 158 buf.append(milliseconds); 159 buf.append("ms"); 160 return buf.toString(); 161 } 162 163 // Visible for TestRpcThrottlingException 164 protected static long timeFromString(String timeDiff) { 165 Pattern pattern = 166 Pattern.compile("^(?:(\\d+)hrs?, )?(?:(\\d+)mins?, )?(?:(\\d+)sec[, ]{0,2})?(?:(\\d+)ms)?"); 167 long[] factors = new long[] { 60 * 60 * 1000, 60 * 1000, 1000, 1 }; 168 Matcher m = pattern.matcher(timeDiff); 169 if (m.find()) { 170 int numGroups = m.groupCount(); 171 long time = 0; 172 for (int j = 1; j <= numGroups; j++) { 173 String group = m.group(j); 174 if (group == null) { 175 continue; 176 } 177 time += Math.round(Float.parseFloat(group) * factors[j - 1]); 178 } 179 return time; 180 } 181 return -1; 182 } 183}