HBASE-3405 Allow HBaseRpcMetrics to register custom interface methods

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1056011 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary Helmling 2011-01-06 19:00:52 +00:00
parent 0ae47644a4
commit e89bfb07f3
7 changed files with 194 additions and 5 deletions

View File

@ -1306,6 +1306,7 @@ Release 0.90.0 - Unreleased
HBASE-3349 Pass HBase configuration to HttpServer
HBASE-3372 HRS shouldn't print a full stack for ServerNotRunningException
HBASE-3392 Update backport of InputSampler to reflect MAPREDUCE-1820
HBASE-3405 Allow HBaseRpcMetrics to register custom interface methods
NEW FEATURES

View File

@ -44,6 +44,7 @@ import java.lang.reflect.Method;
*
*/
public class HBaseRpcMetrics implements Updater {
public static final String NAME_DELIM = "$";
private MetricsRecord metricsRecord;
private static Log LOG = LogFactory.getLog(HBaseRpcMetrics.class);
private final HBaseRPCStatistics rpcStatistics;
@ -102,16 +103,46 @@ public class HBaseRpcMetrics implements Updater {
m.inc(amt);
}
public void createMetrics(Class<?> []ifaces) {
/**
* Generate metrics entries for all the methods defined in the list of
* interfaces. A {@link MetricsTimeVaryingRate} counter will be created for
* each {@code Class.getMethods().getName()} entry.
* @param ifaces Define metrics for all methods in the given classes
*/
public void createMetrics(Class<?>[] ifaces) {
createMetrics(ifaces, false);
}
/**
* Generate metrics entries for all the methods defined in the list of
* interfaces. A {@link MetricsTimeVaryingRate} counter will be created for
* each {@code Class.getMethods().getName()} entry.
*
* <p>
* If {@code prefixWithClass} is {@code true}, each metric will be named as
* {@code [Class.getSimpleName()].[Method.getName()]}. Otherwise each metric
* will just be named according to the method -- {@code Method.getName()}.
* </p>
* @param ifaces Define metrics for all methods in the given classes
* @param prefixWithClass If {@code true}, each metric will be named as
* "classname.method"
*/
public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass) {
for (Class<?> iface : ifaces) {
Method[] methods = iface.getMethods();
for (Method method : methods) {
if (get(method.getName()) == null)
create(method.getName());
String attrName = prefixWithClass ?
getMetricName(iface, method.getName()) : method.getName();
if (get(attrName) == null)
create(attrName);
}
}
}
public static String getMetricName(Class<?> c, String method) {
return c.getSimpleName() + NAME_DELIM + method;
}
/**
* Push the metrics to the monitoring subsystem on doUpdate() call.
* @param context ctx

View File

@ -1326,6 +1326,13 @@ public abstract class HBaseServer implements RpcServer {
this.errorHandler = handler;
}
/**
* Returns the metrics instance for reporting RPC call statistics
*/
public HBaseRpcMetrics getRpcMetrics() {
return rpcMetrics;
}
/**
* When the read or write buffer size is larger than this limit, i/o will be
* done in chunks of this size. Most RPC requests and responses would be

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 The Apache Software Foundation
* Copyright 2011 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@ -9,7 +9,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -63,4 +63,9 @@ public interface RpcServer {
void openServer();
void startThreads();
/**
* Returns the metrics instance for reporting RPC call statistics
*/
HBaseRpcMetrics getRpcMetrics();
}

View File

@ -99,6 +99,7 @@ import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;
import org.apache.hadoop.hbase.ipc.HBaseRPC;
import org.apache.hadoop.hbase.ipc.HBaseRPCErrorHandler;
import org.apache.hadoop.hbase.ipc.HBaseRPCProtocolVersion;
import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
import org.apache.hadoop.hbase.ipc.HMasterRegionInterface;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
import org.apache.hadoop.hbase.ipc.Invocation;
@ -1337,6 +1338,14 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
}
}
/**
* Return a reference to the metrics instance used for counting RPC calls.
* @return
*/
public HBaseRpcMetrics getRpcMetrics() {
return server.getRpcMetrics();
}
/**
* Cause the server to exit without closing the regions it is serving, the log
* it is using and without notifying the master. Used unit testing and on

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import org.apache.hadoop.hbase.HServerInfo;
import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
import org.apache.hadoop.hbase.regionserver.wal.HLog;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.zookeeper.KeeperException;
@ -77,4 +78,9 @@ public interface RegionServerServices extends OnlineRegions {
public void postOpenDeployTasks(final HRegion r, final CatalogTracker ct,
final boolean daughter)
throws KeeperException, IOException;
/**
* Returns a reference to the RPC server metrics.
*/
public HBaseRpcMetrics getRpcMetrics();
}

View File

@ -0,0 +1,130 @@
/*
* Copyright 2011 The Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.regionserver;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
import org.apache.hadoop.metrics.ContextFactory;
import org.apache.hadoop.metrics.MetricsContext;
import org.apache.hadoop.metrics.MetricsUtil;
import org.apache.hadoop.metrics.spi.AbstractMetricsContext;
import org.apache.hadoop.metrics.spi.OutputRecord;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestRpcMetrics {
/**
* Defines test methods to register with HBaseRpcMetrics
*/
public interface TestMetrics {
public void test();
}
/**
* HRegionServer sub-class to register custom metrics
*/
public static class TestRegionServer extends HRegionServer {
public TestRegionServer(Configuration conf)
throws IOException, InterruptedException {
super(conf);
// register custom metrics interface
getRpcMetrics().createMetrics(new Class[]{TestMetrics.class}, true);
}
public void incTest(int amt) {
HBaseRpcMetrics metrics = getRpcMetrics();
// force an increment so we have something to check for
metrics.inc(metrics.getMetricName(TestMetrics.class, "test"), amt);
}
}
/**
* Dummy metrics context to allow retrieval of values
*/
public static class MockMetricsContext extends AbstractMetricsContext {
public MockMetricsContext() {
// update every 1 sec.
setPeriod(1);
}
@Override
protected void emitRecord(String contextName, String recordName,
OutputRecord outputRecord) throws IOException {
for (String name : outputRecord.getMetricNames()) {
Number val = outputRecord.getMetric(name);
if (val != null && val.intValue() > 0) {
METRICS.put(name, Boolean.TRUE);
LOG.debug("Set metric "+name+" to "+val);
}
}
}
}
private static Map<String,Boolean> METRICS = new HashMap<String,Boolean>();
private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static Log LOG = LogFactory.getLog(TestRpcMetrics.class);
@BeforeClass
public static void setupBeforeClass() throws Exception {
// set custom metrics context
ContextFactory factory = ContextFactory.getFactory();
factory.setAttribute("rpc.class", MockMetricsContext.class.getName());
// make sure metrics context is setup, otherwise updating won't start
MetricsContext ctx = MetricsUtil.getContext("rpc");
assertTrue("Wrong MetricContext implementation class",
(ctx instanceof MockMetricsContext));
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Test
public void testCustomMetrics() throws Exception {
TestRegionServer rs = new TestRegionServer(TEST_UTIL.getConfiguration());
rs.incTest(5);
// wait for metrics context update
Thread.sleep(1000);
String metricName = HBaseRpcMetrics.getMetricName(TestMetrics.class, "test");
assertTrue("Metric should have set incremented for "+metricName,
wasSet(metricName + "_num_ops"));
}
public boolean wasSet(String name) {
return METRICS.get(name) != null ? METRICS.get(name) : false;
}
}