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