1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver;
19
20 import java.lang.reflect.Method;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.hbase.HConstants;
27 import org.apache.hadoop.hbase.TableName;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.NotServingRegionException;
30 import org.apache.hadoop.hbase.ipc.PriorityFunction;
31 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
32 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
33 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.ReportRegionStateTransitionRequest;
34 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionStateTransition;
35 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
36 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CompactRegionRequest;
37 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.FlushRegionRequest;
38 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
39 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
40 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
41 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
42 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
43 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
44 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
45 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
46 import org.apache.hadoop.hbase.protobuf.generated.RPCProtos.RequestHeader;
47 import org.apache.hadoop.hbase.regionserver.HRegionServer.QosPriority;
48
49 import com.google.common.annotations.VisibleForTesting;
50 import com.google.protobuf.Message;
51 import com.google.protobuf.TextFormat;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 @InterfaceAudience.Private
76 class AnnotationReadingPriorityFunction implements PriorityFunction {
77 public static final Log LOG =
78 LogFactory.getLog(AnnotationReadingPriorityFunction.class.getName());
79 private final Map<String, Integer> annotatedQos;
80
81
82 private HRegionServer hRegionServer;
83 @SuppressWarnings("unchecked")
84 private final Class<? extends Message>[] knownArgumentClasses = new Class[]{
85 GetRegionInfoRequest.class,
86 GetStoreFileRequest.class,
87 CloseRegionRequest.class,
88 FlushRegionRequest.class,
89 SplitRegionRequest.class,
90 CompactRegionRequest.class,
91 GetRequest.class,
92 MutateRequest.class,
93 ScanRequest.class
94 };
95
96
97 private final Map<String, Class<? extends Message>> argumentToClassMap =
98 new HashMap<String, Class<? extends Message>>();
99 private final Map<String, Map<Class<? extends Message>, Method>> methodMap =
100 new HashMap<String, Map<Class<? extends Message>, Method>>();
101
102 AnnotationReadingPriorityFunction(final HRegionServer hrs) {
103 this.hRegionServer = hrs;
104 Map<String, Integer> qosMap = new HashMap<String, Integer>();
105 for (Method m : HRegionServer.class.getMethods()) {
106 QosPriority p = m.getAnnotation(QosPriority.class);
107 if (p != null) {
108
109
110
111
112
113 String capitalizedMethodName = capitalize(m.getName());
114 qosMap.put(capitalizedMethodName, p.priority());
115 }
116 }
117 this.annotatedQos = qosMap;
118 if (methodMap.get("getRegion") == null) {
119 methodMap.put("hasRegion", new HashMap<Class<? extends Message>, Method>());
120 methodMap.put("getRegion", new HashMap<Class<? extends Message>, Method>());
121 }
122 for (Class<? extends Message> cls : knownArgumentClasses) {
123 argumentToClassMap.put(cls.getName(), cls);
124 try {
125 methodMap.get("hasRegion").put(cls, cls.getDeclaredMethod("hasRegion"));
126 methodMap.get("getRegion").put(cls, cls.getDeclaredMethod("getRegion"));
127 } catch (Exception e) {
128 throw new RuntimeException(e);
129 }
130 }
131 }
132
133 private String capitalize(final String s) {
134 StringBuilder strBuilder = new StringBuilder(s);
135 strBuilder.setCharAt(0, Character.toUpperCase(strBuilder.charAt(0)));
136 return strBuilder.toString();
137 }
138
139 public boolean isMetaRegion(byte[] regionName) {
140 HRegion region;
141 try {
142 region = hRegionServer.getRegion(regionName);
143 } catch (NotServingRegionException ignored) {
144 return false;
145 }
146 return region.getRegionInfo().isMetaTable();
147 }
148
149 @Override
150 public int getPriority(RequestHeader header, Message param) {
151 String methodName = header.getMethodName();
152 Integer priorityByAnnotation = annotatedQos.get(methodName);
153 if (priorityByAnnotation != null) {
154 return priorityByAnnotation;
155 }
156 if (param == null) {
157 return HConstants.NORMAL_QOS;
158 }
159 if (param instanceof MultiRequest) {
160
161
162 return header.hasPriority()? header.getPriority(): HConstants.NORMAL_QOS;
163 }
164 String cls = param.getClass().getName();
165 Class<? extends Message> rpcArgClass = argumentToClassMap.get(cls);
166 RegionSpecifier regionSpecifier = null;
167
168 try {
169
170
171
172
173 Method hasRegion = methodMap.get("hasRegion").get(rpcArgClass);
174 if (hasRegion != null && (Boolean)hasRegion.invoke(param, (Object[])null)) {
175 Method getRegion = methodMap.get("getRegion").get(rpcArgClass);
176 regionSpecifier = (RegionSpecifier)getRegion.invoke(param, (Object[])null);
177 HRegion region = hRegionServer.getRegion(regionSpecifier);
178 if (region.getRegionInfo().isMetaTable()) {
179 if (LOG.isTraceEnabled()) {
180 LOG.trace("High priority because region=" + region.getRegionNameAsString());
181 }
182 return HConstants.HIGH_QOS;
183 }
184 }
185 } catch (Exception ex) {
186
187
188 if (LOG.isTraceEnabled()) LOG.trace("Marking normal priority after getting exception=" + ex);
189 return HConstants.NORMAL_QOS;
190 }
191
192 if (param instanceof ScanRequest) {
193 ScanRequest request = (ScanRequest)param;
194 if (!request.hasScannerId()) {
195 return HConstants.NORMAL_QOS;
196 }
197 RegionScanner scanner = hRegionServer.getScanner(request.getScannerId());
198 if (scanner != null && scanner.getRegionInfo().isMetaRegion()) {
199 if (LOG.isTraceEnabled()) {
200
201 LOG.trace("High priority scanner request " + TextFormat.shortDebugString(request));
202 }
203 return HConstants.HIGH_QOS;
204 }
205 }
206
207
208
209 if (param instanceof ReportRegionStateTransitionRequest) {
210 ReportRegionStateTransitionRequest tRequest = (ReportRegionStateTransitionRequest) param;
211 for (RegionStateTransition transition : tRequest.getTransitionList()) {
212 if (transition.getRegionInfoList() != null) {
213 for (HBaseProtos.RegionInfo info : transition.getRegionInfoList()) {
214 TableName tn = ProtobufUtil.toTableName(info.getTableName());
215 if (tn.isSystemTable()) {
216 return HConstants.HIGH_QOS;
217 }
218 }
219 }
220 }
221 }
222 return HConstants.NORMAL_QOS;
223 }
224
225 @VisibleForTesting
226 void setRegionServer(final HRegionServer hrs) {
227 this.hRegionServer = hrs;
228 }
229 }