1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.metrics;
20
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.concurrent.atomic.AtomicLong;
27 import java.util.concurrent.locks.ReadWriteLock;
28 import java.util.concurrent.locks.ReentrantReadWriteLock;
29
30 import org.apache.hadoop.hbase.util.Pair;
31 import org.apache.hadoop.metrics.MetricsRecord;
32 import org.apache.hadoop.metrics.util.MetricsBase;
33 import org.apache.hadoop.metrics.util.MetricsRegistry;
34 import org.cliffc.high_scale_lib.Counter;
35
36 import com.google.common.base.Function;
37 import com.google.common.collect.Lists;
38 import com.google.common.collect.MapMaker;
39
40 public class ExactCounterMetric extends MetricsBase {
41
42 private static final int DEFAULT_TOP_N = 5;
43
44
45 private final int topN;
46 private final Map<String, Counter> counts;
47
48
49
50
51
52 private final ReadWriteLock lock;
53
54
55
56
57
58
59
60
61
62 public ExactCounterMetric(final String nam, final MetricsRegistry registry,
63 final String description, int topN) {
64 super(nam, description);
65
66 this.counts = new MapMaker().makeComputingMap(
67 new Function<String, Counter>() {
68 @Override
69 public Counter apply(String input) {
70 return new Counter();
71 }
72 });
73
74 this.lock = new ReentrantReadWriteLock();
75 this.topN = topN;
76
77 if (registry != null) {
78 registry.add(nam, this);
79 }
80 }
81
82
83
84
85
86
87 public ExactCounterMetric(final String nam, MetricsRegistry registry) {
88 this(nam, registry, NO_DESCRIPTION, DEFAULT_TOP_N);
89 }
90
91
92 public void update(String type) {
93 this.lock.readLock().lock();
94 try {
95 this.counts.get(type).increment();
96 } finally {
97 this.lock.readLock().unlock();
98 }
99 }
100
101 public void update(String type, long count) {
102 this.lock.readLock().lock();
103 try {
104 this.counts.get(type).add(count);
105 } finally {
106 this.lock.readLock().unlock();
107 }
108 }
109
110 public List<Pair<String, Long>> getTop(int n) {
111 final List<Pair<String, Long>> countsSnapshot =
112 Lists.newArrayListWithCapacity(this.counts.size());
113
114
115 this.lock.writeLock().lock();
116 try {
117 for(Entry<String, Counter> entry : this.counts.entrySet()) {
118 countsSnapshot.add(Pair.newPair(entry.getKey(),
119 entry.getValue().get()));
120 }
121 } finally {
122 this.lock.writeLock().unlock();
123 }
124
125 Collections.sort(countsSnapshot, new Comparator<Pair<String, Long>>() {
126 @Override
127 public int compare(Pair<String, Long> a, Pair<String, Long> b) {
128 return b.getSecond().compareTo(a.getSecond());
129 }
130 });
131
132 return countsSnapshot.subList(0, Math.min(n, countsSnapshot.size()));
133 }
134
135 @Override
136 public void pushMetric(MetricsRecord mr) {
137 final List<Pair<String, Long>> topKeys = getTop(Integer.MAX_VALUE);
138 int sum = 0;
139
140 int counter = 0;
141 for (Pair<String, Long> keyCount : topKeys) {
142 counter++;
143
144 if (counter <= this.topN) {
145 mr.setMetric(getName() + "_" + keyCount.getFirst(),
146 keyCount.getSecond());
147 }
148 sum += keyCount.getSecond();
149 }
150 mr.setMetric(getName() + "_map_size", this.counts.size());
151 mr.setMetric(getName() + "_total_count", sum);
152 }
153
154 }