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