1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import java.io.IOException;
22 import java.util.Comparator;
23 import java.util.List;
24
25 import org.apache.commons.lang.ClassUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.CellScanner;
30 import org.apache.hadoop.hbase.Coprocessor;
31 import org.apache.hadoop.hbase.CoprocessorEnvironment;
32 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
33 import org.apache.hadoop.hbase.MetaMutationAnnotation;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.hbase.classification.InterfaceStability;
36 import org.apache.hadoop.hbase.client.Mutation;
37 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
38 import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor;
39 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
40 import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
41 import org.apache.hadoop.hbase.coprocessor.RegionServerObserver;
42 import org.apache.hadoop.hbase.coprocessor.SingletonCoprocessorService;
43
44 import org.apache.hadoop.hbase.ipc.RpcServer;
45 import org.apache.hadoop.hbase.metrics.MetricRegistry;
46 import org.apache.hadoop.hbase.replication.ReplicationEndpoint;
47 import org.apache.hadoop.hbase.security.User;
48 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.WALEntry;
49
50 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
51 @InterfaceStability.Evolving
52 public class RegionServerCoprocessorHost extends
53 CoprocessorHost<RegionServerCoprocessorHost.RegionServerEnvironment> {
54
55 private static final Log LOG = LogFactory.getLog(RegionServerCoprocessorHost.class);
56
57 private RegionServerServices rsServices;
58
59 public RegionServerCoprocessorHost(RegionServerServices rsServices,
60 Configuration conf) {
61 super(rsServices);
62 this.rsServices = rsServices;
63 this.conf = conf;
64
65
66
67 boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
68 DEFAULT_COPROCESSORS_ENABLED);
69 boolean tableCoprocessorsEnabled = conf.getBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY,
70 DEFAULT_USER_COPROCESSORS_ENABLED);
71 LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
72 LOG.info("Table coprocessor loading is " +
73 ((coprocessorsEnabled && tableCoprocessorsEnabled) ? "enabled" : "disabled"));
74 loadSystemCoprocessors(conf, REGIONSERVER_COPROCESSOR_CONF_KEY);
75 }
76
77 @Override
78 public RegionServerEnvironment createEnvironment(Class<?> implClass,
79 Coprocessor instance, int priority, int sequence, Configuration conf) {
80 return new RegionServerEnvironment(implClass, instance, priority,
81 sequence, conf, this.rsServices);
82 }
83
84 public void preStop(String message) throws IOException {
85
86
87 execShutdown(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
88 @Override
89 public void call(RegionServerObserver oserver,
90 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
91 oserver.preStopRegionServer(ctx);
92 }
93 @Override
94 public void postEnvCall(RegionServerEnvironment env) {
95
96 shutdown(env);
97 }
98 });
99 }
100
101 public boolean preMerge(final HRegion regionA, final HRegion regionB, final User user)
102 throws IOException {
103 return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
104 @Override
105 public void call(RegionServerObserver oserver,
106 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
107 oserver.preMerge(ctx, regionA, regionB);
108 }
109 });
110 }
111
112 public void postMerge(final HRegion regionA, final HRegion regionB, final HRegion mergedRegion,
113 final User user) throws IOException {
114 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
115 @Override
116 public void call(RegionServerObserver oserver,
117 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
118 oserver.postMerge(ctx, regionA, regionB, mergedRegion);
119 }
120 });
121 }
122
123 public boolean preMergeCommit(final HRegion regionA, final HRegion regionB,
124 final @MetaMutationAnnotation List<Mutation> metaEntries, final User user)
125 throws IOException {
126 return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
127 @Override
128 public void call(RegionServerObserver oserver,
129 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
130 oserver.preMergeCommit(ctx, regionA, regionB, metaEntries);
131 }
132 });
133 }
134
135 public void postMergeCommit(final HRegion regionA, final HRegion regionB,
136 final HRegion mergedRegion, final User user) throws IOException {
137 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
138 @Override
139 public void call(RegionServerObserver oserver,
140 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
141 oserver.postMergeCommit(ctx, regionA, regionB, mergedRegion);
142 }
143 });
144 }
145
146 public void preRollBackMerge(final HRegion regionA, final HRegion regionB, final User user)
147 throws IOException {
148 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
149 @Override
150 public void call(RegionServerObserver oserver,
151 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
152 oserver.preRollBackMerge(ctx, regionA, regionB);
153 }
154 });
155 }
156
157 public void postRollBackMerge(final HRegion regionA, final HRegion regionB, final User user)
158 throws IOException {
159 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
160 @Override
161 public void call(RegionServerObserver oserver,
162 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
163 oserver.postRollBackMerge(ctx, regionA, regionB);
164 }
165 });
166 }
167
168 public void preRollWALWriterRequest() throws IOException {
169 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
170 @Override
171 public void call(RegionServerObserver oserver,
172 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
173 oserver.preRollWALWriterRequest(ctx);
174 }
175 });
176 }
177
178 public void postRollWALWriterRequest() throws IOException {
179 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
180 @Override
181 public void call(RegionServerObserver oserver,
182 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
183 oserver.postRollWALWriterRequest(ctx);
184 }
185 });
186 }
187
188 public void preReplicateLogEntries(final List<WALEntry> entries, final CellScanner cells)
189 throws IOException {
190 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
191 @Override
192 public void call(RegionServerObserver oserver,
193 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
194 oserver.preReplicateLogEntries(ctx, entries, cells);
195 }
196 });
197 }
198
199 public void postReplicateLogEntries(final List<WALEntry> entries, final CellScanner cells)
200 throws IOException {
201 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
202 @Override
203 public void call(RegionServerObserver oserver,
204 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
205 oserver.postReplicateLogEntries(ctx, entries, cells);
206 }
207 });
208 }
209
210 public ReplicationEndpoint postCreateReplicationEndPoint(final ReplicationEndpoint endpoint)
211 throws IOException {
212 return execOperationWithResult(endpoint, coprocessors.isEmpty() ? null
213 : new CoprocessOperationWithResult<ReplicationEndpoint>() {
214 @Override
215 public void call(RegionServerObserver oserver,
216 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
217 setResult(oserver.postCreateReplicationEndPoint(ctx, getResult()));
218 }
219 });
220 }
221
222 private <T> T execOperationWithResult(final T defaultValue,
223 final CoprocessOperationWithResult<T> ctx) throws IOException {
224 if (ctx == null)
225 return defaultValue;
226 ctx.setResult(defaultValue);
227 execOperation(ctx);
228 return ctx.getResult();
229 }
230
231 private static abstract class CoprocessorOperation
232 extends ObserverContext<RegionServerCoprocessorEnvironment> {
233 public CoprocessorOperation() {
234 this(RpcServer.getRequestUser());
235 }
236
237 public CoprocessorOperation(User user) {
238 super(user);
239 }
240
241 public abstract void call(RegionServerObserver oserver,
242 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException;
243
244 public void postEnvCall(RegionServerEnvironment env) {
245 }
246 }
247
248 private static abstract class CoprocessOperationWithResult<T> extends CoprocessorOperation {
249 private T result = null;
250
251 public void setResult(final T result) {
252 this.result = result;
253 }
254
255 public T getResult() {
256 return this.result;
257 }
258 }
259
260 private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
261 if (ctx == null) return false;
262 boolean bypass = false;
263 List<RegionServerEnvironment> envs = coprocessors.get();
264 for (int i = 0; i < envs.size(); i++) {
265 RegionServerEnvironment env = envs.get(i);
266 if (env.getInstance() instanceof RegionServerObserver) {
267 ctx.prepare(env);
268 Thread currentThread = Thread.currentThread();
269 ClassLoader cl = currentThread.getContextClassLoader();
270 try {
271 currentThread.setContextClassLoader(env.getClassLoader());
272 ctx.call((RegionServerObserver)env.getInstance(), ctx);
273 } catch (Throwable e) {
274 handleCoprocessorThrowable(env, e);
275 } finally {
276 currentThread.setContextClassLoader(cl);
277 }
278 bypass |= ctx.shouldBypass();
279 if (ctx.shouldComplete()) {
280 break;
281 }
282 }
283 ctx.postEnvCall(env);
284 }
285 return bypass;
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300 private boolean execShutdown(final CoprocessorOperation ctx) throws IOException {
301 if (ctx == null) return false;
302 boolean bypass = false;
303 List<RegionServerEnvironment> envs = coprocessors.get();
304 int envsSize = envs.size();
305
306 for (int i = 0; i < envsSize; i++) {
307 RegionServerEnvironment env = envs.get(i);
308 if (env.getInstance() instanceof RegionServerObserver) {
309 ctx.prepare(env);
310 Thread currentThread = Thread.currentThread();
311 ClassLoader cl = currentThread.getContextClassLoader();
312 try {
313 currentThread.setContextClassLoader(env.getClassLoader());
314 ctx.call((RegionServerObserver) env.getInstance(), ctx);
315 } catch (Throwable e) {
316 handleCoprocessorThrowable(env, e);
317 } finally {
318 currentThread.setContextClassLoader(cl);
319 }
320 bypass |= ctx.shouldBypass();
321 if (ctx.shouldComplete()) {
322 break;
323 }
324 }
325 }
326
327
328 for (int i = 0; i < envsSize; i++) {
329 RegionServerEnvironment env = envs.get(i);
330 ctx.postEnvCall(env);
331 }
332 return bypass;
333 }
334
335
336
337
338
339 static class RegionServerEnvironment extends CoprocessorHost.Environment
340 implements RegionServerCoprocessorEnvironment {
341 private final RegionServerServices regionServerServices;
342 private final MetricRegistry metricRegistry;
343
344 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="BC_UNCONFIRMED_CAST",
345 justification="Intentional; FB has trouble detecting isAssignableFrom")
346 public RegionServerEnvironment(final Class<?> implClass,
347 final Coprocessor impl, final int priority, final int seq,
348 final Configuration conf, final RegionServerServices services) {
349 super(impl, priority, seq, conf);
350 this.regionServerServices = services;
351 for (Object itf : ClassUtils.getAllInterfaces(implClass)) {
352 Class<?> c = (Class<?>) itf;
353 if (SingletonCoprocessorService.class.isAssignableFrom(c)) {
354 this.regionServerServices.registerService(
355 ((SingletonCoprocessorService) impl).getService());
356 break;
357 }
358 }
359 this.metricRegistry =
360 MetricsCoprocessor.createRegistryForRSCoprocessor(implClass.getName());
361 }
362
363 @Override
364 public RegionServerServices getRegionServerServices() {
365 return regionServerServices;
366 }
367
368 @Override
369 public MetricRegistry getMetricRegistryForRegionServer() {
370 return metricRegistry;
371 }
372
373 @Override
374 protected void shutdown() {
375 super.shutdown();
376 MetricsCoprocessor.removeRegistry(metricRegistry);
377 }
378 }
379
380
381
382
383
384 static class EnvironmentPriorityComparator implements
385 Comparator<CoprocessorEnvironment> {
386 @Override
387 public int compare(final CoprocessorEnvironment env1,
388 final CoprocessorEnvironment env2) {
389 if (env1.getPriority() < env2.getPriority()) {
390 return -1;
391 } else if (env1.getPriority() > env2.getPriority()) {
392 return 1;
393 }
394 if (env1.getLoadSequence() < env2.getLoadSequence()) {
395 return -1;
396 } else if (env1.getLoadSequence() > env2.getLoadSequence()) {
397 return 1;
398 }
399 return 0;
400 }
401 }
402 }