View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
8    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
9    * for the specific language governing permissions and limitations under the License.
10   */
11  
12  package org.apache.hadoop.hbase.quotas;
13  
14  import java.util.regex.Matcher;
15  import java.util.regex.Pattern;
16  
17  import org.apache.hadoop.hbase.classification.InterfaceAudience;
18  import org.apache.hadoop.hbase.classification.InterfaceStability;
19  
20  /**
21   * Describe the throttling result. TODO: At some point this will be handled on the client side to
22   * prevent operation to go on the server if the waitInterval is grater than the one got as result of
23   * this exception.
24   */
25  @InterfaceAudience.Public
26  @InterfaceStability.Evolving
27  public class ThrottlingException extends QuotaExceededException {
28    private static final long serialVersionUID = 1406576492085155743L;
29  
30    @InterfaceAudience.Public
31    @InterfaceStability.Evolving
32    public enum Type {
33      NumRequestsExceeded, RequestSizeExceeded, NumReadRequestsExceeded, NumWriteRequestsExceeded,
34      WriteSizeExceeded, ReadSizeExceeded,
35    }
36  
37    private static final String[] MSG_TYPE =
38        new String[] { "number of requests exceeded", "request size limit exceeded",
39            "number of read requests exceeded", "number of write requests exceeded",
40            "write size limit exceeded", "read size limit exceeded", };
41  
42    private static final String MSG_WAIT = " - wait ";
43  
44    private long waitInterval;
45    private Type type;
46  
47    public ThrottlingException(String msg) {
48      super(msg);
49  
50      // Dirty workaround to get the information after
51      // ((RemoteException)e.getCause()).unwrapRemoteException()
52      for (int i = 0; i < MSG_TYPE.length; ++i) {
53        int index = msg.indexOf(MSG_TYPE[i]);
54        if (index >= 0) {
55          String waitTimeStr = msg.substring(index + MSG_TYPE[i].length() + MSG_WAIT.length());
56          type = Type.values()[i];
57          waitInterval = timeFromString(waitTimeStr);
58          break;
59        }
60      }
61    }
62  
63    public ThrottlingException(final Type type, final long waitInterval, final String msg) {
64      super(msg);
65      this.waitInterval = waitInterval;
66      this.type = type;
67    }
68  
69    public Type getType() {
70      return this.type;
71    }
72  
73    public long getWaitInterval() {
74      return this.waitInterval;
75    }
76  
77    public static void throwNumRequestsExceeded(final long waitInterval) throws ThrottlingException {
78      throwThrottlingException(Type.NumRequestsExceeded, waitInterval);
79    }
80    
81    public static void throwRequestSizeExceeded(final long waitInterval)
82        throws ThrottlingException {
83      throwThrottlingException(Type.RequestSizeExceeded, waitInterval);
84    }
85  
86    public static void throwNumReadRequestsExceeded(final long waitInterval)
87        throws ThrottlingException {
88      throwThrottlingException(Type.NumReadRequestsExceeded, waitInterval);
89    }
90  
91    public static void throwNumWriteRequestsExceeded(final long waitInterval)
92        throws ThrottlingException {
93      throwThrottlingException(Type.NumWriteRequestsExceeded, waitInterval);
94    }
95  
96    public static void throwWriteSizeExceeded(final long waitInterval) throws ThrottlingException {
97      throwThrottlingException(Type.WriteSizeExceeded, waitInterval);
98    }
99  
100   public static void throwReadSizeExceeded(final long waitInterval) throws ThrottlingException {
101     throwThrottlingException(Type.ReadSizeExceeded, waitInterval);
102   }
103 
104   private static void throwThrottlingException(final Type type, final long waitInterval)
105       throws ThrottlingException {
106     String msg = MSG_TYPE[type.ordinal()] + MSG_WAIT + formatTime(waitInterval);
107     throw new ThrottlingException(type, waitInterval, msg);
108   }
109 
110   public static String formatTime(long timeDiff) {
111     StringBuilder buf = new StringBuilder();
112     long hours = timeDiff / (60 * 60 * 1000);
113     long rem = (timeDiff % (60 * 60 * 1000));
114     long minutes = rem / (60 * 1000);
115     rem = rem % (60 * 1000);
116     float seconds = rem / 1000.0f;
117 
118     if (hours != 0) {
119       buf.append(hours);
120       buf.append("hrs, ");
121     }
122     if (minutes != 0) {
123       buf.append(minutes);
124       buf.append("mins, ");
125     }
126     buf.append(String.format("%.2fsec", seconds));
127     return buf.toString();
128   }
129 
130   private static long timeFromString(String timeDiff) {
131     Pattern[] patterns =
132         new Pattern[] { Pattern.compile("^(\\d+\\.\\d\\d)sec"),
133             Pattern.compile("^(\\d+)mins, (\\d+\\.\\d\\d)sec"),
134             Pattern.compile("^(\\d+)hrs, (\\d+)mins, (\\d+\\.\\d\\d)sec") };
135 
136     for (int i = 0; i < patterns.length; ++i) {
137       Matcher m = patterns[i].matcher(timeDiff);
138       if (m.find()) {
139         long time = Math.round(Float.parseFloat(m.group(1 + i)) * 1000);
140         if (i > 0) {
141           time += Long.parseLong(m.group(i)) * (60 * 1000);
142         }
143         if (i > 1) {
144           time += Long.parseLong(m.group(i - 1)) * (60 * 60 * 1000);
145         }
146         return time;
147       }
148     }
149 
150     return -1;
151   }
152 }