/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.aliyun.odps.counter;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import com.aliyun.odps.io.Text;
import com.aliyun.odps.io.Writable;
/**
* Counters 由多个 {@link CounterGroup} 组成,保存了所有的 Counter 的信息.
*
* @see Counter
* @see CounterGroup
* @see TaskAttemptContext#getCounter(String, String)
* @see RunningJob#getCounters()
*/
public class Counters implements Iterable<CounterGroup>, Writable {
/**
* A cache from enum values to the associated counter. Dramatically speeds up
* typical usage.
*/
private Map<Enum<?>, Counter> cache = new IdentityHashMap<Enum<?>, Counter>();
private TreeMap<String, CounterGroup> groups = new TreeMap<String, CounterGroup>();
public Counters() {
}
public Counters(Counters counters) {
}
/**
* 查找 Counter,给定 Counter 组名和 Counter 名
*
* @param groupName
* Counter 组名
* @param counterName
* Counter 名称
* @return 查找到的 {@link Counter} 对象
*/
public Counter findCounter(String groupName, String counterName) {
CounterGroup grp = getGroup(groupName);
return grp.findCounter(counterName);
}
/**
* 查找 Counter,给定 enum 对象.
*
* @param key
* enum 对象
* @return 查找到的 {@link Counter} 对象
*/
public synchronized Counter findCounter(Enum<?> key) {
Counter counter = cache.get(key);
if (counter == null) {
counter = findCounter(key.getDeclaringClass().getName(), key.toString());
cache.put(key, counter);
}
return counter;
}
/**
* 返回 Counter 组名的集合
*
* @return Counter 组名的集合
*/
public synchronized Collection<String> getGroupNames() {
return groups.keySet();
}
@Override
public Iterator<CounterGroup> iterator() {
return groups.values().iterator();
}
/**
* 获取给定名字的 Counter 组,若不存在此 Counter 组,则新建一个.
*
* @param groupName
* Counter 组名
* @return Counter 组
*/
public synchronized CounterGroup getGroup(String groupName) {
CounterGroup grp = groups.get(groupName);
if (grp == null) {
grp = new CounterGroup(groupName);
groups.put(groupName, grp);
}
return grp;
}
/**
* 返回Counter的个数
*
* @return Counter的个数
*/
public synchronized int countCounters() {
int result = 0;
for (CounterGroup group : this) {
result += group.size();
}
return result;
}
/**
* 返回Counters的字符串形式.
*
* @return Counters的字符串形式
*/
public synchronized String toString() {
StringBuilder sb = new StringBuilder("User defined counters: "
+ countCounters());
for (CounterGroup group : this) {
sb.append("\n\t" + group.getDisplayName());
for (Counter counter : group) {
sb.append("\n\t\t" + counter.getDisplayName() + "="
+ counter.getValue());
}
}
return sb.toString();
}
/**
* 将传入的 Counters 里的 Counter 值与本 Counters 的Counter值相加
*
* @param other
* 待加的Counters
*/
public synchronized void incrAllCounters(Counters other) {
for (Map.Entry<String, CounterGroup> rightEntry : other.groups.entrySet()) {
CounterGroup left = groups.get(rightEntry.getKey());
CounterGroup right = rightEntry.getValue();
if (left == null) {
left = new CounterGroup(right.getName(), right.getDisplayName());
groups.put(rightEntry.getKey(), left);
}
left.incrAllCounters(right);
}
}
public boolean equals(Object genericRight) {
if (genericRight instanceof Counters) {
Iterator<CounterGroup> right = ((Counters) genericRight).groups.values()
.iterator();
Iterator<CounterGroup> left = groups.values().iterator();
while (left.hasNext()) {
if (!right.hasNext() || !left.next().equals(right.next())) {
return false;
}
}
return !right.hasNext();
}
return false;
}
public int hashCode() {
return groups.hashCode();
}
/**
* 输出到 {@link DataOutput}
*/
@Override
public synchronized void write(DataOutput out) throws IOException {
out.writeInt(groups.size());
for (CounterGroup group : groups.values()) {
Text.writeString(out, group.getName());
group.write(out);
}
}
/**
* 从 {@link DataInput} 读取
*/
@Override
public synchronized void readFields(DataInput in) throws IOException {
cache.clear();
int numClasses = in.readInt();
groups.clear();
while (numClasses-- > 0) {
String groupName = Text.readString(in);
CounterGroup group = new CounterGroup(groupName);
group.readFields(in);
groups.put(groupName, group);
}
}
}