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