1111
1212package org .apache .hadoop .hbase .coprocessor ;
1313
14- import static org .junit .Assert .assertEquals ;
15- import static org .junit .Assert .assertNotNull ;
1614import static org .junit .Assert .assertTrue ;
1715import static org .junit .Assert .fail ;
1816
1917import java .io .IOException ;
2018import java .util .ArrayList ;
21- import java .util .HashSet ;
19+ import java .util .Arrays ;
20+ import java .util .Collections ;
21+ import java .util .HashMap ;
2222import java .util .Hashtable ;
2323import java .util .Iterator ;
2424import java .util .List ;
25+ import java .util .Map ;
2526import java .util .Random ;
2627import java .util .Set ;
2728
4748import org .apache .hadoop .hbase .testclassification .CoprocessorTests ;
4849import org .apache .hadoop .hbase .testclassification .MediumTests ;
4950import org .apache .hadoop .hbase .util .Bytes ;
50- import org .apache .hadoop .hbase .util .Threads ;
51+ import org .hamcrest .CustomTypeSafeMatcher ;
52+ import org .hamcrest .Matcher ;
53+ import org .hamcrest .core .AllOf ;
5154import org .junit .AfterClass ;
5255import org .junit .BeforeClass ;
5356import org .junit .ClassRule ;
5659import org .slf4j .Logger ;
5760import org .slf4j .LoggerFactory ;
5861
59-
6062@ Category ({ CoprocessorTests .class , MediumTests .class })
6163public class TestMetaTableMetrics {
6264
@@ -73,18 +75,19 @@ public class TestMetaTableMetrics {
7375 ColumnFamilyDescriptorBuilder .newBuilder (FAMILY ).build ();
7476 private static final int NUM_ROWS = 5 ;
7577 private static final String value = "foo" ;
76- private static Configuration conf = null ;
78+ private static final String METRICS_ATTRIBUTE_NAME_PREFIX = "MetaTable_" ;
79+ private static final List <String > METRICS_ATTRIBUTE_NAME_POSTFIXES =
80+ Arrays .asList ("_count" , "_mean_rate" , "_1min_rate" , "_5min_rate" , "_15min_rate" );
7781 private static int connectorPort = 61120 ;
7882
79- final byte [] cf = Bytes .toBytes ("info" );
80- final byte [] col = Bytes .toBytes ("any" );
81- byte [] tablename ;
82- final int nthreads = 20 ;
83+ private final byte [] cf = Bytes .toBytes ("info" );
84+ private final byte [] col = Bytes .toBytes ("any" );
85+ private byte [] tablename ;
86+ private final int nthreads = 20 ;
8387
8488 @ BeforeClass
8589 public static void setupBeforeClass () throws Exception {
86-
87- conf = UTIL .getConfiguration ();
90+ Configuration conf = UTIL .getConfiguration ();
8891 // Set system coprocessor so it can be applied to meta regions
8992 UTIL .getConfiguration ().set ("hbase.coprocessor.region.classes" ,
9093 MetaTableMetrics .class .getName ());
@@ -100,7 +103,7 @@ public static void setupBeforeClass() throws Exception {
100103 UTIL .startMiniCluster (1 );
101104 break ;
102105 } catch (Exception e ) {
103- LOG .debug ("Encountered exception when starting cluster. Trying port " + connectorPort , e );
106+ LOG .debug ("Encountered exception when starting cluster. Trying port {}" , connectorPort , e );
104107 try {
105108 // this is to avoid "IllegalStateException: A mini-cluster is already running"
106109 UTIL .shutdownMiniCluster ();
@@ -109,46 +112,108 @@ public static void setupBeforeClass() throws Exception {
109112 }
110113 }
111114 }
112- UTIL .getAdmin ()
113- .createTable (TableDescriptorBuilder .newBuilder (NAME1 )
114- .setColumnFamily (CFD )
115- .build ());
116115 }
117116
118117 @ AfterClass
119118 public static void tearDown () throws Exception {
120119 UTIL .shutdownMiniCluster ();
121120 }
122121
123- private void writeData (Table t ) throws IOException {
124- List <Put > puts = new ArrayList <>(NUM_ROWS );
125- for (int i = 0 ; i < NUM_ROWS ; i ++) {
126- Put p = new Put (Bytes .toBytes (i + 1 ));
127- p .addColumn (FAMILY , QUALIFIER , Bytes .toBytes (value ));
128- puts .add (p );
122+ // Verifies that meta table metrics exist in jmx. In case of one table (one region) with a single
123+ // client: 9 metrics
124+ // are generated and for each metrics, there should be 5 JMX attributes produced. e.g. for one
125+ // table, there should
126+ // be 5 MetaTable_table_<TableName>_request attributes, such as:
127+ // - MetaTable_table_TestExampleMetaTableMetricsOne_request_count
128+ // - MetaTable_table_TestExampleMetaTableMetricsOne_request_mean_rate
129+ // - MetaTable_table_TestExampleMetaTableMetricsOne_request_1min_rate
130+ // - MetaTable_table_TestExampleMetaTableMetricsOne_request_5min_rate
131+ // - MetaTable_table_TestExampleMetaTableMetricsOne_request_15min_rate
132+ @ Test
133+ public void testMetaTableMetricsInJmx () throws Exception {
134+ UTIL .getAdmin ()
135+ .createTable (TableDescriptorBuilder .newBuilder (NAME1 ).setColumnFamily (CFD ).build ());
136+ writeData (NAME1 );
137+ UTIL .deleteTable (NAME1 );
138+
139+ UTIL .waitFor (30000 , 2000 , true , () -> {
140+ Map <String , Double > jmxMetrics = readMetaTableJmxMetrics ();
141+ boolean allMetricsFound = AllOf .allOf (
142+ containsPositiveJmxAttributesFor ("MetaTable_get_request" ),
143+ containsPositiveJmxAttributesFor ("MetaTable_put_request" ),
144+ containsPositiveJmxAttributesFor ("MetaTable_delete_request" ),
145+ containsPositiveJmxAttributesFor ("MetaTable_region_.+_lossy_request" ),
146+ containsPositiveJmxAttributesFor ("MetaTable_table_" + NAME1 + "_request" ),
147+ containsPositiveJmxAttributesFor ("MetaTable_client_.+_put_request" ),
148+ containsPositiveJmxAttributesFor ("MetaTable_client_.+_get_request" ),
149+ containsPositiveJmxAttributesFor ("MetaTable_client_.+_delete_request" ),
150+ containsPositiveJmxAttributesFor ("MetaTable_client_.+_lossy_request" )
151+ ).matches (jmxMetrics );
152+
153+ if (allMetricsFound ) {
154+ LOG .info ("all the meta table metrics found with positive values: {}" , jmxMetrics );
155+ } else {
156+ LOG .warn ("couldn't find all the meta table metrics with positive values: {}" , jmxMetrics );
157+ }
158+ return allMetricsFound ;
159+ });
160+ }
161+
162+ @ Test
163+ public void testConcurrentAccess () {
164+ try {
165+ tablename = Bytes .toBytes ("hbase:meta" );
166+ int numRows = 3000 ;
167+ int numRowsInTableBefore = UTIL .countRows (TableName .valueOf (tablename ));
168+ putData (numRows );
169+ Thread .sleep (2000 );
170+ int numRowsInTableAfter = UTIL .countRows (TableName .valueOf (tablename ));
171+ assertTrue (numRowsInTableAfter >= numRowsInTableBefore + numRows );
172+ getData (numRows );
173+ } catch (InterruptedException e ) {
174+ LOG .info ("Caught InterruptedException while testConcurrentAccess: {}" , e .getMessage ());
175+ fail ();
176+ } catch (IOException e ) {
177+ LOG .info ("Caught IOException while testConcurrentAccess: {}" , e .getMessage ());
178+ fail ();
129179 }
130- t .put (puts );
131180 }
132181
133- private Set <String > readJmxMetricsWithRetry () throws IOException {
134- final int count = 0 ;
135- for (int i = 0 ; i < 10 ; i ++) {
136- Set <String > metrics = readJmxMetrics ();
137- if (metrics != null ) {
138- return metrics ;
182+ private void writeData (TableName tableName ) throws IOException {
183+ try (Table t = UTIL .getConnection ().getTable (tableName )) {
184+ List <Put > puts = new ArrayList <>(NUM_ROWS );
185+ for (int i = 0 ; i < NUM_ROWS ; i ++) {
186+ Put p = new Put (Bytes .toBytes (i + 1 ));
187+ p .addColumn (FAMILY , QUALIFIER , Bytes .toBytes (value ));
188+ puts .add (p );
139189 }
140- LOG .warn ("Failed to get jmxmetrics... sleeping, retrying; " + i + " of " + count + " times" );
141- Threads .sleep (1000 );
190+ t .put (puts );
142191 }
143- return null ;
192+ }
193+
194+ private Matcher <Map <String , Double >> containsPositiveJmxAttributesFor (final String regexp ) {
195+ return new CustomTypeSafeMatcher <Map <String , Double >>(
196+ "failed to find all the 5 positive JMX attributes for: " + regexp ) {
197+
198+ @ Override
199+ protected boolean matchesSafely (final Map <String , Double > values ) {
200+ for (String key : values .keySet ()) {
201+ for (String metricsNamePostfix : METRICS_ATTRIBUTE_NAME_POSTFIXES ) {
202+ if (key .matches (regexp + metricsNamePostfix ) && values .get (key ) > 0 ) {
203+ return true ;
204+ }
205+ }
206+ }
207+ return false ;
208+ }
209+ };
144210 }
145211
146212 /**
147213 * Read the attributes from Hadoop->HBase->RegionServer->MetaTableMetrics in JMX
148214 * @throws IOException when fails to retrieve jmx metrics.
149215 */
150- // this method comes from this class: TestStochasticBalancerJmxMetrics with minor modifications.
151- private Set <String > readJmxMetrics () throws IOException {
216+ private Map <String , Double > readMetaTableJmxMetrics () throws IOException {
152217 JMXConnector connector = null ;
153218 ObjectName target = null ;
154219 MBeanServerConnection mb = null ;
@@ -162,26 +227,30 @@ private Set<String> readJmxMetrics() throws IOException {
162227 pairs .put ("service" , "HBase" );
163228 pairs .put ("name" , "RegionServer" );
164229 pairs .put ("sub" ,
165- "Coprocessor.Region.CP_org.apache.hadoop.hbase.coprocessor"
166- + ".MetaTableMetrics" );
230+ "Coprocessor.Region.CP_org.apache.hadoop.hbase.coprocessor.MetaTableMetrics" );
167231 target = new ObjectName ("Hadoop" , pairs );
168232 MBeanInfo beanInfo = mb .getMBeanInfo (target );
169233
170- Set <String > existingAttrs = new HashSet <>();
234+ Map <String , Double > existingAttrs = new HashMap <>();
171235 for (MBeanAttributeInfo attrInfo : beanInfo .getAttributes ()) {
172- existingAttrs .add (attrInfo .getName ());
236+ Object value = mb .getAttribute (target , attrInfo .getName ());
237+ if (attrInfo .getName ().startsWith (METRICS_ATTRIBUTE_NAME_PREFIX )
238+ && value instanceof Number ) {
239+ existingAttrs .put (attrInfo .getName (), Double .parseDouble (value .toString ()));
240+ }
173241 }
242+ LOG .info ("MBean Found: {}" , target );
174243 return existingAttrs ;
175244 } catch (Exception e ) {
176- LOG .warn ("Failed to get bean." + target , e );
245+ LOG .warn ("Failed to get Meta Table Metrics bean (will retry later): {}" , target , e );
177246 if (mb != null ) {
178247 Set <ObjectInstance > instances = mb .queryMBeans (null , null );
179248 Iterator <ObjectInstance > iterator = instances .iterator ();
180- LOG .warn ( "MBean Found :" );
249+ LOG .debug ( "All the MBeans we found :" );
181250 while (iterator .hasNext ()) {
182251 ObjectInstance instance = iterator .next ();
183- LOG .warn ("Class Name: " + instance .getClassName ());
184- LOG . warn ( "Object Name: " + instance .getObjectName ());
252+ LOG .debug ("Class and object name: {} [{}]" , instance .getClassName (),
253+ instance .getObjectName ());
185254 }
186255 }
187256 } finally {
@@ -193,76 +262,20 @@ private Set<String> readJmxMetrics() throws IOException {
193262 }
194263 }
195264 }
196- return null ;
197- }
198-
199- // verifies meta table metrics exist from jmx
200- // for one table, there should be 5 MetaTable_table_<TableName> metrics.
201- // such as:
202- // [Time-limited test] example.TestMetaTableMetrics(204): ==
203- // MetaTable_table_TestExampleMetaTableMetricsOne_request_count
204- // [Time-limited test] example.TestMetaTableMetrics(204): ==
205- // MetaTable_table_TestExampleMetaTableMetricsOne_request_mean_rate
206- // [Time-limited test] example.TestMetaTableMetrics(204): ==
207- // MetaTable_table_TestExampleMetaTableMetricsOne_request_1min_rate
208- // [Time-limited test] example.TestMetaTableMetrics(204): ==
209- // MetaTable_table_TestExampleMetaTableMetricsOne_request_5min_rate
210- // [Time-limited test] example.TestMetaTableMetrics(204): ==
211- // MetaTable_table_TestExampleMetaTableMetricsOne_request_15min_rate
212- @ Test
213- public void test () throws IOException , InterruptedException {
214- try (Table t = UTIL .getConnection ().getTable (NAME1 )) {
215- writeData (t );
216- // Flush the data
217- UTIL .flush (NAME1 );
218- // Issue a compaction
219- UTIL .compact (NAME1 , true );
220- Thread .sleep (2000 );
221- }
222- Set <String > jmxMetrics = readJmxMetricsWithRetry ();
223- assertNotNull (jmxMetrics );
224- long name1TableMetricsCount =
225- jmxMetrics .stream ().filter (metric -> metric .contains ("MetaTable_table_" + NAME1 )).count ();
226- assertEquals (5L , name1TableMetricsCount );
227-
228- String putWithClientMetricNameRegex = "MetaTable_client_.+_put_request.*" ;
229- long putWithClientMetricsCount =
230- jmxMetrics .stream ().filter (metric -> metric .matches (putWithClientMetricNameRegex ))
231- .count ();
232- assertEquals (5L , putWithClientMetricsCount );
233- }
234-
235- @ Test
236- public void testConcurrentAccess () {
237- try {
238- tablename = Bytes .toBytes ("hbase:meta" );
239- int numRows = 3000 ;
240- int numRowsInTableBefore = UTIL .countRows (TableName .valueOf (tablename ));
241- putData (numRows );
242- Thread .sleep (2000 );
243- int numRowsInTableAfter = UTIL .countRows (TableName .valueOf (tablename ));
244- assertTrue (numRowsInTableAfter >= numRowsInTableBefore + numRows );
245- getData (numRows );
246- } catch (InterruptedException e ) {
247- LOG .info ("Caught InterruptedException while testConcurrentAccess: " + e .getMessage ());
248- fail ();
249- } catch (IOException e ) {
250- LOG .info ("Caught IOException while testConcurrentAccess: " + e .getMessage ());
251- fail ();
252- }
265+ return Collections .emptyMap ();
253266 }
254267
255- public void putData (int nrows ) throws InterruptedException {
256- LOG .info (String . format ( "Putting %d rows in hbase:meta" , nrows ) );
268+ private void putData (int nrows ) throws InterruptedException {
269+ LOG .info ("Putting {} rows in hbase:meta" , nrows );
257270 Thread [] threads = new Thread [nthreads ];
258271 for (int i = 1 ; i <= nthreads ; i ++) {
259272 threads [i - 1 ] = new PutThread (1 , nrows );
260273 }
261274 startThreadsAndWaitToJoin (threads );
262275 }
263276
264- public void getData (int nrows ) throws InterruptedException {
265- LOG .info (String . format ( "Getting %d rows from hbase:meta" , nrows ) );
277+ private void getData (int nrows ) throws InterruptedException {
278+ LOG .info ("Getting {} rows from hbase:meta" , nrows );
266279 Thread [] threads = new Thread [nthreads ];
267280 for (int i = 1 ; i <= nthreads ; i ++) {
268281 threads [i - 1 ] = new GetThread (1 , nrows );
@@ -279,11 +292,11 @@ private void startThreadsAndWaitToJoin(Thread[] threads) throws InterruptedExcep
279292 }
280293 }
281294
282- class PutThread extends Thread {
295+ private class PutThread extends Thread {
283296 int start ;
284297 int end ;
285298
286- public PutThread (int start , int end ) {
299+ PutThread (int start , int end ) {
287300 this .start = start ;
288301 this .end = end ;
289302 }
@@ -297,16 +310,16 @@ public void run() {
297310 table .put (p );
298311 }
299312 } catch (IOException e ) {
300- LOG .info ("Caught IOException while PutThread operation: " + e . getMessage () );
313+ LOG .warn ("Caught IOException while PutThread operation" , e );
301314 }
302315 }
303316 }
304317
305- class GetThread extends Thread {
318+ private class GetThread extends Thread {
306319 int start ;
307320 int end ;
308321
309- public GetThread (int start , int end ) {
322+ GetThread (int start , int end ) {
310323 this .start = start ;
311324 this .end = end ;
312325 }
@@ -319,7 +332,7 @@ public void run() {
319332 table .get (get );
320333 }
321334 } catch (IOException e ) {
322- LOG .info ("Caught IOException while GetThread operation: " + e . getMessage () );
335+ LOG .warn ("Caught IOException while GetThread operation" , e );
323336 }
324337 }
325338 }
0 commit comments