1 /**
2  *  Licensed under the Apache License, Version 2.0 (the "License");
3  *  you may not use this file except in compliance with the License.
4  *  You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  *  Unless required by applicable law or agreed to in writing, software
9  *  distributed under the License is distributed on an "AS IS" BASIS,
10  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  *  See the License for the specific language governing permissions and
12  *  limitations under the License.
13  */
14 
15 
16 package org.apache.hadoop.mapreduce;
17 
18 import java.io.DataInput;
19 import java.io.DataOutput;
20 import java.io.IOException;
21 import java.util.Collection;
22 import java.util.IdentityHashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.TreeMap;
26 
27 import org.apache.hadoop.io.Text;
28 import org.apache.hadoop.io.Writable;
29 
30 public class Counters implements Writable,Iterable<CounterGroup> {
31   /**
32    * A cache from enum values to the associated counter. Dramatically speeds up
33    * typical usage.
34    */
35   private Map<Enum<?>, Counter> cache = new IdentityHashMap<Enum<?>, Counter>();
36 
37   private TreeMap<String, CounterGroup> groups =
38       new TreeMap<String, CounterGroup>();
39 
Counters()40   public Counters() {
41   }
42 
Counters(org.apache.hadoop.mapred.Counters counters)43   public Counters(org.apache.hadoop.mapred.Counters counters) {
44     for(org.apache.hadoop.mapred.Counters.Group group: counters) {
45       String name = group.getName();
46       CounterGroup newGroup = new CounterGroup(name, group.getDisplayName());
47       groups.put(name, newGroup);
48       for(Counter counter: group) {
49         newGroup.addCounter(counter);
50       }
51     }
52   }
53 
findCounter(String groupName, String counterName)54   public Counter findCounter(String groupName, String counterName) {
55     CounterGroup grp = getGroup(groupName);
56     return grp.findCounter(counterName);
57   }
58 
59   /**
60    * Find the counter for the given enum. The same enum will always return the
61    * same counter.
62    * @param key the counter key
63    * @return the matching counter object
64    */
findCounter(Enum<?> key)65   public synchronized Counter findCounter(Enum<?> key) {
66     Counter counter = cache.get(key);
67     if (counter == null) {
68       counter = findCounter(key.getDeclaringClass().getName(), key.toString());
69       cache.put(key, counter);
70     }
71     return counter;
72   }
73 
74   /**
75    * Returns the names of all counter classes.
76    * @return Set of counter names.
77    */
getGroupNames()78   public synchronized Collection<String> getGroupNames() {
79     return groups.keySet();
80   }
81 
82   @Override
iterator()83   public Iterator<CounterGroup> iterator() {
84     return groups.values().iterator();
85   }
86 
87   /**
88    * Returns the named counter group, or an empty group if there is none
89    * with the specified name.
90    */
getGroup(String groupName)91   public synchronized CounterGroup getGroup(String groupName) {
92     CounterGroup grp = groups.get(groupName);
93     if (grp == null) {
94       grp = new CounterGroup(groupName);
95       groups.put(groupName, grp);
96     }
97     return grp;
98   }
99 
100   /**
101    * Returns the total number of counters, by summing the number of counters
102    * in each group.
103    */
countCounters()104   public synchronized  int countCounters() {
105     int result = 0;
106     for (CounterGroup group : this) {
107       result += group.size();
108     }
109     return result;
110   }
111 
112   /**
113    * Write the set of groups.
114    * The external format is:
115    *     #groups (groupName group)*
116    *
117    * i.e. the number of groups followed by 0 or more groups, where each
118    * group is of the form:
119    *
120    *     groupDisplayName #counters (false | true counter)*
121    *
122    * where each counter is of the form:
123    *
124    *     name (false | true displayName) value
125    */
126   @Override
write(DataOutput out)127   public synchronized void write(DataOutput out) throws IOException {
128     out.writeInt(groups.size());
129     for (org.apache.hadoop.mapreduce.CounterGroup group: groups.values()) {
130       Text.writeString(out, group.getName());
131       group.write(out);
132     }
133   }
134 
135   /**
136    * Read a set of groups.
137    */
138   @Override
readFields(DataInput in)139   public synchronized void readFields(DataInput in) throws IOException {
140     int numClasses = in.readInt();
141     groups.clear();
142     while (numClasses-- > 0) {
143       String groupName = Text.readString(in);
144       CounterGroup group = new CounterGroup(groupName);
145       group.readFields(in);
146       groups.put(groupName, group);
147     }
148   }
149 
150   /**
151    * Return textual representation of the counter values.
152    */
toString()153   public synchronized String toString() {
154     StringBuilder sb = new StringBuilder("Counters: " + countCounters());
155     for (CounterGroup group: this) {
156       sb.append("\n\t" + group.getDisplayName());
157       for (Counter counter: group) {
158         sb.append("\n\t\t" + counter.getDisplayName() + "=" +
159                   counter.getValue());
160       }
161     }
162     return sb.toString();
163   }
164 
165   /**
166    * Increments multiple counters by their amounts in another Counters
167    * instance.
168    * @param other the other Counters instance
169    */
incrAllCounters(Counters other)170   public synchronized void incrAllCounters(Counters other) {
171     for(Map.Entry<String, CounterGroup> rightEntry: other.groups.entrySet()) {
172       CounterGroup left = groups.get(rightEntry.getKey());
173       CounterGroup right = rightEntry.getValue();
174       if (left == null) {
175         left = new CounterGroup(right.getName(), right.getDisplayName());
176         groups.put(rightEntry.getKey(), left);
177       }
178       left.incrAllCounters(right);
179     }
180   }
181 
equals(Object genericRight)182   public boolean equals(Object genericRight) {
183     if (genericRight instanceof Counters) {
184       Iterator<CounterGroup> right = ((Counters) genericRight).groups.
185                                        values().iterator();
186       Iterator<CounterGroup> left = groups.values().iterator();
187       while (left.hasNext()) {
188         if (!right.hasNext() || !left.next().equals(right.next())) {
189           return false;
190         }
191       }
192       return !right.hasNext();
193     }
194     return false;
195   }
196 
hashCode()197   public int hashCode() {
198     return groups.hashCode();
199   }
200 }
201