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