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 }