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.ObserverContext;
39 import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment;
40 import org.apache.hadoop.hbase.coprocessor.RegionServerObserver;
41 import org.apache.hadoop.hbase.coprocessor.SingletonCoprocessorService;
42 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.WALEntry;
43 import org.apache.hadoop.hbase.replication.ReplicationEndpoint;
44
45 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
46 @InterfaceStability.Evolving
47 public class RegionServerCoprocessorHost extends
48 CoprocessorHost<RegionServerCoprocessorHost.RegionServerEnvironment> {
49
50 private static final Log LOG = LogFactory.getLog(RegionServerCoprocessorHost.class);
51
52 private RegionServerServices rsServices;
53
54 public RegionServerCoprocessorHost(RegionServerServices rsServices,
55 Configuration conf) {
56 super(rsServices);
57 this.rsServices = rsServices;
58 this.conf = conf;
59
60
61
62 boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
63 DEFAULT_COPROCESSORS_ENABLED);
64 boolean tableCoprocessorsEnabled = conf.getBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY,
65 DEFAULT_USER_COPROCESSORS_ENABLED);
66 LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
67 LOG.info("Table coprocessor loading is " +
68 ((coprocessorsEnabled && tableCoprocessorsEnabled) ? "enabled" : "disabled"));
69 loadSystemCoprocessors(conf, REGIONSERVER_COPROCESSOR_CONF_KEY);
70 }
71
72 @Override
73 public RegionServerEnvironment createEnvironment(Class<?> implClass,
74 Coprocessor instance, int priority, int sequence, Configuration conf) {
75 return new RegionServerEnvironment(implClass, instance, priority,
76 sequence, conf, this.rsServices);
77 }
78
79 public void preStop(String message) throws IOException {
80 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
81 @Override
82 public void call(RegionServerObserver oserver,
83 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
84 oserver.preStopRegionServer(ctx);
85 }
86 @Override
87 public void postEnvCall(RegionServerEnvironment env) {
88
89 shutdown(env);
90 }
91 });
92 }
93
94 public boolean preMerge(final HRegion regionA, final HRegion regionB) throws IOException {
95 return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
96 @Override
97 public void call(RegionServerObserver oserver,
98 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
99 oserver.preMerge(ctx, regionA, regionB);
100 }
101 });
102 }
103
104 public void postMerge(final HRegion regionA, final HRegion regionB, final HRegion mergedRegion)
105 throws IOException {
106 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
107 @Override
108 public void call(RegionServerObserver oserver,
109 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
110 oserver.postMerge(ctx, regionA, regionB, mergedRegion);
111 }
112 });
113 }
114
115 public boolean preMergeCommit(final HRegion regionA, final HRegion regionB,
116 final @MetaMutationAnnotation List<Mutation> metaEntries) throws IOException {
117 return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
118 @Override
119 public void call(RegionServerObserver oserver,
120 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
121 oserver.preMergeCommit(ctx, regionA, regionB, metaEntries);
122 }
123 });
124 }
125
126 public void postMergeCommit(final HRegion regionA, final HRegion regionB,
127 final HRegion mergedRegion) throws IOException {
128 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
129 @Override
130 public void call(RegionServerObserver oserver,
131 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
132 oserver.postMergeCommit(ctx, regionA, regionB, mergedRegion);
133 }
134 });
135 }
136
137 public void preRollBackMerge(final HRegion regionA, final HRegion regionB) throws IOException {
138 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
139 @Override
140 public void call(RegionServerObserver oserver,
141 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
142 oserver.preRollBackMerge(ctx, regionA, regionB);
143 }
144 });
145 }
146
147 public void postRollBackMerge(final HRegion regionA, final HRegion regionB) throws IOException {
148 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
149 @Override
150 public void call(RegionServerObserver oserver,
151 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
152 oserver.postRollBackMerge(ctx, regionA, regionB);
153 }
154 });
155 }
156
157 public void preRollWALWriterRequest() throws IOException {
158 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
159 @Override
160 public void call(RegionServerObserver oserver,
161 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
162 oserver.preRollWALWriterRequest(ctx);
163 }
164 });
165 }
166
167 public void postRollWALWriterRequest() throws IOException {
168 execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
169 @Override
170 public void call(RegionServerObserver oserver,
171 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
172 oserver.postRollWALWriterRequest(ctx);
173 }
174 });
175 }
176
177 public void preReplicateLogEntries(final List<WALEntry> entries, final CellScanner cells)
178 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.preReplicateLogEntries(ctx, entries, cells);
184 }
185 });
186 }
187
188 public void postReplicateLogEntries(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.postReplicateLogEntries(ctx, entries, cells);
195 }
196 });
197 }
198
199 public ReplicationEndpoint postCreateReplicationEndPoint(final ReplicationEndpoint endpoint)
200 throws IOException {
201 return execOperationWithResult(endpoint, coprocessors.isEmpty() ? null
202 : new CoprocessOperationWithResult<ReplicationEndpoint>() {
203 @Override
204 public void call(RegionServerObserver oserver,
205 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException {
206 try {
207 oserver.getClass().getDeclaredMethod("postCreateReplicationEndPoint",
208 ObserverContext.class, ReplicationEndpoint.class);
209 } catch (NoSuchMethodException e) {
210 LOG.warn("The RegionServer Observer class "
211 + oserver.getClass().getName()
212 + " does not have the"
213 + "method postCreateReplicationEndPoint(). Consider upgrading inorder to replicate visibility"
214 + " labels as strings");
215 setResult(endpoint);
216 return;
217 } catch (SecurityException e) {
218 LOG.warn("The RegionServer Observer class "
219 + oserver.getClass().getName()
220 + " does not have the"
221 + "method postCreateReplicationEndPoint(). Consider upgrading inorder to replicate visibility"
222 + " labels as strings");
223 setResult(endpoint);
224 return;
225 }
226 setResult(oserver.postCreateReplicationEndPoint(ctx, getResult()));
227 }
228 });
229 }
230
231 private <T> T execOperationWithResult(final T defaultValue,
232 final CoprocessOperationWithResult<T> ctx) throws IOException {
233 if (ctx == null)
234 return defaultValue;
235 ctx.setResult(defaultValue);
236 execOperation(ctx);
237 return ctx.getResult();
238 }
239
240 private static abstract class CoprocessorOperation extends
241 ObserverContext<RegionServerCoprocessorEnvironment> {
242 public CoprocessorOperation() {
243 }
244
245 public abstract void call(RegionServerObserver oserver,
246 ObserverContext<RegionServerCoprocessorEnvironment> ctx) throws IOException;
247
248 public void postEnvCall(RegionServerEnvironment env) {
249 }
250 }
251
252 private static abstract class CoprocessOperationWithResult<T> extends CoprocessorOperation {
253 private T result = null;
254
255 public void setResult(final T result) {
256 this.result = result;
257 }
258
259 public T getResult() {
260 return this.result;
261 }
262 }
263
264 private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
265 if (ctx == null) return false;
266 boolean bypass = false;
267 List<RegionServerEnvironment> envs = coprocessors.get();
268 for (int i = 0; i < envs.size(); i++) {
269 RegionServerEnvironment env = envs.get(i);
270 if (env.getInstance() instanceof RegionServerObserver) {
271 ctx.prepare(env);
272 Thread currentThread = Thread.currentThread();
273 ClassLoader cl = currentThread.getContextClassLoader();
274 try {
275 currentThread.setContextClassLoader(env.getClassLoader());
276 ctx.call((RegionServerObserver)env.getInstance(), ctx);
277 } catch (Throwable e) {
278 handleCoprocessorThrowable(env, e);
279 } finally {
280 currentThread.setContextClassLoader(cl);
281 }
282 bypass |= ctx.shouldBypass();
283 if (ctx.shouldComplete()) {
284 break;
285 }
286 }
287 ctx.postEnvCall(env);
288 }
289 return bypass;
290 }
291
292
293
294
295
296 static class RegionServerEnvironment extends CoprocessorHost.Environment
297 implements RegionServerCoprocessorEnvironment {
298
299 private RegionServerServices regionServerServices;
300
301 public RegionServerEnvironment(final Class<?> implClass,
302 final Coprocessor impl, final int priority, final int seq,
303 final Configuration conf, final RegionServerServices services) {
304 super(impl, priority, seq, conf);
305 this.regionServerServices = services;
306 for (Object itf : ClassUtils.getAllInterfaces(implClass)) {
307 Class<?> c = (Class<?>) itf;
308 if (SingletonCoprocessorService.class.isAssignableFrom(c)) {
309 this.regionServerServices.registerService(
310 ((SingletonCoprocessorService) impl).getService());
311 break;
312 }
313 }
314 }
315
316 @Override
317 public RegionServerServices getRegionServerServices() {
318 return regionServerServices;
319 }
320 }
321
322
323
324
325
326 static class EnvironmentPriorityComparator implements
327 Comparator<CoprocessorEnvironment> {
328 public int compare(final CoprocessorEnvironment env1,
329 final CoprocessorEnvironment env2) {
330 if (env1.getPriority() < env2.getPriority()) {
331 return -1;
332 } else if (env1.getPriority() > env2.getPriority()) {
333 return 1;
334 }
335 if (env1.getLoadSequence() < env2.getLoadSequence()) {
336 return -1;
337 } else if (env1.getLoadSequence() > env2.getLoadSequence()) {
338 return 1;
339 }
340 return 0;
341 }
342 }
343 }