Package com.taobao.tddl.common

Source Code of com.taobao.tddl.common.StatMonitor$Item

/*(C) 2007-2012 Alibaba Group Holding Limited. 
*This program is free software; you can redistribute it and/or modify 
*it under the terms of the GNU General Public License version 2 as 
* published by the Free Software Foundation. 
* Authors: 
*   junyu <junyu@taobao.com> , shenxun <shenxun@taobao.com>, 
*   linxuan <linxuan@taobao.com> ,qihao <qihao@taobao.com>  
*/ 
package com.taobao.tddl.common;

import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.tddl.common.monitor.BufferedStatLogWriter;
import com.taobao.tddl.common.monitor.SnapshotValuesOutputCallBack;
import com.taobao.tddl.common.monitor.SnapshotValuesOutputCallBack.Values;
import com.taobao.tddl.common.util.NagiosUtils;

/*
* @author guangxia
* @since 1.0, 2010-2-8 ����04:18:39
*/
public class StatMonitor implements StatMonitorMBean {
  private static final Log logger = LogFactory.getLog(StatMonitor.class);

  //��λ�Ǻ���
  private volatile long statInterval = 5 * 60 * 1000;
  private Set<String> blackList = new HashSet<String>(0);
  private int limit = 1000;

  private static final StatMonitor instance = new StatMonitor();

  private StatMonitor() {
  }

  public static StatMonitor getInstance() {
    return instance;
  }

  static class Value2 {
    final StatCounter statCounter = new StatCounter();
    final ConcurrentHashMap<String, StatCounter> map2 = new ConcurrentHashMap<String, StatCounter>();

    public String toString() {
      return map2.toString();
    }
  }

  static class Value1 {
    final StatCounter statCounter = new StatCounter();
    final ConcurrentHashMap<String, Value2> map1 = new ConcurrentHashMap<String, Value2>();

    public String toString() {
      return map1.toString();
    }
  }

  static class Value0 {
    final StatCounter statCounter = new StatCounter();
    final ConcurrentHashMap<String, Value1> map0 = new ConcurrentHashMap<String, Value1>();

    public String toString() {
      return map0.toString();
    }
  }

  static class State {
    final Value0 currentStatMap = new Value0();
    final Value0 lastStatMap;
    final AtomicInteger size = new AtomicInteger(0);
    final long lastResetTime = System.currentTimeMillis();

    State() {
      lastStatMap = currentStatMap;
    }

    State(final State lastState) {
      lastStatMap = lastState.currentStatMap;
    }

    public String toString() {
      return lastStatMap.toString();
    }
  }

  private volatile State state = new State();

  public String toString() {
    return state.toString();
  }

  static class StatCounter {
    private final AtomicLong count = new AtomicLong(0L);
    private final AtomicLong value = new AtomicLong(0L);

    public void incrementCount() {
      this.count.incrementAndGet();
    }

    public void addValue(long value) {
      this.value.addAndGet(value);
    }

    public synchronized void reset() {
      this.count.set(0L);
      this.value.set(0L);
    }

    public String toString() {
      return "{StatCounter, " + count.get() + ", " + value.get() + "}";
    }
  }

  private Thread restTask = new Thread() {
    @Override
    public void run() {
      while (!Thread.currentThread().isInterrupted()) {
        try {
          Thread.sleep(statInterval);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
        }

        StatMonitor.State old = resetState();
        writeMonitor(old);
      }
    }
  };

  private void writeMonitor(State old) {
    try {
      for (Map.Entry<String, Value1> e0 : old.lastStatMap.map0.entrySet()) {
        String key1 = e0.getKey();
        for (Map.Entry<String, Value2> e1 : e0.getValue().map1.entrySet()) {
          String key2 = e1.getKey();
          three: for (Map.Entry<String, StatCounter> e2 : e1.getValue().map2.entrySet()) {
            String key3 = e2.getKey();

            StatCounter counter = e2.getValue();
            if (counter == null) {
              continue three;
            }
            long count = counter.count.get();
            long values = counter.value.get();
            String averageValueStr = "invalid";
            if (count != 0) {
              double averageValue = (double) values / count;
              averageValueStr = String.valueOf(averageValue);
            }
            NagiosUtils.addNagiosLog(key1 + "|" + key2 + "|" + key3, averageValueStr);
          }
        }
      }
      writeCallBackLog();
    } catch (Exception e) {
      logger.warn("", e);
    }
  }

