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