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