// Path: common/src/main/java/com/xqbase/metric/common/Metric.java
// public class Metric {
// 	private static ConcurrentMap<MetricKey, MetricValue>
// 			map = new ConcurrentHashMap<>();
// 
// 	private static void put(MetricKey key, double value) {
// 		MetricValue current;
// 		do {
// 			current = map.get(key);
// 		} while (current == null ? map.putIfAbsent(key, new MetricValue(value)) != null :
// 				!map.replace(key, current, new MetricValue(current, value)));
// 	}
// 
// 	public static void put(String name, double value, Map<String, String> tagMap) {
// 		put(new MetricKey(name, tagMap), value);
// 	}
// 
// 	public static void put(String name, double value, String... tagPairs) {
// 		put(new MetricKey(name, tagPairs), value);
// 	}
// 
// 	public static List<MetricEntry> removeAll() {
// 		List<MetricEntry> metrics = new ArrayList<>();
// 		List<MetricKey> keys = new ArrayList<>(map.keySet());
// 		for (MetricKey key : keys) {
// 			MetricValue value = map.remove(key);
// 			if (value != null) {
// 				metrics.add(new MetricEntry(key, value));
// 			}
// 		}
// 		return metrics;
// 	}
// }
// 
// Path: common/src/main/java/com/xqbase/metric/common/MetricEntry.java
// public class MetricEntry {
// 	private MetricKey key;
// 	private MetricValue value;
// 
// 	public MetricEntry(MetricKey key, MetricValue value) {
// 		this.key = key;
// 		this.value = value;
// 	}
// 
// 	public String getName() {
// 		return key.getName();
// 	}
// 
// 	public Map<String, String> getTagMap() {
// 		return key.getTagMap();
// 	}
// 
// 	public long getCount() {
// 		return value.getCount();
// 	}
// 
// 	public double getSum() {
// 		return value.getSum();
// 	}
// 
// 	public double getMax() {
// 		return value.getMax();
// 	}
// 
// 	public double getMin() {
// 		return value.getMin();
// 	}
// 
// 	public double getSqr() {
// 		return value.getSqr();
// 	}
// }


import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.xqbase.metric.common.Metric;
import com.xqbase.metric.common.MetricEntry;

package com.xqbase.metric.common;



public class TestAggregate {
	private static final int THREADS = 16;

	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		long t = System.currentTimeMillis();
		AtomicInteger latch = new AtomicInteger(THREADS);
		Random random = new Random();
		for (int i = 0; i < THREADS; i ++) {
			executor.execute(() -> {
				for (int j = 0; j < 1048576; j ++) {
					Metric.put("" + random.nextInt(1024), 1);
				}
				latch.decrementAndGet();
			});
		}
		int count = 0;
		while (latch.get() > 0) {
			for (MetricEntry entry : Metric.removeAll()) {
				count += entry.getCount();
			}
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {/**/}
		}

// Path: common/src/main/java/com/xqbase/metric/common/Metric.java
// public class Metric {
// 	private static ConcurrentMap<MetricKey, MetricValue>
// 			map = new ConcurrentHashMap<>();
// 
// 	private static void put(MetricKey key, double value) {
// 		MetricValue current;
// 		do {
// 			current = map.get(key);
// 		} while (current == null ? map.putIfAbsent(key, new MetricValue(value)) != null :
// 				!map.replace(key, current, new MetricValue(current, value)));
// 	}
// 
// 	public static void put(String name, double value, Map<String, String> tagMap) {
// 		put(new MetricKey(name, tagMap), value);
// 	}
// 
// 	public static void put(String name, double value, String... tagPairs) {
// 		put(new MetricKey(name, tagPairs), value);
// 	}
// 
// 	public static List<MetricEntry> removeAll() {
// 		List<MetricEntry> metrics = new ArrayList<>();
// 		List<MetricKey> keys = new ArrayList<>(map.keySet());
// 		for (MetricKey key : keys) {
// 			MetricValue value = map.remove(key);
// 			if (value != null) {
// 				metrics.add(new MetricEntry(key, value));
// 			}
// 		}
// 		return metrics;
// 	}
// }
// 
// Path: common/src/main/java/com/xqbase/metric/common/MetricEntry.java
// public class MetricEntry {
// 	private MetricKey key;
// 	private MetricValue value;
// 
// 	public MetricEntry(MetricKey key, MetricValue value) {
// 		this.key = key;
// 		this.value = value;
// 	}
// 
// 	public String getName() {
// 		return key.getName();
// 	}
// 
// 	public Map<String, String> getTagMap() {
// 		return key.getTagMap();
// 	}
// 
// 	public long getCount() {
// 		return value.getCount();
// 	}
// 
// 	public double getSum() {
// 		return value.getSum();
// 	}
// 
// 	public double getMax() {
// 		return value.getMax();
// 	}
// 
// 	public double getMin() {
// 		return value.getMin();
// 	}
// 
// 	public double getSqr() {
// 		return value.getSqr();
// 	}
// }


// Path: common/src/test/java/com/xqbase/metric/common/TestAggregate.java
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.xqbase.metric.common.Metric;
import com.xqbase.metric.common.MetricEntry;

package com.xqbase.metric.common;



public class TestAggregate {
	private static final int THREADS = 16;

	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		long t = System.currentTimeMillis();
		AtomicInteger latch = new AtomicInteger(THREADS);
		Random random = new Random();
		for (int i = 0; i < THREADS; i ++) {
			executor.execute(() -> {
				for (int j = 0; j < 1048576; j ++) {
					Metric.put("" + random.nextInt(1024), 1);
				}
				latch.decrementAndGet();
			});
		}
		int count = 0;
		while (latch.get() > 0) {
			for (MetricEntry entry : Metric.removeAll()) {
				count += entry.getCount();
			}
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {/**/}
		}

		for (MetricEntry entry : Metric.removeAll()) {
