View Javadoc

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  
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  @Deprecated
41  public class ExactCounterMetric extends MetricsBase {
42  
43    private static final int DEFAULT_TOP_N = 5;
44  
45    // only publish stats on the topN items (default to DEFAULT_TOP_N)
46    private final int topN;
47    private final Map<String, Counter> counts;
48  
49    // all access to the 'counts' map should use this lock.
50    // take a write lock iff you want to guarantee exclusive access
51    // (the map stripes locks internally, so it's already thread safe -
52    // this lock is just so you can take a consistent snapshot of data)
53    private final ReadWriteLock lock;
54    
55    
56    /**
57     * Constructor to create a new counter metric
58     * @param nam         the name to publish this metric under
59     * @param registry    where the metrics object will be registered
60     * @param description metrics description
61     * @param topN        how many 'keys' to publish metrics on 
62     */
63    public ExactCounterMetric(final String nam, final MetricsRegistry registry, 
64        final String description, int topN) {
65      super(nam, description);
66  
67      this.counts = new MapMaker().makeComputingMap(
68          new Function<String, Counter>() {
69            @Override
70            public Counter apply(String input) {
71              return new Counter();
72            }    
73          });
74  
75      this.lock = new ReentrantReadWriteLock();
76      this.topN = topN;
77  
78      if (registry != null) {
79        registry.add(nam, this);      
80      }
81    }
82  
83    /**
84     * Constructor creates a new ExactCounterMetric
85     * @param nam       the name of the metrics to be used to publish the metric
86     * @param registry  where the metrics object will be registered
87     */
88    public ExactCounterMetric(final String nam, MetricsRegistry registry) {
89      this(nam, registry, NO_DESCRIPTION, DEFAULT_TOP_N);
90    }
91  
92    
93    public void update(String type) {
94      this.lock.readLock().lock();
95      try {
96        this.counts.get(type).increment();
97      } finally {
98        this.lock.readLock().unlock();
99      }
100   }
101   
102   public void update(String type, long count) {
103     this.lock.readLock().lock();
104     try {
105       this.counts.get(type).add(count);
106     } finally {
107       this.lock.readLock().unlock();
108     }
109   }
110   
111   public List<Pair<String, Long>> getTop(int n) {
112     final List<Pair<String, Long>> countsSnapshot = 
113         Lists.newArrayListWithCapacity(this.counts.size());
114     
115     // no updates are allowed while I'm holding this lock, so move fast
116     this.lock.writeLock().lock();
117     try {
118       for(Entry<String, Counter> entry : this.counts.entrySet()) {
119         countsSnapshot.add(Pair.newPair(entry.getKey(), 
120             entry.getValue().get()));
121       }
122     } finally {
123       this.lock.writeLock().unlock();
124     }
125     
126     Collections.sort(countsSnapshot, new Comparator<Pair<String, Long>>() {
127       @Override
128       public int compare(Pair<String, Long> a, Pair<String, Long> b) {
129         return b.getSecond().compareTo(a.getSecond());
130       }      
131     });
132     
133     return countsSnapshot.subList(0, Math.min(n, countsSnapshot.size()));
134   }
135   
136   @Override
137   public void pushMetric(MetricsRecord mr) {
138     final List<Pair<String, Long>> topKeys = getTop(Integer.MAX_VALUE);
139     int sum = 0;
140     
141     int counter = 0;
142     for (Pair<String, Long> keyCount : topKeys) {
143       counter++;
144       // only push stats on the topN keys
145       if (counter <= this.topN) {
146         mr.setMetric(getName() + "_" + keyCount.getFirst(), 
147             keyCount.getSecond());        
148       }
149       sum += keyCount.getSecond();
150     }
151     mr.setMetric(getName() + "_map_size", this.counts.size());
152     mr.setMetric(getName() + "_total_count", sum);
153   }
154   
155 }