View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.coprocessor;
21  
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertTrue;
26  
27  import java.io.IOException;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.NavigableSet;
31  import java.util.concurrent.atomic.AtomicBoolean;
32  import java.util.concurrent.atomic.AtomicInteger;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.apache.hadoop.fs.FileSystem;
37  import org.apache.hadoop.fs.Path;
38  import org.apache.hadoop.hbase.Cell;
39  import org.apache.hadoop.hbase.CellUtil;
40  import org.apache.hadoop.hbase.CoprocessorEnvironment;
41  import org.apache.hadoop.hbase.HRegionInfo;
42  import org.apache.hadoop.hbase.KeyValue;
43  import org.apache.hadoop.hbase.client.Append;
44  import org.apache.hadoop.hbase.client.Delete;
45  import org.apache.hadoop.hbase.client.Durability;
46  import org.apache.hadoop.hbase.client.Get;
47  import org.apache.hadoop.hbase.client.Increment;
48  import org.apache.hadoop.hbase.client.Mutation;
49  import org.apache.hadoop.hbase.client.Put;
50  import org.apache.hadoop.hbase.client.Result;
51  import org.apache.hadoop.hbase.client.Scan;
52  import org.apache.hadoop.hbase.filter.ByteArrayComparable;
53  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
54  import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
55  import org.apache.hadoop.hbase.io.Reference;
56  import org.apache.hadoop.hbase.io.hfile.CacheConfig;
57  import org.apache.hadoop.hbase.regionserver.InternalScanner;
58  import org.apache.hadoop.hbase.regionserver.KeyValueScanner;
59  import org.apache.hadoop.hbase.regionserver.Leases;
60  import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
61  import org.apache.hadoop.hbase.regionserver.Region;
62  import org.apache.hadoop.hbase.regionserver.Region.Operation;
63  import org.apache.hadoop.hbase.regionserver.RegionScanner;
64  import org.apache.hadoop.hbase.regionserver.ScanType;
65  import org.apache.hadoop.hbase.regionserver.Store;
66  import org.apache.hadoop.hbase.regionserver.StoreFile;
67  import org.apache.hadoop.hbase.regionserver.StoreFile.Reader;
68  import org.apache.hadoop.hbase.regionserver.wal.HLogKey;
69  import org.apache.hadoop.hbase.wal.WALKey;
70  import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
71  import org.apache.hadoop.hbase.util.Bytes;
72  import org.apache.hadoop.hbase.util.Pair;
73  
74  import com.google.common.collect.ImmutableList;
75  
76  /**
77   * A sample region observer that tests the RegionObserver interface.
78   * It works with TestRegionObserverInterface to provide the test case.
79   */
80  public class SimpleRegionObserver extends BaseRegionObserver {
81    private static final Log LOG = LogFactory.getLog(TestRegionObserverInterface.class);
82  
83    final AtomicInteger ctBeforeDelete = new AtomicInteger(1);
84    final AtomicInteger ctPreOpen = new AtomicInteger(0);
85    final AtomicInteger ctPostOpen = new AtomicInteger(0);
86    final AtomicInteger ctPreClose = new AtomicInteger(0);
87    final AtomicInteger ctPostClose = new AtomicInteger(0);
88    final AtomicInteger ctPreFlush = new AtomicInteger(0);
89    final AtomicInteger ctPreFlushScannerOpen = new AtomicInteger(0);
90    final AtomicInteger ctPostFlush = new AtomicInteger(0);
91    final AtomicInteger ctPreSplit = new AtomicInteger(0);
92    final AtomicInteger ctPostSplit = new AtomicInteger(0);
93    final AtomicInteger ctPreCompactSelect = new AtomicInteger(0);
94    final AtomicInteger ctPostCompactSelect = new AtomicInteger(0);
95    final AtomicInteger ctPreCompactScanner = new AtomicInteger(0);
96    final AtomicInteger ctPreCompact = new AtomicInteger(0);
97    final AtomicInteger ctPostCompact = new AtomicInteger(0);
98    final AtomicInteger ctPreGet = new AtomicInteger(0);
99    final AtomicInteger ctPostGet = new AtomicInteger(0);
100   final AtomicInteger ctPrePut = new AtomicInteger(0);
101   final AtomicInteger ctPostPut = new AtomicInteger(0);
102   final AtomicInteger ctPreDeleted = new AtomicInteger(0);
103   final AtomicInteger ctPrePrepareDeleteTS = new AtomicInteger(0);
104   final AtomicInteger ctPostDeleted = new AtomicInteger(0);
105   final AtomicInteger ctPreGetClosestRowBefore = new AtomicInteger(0);
106   final AtomicInteger ctPostGetClosestRowBefore = new AtomicInteger(0);
107   final AtomicInteger ctPreIncrement = new AtomicInteger(0);
108   final AtomicInteger ctPreIncrementAfterRowLock = new AtomicInteger(0);
109   final AtomicInteger ctPreAppend = new AtomicInteger(0);
110   final AtomicInteger ctPreAppendAfterRowLock = new AtomicInteger(0);
111   final AtomicInteger ctPostIncrement = new AtomicInteger(0);
112   final AtomicInteger ctPostAppend = new AtomicInteger(0);
113   final AtomicInteger ctPreCheckAndPut = new AtomicInteger(0);
114   final AtomicInteger ctPreCheckAndPutAfterRowLock = new AtomicInteger(0);
115   final AtomicInteger ctPostCheckAndPut = new AtomicInteger(0);
116   final AtomicInteger ctPreCheckAndDelete = new AtomicInteger(0);
117   final AtomicInteger ctPreCheckAndDeleteAfterRowLock = new AtomicInteger(0);
118   final AtomicInteger ctPostCheckAndDelete = new AtomicInteger(0);
119   final AtomicInteger ctPreScannerNext = new AtomicInteger(0);
120   final AtomicInteger ctPostScannerNext = new AtomicInteger(0);
121   final AtomicInteger ctPostScannerFilterRow = new AtomicInteger(0);
122   final AtomicInteger ctPreScannerClose = new AtomicInteger(0);
123   final AtomicInteger ctPostScannerClose = new AtomicInteger(0);
124   final AtomicInteger ctPreScannerOpen = new AtomicInteger(0);
125   final AtomicInteger ctPreStoreScannerOpen = new AtomicInteger(0);
126   final AtomicInteger ctPostScannerOpen = new AtomicInteger(0);
127   final AtomicInteger ctPreBulkLoadHFile = new AtomicInteger(0);
128   final AtomicInteger ctPostBulkLoadHFile = new AtomicInteger(0);
129   final AtomicInteger ctPreBatchMutate = new AtomicInteger(0);
130   final AtomicInteger ctPostBatchMutate = new AtomicInteger(0);
131   final AtomicInteger ctPreWALRestore = new AtomicInteger(0);
132   final AtomicInteger ctPostWALRestore = new AtomicInteger(0);
133   final AtomicInteger ctPreWALRestoreDeprecated = new AtomicInteger(0);
134   final AtomicInteger ctPostWALRestoreDeprecated = new AtomicInteger(0);
135   final AtomicInteger ctPreSplitBeforePONR = new AtomicInteger(0);
136   final AtomicInteger ctPreSplitAfterPONR = new AtomicInteger(0);
137   final AtomicInteger ctPreStoreFileReaderOpen = new AtomicInteger(0);
138   final AtomicInteger ctPostStoreFileReaderOpen = new AtomicInteger(0);
139   final AtomicInteger ctPostBatchMutateIndispensably = new AtomicInteger(0);
140   final AtomicInteger ctPostStartRegionOperation = new AtomicInteger(0);
141   final AtomicInteger ctPostCloseRegionOperation = new AtomicInteger(0);
142   final AtomicInteger ctPreWALAppend = new AtomicInteger(0);
143   final AtomicBoolean throwOnPostFlush = new AtomicBoolean(false);
144   static final String TABLE_SKIPPED = "SKIPPED_BY_PREWALRESTORE";
145   static final byte[] WAL_EXTENDED_ATTRIBUTE_BYTES = Bytes.toBytes("foo");
146 
147   public void setThrowOnPostFlush(Boolean val){
148     throwOnPostFlush.set(val);
149   }
150 
151   @Override
152   public void start(CoprocessorEnvironment e) throws IOException {
153     // this only makes sure that leases and locks are available to coprocessors
154     // from external packages
155     RegionCoprocessorEnvironment re = (RegionCoprocessorEnvironment)e;
156     Leases leases = re.getRegionServerServices().getLeases();
157     leases.createLease(re.getRegion().getRegionInfo().getRegionNameAsString(), 2000, null);
158     leases.cancelLease(re.getRegion().getRegionInfo().getRegionNameAsString());
159   }
160 
161   @Override
162   public void preOpen(ObserverContext<RegionCoprocessorEnvironment> c) {
163     ctPreOpen.incrementAndGet();
164   }
165 
166   @Override
167   public void postOpen(ObserverContext<RegionCoprocessorEnvironment> c) {
168     ctPostOpen.incrementAndGet();
169   }
170 
171   public boolean wasOpened() {
172     return ctPreOpen.get() > 0 && ctPostOpen.get() > 0;
173   }
174 
175   @Override
176   public void preClose(ObserverContext<RegionCoprocessorEnvironment> c, boolean abortRequested) {
177     ctPreClose.incrementAndGet();
178   }
179 
180   @Override
181   public void postClose(ObserverContext<RegionCoprocessorEnvironment> c, boolean abortRequested) {
182     ctPostClose.incrementAndGet();
183   }
184 
185   public boolean wasClosed() {
186     return ctPreClose.get() > 0 && ctPostClose.get() > 0;
187   }
188 
189   @Override
190   public InternalScanner preFlush(ObserverContext<RegionCoprocessorEnvironment> c,
191       Store store, InternalScanner scanner) throws IOException {
192     ctPreFlush.incrementAndGet();
193     return scanner;
194   }
195 
196   @Override
197   public InternalScanner preFlushScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
198       Store store, KeyValueScanner memstoreScanner, InternalScanner s) throws IOException {
199     ctPreFlushScannerOpen.incrementAndGet();
200     return null;
201   }
202 
203   @Override
204   public void postFlush(ObserverContext<RegionCoprocessorEnvironment> c,
205       Store store, StoreFile resultFile) throws IOException {
206     ctPostFlush.incrementAndGet();
207     if (throwOnPostFlush.get()){
208       throw new IOException("throwOnPostFlush is true in postFlush");
209     }
210   }
211 
212   public boolean wasFlushed() {
213     return ctPreFlush.get() > 0 && ctPostFlush.get() > 0;
214   }
215 
216   @Override
217   public void preSplit(ObserverContext<RegionCoprocessorEnvironment> c) {
218     ctPreSplit.incrementAndGet();
219   }
220 
221   @Override
222   public void preSplitBeforePONR(
223       ObserverContext<RegionCoprocessorEnvironment> ctx, byte[] splitKey,
224       List<Mutation> metaEntries) throws IOException {
225     ctPreSplitBeforePONR.incrementAndGet();
226   }
227   
228   @Override
229   public void preSplitAfterPONR(
230       ObserverContext<RegionCoprocessorEnvironment> ctx) throws IOException {
231     ctPreSplitAfterPONR.incrementAndGet();
232   }
233   
234   @Override
235   public void postSplit(ObserverContext<RegionCoprocessorEnvironment> c, Region l, Region r) {
236     ctPostSplit.incrementAndGet();
237   }
238 
239   public boolean wasSplit() {
240     return ctPreSplit.get() > 0 && ctPostSplit.get() > 0;
241   }
242 
243   @Override
244   public void preCompactSelection(ObserverContext<RegionCoprocessorEnvironment> c,
245       Store store, List<StoreFile> candidates) {
246     ctPreCompactSelect.incrementAndGet();
247   }
248 
249   @Override
250   public void postCompactSelection(ObserverContext<RegionCoprocessorEnvironment> c,
251       Store store, ImmutableList<StoreFile> selected) {
252     ctPostCompactSelect.incrementAndGet();
253   }
254 
255   @Override
256   public InternalScanner preCompact(ObserverContext<RegionCoprocessorEnvironment> e,
257       Store store, InternalScanner scanner, ScanType scanType) {
258     ctPreCompact.incrementAndGet();
259     return scanner;
260   }
261 
262   @Override
263   public InternalScanner preCompactScannerOpen(
264       final ObserverContext<RegionCoprocessorEnvironment> c,
265       Store store, List<? extends KeyValueScanner> scanners, ScanType scanType, long earliestPutTs,
266       InternalScanner s) throws IOException {
267     ctPreCompactScanner.incrementAndGet();
268     return null;
269   }
270 
271   @Override
272   public void postCompact(ObserverContext<RegionCoprocessorEnvironment> e,
273       Store store, StoreFile resultFile) {
274     ctPostCompact.incrementAndGet();
275   }
276 
277   public boolean wasCompacted() {
278     return ctPreCompact.get() > 0 && ctPostCompact.get() > 0;
279   }
280 
281   @Override
282   public RegionScanner preScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
283       final Scan scan,
284       final RegionScanner s) throws IOException {
285     ctPreScannerOpen.incrementAndGet();
286     return null;
287   }
288 
289   @Override
290   public KeyValueScanner preStoreScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
291       final Store store, final Scan scan, final NavigableSet<byte[]> targetCols,
292       final KeyValueScanner s) throws IOException {
293     ctPreStoreScannerOpen.incrementAndGet();
294     return null;
295   }
296 
297   @Override
298   public RegionScanner postScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> c,
299       final Scan scan, final RegionScanner s)
300       throws IOException {
301     ctPostScannerOpen.incrementAndGet();
302     return s;
303   }
304 
305   @Override
306   public boolean preScannerNext(final ObserverContext<RegionCoprocessorEnvironment> c,
307       final InternalScanner s, final List<Result> results,
308       final int limit, final boolean hasMore) throws IOException {
309     ctPreScannerNext.incrementAndGet();
310     return hasMore;
311   }
312 
313   @Override
314   public boolean postScannerNext(final ObserverContext<RegionCoprocessorEnvironment> c,
315       final InternalScanner s, final List<Result> results, final int limit,
316       final boolean hasMore) throws IOException {
317     ctPostScannerNext.incrementAndGet();
318     return hasMore;
319   }
320 
321   @Override
322   public boolean postScannerFilterRow(final ObserverContext<RegionCoprocessorEnvironment> e,
323       final InternalScanner s, final byte[] currentRow, final int offset, final short length,
324       final boolean hasMore) throws IOException {
325     ctPostScannerFilterRow.incrementAndGet();
326     return hasMore;
327   }
328 
329   @Override
330   public void preScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
331       final InternalScanner s) throws IOException {
332     ctPreScannerClose.incrementAndGet();
333   }
334 
335   @Override
336   public void postScannerClose(final ObserverContext<RegionCoprocessorEnvironment> c,
337       final InternalScanner s) throws IOException {
338     ctPostScannerClose.incrementAndGet();
339   }
340 
341   @Override
342   public void preGetOp(final ObserverContext<RegionCoprocessorEnvironment> c, final Get get,
343       final List<Cell> results) throws IOException {
344     RegionCoprocessorEnvironment e = c.getEnvironment();
345     assertNotNull(e);
346     assertNotNull(e.getRegion());
347     assertNotNull(get);
348     assertNotNull(results);
349     ctPreGet.incrementAndGet();
350   }
351 
352   @Override
353   public void postGetOp(final ObserverContext<RegionCoprocessorEnvironment> c, final Get get,
354       final List<Cell> results) {
355     RegionCoprocessorEnvironment e = c.getEnvironment();
356     assertNotNull(e);
357     assertNotNull(e.getRegion());
358     assertNotNull(get);
359     assertNotNull(results);
360     if (e.getRegion().getTableDesc().getTableName().equals(
361         TestRegionObserverInterface.TEST_TABLE)) {
362       boolean foundA = false;
363       boolean foundB = false;
364       boolean foundC = false;
365       for (Cell kv: results) {
366         if (CellUtil.matchingFamily(kv, TestRegionObserverInterface.A)) {
367           foundA = true;
368         }
369         if (CellUtil.matchingFamily(kv, TestRegionObserverInterface.B)) {
370           foundB = true;
371         }
372         if (CellUtil.matchingFamily(kv, TestRegionObserverInterface.C)) {
373           foundC = true;
374         }
375       }
376       assertTrue(foundA);
377       assertTrue(foundB);
378       assertTrue(foundC);
379     }
380     ctPostGet.incrementAndGet();
381   }
382 
383   @Override
384   public void prePut(final ObserverContext<RegionCoprocessorEnvironment> c, 
385       final Put put, final WALEdit edit,
386       final Durability durability) throws IOException {
387     Map<byte[], List<Cell>> familyMap  = put.getFamilyCellMap();
388     RegionCoprocessorEnvironment e = c.getEnvironment();
389     assertNotNull(e);
390     assertNotNull(e.getRegion());
391     assertNotNull(familyMap);
392     if (e.getRegion().getTableDesc().getTableName().equals(
393         TestRegionObserverInterface.TEST_TABLE)) {
394       List<Cell> cells = familyMap.get(TestRegionObserverInterface.A);
395       assertNotNull(cells);
396       assertNotNull(cells.get(0));
397       KeyValue kv = (KeyValue)cells.get(0);
398       assertTrue(Bytes.equals(kv.getQualifier(),
399           TestRegionObserverInterface.A));
400       cells = familyMap.get(TestRegionObserverInterface.B);
401       assertNotNull(cells);
402       assertNotNull(cells.get(0));
403       kv = (KeyValue)cells.get(0);
404       assertTrue(Bytes.equals(kv.getQualifier(),
405           TestRegionObserverInterface.B));
406       cells = familyMap.get(TestRegionObserverInterface.C);
407       assertNotNull(cells);
408       assertNotNull(cells.get(0));
409       kv = (KeyValue)cells.get(0);
410       assertTrue(Bytes.equals(kv.getQualifier(),
411           TestRegionObserverInterface.C));
412     }
413     ctPrePut.incrementAndGet();
414   }
415 
416   @Override
417   public void postPut(final ObserverContext<RegionCoprocessorEnvironment> c,
418       final Put put, final WALEdit edit,
419       final Durability durability) throws IOException {
420     Map<byte[], List<Cell>> familyMap  = put.getFamilyCellMap();
421     RegionCoprocessorEnvironment e = c.getEnvironment();
422     assertNotNull(e);
423     assertNotNull(e.getRegion());
424     assertNotNull(familyMap);
425     List<Cell> cells = familyMap.get(TestRegionObserverInterface.A);
426     if (e.getRegion().getTableDesc().getTableName().equals(
427         TestRegionObserverInterface.TEST_TABLE)) {
428       assertNotNull(cells);
429       assertNotNull(cells.get(0));
430       // KeyValue v1 expectation.  Cast for now until we go all Cell all the time. TODO
431       KeyValue kv = (KeyValue)cells.get(0);
432       assertTrue(Bytes.equals(kv.getQualifier(), TestRegionObserverInterface.A));
433       cells = familyMap.get(TestRegionObserverInterface.B);
434       assertNotNull(cells);
435       assertNotNull(cells.get(0));
436       // KeyValue v1 expectation.  Cast for now until we go all Cell all the time. TODO
437       kv = (KeyValue)cells.get(0);
438       assertTrue(Bytes.equals(kv.getQualifier(), TestRegionObserverInterface.B));
439       cells = familyMap.get(TestRegionObserverInterface.C);
440       assertNotNull(cells);
441       assertNotNull(cells.get(0));
442       // KeyValue v1 expectation.  Cast for now until we go all Cell all the time. TODO
443       kv = (KeyValue)cells.get(0);
444       assertTrue(Bytes.equals(kv.getQualifier(), TestRegionObserverInterface.C));
445     }
446     ctPostPut.incrementAndGet();
447   }
448 
449   @Override
450   public void preDelete(final ObserverContext<RegionCoprocessorEnvironment> c, 
451       final Delete delete, final WALEdit edit,
452       final Durability durability) throws IOException {
453     Map<byte[], List<Cell>> familyMap  = delete.getFamilyCellMap();
454     RegionCoprocessorEnvironment e = c.getEnvironment();
455     assertNotNull(e);
456     assertNotNull(e.getRegion());
457     assertNotNull(familyMap);
458     if (ctBeforeDelete.get() > 0) {
459       ctPreDeleted.incrementAndGet();
460     }
461   }
462 
463   @Override
464   public void prePrepareTimeStampForDeleteVersion(ObserverContext<RegionCoprocessorEnvironment> e,
465       Mutation delete, Cell cell, byte[] byteNow, Get get) throws IOException {
466     ctPrePrepareDeleteTS.incrementAndGet();
467   }
468 
469   @Override
470   public void postDelete(final ObserverContext<RegionCoprocessorEnvironment> c, 
471       final Delete delete, final WALEdit edit,
472       final Durability durability) throws IOException {
473     Map<byte[], List<Cell>> familyMap  = delete.getFamilyCellMap();
474     RegionCoprocessorEnvironment e = c.getEnvironment();
475     assertNotNull(e);
476     assertNotNull(e.getRegion());
477     assertNotNull(familyMap);
478     ctBeforeDelete.set(0);
479     ctPostDeleted.incrementAndGet();
480   }
481   
482   @Override
483   public void preBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,
484       MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
485     RegionCoprocessorEnvironment e = c.getEnvironment();
486     assertNotNull(e);
487     assertNotNull(e.getRegion());
488     assertNotNull(miniBatchOp);
489     ctPreBatchMutate.incrementAndGet();
490   }
491 
492   @Override
493   public void postBatchMutate(final ObserverContext<RegionCoprocessorEnvironment> c,
494       final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
495     RegionCoprocessorEnvironment e = c.getEnvironment();
496     assertNotNull(e);
497     assertNotNull(e.getRegion());
498     assertNotNull(miniBatchOp);
499     ctPostBatchMutate.incrementAndGet();
500   }
501 
502   @Override
503   public void postStartRegionOperation(final ObserverContext<RegionCoprocessorEnvironment> ctx,
504       Operation op) throws IOException {
505     ctPostStartRegionOperation.incrementAndGet();
506   }
507 
508   @Override
509   public void postCloseRegionOperation(final ObserverContext<RegionCoprocessorEnvironment> ctx,
510       Operation op) throws IOException {
511     if (ctPostStartRegionOperation.get() > 0) {
512       ctPostCloseRegionOperation.incrementAndGet();
513     }
514   }
515 
516   @Override
517   public void postBatchMutateIndispensably(final ObserverContext<RegionCoprocessorEnvironment> ctx,
518       MiniBatchOperationInProgress<Mutation> miniBatchOp, final boolean success) throws IOException {
519     ctPostBatchMutateIndispensably.incrementAndGet();
520   }
521 
522   @Override
523   public void preGetClosestRowBefore(final ObserverContext<RegionCoprocessorEnvironment> c,
524       final byte[] row, final byte[] family, final Result result)
525       throws IOException {
526     RegionCoprocessorEnvironment e = c.getEnvironment();
527     assertNotNull(e);
528     assertNotNull(e.getRegion());
529     assertNotNull(row);
530     assertNotNull(result);
531     if (ctBeforeDelete.get() > 0) {
532       ctPreGetClosestRowBefore.incrementAndGet();
533     }
534   }
535 
536   @Override
537   public void postGetClosestRowBefore(final ObserverContext<RegionCoprocessorEnvironment> c,
538       final byte[] row, final byte[] family, final Result result)
539       throws IOException {
540     RegionCoprocessorEnvironment e = c.getEnvironment();
541     assertNotNull(e);
542     assertNotNull(e.getRegion());
543     assertNotNull(row);
544     assertNotNull(result);
545     ctPostGetClosestRowBefore.incrementAndGet();
546   }
547 
548   @Override
549   public Result preIncrement(final ObserverContext<RegionCoprocessorEnvironment> c,
550       final Increment increment) throws IOException {
551     ctPreIncrement.incrementAndGet();
552     return null;
553   }
554 
555   @Override
556   public Result preIncrementAfterRowLock(ObserverContext<RegionCoprocessorEnvironment> e,
557       Increment increment) throws IOException {
558     ctPreIncrementAfterRowLock.incrementAndGet();
559     return null;
560   }
561 
562   @Override
563   public Result postIncrement(final ObserverContext<RegionCoprocessorEnvironment> c,
564       final Increment increment, final Result result) throws IOException {
565     ctPostIncrement.incrementAndGet();
566     return result;
567   }
568 
569   @Override
570   public boolean preCheckAndPut(ObserverContext<RegionCoprocessorEnvironment> e, byte[] row,
571       byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator,
572       Put put, boolean result) throws IOException {
573     ctPreCheckAndPut.incrementAndGet();
574     return true;
575   }
576 
577   @Override
578   public boolean preCheckAndPutAfterRowLock(ObserverContext<RegionCoprocessorEnvironment> e,
579       byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp,
580       ByteArrayComparable comparator, Put put, boolean result) throws IOException {
581     ctPreCheckAndPutAfterRowLock.incrementAndGet();
582     return true;
583   }
584 
585   @Override
586   public boolean postCheckAndPut(ObserverContext<RegionCoprocessorEnvironment> e, byte[] row,
587       byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator,
588       Put put, boolean result) throws IOException {
589     ctPostCheckAndPut.incrementAndGet();
590     return true;
591   }
592 
593   @Override
594   public boolean preCheckAndDelete(ObserverContext<RegionCoprocessorEnvironment> e, byte[] row,
595       byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator,
596       Delete delete, boolean result) throws IOException {
597     ctPreCheckAndDelete.incrementAndGet();
598     return true;
599   }
600 
601   @Override
602   public boolean preCheckAndDeleteAfterRowLock(ObserverContext<RegionCoprocessorEnvironment> e,
603       byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp,
604       ByteArrayComparable comparator, Delete delete, boolean result) throws IOException {
605     ctPreCheckAndDeleteAfterRowLock.incrementAndGet();
606     return true;
607   }
608 
609   @Override
610   public boolean postCheckAndDelete(ObserverContext<RegionCoprocessorEnvironment> e, byte[] row,
611       byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator,
612       Delete delete, boolean result) throws IOException {
613     ctPostCheckAndDelete.incrementAndGet();
614     return true;
615   }
616 
617   @Override
618   public Result preAppendAfterRowLock(ObserverContext<RegionCoprocessorEnvironment> e, 
619       Append append) throws IOException {
620     ctPreAppendAfterRowLock.incrementAndGet();
621     return null;
622   }
623 
624   @Override
625   public Result preAppend(ObserverContext<RegionCoprocessorEnvironment> e, Append append)
626       throws IOException {
627     ctPreAppend.incrementAndGet();
628     return null;
629   }
630 
631   @Override
632   public Result postAppend(ObserverContext<RegionCoprocessorEnvironment> e, Append append,
633       Result result) throws IOException {
634     ctPostAppend.incrementAndGet();
635     return null;
636   }
637 
638   @Override
639   public void preBulkLoadHFile(ObserverContext<RegionCoprocessorEnvironment> ctx,
640                                List<Pair<byte[], String>> familyPaths) throws IOException {
641     RegionCoprocessorEnvironment e = ctx.getEnvironment();
642     assertNotNull(e);
643     assertNotNull(e.getRegion());
644     if (e.getRegion().getTableDesc().getTableName().equals(
645         TestRegionObserverInterface.TEST_TABLE)) {
646       assertNotNull(familyPaths);
647       assertEquals(1,familyPaths.size());
648       assertArrayEquals(familyPaths.get(0).getFirst(), TestRegionObserverInterface.A);
649       String familyPath = familyPaths.get(0).getSecond();
650       String familyName = Bytes.toString(TestRegionObserverInterface.A);
651       assertEquals(familyPath.substring(familyPath.length()-familyName.length()-1),"/"+familyName);
652     }
653     ctPreBulkLoadHFile.incrementAndGet();
654   }
655 
656   @Override
657   public boolean postBulkLoadHFile(ObserverContext<RegionCoprocessorEnvironment> ctx,
658       List<Pair<byte[], String>> familyPaths, boolean hasLoaded) throws IOException {
659     RegionCoprocessorEnvironment e = ctx.getEnvironment();
660     assertNotNull(e);
661     assertNotNull(e.getRegion());
662     if (e.getRegion().getTableDesc().getTableName().equals(
663         TestRegionObserverInterface.TEST_TABLE)) {
664       assertNotNull(familyPaths);
665       assertEquals(1,familyPaths.size());
666       assertArrayEquals(familyPaths.get(0).getFirst(), TestRegionObserverInterface.A);
667       String familyPath = familyPaths.get(0).getSecond();
668       String familyName = Bytes.toString(TestRegionObserverInterface.A);
669       assertEquals(familyPath.substring(familyPath.length()-familyName.length()-1),"/"+familyName);
670     }
671     ctPostBulkLoadHFile.incrementAndGet();
672     return hasLoaded;
673   }
674 
675   @Override
676   public void preWALRestore(ObserverContext<? extends RegionCoprocessorEnvironment> env,
677       HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
678     String tableName = logKey.getTablename().getNameAsString();
679     if (tableName.equals(TABLE_SKIPPED)) {
680       // skip recovery of TABLE_SKIPPED for testing purpose
681       env.bypass();
682       return;
683     }
684     ctPreWALRestore.incrementAndGet();
685   }
686 
687   @Override
688   public void preWALRestore(ObserverContext<RegionCoprocessorEnvironment> env, HRegionInfo info,
689                             HLogKey logKey, WALEdit logEdit) throws IOException {
690     preWALRestore(env, info, (WALKey)logKey, logEdit);
691     ctPreWALRestoreDeprecated.incrementAndGet();
692   }
693 
694   @Override
695   public void postWALRestore(ObserverContext<? extends RegionCoprocessorEnvironment> env,
696                              HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
697     ctPostWALRestore.incrementAndGet();
698   }
699 
700   @Override
701   public void postWALRestore(ObserverContext<RegionCoprocessorEnvironment> env,
702                              HRegionInfo info, HLogKey logKey, WALEdit logEdit) throws IOException {
703     postWALRestore(env, info, (WALKey)logKey, logEdit);
704     ctPostWALRestoreDeprecated.incrementAndGet();
705   }
706 
707   @Override
708   public Reader preStoreFileReaderOpen(ObserverContext<RegionCoprocessorEnvironment> ctx,
709       FileSystem fs, Path p, FSDataInputStreamWrapper in, long size, CacheConfig cacheConf,
710       Reference r, Reader reader) throws IOException {
711     ctPreStoreFileReaderOpen.incrementAndGet();
712     return null;
713   }
714 
715   @Override
716   public Reader postStoreFileReaderOpen(ObserverContext<RegionCoprocessorEnvironment> ctx,
717       FileSystem fs, Path p, FSDataInputStreamWrapper in, long size, CacheConfig cacheConf,
718       Reference r, Reader reader) throws IOException {
719     ctPostStoreFileReaderOpen.incrementAndGet();
720     return reader;
721   }
722 
723   @Override
724   public void preWALAppend(ObserverContext<RegionCoprocessorEnvironment> ctx,
725                            WALKey key, WALEdit edit) throws IOException {
726     ctPreWALAppend.incrementAndGet();
727 
728     key.addExtendedAttribute(Integer.toString(ctPreWALAppend.get()),
729         Bytes.toBytes("foo"));
730   }
731 
732   public boolean hadPreGet() {
733     return ctPreGet.get() > 0;
734   }
735 
736   public boolean hadPostGet() {
737     return ctPostGet.get() > 0;
738   }
739 
740   public boolean hadPrePut() {
741     return ctPrePut.get() > 0;
742   }
743 
744   public boolean hadPostPut() {
745     return ctPostPut.get() > 0;
746   }
747   
748   public boolean hadPreBatchMutate() {
749     return ctPreBatchMutate.get() > 0;
750   }
751 
752   public boolean hadPostBatchMutate() {
753     return ctPostBatchMutate.get() > 0;
754   }
755 
756   public boolean hadPostBatchMutateIndispensably() {
757     return ctPostBatchMutateIndispensably.get() > 0;
758   }
759 
760   public boolean hadPostStartRegionOperation() {
761     return ctPostStartRegionOperation.get() > 0;
762   }
763 
764   public boolean hadPostCloseRegionOperation() {
765     return ctPostCloseRegionOperation.get() > 0;
766   }
767 
768   public boolean hadDelete() {
769     return !(ctBeforeDelete.get() > 0);
770   }
771 
772   public int getCtPostStartRegionOperation() {
773     return ctPostStartRegionOperation.get();
774   }
775 
776   public int getCtPostCloseRegionOperation() {
777     return ctPostCloseRegionOperation.get();
778   }
779 
780   public boolean hadPreCheckAndPut() {
781     return ctPreCheckAndPut.get() > 0;
782   }
783 
784   public boolean hadPreCheckAndPutAfterRowLock() {
785     return ctPreCheckAndPutAfterRowLock.get() > 0;
786   }
787 
788   public boolean hadPostCheckAndPut() {
789     return ctPostCheckAndPut.get() > 0;
790   }
791 
792   public boolean hadPreCheckAndDelete() {
793     return ctPreCheckAndDelete.get() > 0;
794   }
795 
796   public boolean hadPreCheckAndDeleteAfterRowLock() {
797     return ctPreCheckAndDeleteAfterRowLock.get() > 0;
798   }
799 
800   public boolean hadPostCheckAndDelete() {
801     return ctPostCheckAndDelete.get() > 0;
802   }
803 
804   public boolean hadPreIncrement() {
805     return ctPreIncrement.get() > 0;
806   }
807   
808   public boolean hadPreIncrementAfterRowLock() {
809     return ctPreIncrementAfterRowLock.get() > 0;
810   }
811 
812   public boolean hadPostIncrement() {
813     return ctPostIncrement.get() > 0;
814   }
815 
816   public boolean hadPreAppend() {
817     return ctPreAppend.get() > 0;
818   }
819 
820   public boolean hadPreAppendAfterRowLock() {
821     return ctPreAppendAfterRowLock.get() > 0;
822   }
823 
824   public boolean hadPostAppend() {
825     return ctPostAppend.get() > 0;
826   }
827 
828   public boolean hadPrePreparedDeleteTS() {
829     return ctPrePrepareDeleteTS.get() > 0;
830   }
831   
832   public boolean hadPreWALRestore() {
833     return ctPreWALRestore.get() > 0;
834   }
835 
836   public boolean hadPostWALRestore() {
837     return ctPostWALRestore.get() > 0;
838   }
839 
840   public boolean wasScannerNextCalled() {
841     return ctPreScannerNext.get() > 0 && ctPostScannerNext.get() > 0;
842   }
843   public boolean wasScannerFilterRowCalled() {
844     return ctPostScannerFilterRow.get() > 0;
845   }
846   public boolean wasScannerCloseCalled() {
847     return ctPreScannerClose.get() > 0 && ctPostScannerClose.get() > 0;
848   }
849   public boolean wasScannerOpenCalled() {
850     return ctPreScannerOpen.get() > 0 && ctPostScannerOpen.get() > 0;
851   }
852   public boolean hadDeleted() {
853     return ctPreDeleted.get() > 0 && ctPostDeleted.get() > 0;
854   }
855 
856   public boolean hadPostBulkLoadHFile() {
857     return ctPostBulkLoadHFile.get() > 0;
858   }
859 
860   public boolean hadPreBulkLoadHFile() {
861     return ctPreBulkLoadHFile.get() > 0;
862   }
863 
864 
865   public int getCtBeforeDelete() {
866     return ctBeforeDelete.get();
867   }
868 
869   public int getCtPreOpen() {
870     return ctPreOpen.get();
871   }
872 
873   public int getCtPostOpen() {
874     return ctPostOpen.get();
875   }
876 
877   public int getCtPreClose() {
878     return ctPreClose.get();
879   }
880 
881   public int getCtPostClose() {
882     return ctPostClose.get();
883   }
884 
885   public int getCtPreFlush() {
886     return ctPreFlush.get();
887   }
888 
889   public int getCtPreFlushScannerOpen() {
890     return ctPreFlushScannerOpen.get();
891   }
892 
893   public int getCtPostFlush() {
894     return ctPostFlush.get();
895   }
896 
897   public int getCtPreSplit() {
898     return ctPreSplit.get();
899   }
900   
901   public int getCtPreSplitBeforePONR() {
902     return ctPreSplitBeforePONR.get();
903   }
904 
905   public int getCtPreSplitAfterPONR() {
906     return ctPreSplitAfterPONR.get();
907   }
908 
909   public int getCtPostSplit() {
910     return ctPostSplit.get();
911   }
912 
913   public int getCtPreCompactSelect() {
914     return ctPreCompactSelect.get();
915   }
916 
917   public int getCtPostCompactSelect() {
918     return ctPostCompactSelect.get();
919   }
920 
921   public int getCtPreCompactScanner() {
922     return ctPreCompactScanner.get();
923   }
924 
925   public int getCtPreCompact() {
926     return ctPreCompact.get();
927   }
928 
929   public int getCtPostCompact() {
930     return ctPostCompact.get();
931   }
932 
933   public int getCtPreGet() {
934     return ctPreGet.get();
935   }
936 
937   public int getCtPostGet() {
938     return ctPostGet.get();
939   }
940 
941   public int getCtPrePut() {
942     return ctPrePut.get();
943   }
944 
945   public int getCtPostPut() {
946     return ctPostPut.get();
947   }
948 
949   public int getCtPreDeleted() {
950     return ctPreDeleted.get();
951   }
952 
953   public int getCtPostDeleted() {
954     return ctPostDeleted.get();
955   }
956 
957   public int getCtPreGetClosestRowBefore() {
958     return ctPreGetClosestRowBefore.get();
959   }
960 
961   public int getCtPostGetClosestRowBefore() {
962     return ctPostGetClosestRowBefore.get();
963   }
964 
965   public int getCtPreIncrement() {
966     return ctPreIncrement.get();
967   }
968 
969   public int getCtPostIncrement() {
970     return ctPostIncrement.get();
971   }
972 
973   public int getCtPreWALRestore() {
974     return ctPreWALRestore.get();
975   }
976 
977   public int getCtPostWALRestore() {
978     return ctPostWALRestore.get();
979   }
980 
981   public int getCtPreWALRestoreDeprecated() {
982     return ctPreWALRestoreDeprecated.get();
983   }
984 
985   public int getCtPostWALRestoreDeprecated() {
986     return ctPostWALRestoreDeprecated.get();
987   }
988 
989   public int getCtPreWALAppend() {
990     return ctPreWALAppend.get();
991   }
992 
993   public boolean wasStoreFileReaderOpenCalled() {
994     return ctPreStoreFileReaderOpen.get() > 0 && ctPostStoreFileReaderOpen.get() > 0;
995   }
996 
997   /**
998    * This implementation should trigger our legacy support because it does not directly
999    * implement the newer API calls.
1000    */
1001   public static class Legacy extends SimpleRegionObserver {
1002   }
1003 }