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