Skip to content

Commit ede6a0a

Browse files
symatpetersomogyi
authored andcommitted
HBASE-22637 fix flaky test in TestMetaTableMetrics
Signed-off-by: Peter Somogyi <psomogyi@apache.org> Signed-off-by: Sakthi <sakthivel.azhaku@gmail.com>
1 parent 12c933a commit ede6a0a

File tree

1 file changed

+123
-110
lines changed

1 file changed

+123
-110
lines changed

hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMetaTableMetrics.java

Lines changed: 123 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@
1111

1212
package org.apache.hadoop.hbase.coprocessor;
1313

14-
import static org.junit.Assert.assertEquals;
15-
import static org.junit.Assert.assertNotNull;
1614
import static org.junit.Assert.assertTrue;
1715
import static org.junit.Assert.fail;
1816

1917
import java.io.IOException;
2018
import java.util.ArrayList;
21-
import java.util.HashSet;
19+
import java.util.Arrays;
20+
import java.util.Collections;
21+
import java.util.HashMap;
2222
import java.util.Hashtable;
2323
import java.util.Iterator;
2424
import java.util.List;
25+
import java.util.Map;
2526
import java.util.Random;
2627
import java.util.Set;
2728

@@ -47,7 +48,9 @@
4748
import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
4849
import org.apache.hadoop.hbase.testclassification.MediumTests;
4950
import 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;
5154
import org.junit.AfterClass;
5255
import org.junit.BeforeClass;
5356
import org.junit.ClassRule;
@@ -56,7 +59,6 @@
5659
import org.slf4j.Logger;
5760
import org.slf4j.LoggerFactory;
5861

59-
6062
@Category({ CoprocessorTests.class, MediumTests.class })
6163
public 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

Comments
 (0)