2525import java .io .IOException ;
2626import java .lang .reflect .Method ;
2727import java .util .ArrayList ;
28+ import java .util .Arrays ;
2829import java .util .List ;
2930import java .util .Optional ;
3031import org .apache .hadoop .conf .Configuration ;
4344import org .apache .hadoop .hbase .TableName ;
4445import org .apache .hadoop .hbase .client .Admin ;
4546import org .apache .hadoop .hbase .client .Append ;
47+ import org .apache .hadoop .hbase .client .ColumnFamilyDescriptorBuilder ;
4648import org .apache .hadoop .hbase .client .Delete ;
4749import org .apache .hadoop .hbase .client .Durability ;
4850import org .apache .hadoop .hbase .client .Get ;
5557import org .apache .hadoop .hbase .client .RowMutations ;
5658import org .apache .hadoop .hbase .client .Scan ;
5759import org .apache .hadoop .hbase .client .Table ;
60+ import org .apache .hadoop .hbase .client .TableDescriptor ;
61+ import org .apache .hadoop .hbase .client .TableDescriptorBuilder ;
5862import org .apache .hadoop .hbase .filter .FilterAllFilter ;
5963import org .apache .hadoop .hbase .io .hfile .CacheConfig ;
6064import org .apache .hadoop .hbase .io .hfile .HFile ;
7074import org .apache .hadoop .hbase .regionserver .StoreFile ;
7175import org .apache .hadoop .hbase .regionserver .compactions .CompactionLifeCycleTracker ;
7276import org .apache .hadoop .hbase .regionserver .compactions .CompactionRequest ;
77+ import org .apache .hadoop .hbase .regionserver .wal .WALActionsListener ;
7378import org .apache .hadoop .hbase .testclassification .CoprocessorTests ;
7479import org .apache .hadoop .hbase .testclassification .MediumTests ;
7580import org .apache .hadoop .hbase .tool .BulkLoadHFiles ;
7681import org .apache .hadoop .hbase .util .Bytes ;
7782import org .apache .hadoop .hbase .util .EnvironmentEdgeManager ;
7883import org .apache .hadoop .hbase .util .JVMClusterUtil ;
7984import org .apache .hadoop .hbase .util .Threads ;
85+ import org .apache .hadoop .hbase .wal .WALEdit ;
86+ import org .apache .hadoop .hbase .wal .WALKey ;
87+ import org .apache .hadoop .hbase .wal .WALKeyImpl ;
8088import org .junit .AfterClass ;
89+ import org .junit .Assert ;
8190import org .junit .BeforeClass ;
8291import org .junit .ClassRule ;
8392import org .junit .Rule ;
8493import org .junit .Test ;
8594import org .junit .experimental .categories .Category ;
8695import org .junit .rules .TestName ;
96+ import org .mockito .Mockito ;
8797import org .slf4j .Logger ;
8898import org .slf4j .LoggerFactory ;
8999
@@ -99,6 +109,7 @@ public class TestRegionObserverInterface {
99109 private static final Logger LOG = LoggerFactory .getLogger (TestRegionObserverInterface .class );
100110
101111 public static final TableName TEST_TABLE = TableName .valueOf ("TestTable" );
112+ public static final byte [] FAMILY = Bytes .toBytes ("f" );
102113 public final static byte [] A = Bytes .toBytes ("a" );
103114 public final static byte [] B = Bytes .toBytes ("b" );
104115 public final static byte [] C = Bytes .toBytes ("c" );
@@ -663,6 +674,97 @@ public void testPreWALRestoreSkip() throws Exception {
663674 table .close ();
664675 }
665676
677+ //called from testPreWALAppendIsWrittenToWAL
678+ private void testPreWALAppendHook (Table table , TableName tableName ) throws IOException {
679+ int expectedCalls = 0 ;
680+ String [] methodArray = new String [1 ];
681+ methodArray [0 ] = "getCtPreWALAppend" ;
682+ Object [] resultArray = new Object [1 ];
683+
684+ Put p = new Put (ROW );
685+ p .addColumn (A , A , A );
686+ table .put (p );
687+ resultArray [0 ] = ++expectedCalls ;
688+ verifyMethodResult (SimpleRegionObserver .class , methodArray , tableName , resultArray );
689+
690+ Append a = new Append (ROW );
691+ a .addColumn (B , B , B );
692+ table .append (a );
693+ resultArray [0 ] = ++expectedCalls ;
694+ verifyMethodResult (SimpleRegionObserver .class , methodArray , tableName , resultArray );
695+
696+ Increment i = new Increment (ROW );
697+ i .addColumn (C , C , 1 );
698+ table .increment (i );
699+ resultArray [0 ] = ++expectedCalls ;
700+ verifyMethodResult (SimpleRegionObserver .class , methodArray , tableName , resultArray );
701+
702+ Delete d = new Delete (ROW );
703+ table .delete (d );
704+ resultArray [0 ] = ++expectedCalls ;
705+ verifyMethodResult (SimpleRegionObserver .class , methodArray , tableName , resultArray );
706+ }
707+
708+ @ Test
709+ public void testPreWALAppend () throws Exception {
710+ SimpleRegionObserver sro = new SimpleRegionObserver ();
711+ ObserverContext ctx = Mockito .mock (ObserverContext .class );
712+ WALKey key = new WALKeyImpl (Bytes .toBytes ("region" ), TEST_TABLE ,
713+ EnvironmentEdgeManager .currentTime ());
714+ WALEdit edit = new WALEdit ();
715+ sro .preWALAppend (ctx , key , edit );
716+ Assert .assertEquals (1 , key .getExtendedAttributes ().size ());
717+ Assert .assertArrayEquals (SimpleRegionObserver .WAL_EXTENDED_ATTRIBUTE_BYTES ,
718+ key .getExtendedAttribute (Integer .toString (sro .getCtPreWALAppend ())));
719+ }
720+
721+ @ Test
722+ public void testPreWALAppendIsWrittenToWAL () throws Exception {
723+ final TableName tableName = TableName .valueOf (TEST_TABLE .getNameAsString () +
724+ "." + name .getMethodName ());
725+ Table table = util .createTable (tableName , new byte [][] { A , B , C });
726+
727+ PreWALAppendWALActionsListener listener = new PreWALAppendWALActionsListener ();
728+ List <HRegion > regions = util .getHBaseCluster ().getRegions (tableName );
729+ //should be only one region
730+ HRegion region = regions .get (0 );
731+ region .getWAL ().registerWALActionsListener (listener );
732+ testPreWALAppendHook (table , tableName );
733+ boolean [] expectedResults = {true , true , true , true };
734+ Assert .assertArrayEquals (expectedResults , listener .getWalKeysCorrectArray ());
735+
736+ }
737+
738+ @ Test
739+ public void testPreWALAppendNotCalledOnMetaEdit () throws Exception {
740+ final TableName tableName = TableName .valueOf (TEST_TABLE .getNameAsString () +
741+ "." + name .getMethodName ());
742+ TableDescriptorBuilder tdBuilder = TableDescriptorBuilder .newBuilder (tableName );
743+ ColumnFamilyDescriptorBuilder cfBuilder = ColumnFamilyDescriptorBuilder .newBuilder (FAMILY );
744+ tdBuilder .setColumnFamily (cfBuilder .build ());
745+ tdBuilder .setCoprocessor (SimpleRegionObserver .class .getName ());
746+ TableDescriptor td = tdBuilder .build ();
747+ Table table = util .createTable (td , new byte [][] { A , B , C });
748+
749+ PreWALAppendWALActionsListener listener = new PreWALAppendWALActionsListener ();
750+ List <HRegion > regions = util .getHBaseCluster ().getRegions (tableName );
751+ //should be only one region
752+ HRegion region = regions .get (0 );
753+
754+ region .getWAL ().registerWALActionsListener (listener );
755+ //flushing should write to the WAL
756+ region .flush (true );
757+ //so should compaction
758+ region .compact (false );
759+ //and so should closing the region
760+ region .close ();
761+
762+ //but we still shouldn't have triggered preWALAppend because no user data was written
763+ String [] methods = new String [] {"getCtPreWALAppend" };
764+ Object [] expectedResult = new Integer []{0 };
765+ verifyMethodResult (SimpleRegionObserver .class , methods , tableName , expectedResult );
766+ }
767+
666768 // check each region whether the coprocessor upcalls are called or not.
667769 private void verifyMethodResult (Class <?> coprocessor , String methodName [], TableName tableName ,
668770 Object value []) throws IOException {
@@ -711,4 +813,23 @@ private static void createHFile(Configuration conf, FileSystem fs, Path path, by
711813 writer .close ();
712814 }
713815 }
816+
817+ private static class PreWALAppendWALActionsListener implements WALActionsListener {
818+ boolean [] walKeysCorrect = {false , false , false , false };
819+
820+ @ Override
821+ public void postAppend (long entryLen , long elapsedTimeMillis ,
822+ WALKey logKey , WALEdit logEdit ) throws IOException {
823+ for (int k = 0 ; k < 4 ; k ++) {
824+ if (!walKeysCorrect [k ]) {
825+ walKeysCorrect [k ] = Arrays .equals (SimpleRegionObserver .WAL_EXTENDED_ATTRIBUTE_BYTES ,
826+ logKey .getExtendedAttribute (Integer .toString (k + 1 )));
827+ }
828+ }
829+ }
830+
831+ boolean [] getWalKeysCorrectArray () {
832+ return walKeysCorrect ;
833+ }
834+ }
714835}
0 commit comments