content: /*
   * 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);
      }
    }
  }
  