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