package com.taobao.tddl.monitor.stat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Timer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* 抽象类 -- 用来在 BufferedLogWriter/SoftRefLogWriter 之间共享一些对象。
*
* @author changyuan.lh
*/
public abstract class AbstractStatLogWriter extends StatLogWriter {
protected static ExecutorService flushExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
// changyuan.lh: 给线程命名,
// 并且设置成后台运行
public Thread newThread(Runnable r) {
Thread thd = new Thread(r,
"BufferedStatLogWriter-Flush-Executor");
thd.setDaemon(true);
return thd;
}
});
protected static Timer flushTimer = new Timer( // NL
"BufferedStatLogWriter-Flush-Timer",
true);
public static final class UniversalComparator implements Comparator<Object> {
public static final UniversalComparator INSTANCE = new UniversalComparator();
@SuppressWarnings({ "unchecked", "rawtypes" })
public int compare(Object o1, Object o2) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
if (o1.getClass() == o2.getClass()) {
if (o1 instanceof Comparable) return ((Comparable) o1).compareTo(o2);
}
return System.identityHashCode(o1) - System.identityHashCode(o2);
}
}
public static final class ArrayComparator implements Comparator<Object[]> {
public static final ArrayComparator INSTANCE = new ArrayComparator();
public int compare(Object[] a1, Object[] a2) {
if (a1 == a2) return 0;
if (a1 == null) return -1;
if (a2 == null) return 1;
Comparator<Object> comparator = UniversalComparator.INSTANCE;
final int min = (a1.length < a2.length) ? a1.length : a2.length;
for (int i = 0; i < min; i++) {
final int cmp = comparator.compare(a1[i], a2[i]);
if (cmp != 0) return cmp;
}
return a1.length - a2.length;
}
}
public static final class LogKey implements Comparable<LogKey> {
private final Object[] keys;
private final int hashCode;
public LogKey(Object[] keys){
this.hashCode = Arrays.hashCode(keys);
this.keys = keys;
}
public Object[] getKeys() {
return keys;
}
public int compareTo(LogKey obj) {
if (this == obj) return 0;
if (obj == null) return 1;
return ArrayComparator.INSTANCE.compare(keys, obj.keys);
}
public int hashCode() {
return hashCode;
}
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
LogKey other = (LogKey) obj;
return Arrays.equals(keys, other.keys);
}
}
public static class LogCounter implements Comparable<LogCounter> {
private final LogKey logKey;
private final Object[] fields;
private final AtomicLong count = new AtomicLong();
private final AtomicLong value = new AtomicLong();
private final AtomicLong min = new AtomicLong(Long.MAX_VALUE); // value最小值
private final AtomicLong max = new AtomicLong(Long.MIN_VALUE); // value最大值
public LogCounter(LogKey logKey, Object[] fields){
this.logKey = logKey;
this.fields = fields;
}
public final LogKey getLogKey() {
return logKey;
}
public final Object[] getFields() {
return this.fields;
}
public int compareTo(LogCounter obj) {
if (this == obj) return 0;
if (obj == null) return 1;
long c1 = count.get();
long c2 = obj.count.get();
return (c1 < c2 ? -1 : (c1 == c2 ? 0 : 1));
}
public void stat(long c, long v) {
this.count.addAndGet(c);
this.value.addAndGet(v);
long vmin = min.get();
while (v < vmin && !min.compareAndSet(vmin, v)) {
vmin = min.get(); // 有可能已经被其他线程设置了一个次小的,所以继续判断
}
long vmax = max.get();
while (v > vmax && max.compareAndSet(vmax, v)) {
vmax = max.get(); // 有可能已经被其他线程设置了一个次大的,所以继续判断
}
}
public void clear() {
this.count.lazySet(0L);
this.value.lazySet(0L);
this.min.lazySet(Long.MAX_VALUE);
this.max.lazySet(Long.MIN_VALUE);
}
public final long getCount() {
return this.count.get();
}
public final long getValue() {
// XXX: 保持兼容, 输出总数而不是平均数
return this.value.get();
}
public final long getMin() {
return this.min.get();
}
public final long getMax() {
return this.max.get();
}
public long[] getValues() {
return new long[] { this.count.get(), this.value.get(), this.min.get(), this.max.get() };
}
}
}