1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.coprocessor;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotEquals;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26
27 import java.io.IOException;
28 import java.util.List;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.Cell;
34 import org.apache.hadoop.hbase.CoprocessorEnvironment;
35 import org.apache.hadoop.hbase.HBaseTestingUtility;
36 import org.apache.hadoop.hbase.HColumnDescriptor;
37 import org.apache.hadoop.hbase.HRegionInfo;
38 import org.apache.hadoop.hbase.HRegionLocation;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.TableName;
41 import org.apache.hadoop.hbase.Waiter.Predicate;
42 import org.apache.hadoop.hbase.client.Admin;
43 import org.apache.hadoop.hbase.client.Connection;
44 import org.apache.hadoop.hbase.client.ConnectionFactory;
45 import org.apache.hadoop.hbase.client.Get;
46 import org.apache.hadoop.hbase.client.Mutation;
47 import org.apache.hadoop.hbase.client.Put;
48 import org.apache.hadoop.hbase.client.RegionLocator;
49 import org.apache.hadoop.hbase.client.Table;
50 import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
51 import org.apache.hadoop.hbase.metrics.Counter;
52 import org.apache.hadoop.hbase.metrics.Metric;
53 import org.apache.hadoop.hbase.metrics.MetricRegistries;
54 import org.apache.hadoop.hbase.metrics.MetricRegistry;
55 import org.apache.hadoop.hbase.metrics.MetricRegistryInfo;
56 import org.apache.hadoop.hbase.metrics.Timer;
57 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
58 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
59 import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MultiRowMutationService;
60 import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsRequest;
61 import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsResponse;
62 import org.apache.hadoop.hbase.regionserver.HRegionServer;
63 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
64 import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
65 import org.apache.hadoop.hbase.testclassification.MediumTests;
66 import org.apache.hadoop.hbase.util.Bytes;
67 import org.junit.AfterClass;
68 import org.junit.Before;
69 import org.junit.BeforeClass;
70 import org.junit.Test;
71 import org.junit.experimental.categories.Category;
72
73 import com.google.common.base.Optional;
74 import com.google.common.collect.Lists;
75 import com.google.protobuf.RpcCallback;
76 import com.google.protobuf.RpcController;
77 import com.google.protobuf.ServiceException;
78
79
80
81
82 @Category({CoprocessorTests.class, MediumTests.class})
83 public class TestCoprocessorMetrics {
84
85 private static final Log LOG = LogFactory.getLog(TestCoprocessorMetrics.class);
86 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
87
88 private static final byte[] foo = Bytes.toBytes("foo");
89 private static final byte[] bar = Bytes.toBytes("bar");
90
91
92
93 public static class CustomMasterObserver extends BaseMasterObserver {
94 private Timer createTableTimer;
95 private long start = Long.MIN_VALUE;
96
97 @Override
98 public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
99 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
100 super.preCreateTable(ctx, desc, regions);
101
102
103 this.start = System.currentTimeMillis();
104 }
105
106 @Override
107 public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
108 HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
109 super.postCreateTable(ctx, desc, regions);
110 if (this.start > 0) {
111 long time = System.currentTimeMillis() - start;
112 LOG.info("Create table took: " + time);
113 createTableTimer.updateMillis(time);
114 }
115 }
116
117 @Override
118 public void start(CoprocessorEnvironment env) throws IOException {
119 super.start(env);
120 if (env instanceof MasterCoprocessorEnvironment) {
121 MetricRegistry registry =
122 ((MasterCoprocessorEnvironment) env).getMetricRegistryForMaster();
123
124 createTableTimer = registry.timer("CreateTable");
125 }
126 }
127 }
128
129
130
131
132 public static class CustomRegionServerObserver extends BaseRegionServerObserver {
133
134 private Counter rollWALCounter;
135 @Override
136 public void postRollWALWriterRequest(ObserverContext<RegionServerCoprocessorEnvironment> ctx)
137 throws IOException {
138
139 rollWALCounter.increment();
140 super.postRollWALWriterRequest(ctx);
141 }
142
143 @Override
144 public void start(CoprocessorEnvironment env) throws IOException {
145 super.start(env);
146 if (env instanceof RegionServerCoprocessorEnvironment) {
147 MetricRegistry registry =
148 ((RegionServerCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
149
150 if (rollWALCounter == null) {
151 rollWALCounter = registry.counter("rollWALRequests");
152 }
153 }
154 }
155 }
156
157
158
159
160 public static class CustomWALObserver extends BaseWALObserver {
161 private Counter walEditsCount;
162
163 @Override
164 public void postWALWrite(ObserverContext<? extends WALCoprocessorEnvironment> ctx,
165 HRegionInfo info, org.apache.hadoop.hbase.wal.WALKey logKey,
166 WALEdit logEdit) throws IOException {
167 super.postWALWrite(ctx, info, logKey, logEdit);
168 walEditsCount.increment();
169 }
170
171 @Override
172 public void start(CoprocessorEnvironment env) throws IOException {
173 super.start(env);
174 if (env instanceof WALCoprocessorEnvironment) {
175 MetricRegistry registry =
176 ((WALCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
177
178 if (walEditsCount == null) {
179 walEditsCount = registry.counter("walEditsCount");
180 }
181 }
182 }
183 }
184
185
186
187
188 public static class CustomRegionObserver extends BaseRegionObserver {
189 private Counter preGetCounter;
190
191 @Override
192 public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
193 List<Cell> results) throws IOException {
194 super.preGetOp(e, get, results);
195 preGetCounter.increment();
196 }
197
198 @Override
199 public void start(CoprocessorEnvironment env) throws IOException {
200 super.start(env);
201
202 if (env instanceof RegionCoprocessorEnvironment) {
203 MetricRegistry registry =
204 ((RegionCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
205
206 if (preGetCounter == null) {
207 preGetCounter = registry.counter("preGetRequests");
208 }
209 }
210 }
211 }
212
213 public static class CustomRegionObserver2 extends CustomRegionObserver {
214 }
215
216
217
218
219 public static class CustomRegionEndpoint extends MultiRowMutationEndpoint {
220
221 private Timer endpointExecution;
222
223 @Override
224 public void mutateRows(RpcController controller, MutateRowsRequest request,
225 RpcCallback<MutateRowsResponse> done) {
226 long start = System.nanoTime();
227 super.mutateRows(controller, request, done);
228 endpointExecution.updateNanos(System.nanoTime() - start);
229 }
230
231 @Override
232 public void start(CoprocessorEnvironment env) throws IOException {
233 super.start(env);
234
235 if (env instanceof RegionCoprocessorEnvironment) {
236 MetricRegistry registry =
237 ((RegionCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
238
239 if (endpointExecution == null) {
240 endpointExecution = registry.timer("EndpointExecution");
241 }
242 }
243 }
244 }
245
246 @BeforeClass
247 public static void setupBeforeClass() throws Exception {
248 Configuration conf = UTIL.getConfiguration();
249
250 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
251 CustomMasterObserver.class.getName());
252 conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY,
253 CustomRegionServerObserver.class.getName());
254 conf.set(CoprocessorHost.WAL_COPROCESSOR_CONF_KEY,
255 CustomWALObserver.class.getName());
256 conf.setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, true);
257 UTIL.startMiniCluster();
258 }
259
260 @AfterClass
261 public static void teardownAfterClass() throws Exception {
262 UTIL.shutdownMiniCluster();
263 }
264
265 @Before
266 public void setup() throws IOException {
267 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
268 Admin admin = connection.getAdmin()) {
269 for (HTableDescriptor htd : admin.listTables()) {
270 UTIL.deleteTable(htd.getTableName());
271 }
272 }
273 }
274
275 @Test
276 public void testMasterObserver() throws IOException {
277
278 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForMasterCoprocessor(
279 CustomMasterObserver.class.getName());
280 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
281 assertTrue(registry.isPresent());
282
283 Optional<Metric> metric = registry.get().get("CreateTable");
284 assertTrue(metric.isPresent());
285
286 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
287 Admin admin = connection.getAdmin()) {
288
289 Timer createTableTimer = (Timer)metric.get();
290 long prevCount = createTableTimer.getHistogram().getCount();
291 LOG.info("Creating table");
292 admin.createTable(
293 new HTableDescriptor("testMasterObserver")
294 .addFamily(new HColumnDescriptor("foo")));
295
296 assertEquals(1, createTableTimer.getHistogram().getCount() - prevCount);
297 }
298 }
299
300 @Test
301 public void testRegionServerObserver() throws IOException {
302 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
303 Admin admin = connection.getAdmin()) {
304 LOG.info("Rolling WALs");
305 admin.rollWALWriter(UTIL.getMiniHBaseCluster().getServerHoldingMeta());
306 }
307
308
309 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForRSCoprocessor(
310 CustomRegionServerObserver.class.getName());
311
312 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
313 assertTrue(registry.isPresent());
314
315 Optional<Metric> metric = registry.get().get("rollWALRequests");
316 assertTrue(metric.isPresent());
317
318 Counter rollWalRequests = (Counter)metric.get();
319 assertEquals(1, rollWalRequests.getCount());
320 }
321
322 @Test
323 public void testWALObserver() throws IOException {
324
325 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForWALCoprocessor(
326 CustomWALObserver.class.getName());
327
328 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
329 assertTrue(registry.isPresent());
330
331 Optional<Metric> metric = registry.get().get("walEditsCount");
332 assertTrue(metric.isPresent());
333
334 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
335 Admin admin = connection.getAdmin()) {
336 admin.createTable(
337 new HTableDescriptor("testWALObserver")
338 .addFamily(new HColumnDescriptor("foo")));
339
340 Counter rollWalRequests = (Counter)metric.get();
341 long prevCount = rollWalRequests.getCount();
342 assertTrue(prevCount > 0);
343
344 try (Table table = connection.getTable(TableName.valueOf("testWALObserver"))) {
345 table.put(new Put(foo).addColumn(foo, foo, foo));
346 }
347
348 assertEquals(1, rollWalRequests.getCount() - prevCount);
349 }
350 }
351
352
353
354
355 private void assertPreGetRequestsCounter(Class<?> coprocClass) {
356
357 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForRegionCoprocessor(
358 coprocClass.getName());
359
360 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
361 assertTrue(registry.isPresent());
362
363 Optional<Metric> metric = registry.get().get("preGetRequests");
364 assertTrue(metric.isPresent());
365
366 Counter preGetRequests = (Counter)metric.get();
367 assertEquals(2, preGetRequests.getCount());
368 }
369
370 @Test
371 public void testRegionObserverSingleRegion() throws IOException {
372 TableName tableName = TableName.valueOf("testRegionObserverSingleRegion");
373 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
374 Admin admin = connection.getAdmin()) {
375 admin.createTable(
376 new HTableDescriptor(tableName)
377 .addFamily(new HColumnDescriptor(foo))
378
379 .addCoprocessor(CustomRegionObserver.class.getName()));
380 try (Table table = connection.getTable(tableName)) {
381 table.get(new Get(foo));
382 table.get(new Get(foo));
383 }
384 }
385
386 assertPreGetRequestsCounter(CustomRegionObserver.class);
387 }
388
389 @Test
390 public void testRegionObserverMultiRegion() throws IOException {
391 TableName tableName = TableName.valueOf("testRegionObserverMultiRegion");
392 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
393 Admin admin = connection.getAdmin()) {
394 admin.createTable(
395 new HTableDescriptor(tableName)
396 .addFamily(new HColumnDescriptor(foo))
397
398 .addCoprocessor(CustomRegionObserver.class.getName())
399 , new byte[][]{foo});
400 try (Table table = connection.getTable(tableName);
401 RegionLocator locator = connection.getRegionLocator(tableName)) {
402 table.get(new Get(bar));
403 table.get(new Get(foo));
404 assertEquals(2, locator.getAllRegionLocations().size());
405 assertNotEquals(locator.getRegionLocation(bar).getRegionInfo(),
406 locator.getRegionLocation(foo).getRegionInfo());
407 }
408 }
409
410 assertPreGetRequestsCounter(CustomRegionObserver.class);
411 }
412
413 @Test
414 public void testRegionObserverMultiTable() throws IOException {
415 TableName tableName1 = TableName.valueOf("testRegionObserverMultiTable1");
416 TableName tableName2 = TableName.valueOf("testRegionObserverMultiTable2");
417 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
418 Admin admin = connection.getAdmin()) {
419 admin.createTable(
420 new HTableDescriptor(tableName1)
421 .addFamily(new HColumnDescriptor(foo))
422
423 .addCoprocessor(CustomRegionObserver.class.getName()));
424 admin.createTable(
425 new HTableDescriptor(tableName2)
426 .addFamily(new HColumnDescriptor(foo))
427
428 .addCoprocessor(CustomRegionObserver.class.getName()));
429 try (Table table1 = connection.getTable(tableName1);
430 Table table2 = connection.getTable(tableName2);) {
431 table1.get(new Get(bar));
432 table2.get(new Get(foo));
433 }
434 }
435 assertPreGetRequestsCounter(CustomRegionObserver.class);
436 }
437
438 @Test
439 public void testRegionObserverMultiCoprocessor() throws IOException {
440 TableName tableName = TableName.valueOf("testRegionObserverMultiCoprocessor");
441 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
442 Admin admin = connection.getAdmin()) {
443 admin.createTable(
444 new HTableDescriptor(tableName)
445 .addFamily(new HColumnDescriptor(foo))
446
447 .addCoprocessor(CustomRegionObserver.class.getName())
448 .addCoprocessor(CustomRegionObserver2.class.getName()));
449 try (Table table = connection.getTable(tableName)) {
450 table.get(new Get(foo));
451 table.get(new Get(foo));
452 }
453 }
454
455
456 assertPreGetRequestsCounter(CustomRegionObserver.class);
457 assertPreGetRequestsCounter(CustomRegionObserver2.class);
458 }
459
460 @Test
461 public void testRegionObserverAfterRegionClosed() throws IOException {
462 TableName tableName = TableName.valueOf("testRegionObserverAfterRegionClosed");
463 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
464 Admin admin = connection.getAdmin()) {
465 admin.createTable(
466 new HTableDescriptor(tableName)
467 .addFamily(new HColumnDescriptor(foo))
468
469 .addCoprocessor(CustomRegionObserver.class.getName())
470 , new byte[][]{foo});
471 try (Table table = connection.getTable(tableName)) {
472 table.get(new Get(foo));
473 table.get(new Get(foo));
474 }
475
476 assertPreGetRequestsCounter(CustomRegionObserver.class);
477
478
479 try (RegionLocator locator = connection.getRegionLocator(tableName)) {
480 final HRegionLocation loc = locator.getRegionLocation(foo);
481 admin.closeRegion(loc.getServerName(), loc.getRegionInfo());
482
483 final HRegionServer server = UTIL.getMiniHBaseCluster().getRegionServer(loc.getServerName());
484 UTIL.waitFor(30000,new Predicate<IOException>() {
485 @Override
486 public boolean evaluate() throws IOException {
487 return server.getOnlineRegion(loc.getRegionInfo().getRegionName()) == null;
488 }
489 });
490 assertNull(server.getOnlineRegion(loc.getRegionInfo().getRegionName()));
491 }
492
493
494 assertPreGetRequestsCounter(CustomRegionObserver.class);
495
496
497 admin.disableTable(tableName);
498
499 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForRegionCoprocessor(
500 CustomRegionObserver.class.getName());
501
502
503 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
504 assertFalse(registry.isPresent());
505 }
506 }
507
508 @Test
509 public void testRegionObserverEndpoint() throws IOException, ServiceException {
510 TableName tableName = TableName.valueOf("testRegionObserverEndpoint");
511 try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
512 Admin admin = connection.getAdmin()) {
513 admin.createTable(
514 new HTableDescriptor(tableName)
515 .addFamily(new HColumnDescriptor(foo))
516
517 .addCoprocessor(CustomRegionEndpoint.class.getName()));
518
519 try (Table table = connection.getTable(tableName)) {
520 List<Put> mutations = Lists.newArrayList(new Put(foo), new Put(bar));
521 MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder();
522
523 for (Mutation mutation : mutations) {
524 mrmBuilder.addMutationRequest(ProtobufUtil.toMutation(
525 ClientProtos.MutationProto.MutationType.PUT, mutation));
526 }
527
528 CoprocessorRpcChannel channel = table.coprocessorService(bar);
529 MultiRowMutationService.BlockingInterface service =
530 MultiRowMutationService.newBlockingStub(channel);
531 MutateRowsRequest mrm = mrmBuilder.build();
532 service.mutateRows(null, mrm);
533 }
534 }
535
536
537 MetricRegistryInfo info = MetricsCoprocessor.createRegistryInfoForRegionCoprocessor(
538 CustomRegionEndpoint.class.getName());
539
540 Optional<MetricRegistry> registry = MetricRegistries.global().get(info);
541 assertTrue(registry.isPresent());
542
543 Optional<Metric> metric = registry.get().get("EndpointExecution");
544 assertTrue(metric.isPresent());
545
546 Timer endpointExecutions = (Timer)metric.get();
547 assertEquals(1, endpointExecutions.getHistogram().getCount());
548 }
549 }