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 com.google.protobuf.Message;
21 import com.google.protobuf.TextFormat;
22 import java.lang.reflect.Method;
23 import java.util.HashMap;
24 import java.util.Map;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.ipc.PriorityFunction;
31 import org.apache.hadoop.hbase.ipc.QosPriority;
32 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
33 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CompactRegionRequest;
34 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.FlushRegionRequest;
35 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
36 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
37 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
38 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
39 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
40 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
41 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
42 import org.apache.hadoop.hbase.protobuf.generated.RPCProtos.RequestHeader;
43 import org.apache.hadoop.hbase.security.User;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 @InterfaceAudience.Private
67 public class AnnotationReadingPriorityFunction implements PriorityFunction {
68 private static final Log LOG =
69 LogFactory.getLog(AnnotationReadingPriorityFunction.class.getName());
70
71
72 public static final String SCAN_VTIME_WEIGHT_CONF_KEY = "hbase.ipc.server.scan.vtime.weight";
73
74 protected final Map<String, Integer> annotatedQos;
75
76
77 private RSRpcServices rpcServices;
78 @SuppressWarnings("unchecked")
79 private final Class<? extends Message>[] knownArgumentClasses = new Class[]{
80 GetRegionInfoRequest.class,
81 GetStoreFileRequest.class,
82 CloseRegionRequest.class,
83 FlushRegionRequest.class,
84 SplitRegionRequest.class,
85 CompactRegionRequest.class,
86 GetRequest.class,
87 MutateRequest.class,
88 ScanRequest.class
89 };
90
91
92 private final Map<String, Class<? extends Message>> argumentToClassMap =
93 new HashMap<String, Class<? extends Message>>();
94 private final Map<String, Map<Class<? extends Message>, Method>> methodMap =
95 new HashMap<String, Map<Class<? extends Message>, Method>>();
96
97 private final float scanVirtualTimeWeight;
98
99
100
101
102
103
104
105
106 public AnnotationReadingPriorityFunction(final RSRpcServices rpcServices) {
107 this(rpcServices, rpcServices.getClass());
108 }
109
110
111
112
113
114
115
116
117
118
119 public AnnotationReadingPriorityFunction(final RSRpcServices rpcServices,
120 Class<? extends RSRpcServices> clz) {
121 Map<String,Integer> qosMap = new HashMap<String,Integer>();
122 for (Method m : clz.getMethods()) {
123 QosPriority p = m.getAnnotation(QosPriority.class);
124 if (p != null) {
125
126
127
128
129
130 String capitalizedMethodName = capitalize(m.getName());
131 qosMap.put(capitalizedMethodName, p.priority());
132 }
133 }
134 this.rpcServices = rpcServices;
135 this.annotatedQos = qosMap;
136 if (methodMap.get("getRegion") == null) {
137 methodMap.put("hasRegion", new HashMap<Class<? extends Message>, Method>());
138 methodMap.put("getRegion", new HashMap<Class<? extends Message>, Method>());
139 }
140 for (Class<? extends Message> cls : knownArgumentClasses) {
141 argumentToClassMap.put(cls.getName(), cls);
142 try {
143 methodMap.get("hasRegion").put(cls, cls.getDeclaredMethod("hasRegion"));
144 methodMap.get("getRegion").put(cls, cls.getDeclaredMethod("getRegion"));
145 } catch (Exception e) {
146 throw new RuntimeException(e);
147 }
148 }
149
150 Configuration conf = rpcServices.getConfiguration();
151 scanVirtualTimeWeight = conf.getFloat(SCAN_VTIME_WEIGHT_CONF_KEY, 1.0f);
152 }
153
154 private String capitalize(final String s) {
155 StringBuilder strBuilder = new StringBuilder(s);
156 strBuilder.setCharAt(0, Character.toUpperCase(strBuilder.charAt(0)));
157 return strBuilder.toString();
158 }
159
160
161
162
163
164
165
166
167
168 @Override
169 public int getPriority(RequestHeader header, Message param, User user) {
170 int priorityByAnnotation = getAnnotatedPriority(header);
171
172 if (priorityByAnnotation >= 0) {
173 return priorityByAnnotation;
174 }
175 return getBasePriority(header, param);
176 }
177
178
179
180
181
182
183
184 protected int getAnnotatedPriority(RequestHeader header) {
185 String methodName = header.getMethodName();
186 Integer priorityByAnnotation = annotatedQos.get(methodName);
187 if (priorityByAnnotation != null) {
188 return priorityByAnnotation;
189 }
190 return -1;
191 }
192
193
194
195
196
197
198 protected int getBasePriority(RequestHeader header, Message param) {
199 if (param == null) {
200 return HConstants.NORMAL_QOS;
201 }
202
203
204 if (header.hasPriority()) {
205 return header.getPriority();
206 }
207
208 String cls = param.getClass().getName();
209 Class<? extends Message> rpcArgClass = argumentToClassMap.get(cls);
210 RegionSpecifier regionSpecifier = null;
211
212 try {
213
214
215
216
217 Method hasRegion = methodMap.get("hasRegion").get(rpcArgClass);
218 if (hasRegion != null && (Boolean)hasRegion.invoke(param, (Object[])null)) {
219 Method getRegion = methodMap.get("getRegion").get(rpcArgClass);
220 regionSpecifier = (RegionSpecifier)getRegion.invoke(param, (Object[])null);
221 Region region = rpcServices.getRegion(regionSpecifier);
222 if (region.getRegionInfo().isSystemTable()) {
223 if (LOG.isTraceEnabled()) {
224 LOG.trace("High priority because region=" +
225 region.getRegionInfo().getRegionNameAsString());
226 }
227 return HConstants.SYSTEMTABLE_QOS;
228 }
229 }
230 } catch (Exception ex) {
231
232
233 if (LOG.isTraceEnabled()) LOG.trace("Marking normal priority after getting exception=" + ex);
234 return HConstants.NORMAL_QOS;
235 }
236
237 if (param instanceof ScanRequest) {
238 ScanRequest request = (ScanRequest)param;
239 if (!request.hasScannerId()) {
240 return HConstants.NORMAL_QOS;
241 }
242 RegionScanner scanner = rpcServices.getScanner(request.getScannerId());
243 if (scanner != null && scanner.getRegionInfo().isSystemTable()) {
244 if (LOG.isTraceEnabled()) {
245
246 LOG.trace("High priority scanner request " + TextFormat.shortDebugString(request));
247 }
248 return HConstants.SYSTEMTABLE_QOS;
249 }
250 }
251
252 return HConstants.NORMAL_QOS;
253 }
254
255
256
257
258
259
260
261
262 @Override
263 public long getDeadline(RequestHeader header, Message param) {
264 if (param instanceof ScanRequest) {
265 ScanRequest request = (ScanRequest)param;
266 if (!request.hasScannerId()) {
267 return 0;
268 }
269
270
271
272
273 long vtime = rpcServices.getScannerVirtualTime(request.getScannerId());
274 return Math.round(Math.sqrt(vtime * scanVirtualTimeWeight));
275 }
276 return 0;
277 }
278
279 void setRegionServer(final HRegionServer hrs) {
280 this.rpcServices = hrs.getRSRpcServices();
281 }
282 }