1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.metrics2.lib;
20
21 import static org.apache.hadoop.hbase.metrics.Interns.info;
22
23 import java.io.IOException;
24 import java.util.Map;
25 import java.util.concurrent.TimeUnit;
26
27 import org.apache.commons.lang.StringUtils;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.metrics2.MetricHistogram;
30 import org.apache.hadoop.metrics2.MetricsExecutor;
31 import org.apache.hadoop.metrics2.MetricsInfo;
32 import org.apache.hadoop.metrics2.MetricsRecordBuilder;
33 import org.apache.hadoop.metrics2.util.MetricQuantile;
34 import org.apache.hadoop.metrics2.util.MetricSampleQuantiles;
35
36 import com.google.common.annotations.VisibleForTesting;
37
38
39
40
41
42
43 @InterfaceAudience.Private
44 public class MetricMutableQuantiles extends MutableMetric implements MetricHistogram {
45
46 static final MetricQuantile[] quantiles = {new MetricQuantile(0.50, 0.050),
47 new MetricQuantile(0.75, 0.025), new MetricQuantile(0.90, 0.010),
48 new MetricQuantile(0.95, 0.005), new MetricQuantile(0.99, 0.001)};
49
50 private final MetricsInfo numInfo;
51 private final MetricsInfo[] quantileInfos;
52 private final int interval;
53
54 private MetricSampleQuantiles estimator;
55 private long previousCount = 0;
56 private MetricsExecutor executor;
57
58
59 @VisibleForTesting
60 protected Map<MetricQuantile, Long> previousSnapshot = null;
61
62
63
64
65
66
67
68
69
70
71
72 public MetricMutableQuantiles(String name, String description, String sampleName,
73 String valueName, int interval) {
74 String ucName = StringUtils.capitalize(name);
75 String usName = StringUtils.capitalize(sampleName);
76 String uvName = StringUtils.capitalize(valueName);
77 String desc = StringUtils.uncapitalize(description);
78 String lsName = StringUtils.uncapitalize(sampleName);
79 String lvName = StringUtils.uncapitalize(valueName);
80
81 numInfo = info(ucName + "Num" + usName, String.format(
82 "Number of %s for %s with %ds interval", lsName, desc, interval));
83
84 quantileInfos = new MetricsInfo[quantiles.length];
85 String nameTemplate = "%s%dthPercentile%dsInterval%s";
86 String descTemplate = "%d percentile %s with %d second interval for %s";
87 for (int i = 0; i < quantiles.length; i++) {
88 int percentile = (int) (100 * quantiles[i].quantile);
89 quantileInfos[i] = info(String.format(nameTemplate, ucName, percentile, interval, uvName),
90 String.format(descTemplate, percentile, lvName, interval, desc));
91 }
92
93 estimator = new MetricSampleQuantiles(quantiles);
94 executor = new MetricsExecutorImpl();
95 this.interval = interval;
96 executor.getExecutor().scheduleAtFixedRate(new RolloverSample(this),
97 interval,
98 interval,
99 TimeUnit.SECONDS);
100 }
101
102 @Override
103 public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
104 if (all || changed()) {
105 builder.addGauge(numInfo, previousCount);
106 for (int i = 0; i < quantiles.length; i++) {
107 long newValue = 0;
108
109 if (previousSnapshot != null) {
110 newValue = previousSnapshot.get(quantiles[i]);
111 }
112 builder.addGauge(quantileInfos[i], newValue);
113 }
114 if (changed()) {
115 clearChanged();
116 }
117 }
118 }
119
120 public synchronized void add(long value) {
121 estimator.insert(value);
122 }
123
124 public int getInterval() {
125 return interval;
126 }
127
128
129 private static class RolloverSample implements Runnable {
130
131 MetricMutableQuantiles parent;
132
133 public RolloverSample(MetricMutableQuantiles parent) {
134 this.parent = parent;
135 }
136
137 @Override
138 public void run() {
139 synchronized (parent) {
140 try {
141 parent.previousCount = parent.estimator.getCount();
142 parent.previousSnapshot = parent.estimator.snapshot();
143 } catch (IOException e) {
144
145 parent.previousCount = 0;
146 parent.previousSnapshot = null;
147 }
148 parent.estimator.clear();
149 }
150 parent.setChanged();
151 }
152
153 }
154 }