  private boolean started = false;

  public synchronized void start() {
    if (started) {
      return;
    }
    restTask.start();
    started = true;
    logger.warn("StatMonitor start...");
  }

  public void stop() {
    restTask.interrupt();
    while (restTask.isAlive()) {
      try {
        restTask.join();
      } catch (InterruptedException e) {

      }
    }
  }

  private synchronized final State resetState() {
    State old = state;
    state = new State(state);
    return old;
  }

  private final String getLastStatResult(String key1, String key2, String key3) {
    State local_state = state;
    Value1 value1 = local_state.lastStatMap.map0.get(key1);
    if (value1 == null) {
      logger.warn("getLastStatResult(" + key1 + ", " + key2 + ", " + key3 + ") Invalid key1: " + key1);
      return null;
    }
    Value2 value2 = value1.map1.get(key2);
    if (value2 == null) {
      logger.warn("getLastStatResult(" + key1 + ", " + key2 + ", " + key3 + ") Invalid key2: " + key2);
      return null;
    }
    StatCounter counter = value2.map2.get(key3);
    if (counter == null) {
      logger.warn("getLastStatResult(" + key1 + ", " + key2 + ", " + key3 + ") Invalid key3: " + key3);
      return null;
    }
    long count = counter.count.get();
    long values = counter.value.get();
    String averageValueStr = "invalid";
    String averageCountStr = "invalid";
    if (count != 0) {
      double averageValue = (double) values / count;
      averageValueStr = String.valueOf(averageValue);
    }
    long duration;
    if (local_state.lastStatMap != local_state.currentStatMap) {
      duration = statInterval;
    } else {
      duration = System.currentTimeMillis() - local_state.lastResetTime;
    }
    if (duration != 0) {
      double averageCount = (double) (count * 1000) / duration;
      averageCountStr = String.valueOf(averageCount);
    }
    return "count: " + count + ", value: " + values + ", average: " + averageValueStr + ", Count/Duration: "
        + averageCountStr;
  }

  static class Item {
    final String key1;
    final String key2;
    final String key3;
    final long count;
    final long value;

    public Item(String key1, String key2, String key3, long count, long value) {
      this.key1 = key1;
      this.key2 = key2;
      this.key3 = key3;
      this.count = count;
      this.value = value;
    }

    public String toString() {
      return "{(" + key1 + ", " + key2 + ", " + key3 + "), count: " + count + ", value: " + value + "}";
    }
  }

  static class CountComparator implements Comparator<Item> {
    public int compare(Item o1, Item o2) {
      int ret = -((Long) o1.count).compareTo(o2.count);
      if (ret != 0) {
        return ret;
      }
      if (o1 == o2) {
        return ret;
      }
      return ((Integer) System.identityHashCode(o1)).compareTo(System.identityHashCode(o2));
    }
  }

  static class ValueComparator implements Comparator<Item> {
    public int compare(Item o1, Item o2) {
      int ret = -((Long) o1.value).compareTo(o2.value);
      if (ret != 0) {
        return ret;
      }
      if (o1 == o2) {
        return ret;
      }
      return ((Integer) System.identityHashCode(o1)).compareTo(System.identityHashCode(o2));
    }
  }

  final CountComparator countComparator = new CountComparator();
  final ValueComparator valueComparator = new ValueComparator();

  public SortedSet<Item> getSortedSetByCount(String key1, String key2, String key3) {
    State local_state = state;
    SortedSet<Item> sortedSet = new TreeSet<Item>(countComparator);
    visitMap0(sortedSet, local_state.lastStatMap.map0, key1, key2, key3);
    return sortedSet;
  }

