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.NotServingRegionException;
28 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
29 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CompactRegionRequest;
30 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.FlushRegionRequest;
31 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
32 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
33 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
34 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
35 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
36 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
37 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
38 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
39 import org.apache.hadoop.hbase.protobuf.generated.RPCProtos.RequestHeader;
40 import org.apache.hadoop.hbase.regionserver.HRegionServer.QosPriority;
41 import org.apache.hadoop.hbase.util.Pair;
42
43 import com.google.common.annotations.VisibleForTesting;
44 import com.google.common.base.Function;
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 class QosFunction implements Function<Pair<RequestHeader, Message>, Integer> {
71 public static final Log LOG = LogFactory.getLog(QosFunction.class.getName());
72 private final Map<String, Integer> annotatedQos;
73
74
75 private HRegionServer hRegionServer;
76 @SuppressWarnings("unchecked")
77 private final Class<? extends Message>[] knownArgumentClasses = new Class[]{
78 GetRegionInfoRequest.class,
79 GetStoreFileRequest.class,
80 CloseRegionRequest.class,
81 FlushRegionRequest.class,
82 SplitRegionRequest.class,
83 CompactRegionRequest.class,
84 GetRequest.class,
85 MutateRequest.class,
86 ScanRequest.class,
87 MultiRequest.class
88 };
89
90
91 private final Map<String, Class<? extends Message>> argumentToClassMap =
92 new HashMap<String, Class<? extends Message>>();
93 private final Map<String, Map<Class<? extends Message>, Method>> methodMap =
94 new HashMap<String, Map<Class<? extends Message>, Method>>();
95
96 QosFunction(final HRegionServer hrs) {
97 this.hRegionServer = hrs;
98 Map<String, Integer> qosMap = new HashMap<String, Integer>();
99 for (Method m : HRegionServer.class.getMethods()) {
100 QosPriority p = m.getAnnotation(QosPriority.class);
101 if (p != null) {
102 qosMap.put(m.getName(), p.priority());
103 }
104 }
105 this.annotatedQos = qosMap;
106
107 if (methodMap.get("getRegion") == null) {
108 methodMap.put("hasRegion", new HashMap<Class<? extends Message>, Method>());
109 methodMap.put("getRegion", new HashMap<Class<? extends Message>, Method>());
110 }
111 for (Class<? extends Message> cls : knownArgumentClasses) {
112 argumentToClassMap.put(cls.getName(), cls);
113 try {
114 methodMap.get("hasRegion").put(cls, cls.getDeclaredMethod("hasRegion"));
115 methodMap.get("getRegion").put(cls, cls.getDeclaredMethod("getRegion"));
116 } catch (Exception e) {
117 throw new RuntimeException(e);
118 }
119 }
120 }
121
122 public boolean isMetaRegion(byte[] regionName) {
123 HRegion region;
124 try {
125 region = hRegionServer.getRegion(regionName);
126 } catch (NotServingRegionException ignored) {
127 return false;
128 }
129 return region.getRegionInfo().isMetaTable();
130 }
131
132 @Override
133 public Integer apply(Pair<RequestHeader, Message> headerAndParam) {
134 RequestHeader header = headerAndParam.getFirst();
135 String methodName = header.getMethodName();
136 Integer priorityByAnnotation = annotatedQos.get(header.getMethodName());
137 if (priorityByAnnotation != null) {
138 return priorityByAnnotation;
139 }
140
141 Message param = headerAndParam.getSecond();
142 if (param == null) {
143 return HConstants.NORMAL_QOS;
144 }
145 String cls = param.getClass().getName();
146 Class<? extends Message> rpcArgClass = argumentToClassMap.get(cls);
147 RegionSpecifier regionSpecifier = null;
148
149 try {
150
151
152
153
154 Method hasRegion = methodMap.get("hasRegion").get(rpcArgClass);
155 if (hasRegion != null && (Boolean)hasRegion.invoke(param, (Object[])null)) {
156 Method getRegion = methodMap.get("getRegion").get(rpcArgClass);
157 regionSpecifier = (RegionSpecifier)getRegion.invoke(param, (Object[])null);
158 HRegion region = hRegionServer.getRegion(regionSpecifier);
159 if (region.getRegionInfo().isMetaTable()) {
160 if (LOG.isTraceEnabled()) {
161 LOG.trace("High priority because region=" + region.getRegionNameAsString());
162 }
163 return HConstants.HIGH_QOS;
164 }
165 }
166 } catch (Exception ex) {
167
168
169 if (LOG.isTraceEnabled()) LOG.trace("Marking normal priority after getting exception=" + ex);
170 return HConstants.NORMAL_QOS;
171 }
172
173 if (methodName.equals("scan")) {
174 ScanRequest request = (ScanRequest)param;
175 if (!request.hasScannerId()) {
176 return HConstants.NORMAL_QOS;
177 }
178 RegionScanner scanner = hRegionServer.getScanner(request.getScannerId());
179 if (scanner != null && scanner.getRegionInfo().isMetaRegion()) {
180 if (LOG.isTraceEnabled()) {
181
182 LOG.trace("High priority scanner request " + TextFormat.shortDebugString(request));
183 }
184 return HConstants.HIGH_QOS;
185 }
186 }
187 return HConstants.NORMAL_QOS;
188 }
189
190 @VisibleForTesting
191 void setRegionServer(final HRegionServer hrs) {
192 this.hRegionServer = hrs;
193 }
194 }