Index: conf/hadoop-metrics2.properties =================================================================== --- conf/hadoop-metrics2.properties (revision 0) +++ conf/hadoop-metrics2.properties (revision 0) @@ -0,0 +1,6 @@ +# syntax: [prefix].[source|sink].[instance].[options] +# See javadoc of package-info.java for org.apache.hadoop.metrics2 for details + +*.sink.file.class=org.apache.hadoop.metrics2.sink.FileSink +# default sampling period +*.period=10 Index: hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java (revision 1365064) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java (working copy) @@ -25,6 +25,7 @@ import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.ServerLoad; +import org.apache.hadoop.hbase.master.metrics.MXBeanImpl; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.MediumTests; import org.junit.AfterClass; @@ -48,22 +49,6 @@ TEST_UTIL.shutdownMiniCluster(); } - private void verifyRegionServers(Map regions) { - Set expected = new HashSet(); - for (int i = 0; i < 4; ++i) { - HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i); - expected.add(rs.getServerName().getServerName()); - } - - int found = 0; - for (java.util.Map.Entry entry : regions.entrySet()) { - if (expected.contains(entry.getKey())) { - ++found; - } - } - Assert.assertEquals(4, found); - } - @Test public void testInfo() { HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); @@ -77,20 +62,18 @@ Assert.assertEquals(master.getCoprocessors().length, info.getCoprocessors().length); Assert.assertEquals(master.getServerManager().getOnlineServersList().size(), - info.getRegionServers().size()); + info.getRegionServers()); Assert.assertEquals(master.getAssignmentManager().isRegionsInTransition(), info.getRegionsInTransition().length > 0); - Assert.assertTrue(info.getRegionServers().size() == 4); + Assert.assertTrue(info.getRegionServers() == 4); String zkServers = info.getZookeeperQuorum(); Assert.assertEquals(zkServers.split(",").length, TEST_UTIL.getZkCluster().getZooKeeperServerNum()); - verifyRegionServers(info.getRegionServers()); - TEST_UTIL.getMiniHBaseCluster().stopRegionServer(3, false); TEST_UTIL.getMiniHBaseCluster().waitOnRegionServer(3); - Assert.assertTrue(info.getRegionServers().size() == 3); + Assert.assertTrue(info.getRegionServers() == 3); Assert.assertTrue(info.getDeadRegionServers().length == 1); } Index: hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterMetrics.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterMetrics.java (revision 0) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterMetrics.java (revision 0) @@ -0,0 +1,110 @@ +/** + * 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.master; + +import junit.framework.Assert; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MediumTests; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.master.metrics.MXBeanImpl; +import org.apache.hadoop.hbase.metrics.MetricsAsserts; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; +import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos; +import org.apache.hadoop.hbase.regionserver.HRegionServer; +import org.apache.hadoop.hbase.util.Threads; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(MediumTests.class) +public class TestMasterMetrics { + private static final Log LOG = LogFactory.getLog(TestMasterMetrics.class); + + static { + Logger.getLogger("org.apache.hadoop.hbase").setLevel(Level.DEBUG); + } + + private MiniHBaseCluster cluster; + private HMaster master; + private Configuration conf; + private HBaseTestingUtility TEST_UTIL; + + private void startCluster() throws Exception{ + LOG.info("Starting cluster"); + conf = HBaseConfiguration.create(); + conf.getLong("hbase.splitlog.max.resubmit", 0); + // Make the failure test faster + conf.setInt("zookeeper.recovery.retry", 0); + conf.setInt(HConstants.REGIONSERVER_INFO_PORT, -1); + conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, (float) 100.0); // no load balancing + conf.setBoolean(HConstants.DISTRIBUTED_LOG_SPLITTING_KEY, true); + TEST_UTIL = new HBaseTestingUtility(conf); + TEST_UTIL.startMiniCluster(1, 1); + cluster = TEST_UTIL.getHBaseCluster(); + LOG.info("Waiting for active/ready master"); + cluster.waitForActiveAndReadyMaster(); + master = cluster.getMaster(); + + while (cluster.getLiveRegionServerThreads().size() < 1) { + Threads.sleep(1); + } + } + + @After + public void after() throws Exception { + if (TEST_UTIL != null) { + TEST_UTIL.shutdownMiniCluster(); + } + } + + @Test(timeout=300000) + public void testClusterRequests() throws Exception { + MetricsAsserts.getInstance(); + + startCluster(); + + long val = MetricsAsserts.getInstance() + .getCounterValue("cluster_requests", master.getMetrics().getMetricsSource()); + + // sending fake request to master to see how metric value has changed + RegionServerStatusProtos.RegionServerReportRequest.Builder request = + RegionServerStatusProtos.RegionServerReportRequest.newBuilder(); + HRegionServer rs = cluster.getRegionServer(0); + request.setServer(ProtobufUtil.toServerName(rs.getServerName())); + + HBaseProtos.ServerLoad sl = HBaseProtos.ServerLoad.newBuilder() + .setTotalNumberOfRequests(10) + .build(); + request.setLoad(sl); + master.regionServerReport(null, request.build()); + + MetricsAsserts.getInstance().assertCounter("cluster_requests", val + 10, + master.getMetrics().getMetricsSource()); + master.stopMaster(); + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (revision 1365064) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (working copy) @@ -29,7 +29,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -50,6 +49,7 @@ import org.apache.hadoop.hbase.Abortable; import org.apache.hadoop.hbase.Chore; import org.apache.hadoop.hbase.ClusterStatus; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; import org.apache.hadoop.hbase.DeserializationException; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; @@ -80,8 +80,9 @@ import org.apache.hadoop.hbase.MasterMonitorProtocol; import org.apache.hadoop.hbase.MasterAdminProtocol; import org.apache.hadoop.hbase.RegionServerStatusProtocol; +import org.apache.hadoop.hbase.master.metrics.MXBeanImpl; +import org.apache.hadoop.hbase.metrics.MBeanSource; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; -import org.apache.hadoop.hbase.protobuf.RequestConverter; import org.apache.hadoop.hbase.protobuf.ResponseConverter; import org.apache.hadoop.hbase.ipc.ProtocolSignature; import org.apache.hadoop.hbase.ipc.RpcServer; @@ -401,6 +402,10 @@ } + MasterMetrics getMetrics() { + return metrics; + } + /** * Main processing loop for the HMaster. *
    @@ -2255,10 +2260,10 @@ /** * Register bean with platform management server */ - @SuppressWarnings("deprecation") void registerMBean() { MXBeanImpl mxBeanInfo = MXBeanImpl.init(this); - MBeanUtil.registerMBean("Master", "Master", mxBeanInfo); + mxBean = CompatibilitySingletonFactory.getInstance( + MBeanSource.class).register("hbase", "HMaster,sub=MXBean", mxBeanInfo); LOG.info("Registered HMaster MXBean"); } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java (revision 1365064) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetrics.java (working copy) @@ -17,25 +17,11 @@ */ package org.apache.hadoop.hbase.master.metrics; -import java.io.IOException; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; -import org.apache.hadoop.hbase.metrics.HBaseInfo; -import org.apache.hadoop.hbase.metrics.MetricsRate; -import org.apache.hadoop.hbase.metrics.histogram.MetricsHistogram; -import org.apache.hadoop.metrics.ContextFactory; -import org.apache.hadoop.metrics.MetricsContext; -import org.apache.hadoop.metrics.MetricsRecord; -import org.apache.hadoop.metrics.MetricsUtil; -import org.apache.hadoop.metrics.Updater; -import org.apache.hadoop.metrics.jvm.JvmMetrics; -import org.apache.hadoop.metrics.util.MetricsIntValue; -import org.apache.hadoop.metrics.util.MetricsLongValue; -import org.apache.hadoop.metrics.util.MetricsRegistry; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; - /** * This class is for maintaining the various master statistics * and publishing them through the metrics interfaces. @@ -44,131 +30,46 @@ * these variables (objects) have methods to update their values. */ @InterfaceAudience.Private -public class MasterMetrics implements Updater { +public class MasterMetrics { private final Log LOG = LogFactory.getLog(this.getClass()); - private final MetricsRecord metricsRecord; - private final MetricsRegistry registry = new MetricsRegistry(); - private final MasterStatistics masterStatistics; + private MasterMetricsSource mms; - private long lastUpdate = System.currentTimeMillis(); - private long lastExtUpdate = System.currentTimeMillis(); - private long extendedPeriod = 0; -/* - * Count of requests to the cluster since last call to metrics update - */ - private final MetricsRate cluster_requests = - new MetricsRate("cluster_requests", registry); - - /** Time it takes to finish HLog.splitLog() */ - final MetricsHistogram splitTime = new MetricsHistogram("splitTime", registry); - - /** Size of HLog files being split */ - final MetricsHistogram splitSize = new MetricsHistogram("splitSize", registry); - - /** - * Regions in Transition metrics such as number of RIT regions, oldest - * RIT time and number of such regions that are in transition - * for more than a specified threshold. - */ - public final MetricsIntValue ritCount = - new MetricsIntValue("ritCount", registry); - public final MetricsIntValue ritCountOverThreshold = - new MetricsIntValue("ritCountOverThreshold", registry); - public final MetricsLongValue ritOldestAge = - new MetricsLongValue("ritOldestAge", registry); - public MasterMetrics(final String name) { - MetricsContext context = MetricsUtil.getContext("hbase"); - metricsRecord = MetricsUtil.createRecord(context, "master"); - metricsRecord.setTag("Master", name); - context.registerUpdater(this); - JvmMetrics.init("Master", name); - HBaseInfo.init(); - - // expose the MBean for metrics - masterStatistics = new MasterStatistics(this.registry); - - // get custom attributes - try { - Object m = - ContextFactory.getFactory().getAttribute("hbase.extendedperiod"); - if (m instanceof String) { - this.extendedPeriod = Long.parseLong((String) m)*1000; - } - } catch (IOException ioe) { - LOG.info("Couldn't load ContextFactory for Metrics config info"); - } - - LOG.info("Initialized"); + mms = CompatibilitySingletonFactory.getInstance(MasterMetricsSource.class); } - public void shutdown() { - if (masterStatistics != null) - masterStatistics.shutdown(); + // for unit-test usage + public MasterMetricsSource getMetricsSource() { + return mms; } /** - * Since this object is a registered updater, this method will be called - * periodically, e.g. every 5 seconds. - * @param unused - */ - public void doUpdates(MetricsContext unused) { - synchronized (this) { - this.lastUpdate = System.currentTimeMillis(); - - // has the extended period for long-living stats elapsed? - if (this.extendedPeriod > 0 && - this.lastUpdate - this.lastExtUpdate >= this.extendedPeriod) { - this.lastExtUpdate = this.lastUpdate; - this.splitTime.clear(); - this.splitSize.clear(); - this.resetAllMinMax(); - } - - this.cluster_requests.pushMetric(metricsRecord); - this.splitTime.pushMetric(metricsRecord); - this.splitSize.pushMetric(metricsRecord); - this.ritCount.pushMetric(metricsRecord); - this.ritCountOverThreshold.pushMetric(metricsRecord); - this.ritOldestAge.pushMetric(metricsRecord); - } - this.metricsRecord.update(); - } - - public void resetAllMinMax() { - // Nothing to do - } - - /** * Record a single instance of a split * @param time time that the split took * @param size length of original HLogs that were split */ public synchronized void addSplit(long time, long size) { - splitTime.update(time); - splitSize.update(size); - } - /** - * @return Count of requests. - */ - public float getRequests() { - return this.cluster_requests.getPreviousIntervalValue(); + //TODO use new metrics histogram + } /** * @param inc How much to add to requests. */ public void incrementRequests(final int inc) { - this.cluster_requests.inc(inc); + mms.incRequests(inc); + } + + /** * set new value for number of regions in transition. * @param ritCount */ public void updateRITCount(int ritCount) { - this.ritCount.set(ritCount); + mms.setRIT(ritCount); } /** @@ -177,13 +78,13 @@ * @param ritCountOverThreshold */ public void updateRITCountOverThreshold(int ritCountOverThreshold) { - this.ritCountOverThreshold.set(ritCountOverThreshold); + mms.setRITCountOverThreshold(ritCountOverThreshold); } /** * update the timestamp for oldest region in transition metrics. * @param timestamp */ public void updateRITOldestAge(long timestamp) { - this.ritOldestAge.set(timestamp); + mms.setRITOldestAge(timestamp); } } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBean.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBean.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBean.java (revision 0) @@ -0,0 +1,118 @@ +/** + * 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.master.metrics; + +import java.util.Map; + +import org.apache.hadoop.classification.InterfaceStability.Evolving; +import org.apache.hadoop.hbase.ServerLoad; + +/** + * This is the JMX management interface for Hbase master information + */ +@Evolving +public interface MXBean { + + /** + * Required for MXBean implementation + */ + public static interface RegionsInTransitionInfo { + /** + * Name of region in transition + */ + public String getRegionName(); + /** + * Current transition state + */ + public String getRegionState(); + /** + * Get Region Server name + */ + public String getRegionServerName(); + /** + * Get last update time + */ + public long getLastUpdateTime(); + } + + /** + * Get ServerName + */ + public String getServerName(); + + /** + * Get Average Load + * @return Average Load + */ + public double getAverageLoad(); + + /** + * Get the Cluster ID + * @return Cluster ID + */ + public String getClusterId(); + + /** + * Get the Zookeeper Quorum Info + * @return Zookeeper Quorum Info + */ + public String getZookeeperQuorum(); + + /** + * Get the co-processors + * @return Co-processors + */ + public String[] getCoprocessors(); + + /** + * Get hbase master start time + * @return Start time of master in milliseconds + */ + public long getMasterStartTime(); + + /** + * Get the hbase master active time + * @return Time in milliseconds when master became active + */ + public long getMasterActiveTime(); + + /** + * Whether this master is the active master + * @return True if this is the active master + */ + public boolean getIsActiveMaster(); + + /** + * Get the live region servers + * @return Live region servers + */ + public int getRegionServers(); + + /** + * Get the dead region servers + * @return Dead region Servers + */ + public String[] getDeadRegionServers(); + + /** + * Get information on regions in transition + * @return Regions in transition + */ + public RegionsInTransitionInfo[] getRegionsInTransition(); + +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBeanImpl.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBeanImpl.java (revision 0) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/MXBeanImpl.java (revision 0) @@ -0,0 +1,145 @@ +/** + * 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.master.metrics; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.hadoop.hbase.ServerLoad; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; +import org.apache.hadoop.hbase.master.HMaster; + +/** + * Impl for exposing HMaster Information through JMX + */ +public class MXBeanImpl implements MXBean { + + private final HMaster master; + + private static MXBeanImpl instance = null; + public synchronized static MXBeanImpl init(final HMaster master) { + if (instance == null) { + instance = new MXBeanImpl(master); + } + return instance; + } + + protected MXBeanImpl(final HMaster master) { + this.master = master; + } + + @Override + public double getAverageLoad() { + return master.getAverageLoad(); + } + + @Override + public String getClusterId() { + return master.getClusterId(); + } + + @Override + public String getZookeeperQuorum() { + return master.getZooKeeperWatcher().getQuorum(); + } + + @Override + public String[] getCoprocessors() { + return master.getCoprocessors(); + } + + @Override + public long getMasterStartTime() { + return master.getMasterStartTime(); + } + + @Override + public long getMasterActiveTime() { + return master.getMasterActiveTime(); + } + + @Override + public int getRegionServers() { + return this.master.getServerManager().getOnlineServers().size(); + } + + @Override + public String[] getDeadRegionServers() { + List deadServers = new ArrayList(); + for (ServerName name : master.getServerManager().getDeadServers()) { + deadServers.add(name.getHostAndPort()); + } + return deadServers.toArray(new String[0]); + } + + @Override + public RegionsInTransitionInfo[] getRegionsInTransition() { + List info = + new ArrayList(); + for (final Entry entry : + master.getAssignmentManager().copyRegionsInTransition().entrySet()) { + RegionsInTransitionInfo innerinfo = new RegionsInTransitionInfo() { + + @Override + public String getRegionState() { + return entry.getValue().getState().toString(); + } + + @Override + public String getRegionName() { + return entry.getKey(); + } + + @Override + public long getLastUpdateTime() { + return entry.getValue().getStamp(); + } + + @Override + public String getRegionServerName() { + ServerName serverName = entry.getValue().getServerName(); + if (serverName != null) { + return serverName.getServerName(); + } + else { + return ""; + } + } + }; + info.add(innerinfo); + } + RegionsInTransitionInfo[] data = + new RegionsInTransitionInfo[info.size()]; + info.toArray(data); + return data; + } + + @Override + public String getServerName() { + return master.getServerName().getServerName(); + } + + @Override + public boolean getIsActiveMaster() { + return master.isActiveMaster(); + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSourceMetrics.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSourceMetrics.java (revision 1365064) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSourceMetrics.java (working copy) @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; /** * This class is for maintaining the various replication statistics for a source and publishing them @@ -65,7 +66,7 @@ logEditsFilteredKey = "source." + id + ".logEditsFiltered"; shippedBatchesKey = "source." + this.id + ".shippedBatches"; shippedOpsKey = "source." + this.id + ".shippedOps"; - rms = ReplicationMetricsSourceFactory.getInstance(); + rms = CompatibilitySingletonFactory.getInstance(ReplicationMetricsSource.class); } /** Index: hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSinkMetrics.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSinkMetrics.java (revision 1365064) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationSinkMetrics.java (working copy) @@ -19,8 +19,7 @@ package org.apache.hadoop.hbase.replication.regionserver.metrics; import org.apache.hadoop.classification.InterfaceAudience; -import org.apache.hadoop.hbase.replication.regionserver.metrics.ReplicationMetricsSource; -import org.apache.hadoop.hbase.replication.regionserver.metrics.ReplicationMetricsSourceFactory; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; /** * This class is for maintaining the various replication statistics for a sink and publishing them @@ -36,7 +35,7 @@ private ReplicationMetricsSource rms; public ReplicationSinkMetrics() { - rms = ReplicationMetricsSourceFactory.getInstance(); + rms = CompatibilitySingletonFactory.getInstance(ReplicationMetricsSource.class); } /** Index: hbase-server/pom.xml =================================================================== --- hbase-server/pom.xml (revision 1365064) +++ hbase-server/pom.xml (working copy) @@ -497,6 +497,22 @@ jettison test + + org.apache.hbase + hbase-hadoop-compat + ${project.version} + test-jar + true + test + + + org.apache.hbase + ${compat.module} + ${project.version} + test-jar + true + test + Index: hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java =================================================================== --- hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java (revision 1365064) +++ hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java (working copy) @@ -43,10 +43,10 @@ public void testSetGauge() throws Exception { String key = "testset"; bmsi.setGauge(key, 100); - MetricMutableGaugeLong g = bmsi.gauges.get(key); + MetricMutableGaugeLong g = (MetricMutableGaugeLong) bmsi.metricsRegistry.get(key); assertEquals(key, g.name); bmsi.setGauge(key, 110); - assertSame(g, bmsi.gauges.get(key)); + assertSame(g, bmsi.metricsRegistry.get(key)); } @@ -54,37 +54,37 @@ public void testIncGauge() throws Exception { String key = "testincgauge"; bmsi.incGauge(key, 100); - MetricMutableGaugeLong g = bmsi.gauges.get(key); + MetricMutableGaugeLong g = (MetricMutableGaugeLong) bmsi.metricsRegistry.get(key); assertEquals(key, g.name); bmsi.incGauge(key, 10); - assertSame(g, bmsi.gauges.get(key)); + assertSame(g, bmsi.metricsRegistry.get(key)); } @Test public void testDecGauge() throws Exception { String key = "testdec"; bmsi.decGauge(key, 100); - MetricMutableGaugeLong g = bmsi.gauges.get(key); + MetricMutableGaugeLong g = (MetricMutableGaugeLong) bmsi.metricsRegistry.get(key); assertEquals(key, g.name); bmsi.decGauge(key, 100); - assertSame(g, bmsi.gauges.get(key)); + assertSame(g, bmsi.metricsRegistry.get(key)); } @Test public void testIncCounters() throws Exception { String key = "testinccounter"; bmsi.incCounters(key, 100); - MetricMutableCounterLong c = bmsi.counters.get(key); + MetricMutableCounterLong c = (MetricMutableCounterLong) bmsi.metricsRegistry.get(key); assertEquals(key, c.name); bmsi.incCounters(key, 100); - assertSame(c, bmsi.counters.get(key)); + assertSame(c, bmsi.metricsRegistry.get(key)); } @Test public void testRemoveGauge() throws Exception { bmsi.setGauge("testrm", 100); bmsi.removeGauge("testrm"); - assertNull(bmsi.gauges.get("testrm")); + assertNull(bmsi.metricsRegistry.get("testrm")); } @@ -92,6 +92,6 @@ public void testRemoveCounter() throws Exception { bmsi.incCounters("testrm", 100); bmsi.removeCounter("testrm"); - assertNull(bmsi.counters.get("testrm")); + assertNull(bmsi.metricsRegistry.get("testrm")); } } Index: hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java =================================================================== --- hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java (revision 0) +++ hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java (revision 0) @@ -0,0 +1,65 @@ +/** + * 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.metrics; + +import org.apache.hadoop.metrics2.MetricsBuilder; +import org.apache.hadoop.metrics2.MetricsRecordBuilder; +import org.mockito.Mockito; +import org.mockito.internal.stubbing.defaultanswers.ReturnsMocks; +import org.mockito.invocation.InvocationOnMock; + +/** + * Helpers for metrics source tests + */ +public class MetricsAssertsImpl extends MetricsAsserts { + @Override + public void assertCounter(String name, long value, BaseMetricsSource ms) { + BaseMetricsSourceImpl bms = (BaseMetricsSourceImpl) ms; + org.apache.hadoop.test.MetricsAsserts.assertCounter(name, value, bms); + } + + @Override + public long getCounterValue(final String name, BaseMetricsSource ms) { + // This looks ugly, but this is is the only usable way I found + // to get metrics value in hadoop 1.0... + final long[] value = new long[1]; + final MetricsRecordBuilder mrb = Mockito.mock(MetricsRecordBuilder.class, new ReturnsMocks() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + if (args[0].equals(name)) { // TODO: remove check? We do it in MetricsBuilder impl below + value[0] = (Long) args[2]; // args are: name, description, value + } + return invocation.getMock(); + } + }); + + BaseMetricsSourceImpl bms = (BaseMetricsSourceImpl) ms; + MetricsBuilder mb = new MetricsBuilder() { + @Override + public MetricsRecordBuilder addRecord(String s) { + return mrb; + } + }; + + bms.getMetrics(mb, true); + + return value[0]; + } +} Index: hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java =================================================================== --- hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java (revision 1365064) +++ hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java (working copy) @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.replication.regionserver.metrics; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; import org.junit.Test; import static org.junit.Assert.assertTrue; @@ -29,7 +30,8 @@ @Test public void testGetInstance() throws Exception { - ReplicationMetricsSource rms = ReplicationMetricsSourceFactory.getInstance(); + ReplicationMetricsSource rms = CompatibilitySingletonFactory + .getInstance(ReplicationMetricsSource.class); assertTrue(rms instanceof ReplicationMetricsSourceImpl); } } Index: hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java =================================================================== --- hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java (revision 0) +++ hbase-hadoop1-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java (revision 0) @@ -0,0 +1,40 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; +import org.junit.Test; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** + * Test for MasterMetricsSourceImpl + */ +public class MasterMetricsSourceImplTest { + + @Test + public void testGetInstance() throws Exception { + MasterMetricsSource rms = CompatibilitySingletonFactory + .getInstance(MasterMetricsSource.class); + assertTrue(rms instanceof MasterMetricsSourceImpl); + assertSame(rms, CompatibilitySingletonFactory.getInstance(MasterMetricsSource.class)); + } + +} Index: hbase-hadoop1-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts =================================================================== --- hbase-hadoop1-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts (revision 0) +++ hbase-hadoop1-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.metrics.MetricsAssertsImpl \ No newline at end of file Index: hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java =================================================================== --- hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java (revision 1365064) +++ hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java (working copy) @@ -19,59 +19,82 @@ package org.apache.hadoop.hbase.metrics; import org.apache.hadoop.metrics2.MetricsBuilder; +import org.apache.hadoop.metrics2.MetricsException; import org.apache.hadoop.metrics2.MetricsRecordBuilder; import org.apache.hadoop.metrics2.MetricsSource; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry; +import org.apache.hadoop.metrics2.lib.MetricMutable; import org.apache.hadoop.metrics2.lib.MetricMutableCounterLong; import org.apache.hadoop.metrics2.lib.MetricMutableGaugeLong; +import org.apache.hadoop.metrics2.source.JvmMetricsSource; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** - * Hadoop 1 implementation of BaseMetricsSource + * Hadoop 1 metrics 1 implementation of BaseMetricsSource */ public class BaseMetricsSourceImpl implements BaseMetricsSource, MetricsSource { private static boolean defaultMetricsSystemInited = false; public static final String HBASE_METRICS_SYSTEM_NAME = "hbase"; - public ConcurrentMap - gauges = new ConcurrentHashMap(); - public ConcurrentMap counters = - new ConcurrentHashMap(); + final DynamicMetricsRegistry metricsRegistry; - protected String metricsContext; - protected String metricsName; - protected String metricsDescription; + private JvmMetricsSource jvmMetricsSource; public BaseMetricsSourceImpl( String metricsName, String metricsDescription, String metricsContext) { - this.metricsContext = metricsContext; - this.metricsName = metricsName; - this.metricsDescription = metricsDescription; + metricsRegistry = new DynamicMetricsRegistry(metricsName).setContext(metricsContext); + if (!defaultMetricsSystemInited) { //Not too worried about mutli-threaded here as all it does is spam the logs. defaultMetricsSystemInited = true; DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME); + + //If this is the first time through register a jvm source. + jvmMetricsSource = JvmMetricsSource.create(metricsName, ""); } //Register this instance. - DefaultMetricsSystem.registerSource(this.metricsContext, this.metricsDescription, this); + DefaultMetricsSystem.INSTANCE.registerSource(metricsContext, metricsDescription, this); } /** + * Get a MetricMutableGaugeLong from the storage. If it is not there atomically put it. + * + * @param gaugeName name of the gauge to create or get. + * @param potentialStartingValue value of the new counter if we have to create it. + * @return + */ + protected MetricMutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { + return metricsRegistry.getLongGauge(gaugeName, potentialStartingValue); + } + + /** + * Get a MetricMutableCounterLong from the storage. If it is not there atomically put it. + * + * @param counterName Name of the counter to get + * @param potentialStartingValue starting value if we have to create a new counter + * @return + */ + protected MetricMutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { + return metricsRegistry.getLongCounter(counterName, potentialStartingValue); + } + + /** * Set a single gauge to a value. * * @param gaugeName gauge name * @param value the new value of the gauge. */ public void setGauge(String gaugeName, long value) { - MetricMutableGaugeLong gaugeInt = getLongGauge(gaugeName, value); + MetricMutableGaugeLong gaugeInt = metricsRegistry.getLongGauge(gaugeName, value); gaugeInt.set(value); } @@ -82,7 +105,7 @@ * @param delta The amount to increment the gauge by. */ public void incGauge(String gaugeName, long delta) { - MetricMutableGaugeLong gaugeInt = getLongGauge(gaugeName, 0l); + MetricMutableGaugeLong gaugeInt = metricsRegistry.getLongGauge(gaugeName, 0l); gaugeInt.incr(delta); } @@ -93,7 +116,7 @@ * @param delta the ammount to subtract from a gauge value. */ public void decGauge(String gaugeName, long delta) { - MetricMutableGaugeLong gaugeInt = getLongGauge(gaugeName, 0l); + MetricMutableGaugeLong gaugeInt = metricsRegistry.getLongGauge(gaugeName, 0l); gaugeInt.decr(delta); } @@ -104,7 +127,7 @@ * @param delta the ammount to increment */ public void incCounters(String key, long delta) { - MetricMutableCounterLong counter = getLongCounter(key, 0l); + MetricMutableCounterLong counter = metricsRegistry.getLongCounter(key, 0l); counter.incr(delta); } @@ -115,7 +138,7 @@ * @param key */ public void removeGauge(String key) { - gauges.remove(key); + metricsRegistry.removeMetric(key); } /** @@ -124,7 +147,7 @@ * @param key */ public void removeCounter(String key) { - counters.remove(key); + metricsRegistry.removeMetric(key); } /** @@ -135,67 +158,6 @@ */ @Override public void getMetrics(MetricsBuilder metricsBuilder, boolean all) { - - MetricsRecordBuilder rb = metricsBuilder.addRecord(metricsName).setContext(metricsContext); - - for (Map.Entry entry : counters.entrySet()) { - entry.getValue().snapshot(rb, all); - } - for (Map.Entry entry : gauges.entrySet()) { - entry.getValue().snapshot(rb, all); - } - + metricsRegistry.snapshot(metricsBuilder.addRecord(metricsRegistry.name()), all); } - - /** - * Get a MetricMutableGaugeLong from the storage. If it is not there atomically put it. - * - * @param gaugeName name of the gauge to create or get. - * @param potentialStartingValue value of the new counter if we have to create it. - * @return - */ - private MetricMutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { - //Try and get the guage. - MetricMutableGaugeLong gauge = gauges.get(gaugeName); - - //If it's not there then try and put a new one in the storage. - if (gauge == null) { - - //Create the potential new gauge. - MetricMutableGaugeLong newGauge = new MetricMutableGaugeLong(gaugeName, "", - potentialStartingValue); - - // Try and put the gauge in. This is atomic. - gauge = gauges.putIfAbsent(gaugeName, newGauge); - - //If the value we get back is null then the put was successful and we will return that. - //otherwise gaugeLong should contain the thing that was in before the put could be completed. - if (gauge == null) { - gauge = newGauge; - } - } - return gauge; - } - - /** - * Get a MetricMutableCounterLong from the storage. If it is not there atomically put it. - * - * @param counterName Name of the counter to get - * @param potentialStartingValue starting value if we have to create a new counter - * @return - */ - private MetricMutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { - //See getLongGauge for description on how this works. - MetricMutableCounterLong counter = counters.get(counterName); - if (counter == null) { - MetricMutableCounterLong newCounter = - new MetricMutableCounterLong(counterName, "", potentialStartingValue); - counter = counters.putIfAbsent(counterName, newCounter); - if (counter == null) { - counter = newCounter; - } - } - return counter; - } - } Index: hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java =================================================================== --- hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java (revision 0) +++ hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java (revision 0) @@ -0,0 +1,41 @@ +/** + * 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.metrics; + +import org.apache.hadoop.metrics2.util.MBeans; + +import javax.management.ObjectName; + +/** + * Hadoop1 metrics2 implementation of an object that registers MBeans. + */ +public class MBeanSourceImpl implements MBeanSource { + + /** + * Register an mbean with the underlying metrics system + * @param serviceName Metrics service/system name + * @param nameName name of the metrics obejct to expose + * @param theMbean the actual MBean + * @return ObjectName from jmx + */ + @Override + public ObjectName register(String serviceName, String nameName, Object theMbean) { + return MBeans.register(serviceName, nameName, theMbean); + } +} Index: hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java =================================================================== --- hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java (revision 1365064) +++ hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java (working copy) @@ -28,10 +28,8 @@ public class ReplicationMetricsSourceImpl extends BaseMetricsSourceImpl implements ReplicationMetricsSource { - public static final String METRICS_NAME = "ReplicationMetrics"; - public static final String METRICS_CONTEXT = "replicationmetrics"; - public static final String METRICS_DESCRIPTION = "Metrics about HBase replication"; + public ReplicationMetricsSourceImpl() { this(METRICS_NAME, METRICS_DESCRIPTION, METRICS_CONTEXT); } Index: hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java =================================================================== --- hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java (revision 0) +++ hbase-hadoop1-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java (revision 0) @@ -0,0 +1,66 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.metrics.BaseMetricsSourceImpl; +import org.apache.hadoop.metrics2.lib.MetricMutableCounterLong; +import org.apache.hadoop.metrics2.lib.MetricMutableGaugeLong; + +/** + * + */ +public class MasterMetricsSourceImpl extends BaseMetricsSourceImpl implements MasterMetricsSource { + + MetricMutableCounterLong clusterRequestsCounter; + MetricMutableGaugeLong ritGauge; + MetricMutableGaugeLong ritCountOverThresholdGauge; + MetricMutableGaugeLong ritOldestAgeGauge; + + + public MasterMetricsSourceImpl() { + this(METRICS_NAME, METRICS_DESCRIPTION, METRICS_CONTEXT); + } + + public MasterMetricsSourceImpl(String metricsName, + String metricsDescription, + String metricsContext) { + super(metricsName, metricsDescription, metricsContext); + + clusterRequestsCounter = getLongCounter("cluster_requests", 0); + ritGauge = getLongGauge("ritCount", 0); + ritCountOverThresholdGauge = getLongGauge("ritCountOverThreshold", 0); + ritOldestAgeGauge = getLongGauge("ritOldestAge", 0); + } + + public void incRequests(final int inc) { + this.clusterRequestsCounter.incr(inc); + } + + public void setRIT(int ritCount) { + ritGauge.set(ritCount); + } + + public void setRITCountOverThreshold(int ritCount) { + ritCountOverThresholdGauge.set(ritCount); + } + + public void setRITOldestAge(long ritCount) { + ritCountOverThresholdGauge.set(ritCount); + } +} Index: hbase-hadoop1-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java =================================================================== --- hbase-hadoop1-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java (revision 0) +++ hbase-hadoop1-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java (revision 0) @@ -0,0 +1,443 @@ +/** + * 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.metrics2.lib; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.hadoop.metrics2.MetricsException; +import org.apache.hadoop.metrics2.MetricsRecordBuilder; +import org.apache.hadoop.metrics2.MetricsTag; + +/** + * An optional metrics registry class for creating and maintaining a + * collection of MetricsMutables, making writing metrics source easier. + * NOTE: this is a copy of org.apache.hadoop.metrics2.lib.MetricsRegistry with added one + * feature: metrics can be removed. When HADOOP-8313 is fixed, usages of this class + * should be substituted with org.apache.hadoop.metrics2.lib.MetricsRegistry. + * This implementation also provides handy methods for creating metrics dynamically. + * Another difference is that metricsMap implementation is substituted with thread-safe + * map, as we allow dynamic metrics additions/removals. + */ +public class DynamicMetricsRegistry { + + /** key for the context tag */ + public static final String CONTEXT_KEY = "context"; + /** description for the context tag */ + public static final String CONTEXT_DESC = "Metrics context"; + + private final ConcurrentMap metricsMap = + new ConcurrentHashMap(); + private final LinkedHashMap tagsMap = + new LinkedHashMap(); + private final String name; + private final MetricMutableFactory mf; + + /** + * Construct the registry with a record name + * @param name of the record of the metrics + */ + public DynamicMetricsRegistry(String name) { + this.name = name; + this.mf = new MetricMutableFactory(); + } + + /** + * Construct the registry with a name and a metric factory + * @param name of the record of the metrics + * @param factory for creating new mutable metrics + */ + public DynamicMetricsRegistry(String name, MetricMutableFactory factory) { + this.name = name; + this.mf = factory; + } + + /** + * @return the name of the metrics registry + */ + public String name() { + return name; + } + + /** + * Get a metric by name + * @param name of the metric + * @return the metric object + */ + public MetricMutable get(String name) { + return metricsMap.get(name); + } + + /** + * Create a mutable integer counter + * @param name of the metric + * @param description of the metric + * @param initValue of the metric + * @return a new counter object + */ + public MetricMutableCounterInt + newCounter(String name, String description, int initValue) { + checkMetricName(name); + MetricMutableCounterInt ret = mf.newCounter(name, description, initValue); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable long integer counter + * @param name of the metric + * @param description of the metric + * @param initValue of the metric + * @return a new counter object + */ + public MetricMutableCounterLong + newCounter(String name, String description, long initValue) { + checkMetricName(name); + MetricMutableCounterLong ret = mf.newCounter(name, description, initValue); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable integer gauge + * @param name of the metric + * @param description of the metric + * @param initValue of the metric + * @return a new gauge object + */ + public MetricMutableGaugeInt + newGauge(String name, String description, int initValue) { + checkMetricName(name); + MetricMutableGaugeInt ret = mf.newGauge(name, description, initValue); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable long integer gauge + * @param name of the metric + * @param description of the metric + * @param initValue of the metric + * @return a new gauge object + */ + public MetricMutableGaugeLong + newGauge(String name, String description, long initValue) { + checkMetricName(name); + MetricMutableGaugeLong ret = mf.newGauge(name, description, initValue); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable metric with stats + * @param name of the metric + * @param description of the metric + * @param sampleName of the metric (e.g., "ops") + * @param valueName of the metric (e.g., "time" or "latency") + * @param extended produce extended stat (stdev, min/max etc.) if true. + * @return a new metric object + */ + public MetricMutableStat newStat(String name, String description, + String sampleName, String valueName, + boolean extended) { + checkMetricName(name); + MetricMutableStat ret = + mf.newStat(name, description, sampleName, valueName, extended); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable metric with stats + * @param name of the metric + * @param description of the metric + * @param sampleName of the metric (e.g., "ops") + * @param valueName of the metric (e.g., "time" or "latency") + * @return a new metric object + */ + public MetricMutableStat newStat(String name, String description, + String sampleName, String valueName) { + return newStat(name, description, sampleName, valueName, false); + } + + /** + * Create a mutable metric with stats using the name only + * @param name of the metric + * @return a new metric object + */ + public MetricMutableStat newStat(String name) { + return newStat(name, "", "ops", "time", false); + } + + /** + * Increment a metric by name. + * @param name of the metric + */ + public void incr(String name) { + incr(name, mf); + } + + /** + * Increment a metric by name. + * @param name of the metric + * @param factory to lazily create the metric if not null + */ + public void incr(String name, MetricMutableFactory factory) { + MetricMutable m = metricsMap.get(name); + + if (m != null) { + if (m instanceof MetricMutableGauge) { + ((MetricMutableGauge) m).incr(); + } + else if (m instanceof MetricMutableCounter) { + ((MetricMutableCounter) m).incr(); + } + else { + throw new MetricsException("Unsupported incr() for metric "+ name); + } + } + else if (factory != null) { + metricsMap.put(name, factory.newMetric(name)); + incr(name, null); + } + else { + throw new MetricsException("Metric "+ name +" doesn't exist"); + } + } + + /** + * Decrement a metric by name. + * @param name of the metric + */ + public void decr(String name) { + decr(name, mf); + } + + /** + * Decrement a metric by name. + * @param name of the metric + * @param factory to lazily create the metric if not null + */ + public void decr(String name, MetricMutableFactory factory) { + MetricMutable m = metricsMap.get(name); + + if (m != null) { + if (m instanceof MetricMutableGauge) { + ((MetricMutableGauge) m).decr(); + } + else { + throw new MetricsException("Unsupported decr() for metric "+ name); + } + } + else if (factory != null) { + metricsMap.put(name, factory.newMetric(name)); + decr(name, null); + } + else { + throw new MetricsException("Metric "+ name +" doesn't exist"); + } + } + + /** + * Add a value to a metric by name. + * @param name of the metric + * @param value of the snapshot to add + */ + public void add(String name, long value) { + add(name, value, mf); + } + + /** + * Decrement a metric by name. + * @param name of the metric + * @param value of the snapshot to add + * @param factory to lazily create the metric if not null + */ + public void add(String name, long value, MetricMutableFactory factory) { + MetricMutable m = metricsMap.get(name); + + if (m != null) { + if (m instanceof MetricMutableStat) { + ((MetricMutableStat) m).add(value); + } + else { + throw new MetricsException("Unsupported add(value) for metric "+ name); + } + } + else if (factory != null) { + metricsMap.put(name, factory.newStat(name)); + add(name, value, null); + } + else { + throw new MetricsException("Metric "+ name +" doesn't exist"); + } + } + + /** + * Set the metrics context tag + * @param name of the context + * @return the registry itself as a convenience + */ + public DynamicMetricsRegistry setContext(String name) { + return tag(CONTEXT_KEY, CONTEXT_DESC, name); + } + + /** + * Add a tag to the metrics + * @param name of the tag + * @param description of the tag + * @param value of the tag + * @return the registry (for keep adding tags) + */ + public DynamicMetricsRegistry tag(String name, String description, String value) { + return tag(name, description, value, false); + } + + /** + * Add a tag to the metrics + * @param name of the tag + * @param description of the tag + * @param value of the tag + * @param override existing tag if true + * @return the registry (for keep adding tags) + */ + public DynamicMetricsRegistry tag(String name, String description, String value, + boolean override) { + if (!override) checkTagName(name); + tagsMap.put(name, new MetricsTag(name, description, value)); + return this; + } + + /** + * Get the tags + * @return the tags set + */ + public Set> tags() { + return tagsMap.entrySet(); + } + + /** + * Get the metrics + * @return the metrics set + */ + public Set> metrics() { + return metricsMap.entrySet(); + } + + private void checkMetricName(String name) { + if (metricsMap.containsKey(name)) { + throw new MetricsException("Metric name "+ name +" already exists!"); + } + } + + private void checkTagName(String name) { + if (tagsMap.containsKey(name)) { + throw new MetricsException("Tag "+ name +" already exists!"); + } + } + + /** + * Sample all the mutable metrics and put the snapshot in the builder + * @param builder to contain the metrics snapshot + * @param all get all the metrics even if the values are not changed. + */ + public void snapshot(MetricsRecordBuilder builder, boolean all) { + for (Entry entry : tags()) { + builder.add(entry.getValue()); + } + for (Entry entry : metrics()) { + entry.getValue().snapshot(builder, all); + } + } + + /** + * Removes metric by name + * @param name name of the metric to remove + */ + public void removeMetric(String name) { + metricsMap.remove(name); + } + + /** + * Get a MetricMutableGaugeLong from the storage. If it is not there atomically put it. + * + * @param gaugeName name of the gauge to create or get. + * @param potentialStartingValue value of the new counter if we have to create it. + * @return + */ + public MetricMutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { + //Try and get the guage. + MetricMutable metric = metricsMap.get(gaugeName); + + //If it's not there then try and put a new one in the storage. + if (metric == null) { + + //Create the potential new gauge. + MetricMutableGaugeLong newGauge = new MetricMutableGaugeLong(gaugeName, "", + potentialStartingValue); + + // Try and put the gauge in. This is atomic. + metric = metricsMap.putIfAbsent(gaugeName, newGauge); + + //If the value we get back is null then the put was successful and we will return that. + //otherwise gaugeLong should contain the thing that was in before the put could be completed. + if (metric == null) { + return newGauge; + } + } + + if (!(metric instanceof MetricMutableGaugeLong)) { + throw new MetricsException("Metric already exists in registry for metric name: " + name + + " and not of type MetricMutableGaugeLong"); + } + + return (MetricMutableGaugeLong) metric; + } + + /** + * Get a MetricMutableCounterLong from the storage. If it is not there atomically put it. + * + * @param counterName Name of the counter to get + * @param potentialStartingValue starting value if we have to create a new counter + * @return + */ + public MetricMutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { + //See getLongGauge for description on how this works. + MetricMutable counter = metricsMap.get(counterName); + if (counter == null) { + MetricMutableCounterLong newCounter = + new MetricMutableCounterLong(counterName, "", potentialStartingValue); + counter = metricsMap.putIfAbsent(counterName, newCounter); + if (counter == null) { + return newCounter; + } + } + + + if (!(counter instanceof MetricMutableCounterLong)) { + throw new MetricsException("Metric already exists in registry for metric name: " + name + + " and not of type MetricMutableCounterLong"); + } + + return (MetricMutableCounterLong) counter; + } +} Index: hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource =================================================================== --- hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource (revision 0) +++ hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.master.metrics.MasterMetricsSourceImpl Index: hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource =================================================================== --- hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource (revision 0) +++ hbase-hadoop1-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.metrics.MBeanSourceImpl Index: hbase-hadoop1-compat/pom.xml =================================================================== --- hbase-hadoop1-compat/pom.xml (revision 1365064) +++ hbase-hadoop1-compat/pom.xml (working copy) @@ -93,5 +93,13 @@ true test + + org.apache.hbase + hbase-hadoop-compat + ${project.version} + test-jar + true + test + Index: hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java =================================================================== --- hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java (revision 1365064) +++ hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImplTest.java (working copy) @@ -18,6 +18,8 @@ package org.apache.hadoop.hbase.metrics; +import org.apache.hadoop.metrics2.lib.MutableCounterLong; +import org.apache.hadoop.metrics2.lib.MutableGaugeLong; import org.junit.BeforeClass; import org.junit.Test; @@ -39,36 +41,36 @@ @Test public void testSetGauge() throws Exception { bmsi.setGauge("testset", 100); - assertEquals(100, bmsi.gauges.get("testset").value()); + assertEquals(100, ((MutableGaugeLong) bmsi.metricsRegistry.get("testset")).value()); bmsi.setGauge("testset", 300); - assertEquals(300, bmsi.gauges.get("testset").value()); + assertEquals(300, ((MutableGaugeLong) bmsi.metricsRegistry.get("testset")).value()); } @Test public void testIncGauge() throws Exception { bmsi.incGauge("testincgauge", 100); - assertEquals(100, bmsi.gauges.get("testincgauge").value()); + assertEquals(100, ((MutableGaugeLong) bmsi.metricsRegistry.get("testincgauge")).value()); bmsi.incGauge("testincgauge", 100); - assertEquals(200, bmsi.gauges.get("testincgauge").value()); + assertEquals(200, ((MutableGaugeLong) bmsi.metricsRegistry.get("testincgauge")).value()); } @Test public void testDecGauge() throws Exception { bmsi.decGauge("testdec", 100); - assertEquals(-100, bmsi.gauges.get("testdec").value()); + assertEquals(-100, ((MutableGaugeLong) bmsi.metricsRegistry.get("testdec")).value()); bmsi.decGauge("testdec", 100); - assertEquals(-200, bmsi.gauges.get("testdec").value()); + assertEquals(-200, ((MutableGaugeLong) bmsi.metricsRegistry.get("testdec")).value()); } @Test public void testIncCounters() throws Exception { bmsi.incCounters("testinccounter", 100); - assertEquals(100, bmsi.counters.get("testinccounter").value()); + assertEquals(100, ((MutableCounterLong) bmsi.metricsRegistry.get("testinccounter")).value()); bmsi.incCounters("testinccounter", 100); - assertEquals(200, bmsi.counters.get("testinccounter").value()); + assertEquals(200, ((MutableCounterLong) bmsi.metricsRegistry.get("testinccounter")).value()); } @@ -76,13 +78,13 @@ public void testRemoveGauge() throws Exception { bmsi.setGauge("testrmgauge", 100); bmsi.removeGauge("testrmgauge"); - assertNull(bmsi.gauges.get("testrmgauge")); + assertNull(bmsi.metricsRegistry.get("testrmgauge")); } @Test public void testRemoveCounter() throws Exception { bmsi.incCounters("testrmcounter", 100); bmsi.removeCounter("testrmcounter"); - assertNull(bmsi.counters.get("testrmcounter")); + assertNull(bmsi.metricsRegistry.get("testrmcounter")); } } Index: hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java =================================================================== --- hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java (revision 0) +++ hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAssertsImpl.java (revision 0) @@ -0,0 +1,38 @@ +/** + * 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.metrics; + +import org.apache.hadoop.metrics2.lib.MutableCounterLong; + +/** + * Helpers for metrics source tests + */ +public class MetricsAssertsImpl extends MetricsAsserts { + @Override + public void assertCounter(String name, long value, BaseMetricsSource ms) { + BaseMetricsSourceImpl bms = (BaseMetricsSourceImpl) ms; + org.apache.hadoop.test.MetricsAsserts.assertCounter(name, value, bms); + } + + @Override + public long getCounterValue(String name, BaseMetricsSource ms) { + BaseMetricsSourceImpl bms = (BaseMetricsSourceImpl) ms; + return ((MutableCounterLong) bms.metricsRegistry.get(name)).value(); + } +} Index: hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java =================================================================== --- hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java (revision 1365064) +++ hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImplTest.java (working copy) @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.replication.regionserver.metrics; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; import org.junit.Test; import static org.junit.Assert.assertTrue; @@ -27,7 +28,8 @@ @Test public void testGetInstance() throws Exception { - ReplicationMetricsSource rms = ReplicationMetricsSourceFactory.getInstance(); + ReplicationMetricsSource rms = CompatibilitySingletonFactory + .getInstance(ReplicationMetricsSource.class); assertTrue(rms instanceof ReplicationMetricsSourceImpl); } } Index: hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java =================================================================== --- hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java (revision 0) +++ hbase-hadoop2-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImplTest.java (revision 0) @@ -0,0 +1,40 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; +import org.junit.Test; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** + * Test for MasterMetricsSourceImpl + */ +public class MasterMetricsSourceImplTest { + + @Test + public void testGetInstance() throws Exception { + MasterMetricsSource rms = CompatibilitySingletonFactory + .getInstance(MasterMetricsSource.class); + assertTrue(rms instanceof MasterMetricsSourceImpl); + assertSame(rms, CompatibilitySingletonFactory.getInstance(MasterMetricsSource.class)); + } + +} Index: hbase-hadoop2-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts =================================================================== --- hbase-hadoop2-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts (revision 0) +++ hbase-hadoop2-compat/src/test/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MetricsAsserts (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.metrics.MetricsAssertsImpl \ No newline at end of file Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java (revision 1365064) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/BaseMetricsSourceImpl.java (working copy) @@ -19,45 +19,35 @@ package org.apache.hadoop.hbase.metrics; import org.apache.hadoop.metrics2.MetricsCollector; -import org.apache.hadoop.metrics2.MetricsRecordBuilder; import org.apache.hadoop.metrics2.MetricsSource; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; -import org.apache.hadoop.metrics2.lib.HBaseMetricsFactory; +import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry; import org.apache.hadoop.metrics2.lib.MutableCounterLong; import org.apache.hadoop.metrics2.lib.MutableGaugeLong; +import org.apache.hadoop.metrics2.source.JvmMetrics; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - /** Hadoop 2 implementation of BaseMetricsSource for */ public class BaseMetricsSourceImpl implements BaseMetricsSource, MetricsSource { private static boolean defaultMetricsSystemInited = false; public static final String HBASE_METRICS_SYSTEM_NAME = "hbase"; - public ConcurrentMap - gauges = new ConcurrentHashMap(); - public ConcurrentMap counters = - new ConcurrentHashMap(); + final DynamicMetricsRegistry metricsRegistry; - protected String metricsContext; - protected String metricsName; - protected String metricsDescription; + private JvmMetrics jvmMetricsSource; public BaseMetricsSourceImpl(String metricsName, String metricsDescription, String metricsContext) { - this.metricsContext = metricsContext; - this.metricsName = metricsName; - this.metricsDescription = metricsDescription; + metricsRegistry = new DynamicMetricsRegistry(metricsName).setContext(metricsContext); if (!defaultMetricsSystemInited) { //Not too worried about mutlithread here as all it does is spam the logs. defaultMetricsSystemInited = true; DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME); + jvmMetricsSource = JvmMetrics.create(metricsName, "", DefaultMetricsSystem.instance()); } - DefaultMetricsSystem.instance().register(this.metricsContext, this.metricsDescription, this); + DefaultMetricsSystem.instance().register(metricsContext, metricsDescription, this); } @@ -112,7 +102,7 @@ * @param key */ public void removeGauge(String key) { - gauges.remove(key); + metricsRegistry.removeMetric(key); } /** @@ -121,21 +111,12 @@ * @param key */ public void removeCounter(String key) { - counters.remove(key); + metricsRegistry.removeMetric(key); } @Override public void getMetrics(MetricsCollector metricsCollector, boolean all) { - MetricsRecordBuilder rb = - metricsCollector.addRecord(this.metricsName).setContext(metricsContext); - - for (Map.Entry entry : counters.entrySet()) { - entry.getValue().snapshot(rb, all); - } - for (Map.Entry entry : gauges.entrySet()) { - entry.getValue().snapshot(rb, all); - } - + metricsRegistry.snapshot(metricsCollector.addRecord(metricsRegistry.info()), all); } /** @@ -145,28 +126,8 @@ * @param potentialStartingValue value of the new counter if we have to create it. * @return */ - private MutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { - //Try and get the guage. - MutableGaugeLong gaugeInt = gauges.get(gaugeName); - - //If it's not there then try and put a new one in the storage. - if (gaugeInt == null) { - - //Create the potential new gauge. - MutableGaugeLong newGauge = HBaseMetricsFactory.newGauge(gaugeName, - "", - potentialStartingValue); - - // Try and put the gauge in. This is atomic. - gaugeInt = gauges.putIfAbsent(gaugeName, newGauge); - - //If the value we get back is null then the put was successful and we will return that. - //otherwise gaugeInt should contain the thing that was in before the put could be completed. - if (gaugeInt == null) { - gaugeInt = newGauge; - } - } - return gaugeInt; + protected MutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { + return metricsRegistry.getLongGauge(gaugeName, potentialStartingValue); } /** @@ -176,18 +137,7 @@ * @param potentialStartingValue starting value if we have to create a new counter * @return */ - private MutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { - //See getLongGauge for description on how this works. - MutableCounterLong counter = counters.get(counterName); - if (counter == null) { - MutableCounterLong newCounter = - HBaseMetricsFactory.newCounter(counterName, "", potentialStartingValue); - counter = counters.putIfAbsent(counterName, newCounter); - if (counter == null) { - counter = newCounter; - } - } - return counter; + protected MutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { + return metricsRegistry.getLongCounter(counterName, potentialStartingValue); } - } Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java (revision 0) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSourceImpl.java (revision 0) @@ -0,0 +1,41 @@ +/** + * 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.metrics; + +import org.apache.hadoop.metrics2.util.MBeans; + +import javax.management.ObjectName; + +/** + * Hadoop2 metrics2 implementation of an object that registers MBeans. + */ +public class MBeanSourceImpl implements MBeanSource { + + /** + * Register an mbean with the underlying metrics system + * @param serviceName Metrics service/system name + * @param nameName name of the metrics obejct to expose + * @param theMbean the actual MBean + * @return ObjectName from jmx + */ + @Override + public ObjectName register(String serviceName, String nameName, Object theMbean) { + return MBeans.register(serviceName, nameName, theMbean); + } +} Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java (revision 1365064) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceImpl.java (working copy) @@ -28,10 +28,6 @@ public class ReplicationMetricsSourceImpl extends BaseMetricsSourceImpl implements ReplicationMetricsSource { - public static final String METRICS_NAME = "ReplicationMetrics"; - public static final String METRICS_CONTEXT = "replicationmetrics"; - public static final String METRICS_DESCRIPTION = "Metrics about HBase replication"; - public ReplicationMetricsSourceImpl() { this(METRICS_NAME, METRICS_DESCRIPTION, METRICS_CONTEXT); } Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java (revision 0) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceImpl.java (revision 0) @@ -0,0 +1,65 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.metrics.BaseMetricsSourceImpl; +import org.apache.hadoop.metrics2.lib.MutableCounterLong; +import org.apache.hadoop.metrics2.lib.MutableGaugeLong; + +/** + * + */ +public class MasterMetricsSourceImpl extends BaseMetricsSourceImpl implements MasterMetricsSource { + + MutableCounterLong clusterRequestsCounter; + MutableGaugeLong ritGauge; + MutableGaugeLong ritCountOverThresholdGauge; + MutableGaugeLong ritOldestAgeGauge; + + public MasterMetricsSourceImpl() { + this(METRICS_NAME, METRICS_DESCRIPTION, METRICS_CONTEXT); + } + + public MasterMetricsSourceImpl(String metricsName, + String metricsDescription, + String metricsContext) { + super(metricsName, metricsDescription, metricsContext); + + clusterRequestsCounter = getLongCounter("cluster_requests", 0); + ritGauge = getLongGauge("ritCount", 0); + ritCountOverThresholdGauge = getLongGauge("ritCountOverThreshold", 0); + ritOldestAgeGauge = getLongGauge("ritOldestAge", 0); + } + + public void incRequests(final int inc) { + this.clusterRequestsCounter.incr(inc); + } + + public void setRIT(int ritCount) { + ritGauge.set(ritCount); + } + + public void setRITCountOverThreshold(int ritCount) { + ritCountOverThresholdGauge.set(ritCount); + } + + public void setRITOldestAge(long ritCount) { + ritCountOverThresholdGauge.set(ritCount); + } +} Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/HBaseMetricsFactory.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/HBaseMetricsFactory.java (revision 1365064) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/HBaseMetricsFactory.java (working copy) @@ -1,50 +0,0 @@ -/** - * 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.metrics2.lib; - -/** - * Factory providing static methods to create MutableMetrics classes. - * HBase uses this class rather than MetricsRegistry because MetricsRegistry does not - * allow metrics to be removed. - */ -public class HBaseMetricsFactory { - - /** - * Create a new gauge - * @param name Name of the gauge - * @param desc Description of the gauge - * @param startingValue The starting value - * @return a new MutableGaugeLong that has a starting value. - */ - public static MutableGaugeLong newGauge(String name, String desc, long startingValue) { - return new MutableGaugeLong(Interns.info(name, desc), startingValue); - } - - /** - * Create a new counter. - * @param name Name of the counter. - * @param desc Description of the counter. - * @param startingValue The starting value. - * @return a new MutableCounterLong that has a starting value. - */ - public static MutableCounterLong newCounter(String name, String desc, long startingValue) { - return new MutableCounterLong(Interns.info(name, desc), startingValue); - } - -} Index: hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java =================================================================== --- hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java (revision 0) +++ hbase-hadoop2-compat/src/main/java/org/apache/hadoop/metrics2/lib/DynamicMetricsRegistry.java (revision 0) @@ -0,0 +1,454 @@ +/** + * 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.metrics2.lib; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import com.google.common.base.Objects; +import com.google.common.collect.Maps; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.metrics2.MetricsException; +import org.apache.hadoop.metrics2.MetricsInfo; +import org.apache.hadoop.metrics2.MetricsRecordBuilder; +import org.apache.hadoop.metrics2.MetricsTag; +import org.apache.hadoop.metrics2.impl.MsInfo; + +/** + * An optional metrics registry class for creating and maintaining a + * collection of MetricsMutables, making writing metrics source easier. + * NOTE: this is a copy of org.apache.hadoop.metrics2.lib.MetricsRegistry with added one + * feature: metrics can be removed. When HADOOP-8313 is fixed, usages of this class + * should be substituted with org.apache.hadoop.metrics2.lib.MetricsRegistry. + * This implementation also provides handy methods for creating metrics dynamically. + * Another difference is that metricsMap implementation is substituted with thread-safe + * map, as we allow dynamic metrics additions/removals. + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public class DynamicMetricsRegistry { + private final ConcurrentMap metricsMap = Maps.newConcurrentMap(); + private final Map tagsMap = Maps.newLinkedHashMap(); + private final MetricsInfo metricsInfo; + + /** + * Construct the registry with a record name + * @param name of the record of the metrics + */ + public DynamicMetricsRegistry(String name) { + metricsInfo = Interns.info(name, name); + } + + /** + * Construct the registry with a metadata object + * @param info the info object for the metrics record/group + */ + public DynamicMetricsRegistry(MetricsInfo info) { + metricsInfo = info; + } + + /** + * @return the info object of the metrics registry + */ + public MetricsInfo info() { + return metricsInfo; + } + + /** + * Get a metric by name + * @param name of the metric + * @return the metric object + */ + public synchronized MutableMetric get(String name) { + return metricsMap.get(name); + } + + /** + * Get a tag by name + * @param name of the tag + * @return the tag object + */ + public synchronized MetricsTag getTag(String name) { + return tagsMap.get(name); + } + + /** + * Create a mutable integer counter + * @param name of the metric + * @param desc metric description + * @param iVal initial value + * @return a new counter object + */ + public MutableCounterInt newCounter(String name, String desc, int iVal) { + return newCounter(Interns.info(name, desc), iVal); + } + + /** + * Create a mutable integer counter + * @param info metadata of the metric + * @param iVal initial value + * @return a new counter object + */ + public synchronized MutableCounterInt newCounter(MetricsInfo info, int iVal) { + checkMetricName(info.name()); + MutableCounterInt ret = new MutableCounterInt(info, iVal); + metricsMap.put(info.name(), ret); + return ret; + } + + /** + * Create a mutable long integer counter + * @param name of the metric + * @param desc metric description + * @param iVal initial value + * @return a new counter object + */ + public MutableCounterLong newCounter(String name, String desc, long iVal) { + return newCounter(Interns.info(name, desc), iVal); + } + + /** + * Create a mutable long integer counter + * @param info metadata of the metric + * @param iVal initial value + * @return a new counter object + */ + public synchronized MutableCounterLong newCounter(MetricsInfo info, long iVal) { + checkMetricName(info.name()); + MutableCounterLong ret = new MutableCounterLong(info, iVal); + metricsMap.put(info.name(), ret); + return ret; + } + + /** + * Create a mutable integer gauge + * @param name of the metric + * @param desc metric description + * @param iVal initial value + * @return a new gauge object + */ + public MutableGaugeInt newGauge(String name, String desc, int iVal) { + return newGauge(Interns.info(name, desc), iVal); + } + /** + * Create a mutable integer gauge + * @param info metadata of the metric + * @param iVal initial value + * @return a new gauge object + */ + public synchronized MutableGaugeInt newGauge(MetricsInfo info, int iVal) { + checkMetricName(info.name()); + MutableGaugeInt ret = new MutableGaugeInt(info, iVal); + metricsMap.put(info.name(), ret); + return ret; + } + + /** + * Create a mutable long integer gauge + * @param name of the metric + * @param desc metric description + * @param iVal initial value + * @return a new gauge object + */ + public MutableGaugeLong newGauge(String name, String desc, long iVal) { + return newGauge(Interns.info(name, desc), iVal); + } + + /** + * Create a mutable long integer gauge + * @param info metadata of the metric + * @param iVal initial value + * @return a new gauge object + */ + public synchronized MutableGaugeLong newGauge(MetricsInfo info, long iVal) { + checkMetricName(info.name()); + MutableGaugeLong ret = new MutableGaugeLong(info, iVal); + metricsMap.put(info.name(), ret); + return ret; + } + + /** + * Create a mutable metric with stats + * @param name of the metric + * @param desc metric description + * @param sampleName of the metric (e.g., "Ops") + * @param valueName of the metric (e.g., "Time" or "Latency") + * @param extended produce extended stat (stdev, min/max etc.) if true. + * @return a new mutable stat metric object + */ + public synchronized MutableStat newStat(String name, String desc, + String sampleName, String valueName, boolean extended) { + checkMetricName(name); + MutableStat ret = + new MutableStat(name, desc, sampleName, valueName, extended); + metricsMap.put(name, ret); + return ret; + } + + /** + * Create a mutable metric with stats + * @param name of the metric + * @param desc metric description + * @param sampleName of the metric (e.g., "Ops") + * @param valueName of the metric (e.g., "Time" or "Latency") + * @return a new mutable metric object + */ + public MutableStat newStat(String name, String desc, + String sampleName, String valueName) { + return newStat(name, desc, sampleName, valueName, false); + } + + /** + * Create a mutable rate metric + * @param name of the metric + * @return a new mutable metric object + */ + public MutableRate newRate(String name) { + return newRate(name, name, false); + } + + /** + * Create a mutable rate metric + * @param name of the metric + * @param description of the metric + * @return a new mutable rate metric object + */ + public MutableRate newRate(String name, String description) { + return newRate(name, description, false); + } + + /** + * Create a mutable rate metric (for throughput measurement) + * @param name of the metric + * @param desc description + * @param extended produce extended stat (stdev/min/max etc.) if true + * @return a new mutable rate metric object + */ + public MutableRate newRate(String name, String desc, boolean extended) { + return newRate(name, desc, extended, true); + } + + @InterfaceAudience.Private + public synchronized MutableRate newRate(String name, String desc, + boolean extended, boolean returnExisting) { + if (returnExisting) { + MutableMetric rate = metricsMap.get(name); + if (rate != null) { + if (rate instanceof MutableRate) return (MutableRate) rate; + throw new MetricsException("Unexpected metrics type "+ rate.getClass() + +" for "+ name); + } + } + checkMetricName(name); + MutableRate ret = new MutableRate(name, desc, extended); + metricsMap.put(name, ret); + return ret; + } + + synchronized void add(String name, MutableMetric metric) { + checkMetricName(name); + metricsMap.put(name, metric); + } + + /** + * Add sample to a stat metric by name. + * @param name of the metric + * @param value of the snapshot to add + */ + public synchronized void add(String name, long value) { + MutableMetric m = metricsMap.get(name); + + if (m != null) { + if (m instanceof MutableStat) { + ((MutableStat) m).add(value); + } + else { + throw new MetricsException("Unsupported add(value) for metric "+ name); + } + } + else { + metricsMap.put(name, newRate(name)); // default is a rate metric + add(name, value); + } + } + + /** + * Set the metrics context tag + * @param name of the context + * @return the registry itself as a convenience + */ + public DynamicMetricsRegistry setContext(String name) { + return tag(MsInfo.Context, name, true); + } + + /** + * Add a tag to the metrics + * @param name of the tag + * @param description of the tag + * @param value of the tag + * @return the registry (for keep adding tags) + */ + public DynamicMetricsRegistry tag(String name, String description, String value) { + return tag(name, description, value, false); + } + + /** + * Add a tag to the metrics + * @param name of the tag + * @param description of the tag + * @param value of the tag + * @param override existing tag if true + * @return the registry (for keep adding tags) + */ + public DynamicMetricsRegistry tag(String name, String description, String value, + boolean override) { + return tag(Interns.info(name, description), value, override); + } + + /** + * Add a tag to the metrics + * @param info metadata of the tag + * @param value of the tag + * @param override existing tag if true + * @return the registry (for keep adding tags etc.) + */ + public synchronized DynamicMetricsRegistry tag(MetricsInfo info, String value, boolean override) { + if (!override) checkTagName(info.name()); + tagsMap.put(info.name(), Interns.tag(info, value)); + return this; + } + + public DynamicMetricsRegistry tag(MetricsInfo info, String value) { + return tag(info, value, false); + } + + Collection tags() { + return tagsMap.values(); + } + + Collection metrics() { + return metricsMap.values(); + } + + private void checkMetricName(String name) { + if (metricsMap.containsKey(name)) { + throw new MetricsException("Metric name "+ name +" already exists!"); + } + } + + private void checkTagName(String name) { + if (tagsMap.containsKey(name)) { + throw new MetricsException("Tag "+ name +" already exists!"); + } + } + + /** + * Sample all the mutable metrics and put the snapshot in the builder + * @param builder to contain the metrics snapshot + * @param all get all the metrics even if the values are not changed. + */ + public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) { + for (MetricsTag tag : tags()) { + builder.add(tag); + } + for (MutableMetric metric : metrics()) { + metric.snapshot(builder, all); + } + } + + @Override public String toString() { + return Objects.toStringHelper(this) + .add("info", metricsInfo).add("tags", tags()).add("metrics", metrics()) + .toString(); + } + + /** + * Removes metric by name + * @param name name of the metric to remove + */ + public void removeMetric(String name) { + metricsMap.remove(name); + } + + /** + * Get a MetricMutableGaugeLong from the storage. If it is not there atomically put it. + * + * @param gaugeName name of the gauge to create or get. + * @param potentialStartingValue value of the new counter if we have to create it. + * @return + */ + public MutableGaugeLong getLongGauge(String gaugeName, long potentialStartingValue) { + //Try and get the guage. + MutableMetric metric = metricsMap.get(gaugeName); + + //If it's not there then try and put a new one in the storage. + if (metric == null) { + + //Create the potential new gauge. + MutableGaugeLong newGauge = new MutableGaugeLong(Interns.info(gaugeName, ""), + potentialStartingValue); + + // Try and put the gauge in. This is atomic. + metric = metricsMap.putIfAbsent(gaugeName, newGauge); + + //If the value we get back is null then the put was successful and we will return that. + //otherwise gaugeLong should contain the thing that was in before the put could be completed. + if (metric == null) { + return newGauge; + } + } + + if (!(metric instanceof MutableGaugeLong)) { + throw new MetricsException("Metric already exists in registry for metric name: " + gaugeName + + " and not of type MetricMutableGaugeLong"); + } + + return (MutableGaugeLong) metric; + } + + /** + * Get a MetricMutableCounterLong from the storage. If it is not there atomically put it. + * + * @param counterName Name of the counter to get + * @param potentialStartingValue starting value if we have to create a new counter + * @return + */ + public MutableCounterLong getLongCounter(String counterName, long potentialStartingValue) { + //See getLongGauge for description on how this works. + MutableMetric counter = metricsMap.get(counterName); + if (counter == null) { + MutableCounterLong newCounter = + new MutableCounterLong(Interns.info(counterName, ""), potentialStartingValue); + counter = metricsMap.putIfAbsent(counterName, newCounter); + if (counter == null) { + return newCounter; + } + } + + + if (!(counter instanceof MutableCounterLong)) { + throw new MetricsException("Metric already exists in registry for metric name: " + counterName + + " and not of type MetricMutableCounterLong"); + } + + return (MutableCounterLong) counter; + } +} Index: hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource =================================================================== --- hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource (revision 0) +++ hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.master.metrics.MasterMetricsSource (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.master.metrics.MasterMetricsSourceImpl Index: hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource =================================================================== --- hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource (revision 0) +++ hbase-hadoop2-compat/src/main/resources/META-INF/services/org.apache.hadoop.hbase.metrics.MBeanSource (revision 0) @@ -0,0 +1 @@ +org.apache.hadoop.hbase.metrics.MBeanSourceImpl Index: hbase-hadoop2-compat/pom.xml =================================================================== --- hbase-hadoop2-compat/pom.xml (revision 1365064) +++ hbase-hadoop2-compat/pom.xml (working copy) @@ -129,5 +129,13 @@ hadoop-minicluster ${hadoop-two.version} + + org.apache.hbase + hbase-hadoop-compat + ${project.version} + test-jar + true + test + Index: hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAsserts.java =================================================================== --- hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAsserts.java (revision 0) +++ hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/MetricsAsserts.java (revision 0) @@ -0,0 +1,75 @@ +/** + * 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.metrics; + +import java.util.ServiceLoader; + +import org.apache.hadoop.hbase.metrics.BaseMetricsSource; + +/** + * Class to load MetricsAsserts from the class path. Will only return a singleton + * instance. + * Contains helpers for metrics source tests. + */ +public abstract class MetricsAsserts { + + private static MetricsAsserts factory = null; + public static final String EXCEPTION_STRING = "Could not create a MetricsAsserts metrics source. " + + "Is the hadoop compatibility jar on the classpath?"; + + + /** + * Verifies counter value + * @param name name of counter + * @param value value to verify against + * @param ms metrics source + */ + public abstract void assertCounter(String name, long value, BaseMetricsSource ms); + + /** + * Gets value of a counter. Handy in unit-tests + * @param name name of counter + * @param ms metrics source + * @return + */ + public abstract long getCounterValue(String name, BaseMetricsSource ms); + + /** + * Get the singleton instance of ReplicationMetricsSource + * + * @return the singleton + */ + public static synchronized MetricsAsserts getInstance() { + if (factory == null) { + try { + factory = ServiceLoader.load(MetricsAsserts.class).iterator().next(); + } catch (Exception e) { + throw new RuntimeException(EXCEPTION_STRING, e); + } catch (Error e) { + throw new RuntimeException(EXCEPTION_STRING, e); + } + + // If there was nothing returned and no exception then throw an exception. + if (factory == null) { + throw new RuntimeException(EXCEPTION_STRING); + } + } + return factory; + } +} Index: hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceFactoryTest.java =================================================================== --- hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceFactoryTest.java (revision 1365064) +++ hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSourceFactoryTest.java (working copy) @@ -18,17 +18,18 @@ package org.apache.hadoop.hbase.replication.regionserver.metrics; +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; import org.junit.Test; /** - * Test for the ReplicationMetricsSourceFactory + * Test for the CompatibilitySingletonFactory and building ReplicationMetricsSource */ public class ReplicationMetricsSourceFactoryTest { @Test(expected=RuntimeException.class) public void testGetInstanceNoHadoopCompat() throws Exception { //This should throw an exception because there is no compat lib on the class path. - ReplicationMetricsSourceFactory.getInstance(); + CompatibilitySingletonFactory.getInstance(ReplicationMetricsSource.class); } } Index: hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceFactoryTest.java =================================================================== --- hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceFactoryTest.java (revision 0) +++ hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSourceFactoryTest.java (revision 0) @@ -0,0 +1,35 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.CompatibilitySingletonFactory; +import org.junit.Test; + +/** + * Test for the CompatibilitySingletonFactory and building MasterMetricsSource + */ +public class MasterMetricsSourceFactoryTest { + + @Test(expected=RuntimeException.class) + public void testGetInstanceNoHadoopCompat() throws Exception { + //This should throw an exception because there is no compat lib on the class path. + CompatibilitySingletonFactory.getInstance(MasterMetricsSource.class); + + } +} Index: hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/CompatibilitySingletonFactory.java =================================================================== --- hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/CompatibilitySingletonFactory.java (revision 0) +++ hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/CompatibilitySingletonFactory.java (revision 0) @@ -0,0 +1,65 @@ +/** + * 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; + +import org.apache.hadoop.hbase.master.metrics.MasterMetricsSource; + +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * Factory for classes supplied by hadoop compatibility modules. + */ +public class CompatibilitySingletonFactory { + public static final String EXCEPTION_START = "Could not create "; + public static final String EXCEPTION_END = " Is the hadoop compatibility jar on the classpath?"; + + private static final Map instances = new HashMap(); + + /** + * Get the singleton instance of Any classes defined by compatibiliy jar's + * + * @return the singleton + */ + public static synchronized T getInstance(Class klass) { + T instance = (T) instances.get(klass); + if (instance == null) { + try { + instance = ServiceLoader.load(klass).iterator().next(); + } catch (Exception e) { + throw new RuntimeException(createExceptionString(klass), e); + } catch (Error e) { + throw new RuntimeException(createExceptionString(klass), e); + } + + // If there was nothing returned and no exception then throw an exception. + if (instance == null) { + throw new RuntimeException(createExceptionString(klass)); + } + instances.put(klass, instance); + } + return instance; + } + + private static String createExceptionString(Class klass) { + return EXCEPTION_START + klass.toString() + EXCEPTION_END; + } + +} Index: hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSource.java =================================================================== --- hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSource.java (revision 0) +++ hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/metrics/MBeanSource.java (revision 0) @@ -0,0 +1,38 @@ +/** + * 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.metrics; + +import javax.management.ObjectName; + +/** + * Object that will register an mbean with the underlying metrics implementation. + */ +public interface MBeanSource { + + /** + * Register an mbean with the underlying metrics system + * @param serviceName Metrics service/system name + * @param nameName name of the metrics obejct to expose + * @param theMbean the actual MBean + * @return ObjectName from jmx + */ + public ObjectName register(String serviceName, String nameName, + Object theMbean); + +} Index: hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSource.java =================================================================== --- hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSource.java (revision 1365064) +++ hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/replication/regionserver/metrics/ReplicationMetricsSource.java (working copy) @@ -25,6 +25,19 @@ * hadoop2's metrics2 classes and publishing. */ public interface ReplicationMetricsSource extends BaseMetricsSource { - //Empty interface so that ServiceLoader can find the right implementation. + /** + * The name of the metrics + */ + public static final String METRICS_NAME = "ReplicationMetrics"; + /** + * The name of the metrics context that metrics will be under. + */ + public static final String METRICS_CONTEXT = "replicationmetrics"; + + /** + * A description. + */ + public static final String METRICS_DESCRIPTION = "Metrics about HBase replication"; + } Index: hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSource.java =================================================================== --- hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSource.java (revision 0) +++ hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/metrics/MasterMetricsSource.java (revision 0) @@ -0,0 +1,67 @@ +/** + * 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.master.metrics; + +import org.apache.hadoop.hbase.metrics.BaseMetricsSource; + +/** + * Interface that classes that expose metrics about the master will implement. + */ +public interface MasterMetricsSource extends BaseMetricsSource { + + /** + * The name of the metrics + */ + public static final String METRICS_NAME = "HMaster"; + + /** + * The name of the metrics context that metrics will be under. + */ + public static final String METRICS_CONTEXT = "HMaster,sub=Dynamic"; + + /** + * Description + */ + public static final String METRICS_DESCRIPTION = "Metrics about HBase master server"; + + /** + * Increment the number of request the cluster has seen. + * @param inc Ammount to increment the total by. + */ + public void incRequests(final int inc); + + /** + * Set the number of regions in transition. + * @param ritCount count of the regions in transition. + */ + public void setRIT(int ritCount); + + /** + * Set the count of the number of regions that have been in transition over the threshold time. + * @param ritCountOverThreshold number of regions in transition for longer than threshold. + */ + public void setRITCountOverThreshold(int ritCountOverThreshold); + + /** + * Set the oldest region in transition. + * @param age age of the oldest RIT. + */ + public void setRITOldestAge(long age); + +}