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.metrics2.lib.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 = ucName + "%dthPercentile" + interval + "sInterval"
86 + uvName;
87 String descTemplate = "%d percentile " + lvName + " with " + interval
88 + " second interval for " + desc;
89 for (int i = 0; i < quantiles.length; i++) {
90 int percentile = (int) (100 * quantiles[i].quantile);
91 quantileInfos[i] = info(String.format(nameTemplate, percentile),
92 String.format(descTemplate, percentile));
93 }
94
95 estimator = new MetricSampleQuantiles(quantiles);
96 executor = new MetricsExecutorImpl();
97 this.interval = interval;
98 executor.getExecutor().scheduleAtFixedRate(new RolloverSample(this),
99 interval,
100 interval,
101 TimeUnit.SECONDS);
102 }
103
104 @Override
105 public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
106 if (all || changed()) {
107 builder.addGauge(numInfo, previousCount);
108 for (int i = 0; i < quantiles.length; i++) {
109 long newValue = 0;
110
111 if (previousSnapshot != null) {
112 newValue = previousSnapshot.get(quantiles[i]);
113 }
114 builder.addGauge(quantileInfos[i], newValue);
115 }
116 if (changed()) {
117 clearChanged();
118 }
119 }
120 }
121
122 public synchronized void add(long value) {
123 estimator.insert(value);
124 }
125
126 public int getInterval() {
127 return interval;
128 }
129
130
131 private static class RolloverSample implements Runnable {
132
133 MetricMutableQuantiles parent;
134
135 public RolloverSample(MetricMutableQuantiles parent) {
136 this.parent = parent;
137 }
138
139 @Override
140 public void run() {
141 synchronized (parent) {
142 try {
143 parent.previousCount = parent.estimator.getCount();
144 parent.previousSnapshot = parent.estimator.snapshot();
145 } catch (IOException e) {
146
147 parent.previousCount = 0;
148 parent.previousSnapshot = null;
149 }
150 parent.estimator.clear();
151 }
152 parent.setChanged();
153 }
154
155 }
156 }