1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.NavigableSet;
27 import java.util.UUID;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 import java.util.regex.Matcher;
31
32 import org.apache.commons.collections.map.AbstractReferenceMap;
33 import org.apache.commons.collections.map.ReferenceMap;
34 import org.apache.commons.lang.ClassUtils;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.hadoop.hbase.classification.InterfaceAudience;
38 import org.apache.hadoop.hbase.classification.InterfaceStability;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.fs.FileSystem;
41 import org.apache.hadoop.fs.Path;
42 import org.apache.hadoop.hbase.Cell;
43 import org.apache.hadoop.hbase.Coprocessor;
44 import org.apache.hadoop.hbase.CoprocessorEnvironment;
45 import org.apache.hadoop.hbase.HBaseConfiguration;
46 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
47 import org.apache.hadoop.hbase.HConstants;
48 import org.apache.hadoop.hbase.HRegionInfo;
49 import org.apache.hadoop.hbase.HTableDescriptor;
50 import org.apache.hadoop.hbase.client.Append;
51 import org.apache.hadoop.hbase.client.Delete;
52 import org.apache.hadoop.hbase.client.Durability;
53 import org.apache.hadoop.hbase.client.Get;
54 import org.apache.hadoop.hbase.client.Increment;
55 import org.apache.hadoop.hbase.client.Mutation;
56 import org.apache.hadoop.hbase.client.Put;
57 import org.apache.hadoop.hbase.client.Result;
58 import org.apache.hadoop.hbase.client.Scan;
59 import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
60 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
61 import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
62 import org.apache.hadoop.hbase.coprocessor.EndpointObserver;
63 import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor;
64 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
65 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
66 import org.apache.hadoop.hbase.coprocessor.RegionObserver;
67 import org.apache.hadoop.hbase.coprocessor.RegionObserver.MutationType;
68 import org.apache.hadoop.hbase.filter.ByteArrayComparable;
69 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
70 import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
71 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
72 import org.apache.hadoop.hbase.io.Reference;
73 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
74 import org.apache.hadoop.hbase.ipc.RpcServer;
75 import org.apache.hadoop.hbase.metrics.MetricRegistry;
76 import org.apache.hadoop.hbase.regionserver.DeleteTracker;
77 import org.apache.hadoop.hbase.regionserver.Region.Operation;
78 import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
79 import org.apache.hadoop.hbase.regionserver.wal.HLogKey;
80 import org.apache.hadoop.hbase.wal.WALKey;
81 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
82 import org.apache.hadoop.hbase.security.User;
83 import org.apache.hadoop.hbase.util.Bytes;
84 import org.apache.hadoop.hbase.util.CoprocessorClassLoader;
85 import org.apache.hadoop.hbase.util.Pair;
86
87 import com.google.common.collect.ImmutableList;
88 import com.google.common.collect.Lists;
89 import com.google.protobuf.Message;
90 import com.google.protobuf.Service;
91
92
93
94
95
96 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
97 @InterfaceStability.Evolving
98 public class RegionCoprocessorHost
99 extends CoprocessorHost<RegionCoprocessorHost.RegionEnvironment> {
100
101 private static final Log LOG = LogFactory.getLog(RegionCoprocessorHost.class);
102
103 private static ReferenceMap sharedDataMap =
104 new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
105
106
107 private final boolean hasCustomPostScannerFilterRow;
108
109
110
111
112
113 static class RegionEnvironment extends CoprocessorHost.Environment
114 implements RegionCoprocessorEnvironment {
115
116 private Region region;
117 private RegionServerServices rsServices;
118 ConcurrentMap<String, Object> sharedData;
119 private final boolean useLegacyPre;
120 private final boolean useLegacyPost;
121 private final MetricRegistry metricRegistry;
122
123
124
125
126
127
128 public RegionEnvironment(final Coprocessor impl, final int priority,
129 final int seq, final Configuration conf, final Region region,
130 final RegionServerServices services, final ConcurrentMap<String, Object> sharedData) {
131 super(impl, priority, seq, conf);
132 this.region = region;
133 this.rsServices = services;
134 this.sharedData = sharedData;
135
136
137
138
139 useLegacyPre = useLegacyMethod(impl.getClass(), "preWALRestore", ObserverContext.class,
140 HRegionInfo.class, WALKey.class, WALEdit.class);
141 useLegacyPost = useLegacyMethod(impl.getClass(), "postWALRestore", ObserverContext.class,
142 HRegionInfo.class, WALKey.class, WALEdit.class);
143 this.metricRegistry =
144 MetricsCoprocessor.createRegistryForRegionCoprocessor(impl.getClass().getName());
145 }
146
147
148 @Override
149 public Region getRegion() {
150 return region;
151 }
152
153
154 @Override
155 public RegionServerServices getRegionServerServices() {
156 return rsServices;
157 }
158
159 @Override
160 public void shutdown() {
161 super.shutdown();
162 MetricsCoprocessor.removeRegistry(this.metricRegistry);
163 }
164
165 @Override
166 public ConcurrentMap<String, Object> getSharedData() {
167 return sharedData;
168 }
169
170 @Override
171 public HRegionInfo getRegionInfo() {
172 return region.getRegionInfo();
173 }
174
175 @Override
176 public MetricRegistry getMetricRegistryForRegionServer() {
177 return metricRegistry;
178 }
179 }
180
181 static class TableCoprocessorAttribute {
182 private Path path;
183 private String className;
184 private int priority;
185 private Configuration conf;
186
187 public TableCoprocessorAttribute(Path path, String className, int priority,
188 Configuration conf) {
189 this.path = path;
190 this.className = className;
191 this.priority = priority;
192 this.conf = conf;
193 }
194
195 public Path getPath() {
196 return path;
197 }
198
199 public String getClassName() {
200 return className;
201 }
202
203 public int getPriority() {
204 return priority;
205 }
206
207 public Configuration getConf() {
208 return conf;
209 }
210 }
211
212
213 RegionServerServices rsServices;
214
215 Region region;
216
217
218
219
220
221
222
223 public RegionCoprocessorHost(final Region region,
224 final RegionServerServices rsServices, final Configuration conf) {
225 super(rsServices);
226 this.conf = conf;
227 this.rsServices = rsServices;
228 this.region = region;
229 this.pathPrefix = Integer.toString(this.region.getRegionInfo().hashCode());
230
231
232 loadSystemCoprocessors(conf, REGION_COPROCESSOR_CONF_KEY);
233
234
235 if (!region.getRegionInfo().getTable().isSystemTable()) {
236 loadSystemCoprocessors(conf, USER_REGION_COPROCESSOR_CONF_KEY);
237 }
238
239
240 loadTableCoprocessors(conf);
241
242
243 boolean hasCustomPostScannerFilterRow = false;
244 out: for (RegionEnvironment env: coprocessors) {
245 if (env.getInstance() instanceof RegionObserver) {
246 Class<?> clazz = env.getInstance().getClass();
247 for(;;) {
248 if (clazz == null) {
249
250 hasCustomPostScannerFilterRow = true;
251 break out;
252 }
253 if (clazz == BaseRegionObserver.class) {
254
255 break;
256 }
257 try {
258 clazz.getDeclaredMethod("postScannerFilterRow", ObserverContext.class,
259 InternalScanner.class, byte[].class, int.class, short.class, boolean.class);
260
261 hasCustomPostScannerFilterRow = true;
262 break out;
263 } catch (NoSuchMethodException ignore) {
264 }
265 clazz = clazz.getSuperclass();
266 }
267 }
268 }
269 this.hasCustomPostScannerFilterRow = hasCustomPostScannerFilterRow;
270 }
271
272 static List<TableCoprocessorAttribute> getTableCoprocessorAttrsFromSchema(Configuration conf,
273 HTableDescriptor htd) {
274 List<TableCoprocessorAttribute> result = Lists.newArrayList();
275 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e: htd.getValues().entrySet()) {
276 String key = Bytes.toString(e.getKey().get()).trim();
277 if (HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(key).matches()) {
278 String spec = Bytes.toString(e.getValue().get()).trim();
279
280 try {
281 Matcher matcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(spec);
282 if (matcher.matches()) {
283
284
285 Path path = matcher.group(1).trim().isEmpty() ?
286 null : new Path(matcher.group(1).trim());
287 String className = matcher.group(2).trim();
288 if (className.isEmpty()) {
289 LOG.error("Malformed table coprocessor specification, Class name is empty: key=" + key
290 + ", spec: " + spec);
291 continue;
292 }
293 int priority = matcher.group(3).trim().isEmpty() ?
294 Coprocessor.PRIORITY_USER : Integer.parseInt(matcher.group(3));
295 String cfgSpec = null;
296 try {
297 cfgSpec = matcher.group(4);
298 } catch (IndexOutOfBoundsException ex) {
299
300 }
301 Configuration ourConf;
302 if (cfgSpec != null && !cfgSpec.trim().equals("|")) {
303 cfgSpec = cfgSpec.substring(cfgSpec.indexOf('|') + 1);
304
305 ourConf = new Configuration(false);
306 HBaseConfiguration.merge(ourConf, conf);
307 Matcher m = HConstants.CP_HTD_ATTR_VALUE_PARAM_PATTERN.matcher(cfgSpec);
308 while (m.find()) {
309 ourConf.set(m.group(1), m.group(2));
310 }
311 } else {
312 ourConf = conf;
313 }
314 result.add(new TableCoprocessorAttribute(path, className, priority, ourConf));
315 } else {
316 LOG.error("Malformed table coprocessor specification: key=" + key +
317 ", spec: " + spec);
318 }
319 } catch (Exception ioe) {
320 LOG.error("Malformed table coprocessor specification: key=" + key + ", spec: " + spec,
321 ioe);
322 }
323 }
324 }
325 return result;
326 }
327
328
329
330
331
332
333
334
335 public static void testTableCoprocessorAttrs(final Configuration conf,
336 final HTableDescriptor htd) throws IOException {
337 String pathPrefix = UUID.randomUUID().toString();
338 for (TableCoprocessorAttribute attr: getTableCoprocessorAttrsFromSchema(conf, htd)) {
339 if (attr.getPriority() < 0) {
340 throw new IOException("Priority for coprocessor " + attr.getClassName() +
341 " cannot be less than 0");
342 }
343 ClassLoader old = Thread.currentThread().getContextClassLoader();
344 try {
345 ClassLoader cl;
346 if (attr.getPath() != null) {
347 cl = CoprocessorClassLoader.getClassLoader(attr.getPath(),
348 CoprocessorHost.class.getClassLoader(), pathPrefix, conf);
349 } else {
350 cl = CoprocessorHost.class.getClassLoader();
351 }
352 Thread.currentThread().setContextClassLoader(cl);
353 cl.loadClass(attr.getClassName());
354 } catch (ClassNotFoundException e) {
355 throw new IOException("Class " + attr.getClassName() + " cannot be loaded", e);
356 } finally {
357 Thread.currentThread().setContextClassLoader(old);
358 }
359 }
360 }
361
362 void loadTableCoprocessors(final Configuration conf) {
363 boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
364 DEFAULT_COPROCESSORS_ENABLED);
365 boolean tableCoprocessorsEnabled = conf.getBoolean(USER_COPROCESSORS_ENABLED_CONF_KEY,
366 DEFAULT_USER_COPROCESSORS_ENABLED);
367 if (!(coprocessorsEnabled && tableCoprocessorsEnabled)) {
368 return;
369 }
370
371
372
373 List<RegionEnvironment> configured = new ArrayList<RegionEnvironment>();
374 for (TableCoprocessorAttribute attr: getTableCoprocessorAttrsFromSchema(conf,
375 region.getTableDesc())) {
376
377 try {
378 RegionEnvironment env = load(attr.getPath(), attr.getClassName(), attr.getPriority(),
379 attr.getConf());
380 configured.add(env);
381 LOG.info("Loaded coprocessor " + attr.getClassName() + " from HTD of " +
382 region.getTableDesc().getTableName().getNameAsString() + " successfully.");
383 } catch (Throwable t) {
384
385 if (conf.getBoolean(ABORT_ON_ERROR_KEY, DEFAULT_ABORT_ON_ERROR)) {
386 abortServer(attr.getClassName(), t);
387 } else {
388 LOG.error("Failed to load coprocessor " + attr.getClassName(), t);
389 }
390 }
391 }
392
393 coprocessors.addAll(configured);
394 }
395
396 @Override
397 public RegionEnvironment createEnvironment(Class<?> implClass,
398 Coprocessor instance, int priority, int seq, Configuration conf) {
399
400
401
402
403
404 for (Object itf : ClassUtils.getAllInterfaces(implClass)) {
405 Class<?> c = (Class<?>) itf;
406 if (CoprocessorService.class.isAssignableFrom(c)) {
407 region.registerService( ((CoprocessorService)instance).getService() );
408 }
409 }
410 ConcurrentMap<String, Object> classData;
411
412 synchronized (sharedDataMap) {
413
414
415 classData = (ConcurrentMap<String, Object>)sharedDataMap.get(implClass.getName());
416 if (classData == null) {
417 classData = new ConcurrentHashMap<String, Object>();
418 sharedDataMap.put(implClass.getName(), classData);
419 }
420 }
421 return new RegionEnvironment(instance, priority, seq, conf, region,
422 rsServices, classData);
423 }
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438 private void handleCoprocessorThrowableNoRethrow(
439 final CoprocessorEnvironment env, final Throwable e) {
440 try {
441 handleCoprocessorThrowable(env,e);
442 } catch (IOException ioe) {
443
444 LOG.warn(
445 "handleCoprocessorThrowable() threw an IOException while attempting to handle Throwable " +
446 e + ". Ignoring.",e);
447 }
448 }
449
450
451
452
453
454
455 public void preOpen() throws IOException {
456 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
457 @Override
458 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
459 throws IOException {
460 oserver.preOpen(ctx);
461 }
462 });
463 }
464
465
466
467
468 public void postOpen() {
469 try {
470 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
471 @Override
472 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
473 throws IOException {
474 oserver.postOpen(ctx);
475 }
476 });
477 } catch (IOException e) {
478 LOG.warn(e);
479 }
480 }
481
482
483
484
485 public void postLogReplay() {
486 try {
487 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
488 @Override
489 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
490 throws IOException {
491 oserver.postLogReplay(ctx);
492 }
493 });
494 } catch (IOException e) {
495 LOG.warn(e);
496 }
497 }
498
499
500
501
502
503 public void preClose(final boolean abortRequested) throws IOException {
504 execOperation(false, new RegionOperation() {
505 @Override
506 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
507 throws IOException {
508 oserver.preClose(ctx, abortRequested);
509 }
510 });
511 }
512
513
514
515
516
517 public void postClose(final boolean abortRequested) {
518 try {
519 execOperation(false, new RegionOperation() {
520 @Override
521 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
522 throws IOException {
523 oserver.postClose(ctx, abortRequested);
524 }
525 @Override
526 public void postEnvCall(RegionEnvironment env) {
527 shutdown(env);
528 }
529 });
530 } catch (IOException e) {
531 LOG.warn(e);
532 }
533 }
534
535
536
537
538
539
540 public InternalScanner preCompactScannerOpen(final Store store,
541 final List<StoreFileScanner> scanners, final ScanType scanType, final long earliestPutTs,
542 final CompactionRequest request, final long readPoint, final User user) throws IOException {
543 return execOperationWithResult(null,
544 coprocessors.isEmpty() ? null : new RegionOperationWithResult<InternalScanner>(user) {
545 @Override
546 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
547 throws IOException {
548 setResult(oserver.preCompactScannerOpen(ctx, store, scanners, scanType,
549 earliestPutTs, getResult(), request, readPoint));
550 }
551 });
552 }
553
554
555
556
557
558
559
560
561
562
563 public boolean preCompactSelection(final Store store, final List<StoreFile> candidates,
564 final CompactionRequest request, final User user) throws IOException {
565 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
566 @Override
567 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
568 throws IOException {
569 oserver.preCompactSelection(ctx, store, candidates, request);
570 }
571 });
572 }
573
574
575
576
577
578
579
580
581 public void postCompactSelection(final Store store, final ImmutableList<StoreFile> selected,
582 final CompactionRequest request, final User user) {
583 try {
584 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
585 @Override
586 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
587 throws IOException {
588 oserver.postCompactSelection(ctx, store, selected, request);
589 }
590 });
591 } catch (IOException e) {
592 LOG.warn(e);
593 }
594 }
595
596
597
598
599
600
601
602
603
604 public InternalScanner preCompact(final Store store, final InternalScanner scanner,
605 final ScanType scanType, final CompactionRequest request, final User user)
606 throws IOException {
607 return execOperationWithResult(false, scanner,
608 coprocessors.isEmpty() ? null : new RegionOperationWithResult<InternalScanner>(user) {
609 @Override
610 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
611 throws IOException {
612 setResult(oserver.preCompact(ctx, store, getResult(), scanType, request));
613 }
614 });
615 }
616
617
618
619
620
621
622
623
624 public void postCompact(final Store store, final StoreFile resultFile,
625 final CompactionRequest request, final User user) throws IOException {
626 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
627 @Override
628 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
629 throws IOException {
630 oserver.postCompact(ctx, store, resultFile, request);
631 }
632 });
633 }
634
635
636
637
638
639 public InternalScanner preFlush(final Store store, final InternalScanner scanner)
640 throws IOException {
641 return execOperationWithResult(false, scanner,
642 coprocessors.isEmpty() ? null : new RegionOperationWithResult<InternalScanner>() {
643 @Override
644 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
645 throws IOException {
646 setResult(oserver.preFlush(ctx, store, getResult()));
647 }
648 });
649 }
650
651
652
653
654
655 public void preFlush() throws IOException {
656 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
657 @Override
658 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
659 throws IOException {
660 oserver.preFlush(ctx);
661 }
662 });
663 }
664
665
666
667
668
669
670 public InternalScanner preFlushScannerOpen(final Store store,
671 final KeyValueScanner memstoreScanner, final long readPoint) throws IOException {
672 return execOperationWithResult(null,
673 coprocessors.isEmpty() ? null : new RegionOperationWithResult<InternalScanner>() {
674 @Override
675 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
676 throws IOException {
677 setResult(oserver.preFlushScannerOpen(ctx, store, memstoreScanner, getResult(), readPoint));
678 }
679 });
680 }
681
682
683
684
685
686 public void postFlush() throws IOException {
687 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
688 @Override
689 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
690 throws IOException {
691 oserver.postFlush(ctx);
692 }
693 });
694 }
695
696
697
698
699
700 public void postFlush(final Store store, final StoreFile storeFile) throws IOException {
701 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
702 @Override
703 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
704 throws IOException {
705 oserver.postFlush(ctx, store, storeFile);
706 }
707 });
708 }
709
710
711
712
713
714
715 public void preSplit(final User user) throws IOException {
716 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
717 @Override
718 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
719 throws IOException {
720 oserver.preSplit(ctx);
721 }
722 });
723 }
724
725
726
727
728
729 public void preSplit(final byte[] splitRow, final User user) throws IOException {
730 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
731 @Override
732 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
733 throws IOException {
734 oserver.preSplit(ctx, splitRow);
735 }
736 });
737 }
738
739
740
741
742
743
744
745 public void postSplit(final Region l, final Region r, final User user) throws IOException {
746 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
747 @Override
748 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
749 throws IOException {
750 oserver.postSplit(ctx, l, r);
751 }
752 });
753 }
754
755 public boolean preSplitBeforePONR(final byte[] splitKey,
756 final List<Mutation> metaEntries, final User user) throws IOException {
757 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
758 @Override
759 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
760 throws IOException {
761 oserver.preSplitBeforePONR(ctx, splitKey, metaEntries);
762 }
763 });
764 }
765
766 public void preSplitAfterPONR(final User user) throws IOException {
767 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
768 @Override
769 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
770 throws IOException {
771 oserver.preSplitAfterPONR(ctx);
772 }
773 });
774 }
775
776
777
778
779
780 public void preRollBackSplit(final User user) throws IOException {
781 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
782 @Override
783 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
784 throws IOException {
785 oserver.preRollBackSplit(ctx);
786 }
787 });
788 }
789
790
791
792
793
794 public void postRollBackSplit(final User user) throws IOException {
795 execOperation(coprocessors.isEmpty() ? null : new RegionOperation(user) {
796 @Override
797 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
798 throws IOException {
799 oserver.postRollBackSplit(ctx);
800 }
801 });
802 }
803
804
805
806
807
808 public void postCompleteSplit() throws IOException {
809 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
810 @Override
811 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
812 throws IOException {
813 oserver.postCompleteSplit(ctx);
814 }
815 });
816 }
817
818
819
820
821
822
823
824
825
826
827 public boolean preGetClosestRowBefore(final byte[] row, final byte[] family,
828 final Result result) throws IOException {
829 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
830 @Override
831 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
832 throws IOException {
833 oserver.preGetClosestRowBefore(ctx, row, family, result);
834 }
835 });
836 }
837
838
839
840
841
842
843
844 public void postGetClosestRowBefore(final byte[] row, final byte[] family,
845 final Result result) throws IOException {
846 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
847 @Override
848 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
849 throws IOException {
850 oserver.postGetClosestRowBefore(ctx, row, family, result);
851 }
852 });
853 }
854
855
856
857
858
859
860 public boolean preGet(final Get get, final List<Cell> results)
861 throws IOException {
862 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
863 @Override
864 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
865 throws IOException {
866 oserver.preGetOp(ctx, get, results);
867 }
868 });
869 }
870
871
872
873
874
875
876 public void postGet(final Get get, final List<Cell> results)
877 throws IOException {
878 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
879 @Override
880 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
881 throws IOException {
882 oserver.postGetOp(ctx, get, results);
883 }
884 });
885 }
886
887
888
889
890
891
892
893 public Boolean preExists(final Get get) throws IOException {
894 return execOperationWithResult(true, false,
895 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
896 @Override
897 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
898 throws IOException {
899 setResult(oserver.preExists(ctx, get, getResult()));
900 }
901 });
902 }
903
904
905
906
907
908
909
910 public boolean postExists(final Get get, boolean exists)
911 throws IOException {
912 return execOperationWithResult(exists,
913 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
914 @Override
915 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
916 throws IOException {
917 setResult(oserver.postExists(ctx, get, getResult()));
918 }
919 });
920 }
921
922
923
924
925
926
927
928
929 public boolean prePut(final Put put, final WALEdit edit, final Durability durability)
930 throws IOException {
931 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
932 @Override
933 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
934 throws IOException {
935 oserver.prePut(ctx, put, edit, durability);
936 }
937 });
938 }
939
940
941
942
943
944
945
946
947
948
949
950 public boolean prePrepareTimeStampForDeleteVersion(final Mutation mutation,
951 final Cell kv, final byte[] byteNow, final Get get) throws IOException {
952 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
953 @Override
954 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
955 throws IOException {
956 oserver.prePrepareTimeStampForDeleteVersion(ctx, mutation, kv, byteNow, get);
957 }
958 });
959 }
960
961
962
963
964
965
966
967 public void postPut(final Put put, final WALEdit edit, final Durability durability)
968 throws IOException {
969 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
970 @Override
971 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
972 throws IOException {
973 oserver.postPut(ctx, put, edit, durability);
974 }
975 });
976 }
977
978
979
980
981
982
983
984
985 public boolean preDelete(final Delete delete, final WALEdit edit, final Durability durability)
986 throws IOException {
987 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
988 @Override
989 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
990 throws IOException {
991 oserver.preDelete(ctx, delete, edit, durability);
992 }
993 });
994 }
995
996
997
998
999
1000
1001
1002 public void postDelete(final Delete delete, final WALEdit edit, final Durability durability)
1003 throws IOException {
1004 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1005 @Override
1006 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1007 throws IOException {
1008 oserver.postDelete(ctx, delete, edit, durability);
1009 }
1010 });
1011 }
1012
1013
1014
1015
1016
1017
1018 public boolean preBatchMutate(
1019 final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
1020 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1021 @Override
1022 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1023 throws IOException {
1024 oserver.preBatchMutate(ctx, miniBatchOp);
1025 }
1026 });
1027 }
1028
1029
1030
1031
1032
1033 public void postBatchMutate(
1034 final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
1035 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1036 @Override
1037 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1038 throws IOException {
1039 oserver.postBatchMutate(ctx, miniBatchOp);
1040 }
1041 });
1042 }
1043
1044 public void postBatchMutateIndispensably(
1045 final MiniBatchOperationInProgress<Mutation> miniBatchOp, final boolean success)
1046 throws IOException {
1047 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1048 @Override
1049 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1050 throws IOException {
1051 oserver.postBatchMutateIndispensably(ctx, miniBatchOp, success);
1052 }
1053 });
1054 }
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 public Boolean preCheckAndPut(final byte [] row, final byte [] family,
1068 final byte [] qualifier, final CompareOp compareOp,
1069 final ByteArrayComparable comparator, final Put put)
1070 throws IOException {
1071 return execOperationWithResult(true, false,
1072 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1073 @Override
1074 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1075 throws IOException {
1076 setResult(oserver.preCheckAndPut(ctx, row, family, qualifier,
1077 compareOp, comparator, put, getResult()));
1078 }
1079 });
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 public Boolean preCheckAndPutAfterRowLock(final byte[] row, final byte[] family,
1094 final byte[] qualifier, final CompareOp compareOp, final ByteArrayComparable comparator,
1095 final Put put) throws IOException {
1096 return execOperationWithResult(true, false,
1097 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1098 @Override
1099 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1100 throws IOException {
1101 setResult(oserver.preCheckAndPutAfterRowLock(ctx, row, family, qualifier,
1102 compareOp, comparator, put, getResult()));
1103 }
1104 });
1105 }
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 public boolean postCheckAndPut(final byte [] row, final byte [] family,
1117 final byte [] qualifier, final CompareOp compareOp,
1118 final ByteArrayComparable comparator, final Put put,
1119 boolean result) throws IOException {
1120 return execOperationWithResult(result,
1121 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1122 @Override
1123 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1124 throws IOException {
1125 setResult(oserver.postCheckAndPut(ctx, row, family, qualifier,
1126 compareOp, comparator, put, getResult()));
1127 }
1128 });
1129 }
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142 public Boolean preCheckAndDelete(final byte [] row, final byte [] family,
1143 final byte [] qualifier, final CompareOp compareOp,
1144 final ByteArrayComparable comparator, final Delete delete)
1145 throws IOException {
1146 return execOperationWithResult(true, false,
1147 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1148 @Override
1149 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1150 throws IOException {
1151 setResult(oserver.preCheckAndDelete(ctx, row, family,
1152 qualifier, compareOp, comparator, delete, getResult()));
1153 }
1154 });
1155 }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 public Boolean preCheckAndDeleteAfterRowLock(final byte[] row, final byte[] family,
1169 final byte[] qualifier, final CompareOp compareOp, final ByteArrayComparable comparator,
1170 final Delete delete) throws IOException {
1171 return execOperationWithResult(true, false,
1172 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1173 @Override
1174 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1175 throws IOException {
1176 setResult(oserver.preCheckAndDeleteAfterRowLock(ctx, row,
1177 family, qualifier, compareOp, comparator, delete, getResult()));
1178 }
1179 });
1180 }
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 public boolean postCheckAndDelete(final byte [] row, final byte [] family,
1192 final byte [] qualifier, final CompareOp compareOp,
1193 final ByteArrayComparable comparator, final Delete delete,
1194 boolean result) throws IOException {
1195 return execOperationWithResult(result,
1196 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1197 @Override
1198 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1199 throws IOException {
1200 setResult(oserver.postCheckAndDelete(ctx, row, family,
1201 qualifier, compareOp, comparator, delete, getResult()));
1202 }
1203 });
1204 }
1205
1206
1207
1208
1209
1210
1211
1212 public Result preAppend(final Append append) throws IOException {
1213 return execOperationWithResult(true, null,
1214 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1215 @Override
1216 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1217 throws IOException {
1218 setResult(oserver.preAppend(ctx, append));
1219 }
1220 });
1221 }
1222
1223
1224
1225
1226
1227
1228
1229 public Result preAppendAfterRowLock(final Append append) throws IOException {
1230 return execOperationWithResult(true, null,
1231 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1232 @Override
1233 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1234 throws IOException {
1235 setResult(oserver.preAppendAfterRowLock(ctx, append));
1236 }
1237 });
1238 }
1239
1240
1241
1242
1243
1244
1245
1246 public Result preIncrement(final Increment increment) throws IOException {
1247 return execOperationWithResult(true, null,
1248 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1249 @Override
1250 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1251 throws IOException {
1252 setResult(oserver.preIncrement(ctx, increment));
1253 }
1254 });
1255 }
1256
1257
1258
1259
1260
1261
1262
1263 public Result preIncrementAfterRowLock(final Increment increment) throws IOException {
1264 return execOperationWithResult(true, null,
1265 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1266 @Override
1267 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1268 throws IOException {
1269 setResult(oserver.preIncrementAfterRowLock(ctx, increment));
1270 }
1271 });
1272 }
1273
1274
1275
1276
1277
1278
1279 public Result postAppend(final Append append, final Result result) throws IOException {
1280 return execOperationWithResult(result,
1281 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1282 @Override
1283 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1284 throws IOException {
1285 setResult(oserver.postAppend(ctx, append, result));
1286 }
1287 });
1288 }
1289
1290
1291
1292
1293
1294
1295 public Result postIncrement(final Increment increment, Result result) throws IOException {
1296 return execOperationWithResult(result,
1297 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Result>() {
1298 @Override
1299 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1300 throws IOException {
1301 setResult(oserver.postIncrement(ctx, increment, getResult()));
1302 }
1303 });
1304 }
1305
1306
1307
1308
1309
1310
1311
1312 public RegionScanner preScannerOpen(final Scan scan) throws IOException {
1313 return execOperationWithResult(true, null,
1314 coprocessors.isEmpty() ? null : new RegionOperationWithResult<RegionScanner>() {
1315 @Override
1316 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1317 throws IOException {
1318 setResult(oserver.preScannerOpen(ctx, scan, getResult()));
1319 }
1320 });
1321 }
1322
1323
1324
1325
1326
1327
1328 public KeyValueScanner preStoreScannerOpen(final Store store, final Scan scan,
1329 final NavigableSet<byte[]> targetCols) throws IOException {
1330 return execOperationWithResult(null,
1331 coprocessors.isEmpty() ? null : new RegionOperationWithResult<KeyValueScanner>() {
1332 @Override
1333 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1334 throws IOException {
1335 setResult(oserver.preStoreScannerOpen(ctx, store, scan, targetCols, getResult()));
1336 }
1337 });
1338 }
1339
1340
1341
1342
1343
1344
1345
1346 public RegionScanner postScannerOpen(final Scan scan, RegionScanner s) throws IOException {
1347 return execOperationWithResult(s,
1348 coprocessors.isEmpty() ? null : new RegionOperationWithResult<RegionScanner>() {
1349 @Override
1350 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1351 throws IOException {
1352 setResult(oserver.postScannerOpen(ctx, scan, getResult()));
1353 }
1354 });
1355 }
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365 public Boolean preScannerNext(final InternalScanner s,
1366 final List<Result> results, final int limit) throws IOException {
1367 return execOperationWithResult(true, false,
1368 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1369 @Override
1370 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1371 throws IOException {
1372 setResult(oserver.preScannerNext(ctx, s, results, limit, getResult()));
1373 }
1374 });
1375 }
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385 public boolean postScannerNext(final InternalScanner s,
1386 final List<Result> results, final int limit, boolean hasMore)
1387 throws IOException {
1388 return execOperationWithResult(hasMore,
1389 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1390 @Override
1391 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1392 throws IOException {
1393 setResult(oserver.postScannerNext(ctx, s, results, limit, getResult()));
1394 }
1395 });
1396 }
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 public boolean postScannerFilterRow(final InternalScanner s, final byte[] currentRow,
1409 final int offset, final short length) throws IOException {
1410
1411 if (!hasCustomPostScannerFilterRow) return true;
1412 return execOperationWithResult(true,
1413 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1414 @Override
1415 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1416 throws IOException {
1417 setResult(oserver.postScannerFilterRow(ctx, s, currentRow, offset,length, getResult()));
1418 }
1419 });
1420 }
1421
1422
1423
1424
1425
1426
1427 public boolean preScannerClose(final InternalScanner s) throws IOException {
1428 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1429 @Override
1430 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1431 throws IOException {
1432 oserver.preScannerClose(ctx, s);
1433 }
1434 });
1435 }
1436
1437
1438
1439
1440 public void postScannerClose(final InternalScanner s) throws IOException {
1441 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1442 @Override
1443 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1444 throws IOException {
1445 oserver.postScannerClose(ctx, s);
1446 }
1447 });
1448 }
1449
1450
1451
1452
1453
1454
1455
1456
1457 public boolean preWALRestore(final HRegionInfo info, final WALKey logKey,
1458 final WALEdit logEdit) throws IOException {
1459 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1460 @Override
1461 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1462 throws IOException {
1463
1464
1465 final RegionEnvironment env = (RegionEnvironment)ctx.getEnvironment();
1466 if (env.useLegacyPre) {
1467 if (logKey instanceof HLogKey) {
1468 oserver.preWALRestore(ctx, info, (HLogKey)logKey, logEdit);
1469 } else {
1470 legacyWarning(oserver.getClass(), "There are wal keys present that are not HLogKey.");
1471 }
1472 } else {
1473 oserver.preWALRestore(ctx, info, logKey, logEdit);
1474 }
1475 }
1476 });
1477 }
1478
1479
1480
1481
1482
1483 @Deprecated
1484 public boolean preWALRestore(final HRegionInfo info, final HLogKey logKey,
1485 final WALEdit logEdit) throws IOException {
1486 return preWALRestore(info, (WALKey)logKey, logEdit);
1487 }
1488
1489
1490
1491
1492
1493
1494
1495 public void postWALRestore(final HRegionInfo info, final WALKey logKey, final WALEdit logEdit)
1496 throws IOException {
1497 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1498 @Override
1499 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1500 throws IOException {
1501
1502
1503 final RegionEnvironment env = (RegionEnvironment)ctx.getEnvironment();
1504 if (env.useLegacyPost) {
1505 if (logKey instanceof HLogKey) {
1506 oserver.postWALRestore(ctx, info, (HLogKey)logKey, logEdit);
1507 } else {
1508 legacyWarning(oserver.getClass(), "There are wal keys present that are not HLogKey.");
1509 }
1510 } else {
1511 oserver.postWALRestore(ctx, info, logKey, logEdit);
1512 }
1513 }
1514 });
1515 }
1516
1517
1518
1519
1520 @Deprecated
1521 public void postWALRestore(final HRegionInfo info, final HLogKey logKey, final WALEdit logEdit)
1522 throws IOException {
1523 postWALRestore(info, (WALKey)logKey, logEdit);
1524 }
1525
1526 public boolean preCommitStoreFile(final byte[] family, final List<Pair<Path, Path>> pairs)
1527 throws IOException {
1528 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1529 @Override
1530 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1531 throws IOException {
1532 oserver.preCommitStoreFile(ctx, family, pairs);
1533 }
1534 });
1535 }
1536 public void postCommitStoreFile(final byte[] family, final Path srcPath, final Path dstPath)
1537 throws IOException {
1538 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1539 @Override
1540 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1541 throws IOException {
1542 oserver.postCommitStoreFile(ctx, family, srcPath, dstPath);
1543 }
1544 });
1545 }
1546
1547
1548
1549
1550
1551
1552 public boolean preBulkLoadHFile(final List<Pair<byte[], String>> familyPaths) throws IOException {
1553 return execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1554 @Override
1555 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1556 throws IOException {
1557 oserver.preBulkLoadHFile(ctx, familyPaths);
1558 }
1559 });
1560 }
1561
1562
1563
1564
1565
1566
1567
1568 public boolean postBulkLoadHFile(final List<Pair<byte[], String>> familyPaths,
1569 boolean hasLoaded) throws IOException {
1570 return execOperationWithResult(hasLoaded,
1571 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Boolean>() {
1572 @Override
1573 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1574 throws IOException {
1575 setResult(oserver.postBulkLoadHFile(ctx, familyPaths, getResult()));
1576 }
1577 });
1578 }
1579
1580 public void postStartRegionOperation(final Operation op) throws IOException {
1581 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1582 @Override
1583 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1584 throws IOException {
1585 oserver.postStartRegionOperation(ctx, op);
1586 }
1587 });
1588 }
1589
1590 public void postCloseRegionOperation(final Operation op) throws IOException {
1591 execOperation(coprocessors.isEmpty() ? null : new RegionOperation() {
1592 @Override
1593 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1594 throws IOException {
1595 oserver.postCloseRegionOperation(ctx, op);
1596 }
1597 });
1598 }
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611 public StoreFile.Reader preStoreFileReaderOpen(final FileSystem fs, final Path p,
1612 final FSDataInputStreamWrapper in, final long size, final CacheConfig cacheConf,
1613 final Reference r) throws IOException {
1614 return execOperationWithResult(null,
1615 coprocessors.isEmpty() ? null : new RegionOperationWithResult<StoreFile.Reader>() {
1616 @Override
1617 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1618 throws IOException {
1619 setResult(oserver.preStoreFileReaderOpen(ctx, fs, p, in, size, cacheConf, r, getResult()));
1620 }
1621 });
1622 }
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635 public StoreFile.Reader postStoreFileReaderOpen(final FileSystem fs, final Path p,
1636 final FSDataInputStreamWrapper in, final long size, final CacheConfig cacheConf,
1637 final Reference r, final StoreFile.Reader reader) throws IOException {
1638 return execOperationWithResult(reader,
1639 coprocessors.isEmpty() ? null : new RegionOperationWithResult<StoreFile.Reader>() {
1640 @Override
1641 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1642 throws IOException {
1643 setResult(oserver.postStoreFileReaderOpen(ctx, fs, p, in, size, cacheConf, r, getResult()));
1644 }
1645 });
1646 }
1647
1648 public Cell postMutationBeforeWAL(final MutationType opType, final Mutation mutation,
1649 final Cell oldCell, Cell newCell) throws IOException {
1650 return execOperationWithResult(newCell,
1651 coprocessors.isEmpty() ? null : new RegionOperationWithResult<Cell>() {
1652 @Override
1653 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1654 throws IOException {
1655 setResult(oserver.postMutationBeforeWAL(ctx, opType, mutation, oldCell, getResult()));
1656 }
1657 });
1658 }
1659
1660 public Message preEndpointInvocation(final Service service, final String methodName,
1661 Message request) throws IOException {
1662 return execOperationWithResult(request,
1663 coprocessors.isEmpty() ? null : new EndpointOperationWithResult<Message>() {
1664 @Override
1665 public void call(EndpointObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1666 throws IOException {
1667 setResult(oserver.preEndpointInvocation(ctx, service, methodName, getResult()));
1668 }
1669 });
1670 }
1671
1672 public void postEndpointInvocation(final Service service, final String methodName,
1673 final Message request, final Message.Builder responseBuilder) throws IOException {
1674 execOperation(coprocessors.isEmpty() ? null : new EndpointOperation() {
1675 @Override
1676 public void call(EndpointObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1677 throws IOException {
1678 oserver.postEndpointInvocation(ctx, service, methodName, request, responseBuilder);
1679 }
1680 });
1681 }
1682
1683 public DeleteTracker postInstantiateDeleteTracker(DeleteTracker tracker) throws IOException {
1684 return execOperationWithResult(tracker,
1685 coprocessors.isEmpty() ? null : new RegionOperationWithResult<DeleteTracker>() {
1686 @Override
1687 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1688 throws IOException {
1689 setResult(oserver.postInstantiateDeleteTracker(ctx, getResult()));
1690 }
1691 });
1692 }
1693
1694 public void preWALAppend(final WALKey key, final WALEdit edit) throws IOException {
1695 if (coprocessors.isEmpty()){
1696 return;
1697 }
1698 execOperation(new RegionOperation() {
1699 @Override
1700 public void call(RegionObserver oserver, ObserverContext<RegionCoprocessorEnvironment> ctx)
1701 throws IOException {
1702 oserver.preWALAppend(ctx, key, edit);
1703 }
1704 });
1705 }
1706
1707 private static abstract class CoprocessorOperation
1708 extends ObserverContext<RegionCoprocessorEnvironment> {
1709 public CoprocessorOperation() {
1710 this(RpcServer.getRequestUser());
1711 }
1712
1713 public CoprocessorOperation(User user) {
1714 super(user);
1715 }
1716
1717 public abstract void call(Coprocessor observer,
1718 ObserverContext<RegionCoprocessorEnvironment> ctx) throws IOException;
1719 public abstract boolean hasCall(Coprocessor observer);
1720 public void postEnvCall(RegionEnvironment env) { }
1721 }
1722
1723 private static abstract class RegionOperation extends CoprocessorOperation {
1724 public RegionOperation() {
1725 }
1726
1727 public RegionOperation(User user) {
1728 super(user);
1729 }
1730
1731 public abstract void call(RegionObserver observer,
1732 ObserverContext<RegionCoprocessorEnvironment> ctx) throws IOException;
1733
1734 @Override
1735 public boolean hasCall(Coprocessor observer) {
1736 return observer instanceof RegionObserver;
1737 }
1738
1739 @Override
1740 public void call(Coprocessor observer, ObserverContext<RegionCoprocessorEnvironment> ctx)
1741 throws IOException {
1742 call((RegionObserver)observer, ctx);
1743 }
1744 }
1745
1746 private static abstract class RegionOperationWithResult<T> extends RegionOperation {
1747 public RegionOperationWithResult() {
1748 }
1749
1750 public RegionOperationWithResult(User user) {
1751 super(user);
1752 }
1753
1754 private T result = null;
1755 public void setResult(final T result) { this.result = result; }
1756 public T getResult() { return this.result; }
1757 }
1758
1759 private static abstract class EndpointOperation extends CoprocessorOperation {
1760 public abstract void call(EndpointObserver observer,
1761 ObserverContext<RegionCoprocessorEnvironment> ctx) throws IOException;
1762
1763 @Override
1764 public boolean hasCall(Coprocessor observer) {
1765 return observer instanceof EndpointObserver;
1766 }
1767
1768 @Override
1769 public void call(Coprocessor observer, ObserverContext<RegionCoprocessorEnvironment> ctx)
1770 throws IOException {
1771 call((EndpointObserver)observer, ctx);
1772 }
1773 }
1774
1775 private static abstract class EndpointOperationWithResult<T> extends EndpointOperation {
1776 private T result = null;
1777 public void setResult(final T result) { this.result = result; }
1778 public T getResult() { return this.result; }
1779 }
1780
1781 private boolean execOperation(final CoprocessorOperation ctx)
1782 throws IOException {
1783 return execOperation(true, ctx);
1784 }
1785
1786 private <T> T execOperationWithResult(final T defaultValue,
1787 final RegionOperationWithResult<T> ctx) throws IOException {
1788 if (ctx == null) return defaultValue;
1789 ctx.setResult(defaultValue);
1790 execOperation(true, ctx);
1791 return ctx.getResult();
1792 }
1793
1794 private <T> T execOperationWithResult(final boolean ifBypass, final T defaultValue,
1795 final RegionOperationWithResult<T> ctx) throws IOException {
1796 boolean bypass = false;
1797 T result = defaultValue;
1798 if (ctx != null) {
1799 ctx.setResult(defaultValue);
1800 bypass = execOperation(true, ctx);
1801 result = ctx.getResult();
1802 }
1803 return bypass == ifBypass ? result : null;
1804 }
1805
1806 private <T> T execOperationWithResult(final T defaultValue,
1807 final EndpointOperationWithResult<T> ctx) throws IOException {
1808 if (ctx == null) return defaultValue;
1809 ctx.setResult(defaultValue);
1810 execOperation(true, ctx);
1811 return ctx.getResult();
1812 }
1813
1814 private boolean execOperation(final boolean earlyExit, final CoprocessorOperation ctx)
1815 throws IOException {
1816 boolean bypass = false;
1817 List<RegionEnvironment> envs = coprocessors.get();
1818 for (int i = 0; i < envs.size(); i++) {
1819 RegionEnvironment env = envs.get(i);
1820 Coprocessor observer = env.getInstance();
1821 if (ctx.hasCall(observer)) {
1822 ctx.prepare(env);
1823 Thread currentThread = Thread.currentThread();
1824 ClassLoader cl = currentThread.getContextClassLoader();
1825 try {
1826 currentThread.setContextClassLoader(env.getClassLoader());
1827 ctx.call(observer, ctx);
1828 } catch (Throwable e) {
1829 handleCoprocessorThrowable(env, e);
1830 } finally {
1831 currentThread.setContextClassLoader(cl);
1832 }
1833 bypass |= ctx.shouldBypass();
1834 if (earlyExit && ctx.shouldComplete()) {
1835 break;
1836 }
1837 }
1838
1839 ctx.postEnvCall(env);
1840 }
1841 return bypass;
1842 }
1843 }