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