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