/*
* Copyright 2014 NAVER Corp.
*
* Licensed 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.navercorp.pinpoint.collector.util;
import com.navercorp.pinpoint.common.util.MathUtils;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @deprecated Since 1.7.0. Use {@link com.google.common.util.concurrent.AtomicLongMap}
* @author emeroad
*/
@Deprecated
public class ConcurrentCounterMap<T> {
private final int concurrencyLevel;
private final AtomicInteger entrySelector;
private final Entry<T>[] entryArray;
public ConcurrentCounterMap() {
this(16);
}
public ConcurrentCounterMap(int concurrencyLevel) {
this(concurrencyLevel, 0);
}
public ConcurrentCounterMap(int concurrencyLevel, int entrySelectorId) {
this.concurrencyLevel = concurrencyLevel;
this.entryArray = createEntry();
this.entrySelector = new AtomicInteger(entrySelectorId);
}
private Entry<T>[] createEntry() {
final int concurrencyLevel = this.concurrencyLevel;
final Entry<T>[] entry = new Entry[concurrencyLevel];
for (int i = 0; i < entry.length; i++) {
entry[i] = new Entry<>();
}
return entry;
}
private Entry<T> getEntry() {
final int selectKey = MathUtils.fastAbs(entrySelector.getAndIncrement());
final int mod = selectKey % concurrencyLevel;
return entryArray[mod];
}
public void increment(T key, Long increment) {
Entry<T> entry = getEntry();
entry.increment(key, increment);
}
public Map<T, LongAdder> remove() {
// make a copy of the current snapshot of the entries for consistency
final List<Map<T, LongAdder>> copy = removeAll();
// merge
final Map<T, LongAdder> mergeMap = new HashMap<>();
for (Map<T, LongAdder> mutableLongMap : copy) {
for (Map.Entry<T, LongAdder> entry : mutableLongMap.entrySet()) {
final T key = entry.getKey();
LongAdder longAdder = mergeMap.get(key);
if (longAdder == null) {
mergeMap.put(key, entry.getValue());
} else {
longAdder.increment(entry.getValue().get());
}
}
}
return mergeMap;
}
private List<Map<T, LongAdder>> removeAll() {
final List<Map<T, LongAdder>> copy = new ArrayList<>(entryArray.length);
final int entryArrayLength = entryArray.length;
for (int i = 0; i < entryArrayLength; i++ ) {
Entry<T> tEntry = entryArray[i];
Map<T, LongAdder> remove = tEntry.remove();
copy.add(remove);
}
return copy;
}
public static class LongAdder {
private long value = 0;
public LongAdder(long increase) {
this.value = increase;
}
public void increment(long increment) {
this.value += increment;
}
public long get() {
return this.value;
}
}
private static class Entry<T> {
private static final Map EMPTY = Collections.emptyMap();
private Map<T, LongAdder> map = new HashMap<>();
public synchronized void increment(T key, Long increment) {
LongAdder longAdder = map.get(key);
if (longAdder == null) {
map.put(key, new LongAdder(increment));
} else {
longAdder.increment(increment);
}
}
public Map<T, LongAdder> remove() {
Map<T, LongAdder> old;
synchronized (this) {
old = this.map;
if (old.isEmpty()) {
return EMPTY;
}
this.map = new HashMap<>();
}
return old;
}
}
}