  public SortedSet<Item> getSortedSetByValue(String key1, String key2, String key3) {
    State local_state = state;
    SortedSet<Item> sortedSet = new TreeSet<Item>(valueComparator);
    visitMap0(sortedSet, local_state.lastStatMap.map0, key1, key2, key3);
    return sortedSet;
  }

  void visitMap0(SortedSet<Item> sortedSet, ConcurrentHashMap<String, Value1> map0, String key1, String key2,
      String key3) {
    if ("*".equals(key1)) {
      for (Map.Entry<String, Value1> entry : map0.entrySet()) {
        visitMap1(sortedSet, entry.getValue().map1, entry.getKey(), key2, key3);
      }
    } else {
      Value1 value1 = map0.get(key1);
      if (value1 != null) {
        visitMap1(sortedSet, value1.map1, key1, key2, key3);
      }
    }
  }

  void visitMap1(SortedSet<Item> sortedSet, ConcurrentHashMap<String, Value2> map1, String key1, String key2,
      String key3) {
    if ("*".equals(key2)) {
      for (Map.Entry<String, Value2> entry : map1.entrySet()) {
        visitMap2(sortedSet, entry.getValue().map2, key1, entry.getKey(), key3);
      }
    } else {
      Value2 value2 = map1.get(key2);
      if (value2 != null) {
        visitMap2(sortedSet, value2.map2, key1, key2, key3);
      }
    }
  }

  void visitMap2(SortedSet<Item> sortedSet, ConcurrentHashMap<String, StatCounter> map2, String key1, String key2,
      String key3) {
    if ("*".equals(key3)) {
      for (Map.Entry<String, StatCounter> entry : map2.entrySet()) {
        sortedSet.add(new Item(key1, key2, entry.getKey(), entry.getValue().count.get(), entry.getValue().value
            .get()));
      }
    } else {
      StatCounter statCounter = map2.get(key3);
      if (statCounter != null) {
        sortedSet.add(new Item(key1, key2, key3, statCounter.count.get(), statCounter.value.get()));
      }
    }
  }

  public long getDuration() {
    State local_state = state;
    return (System.currentTimeMillis() - local_state.lastResetTime) / 1000;
  }

  public final boolean addStat(String keyOne, String keyTwo, String keyThree) {
    return realTimeStat(keyOne, keyTwo, keyThree, 0);
  }

  private final boolean realTimeStat(String key1, String key2, String key3, long value) {
    if (blackList.contains(key1)) {
      return false;
    }
    return processMap2(key1, key2, key3, value);
  }

  private boolean processMap2(String key1, String key2, String key3, long value) {
    State local_state = state;
    Value1 value1 = local_state.currentStatMap.map0.get(key1);
    if (value1 == null) {
      value1 = new Value1();
      Value1 oldValue1 = local_state.currentStatMap.map0.putIfAbsent(key1, value1);
      if (oldValue1 != null) {
        value1 = oldValue1;
      }
    }
    Value2 value2 = value1.map1.get(key2);
    if (value2 == null) {
      value2 = new Value2();
      Value2 oldValue2 = value1.map1.putIfAbsent(key2, value2);
      if (oldValue2 != null) {
        value2 = oldValue2;
      }
    }

    StatCounter statCounter = value2.map2.get(key3);
    if (statCounter == null) {
      if (local_state.size.get() >= limit) {
        return false;
      }
      statCounter = new StatCounter();
      StatCounter oldCounter = value2.map2.putIfAbsent(key3, statCounter);
      if (oldCounter != null) {
        statCounter = oldCounter;
      } else {
        local_state.size.incrementAndGet();
      }
    }
    //��ʱ����value2��value1��statCounter���в���, ��Ϊû���������
    statCounter.incrementCount();
    statCounter.addValue(value);
    return true;
  }

  public final boolean addStat(String keyOne, String keyTwo, String keyThree, long value) {
    return realTimeStat(keyOne, keyTwo, keyThree, value);
  }

  public void setStatInterval(long statInterval) {
    this.statInterval = statInterval;
  }

  public long getStatInterval() {
    return statInterval;
  }

