1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hbase.metrics; 19 20 import org.apache.commons.logging.Log; 21 import org.apache.commons.logging.LogFactory; 22 import org.apache.hadoop.metrics.MetricsRecord; 23 import org.apache.hadoop.metrics.util.MetricsRegistry; 24 import org.apache.hadoop.metrics.util.MetricsTimeVaryingRate; 25 import org.apache.hadoop.util.StringUtils; 26 27 /** 28 * This class extends MetricsTimeVaryingRate to let the metrics 29 * persist past a pushMetric() call 30 */ 31 public class PersistentMetricsTimeVaryingRate extends MetricsTimeVaryingRate { 32 protected static final Log LOG = 33 LogFactory.getLog("org.apache.hadoop.hbase.metrics"); 34 35 protected boolean reset = false; 36 protected long lastOper = 0; 37 protected long totalOps = 0; 38 39 /** 40 * Constructor - create a new metric 41 * @param nam the name of the metrics to be used to publish the metric 42 * @param registry - where the metrics object will be registered 43 * @param description metrics description 44 */ 45 public PersistentMetricsTimeVaryingRate(final String nam, 46 final MetricsRegistry registry, 47 final String description) { 48 super(nam, registry, description); 49 } 50 51 /** 52 * Constructor - create a new metric 53 * @param nam the name of the metrics to be used to publish the metric 54 * @param registry - where the metrics object will be registered 55 */ 56 public PersistentMetricsTimeVaryingRate(final String nam, 57 MetricsRegistry registry) { 58 this(nam, registry, NO_DESCRIPTION); 59 } 60 61 /** 62 * Push updated metrics to the mr. 63 * 64 * Note this does NOT push to JMX 65 * (JMX gets the info via {@link #getPreviousIntervalAverageTime()} and 66 * {@link #getPreviousIntervalNumOps()} 67 * 68 * @param mr owner of this metric 69 */ 70 @Override 71 public synchronized void pushMetric(final MetricsRecord mr) { 72 // this will reset the currentInterval & num_ops += prevInterval() 73 super.pushMetric(mr); 74 // since we're retaining prevInterval(), we don't want to do the incr 75 // instead, we want to set that value because we have absolute ops 76 try { 77 mr.setMetric(getName() + "_num_ops", totalOps); 78 } catch (Exception e) { 79 LOG.info("pushMetric failed for " + getName() + "\n" + 80 StringUtils.stringifyException(e)); 81 } 82 if (reset) { 83 // use the previous avg as our starting min/max/avg 84 super.inc(getPreviousIntervalAverageTime()); 85 reset = false; 86 } else { 87 // maintain the stats that pushMetric() cleared 88 maintainStats(); 89 } 90 } 91 92 /** 93 * Increment the metrics for numOps operations 94 * @param numOps - number of operations 95 * @param time - time for numOps operations 96 */ 97 @Override 98 public synchronized void inc(final int numOps, final long time) { 99 super.inc(numOps, time); 100 totalOps += numOps; 101 } 102 103 /** 104 * Increment the metrics for numOps operations 105 * @param time - time for numOps operations 106 */ 107 @Override 108 public synchronized void inc(final long time) { 109 super.inc(time); 110 ++totalOps; 111 } 112 113 /** 114 * Rollover to a new interval 115 * NOTE: does not reset numOps. this is an absolute value 116 */ 117 public synchronized void resetMinMaxAvg() { 118 reset = true; 119 } 120 121 /* MetricsTimeVaryingRate will reset every time pushMetric() is called 122 * This is annoying for long-running stats that might not get a single 123 * operation in the polling period. This function ensures that values 124 * for those stat entries don't get reset. 125 */ 126 protected void maintainStats() { 127 int curOps = this.getPreviousIntervalNumOps(); 128 if (curOps > 0) { 129 long curTime = this.getPreviousIntervalAverageTime(); 130 long totalTime = curTime * curOps; 131 if (curTime == 0 || totalTime / curTime == curOps) { 132 super.inc(curOps, totalTime); 133 } else { 134 LOG.info("Stats for " + this.getName() + " overflowed! resetting"); 135 } 136 } 137 } 138 }