  public long getStatDuration() {
    State local_state = state;
    return local_state.lastResetTime;
  }

  public String getStatResult(String key1, String key2, String key3) {
    return getLastStatResult(key1, key2, key3);
  }

  public void resetStat() {
    resetState();
  }

  public void setLimit(int limit) {
    this.limit = limit;
  }

  public int getLimit() {
    return limit;
  }

  public void setBlackList(Set<String> blackList) {
    if (!(blackList instanceof HashSet)) {
      blackList = new HashSet<String>(blackList);
    }
    this.blackList = blackList;
  }

  public Set<String> getBlackList() {
    return blackList;
  }

  private static List<SnapshotValuesOutputCallBack> snapshotValueCallBack = new LinkedList<SnapshotValuesOutputCallBack>();

  public static synchronized void addSnapshotValuesCallbask(SnapshotValuesOutputCallBack callbackList) {
    if (snapshotValueCallBack.contains(callbackList)) {
      // only one instance is allowed
      return;
    }
    snapshotValueCallBack.add(callbackList);
  }

  public static synchronized void removeSnapshotValuesCallback(SnapshotValuesOutputCallBack callbackList) {
    snapshotValueCallBack.remove(callbackList);
  }

  /**
   * ��ȡ�Զ�����־���ݲ���ӡ(���̣߳�������)
   */
  private static void writeCallBackLog() {
    ConcurrentHashMap<String, Values> tempMap = new ConcurrentHashMap<String, Values>();
    for (SnapshotValuesOutputCallBack callBack : snapshotValueCallBack) {
      ConcurrentHashMap<String, Values> values = callBack.getValues();
      Map<String, Values> copiedMap = new HashMap<String, Values>(values);
      for (Entry<String, Values> entry : copiedMap.entrySet()) {
        Values value = tempMap.get(entry.getKey());
        if (null == value) {
          Values newValues = new Values();
          value = tempMap.putIfAbsent(entry.getKey(), newValues);
          if (value == null) {
            value = newValues;
          }
        }
        value.value1.addAndGet(entry.getValue().value1.get());
        value.value2.addAndGet(entry.getValue().value2.get());
      }
    }

    writeLogMapToFile(tempMap);
  }

  /**
   * ���ڴ������������־��
   */
  @SuppressWarnings("unused")
  private static void writeLogMapToFile_Nagios(ConcurrentHashMap<String, Values> map) {
    for (Entry<String, Values> entry : map.entrySet()) {
      Values values = entry.getValue();
      if (values != null) {
        String key = new StringBuilder(entry.getKey()).append("||").toString();
        String value = new StringBuilder().append(values.value1).append("|").append(values.value2).append("|")
            .append(values.value2).append((double) values.value1.get() / values.value2.get()).toString();
        NagiosUtils.addNagiosLog(key, value);
      }
    }
  }

  /**
   * ���ڴ������������־��
   * SELECT xxx #@#my065037_cm4_feel_25#@#EXECUTE_A_SQL_SUCCESS#@#1#@#1#@#1#@#1#@#10-12-27 13:58:35:224
   * SELECT sss #@#my065026_cm4_feel_03#@#EXECUTE_A_SQL_SUCCESS#@#1#@#1#@#1#@#1#@#10-12-27 13:58:35:224
   */
  private static void writeLogMapToFile(ConcurrentHashMap<String, Values> map) {
    String time = BufferedStatLogWriter.df.format(new Date());
    for (Entry<String, Values> entry : map.entrySet()) {
      Values values = entry.getValue();
      if (values != null) {
        String key = entry.getKey();
        LoggerInit.TDDL_Snapshot_LOG.warn(new StringBuilder().append(values.value1).append(
            BufferedStatLogWriter.logFieldSep).append(values.value2).append(
            BufferedStatLogWriter.logFieldSep).append(key).append(BufferedStatLogWriter.logFieldSep)
            .append(time).append(BufferedStatLogWriter.linesep));
      }
    }
  }
}
TOP

Related Classes of com.taobao.tddl.common.StatMonitor$Item

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.