|
|
|
@ -23,10 +23,11 @@ import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
import java.util.function.BiFunction;
|
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @author Nikita Koksharov
|
|
|
|
|
*
|
|
|
|
|
* @param <K> key
|
|
|
|
@ -38,6 +39,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
final ConcurrentMap<K, CachedValue<K, V>> map = new ConcurrentHashMap<>();
|
|
|
|
|
private final long timeToLiveInMillis;
|
|
|
|
|
private final long maxIdleInMillis;
|
|
|
|
|
private Consumer<CachedValue<K, V>> removalListener;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public AbstractCacheMap(int size, long timeToLiveInMillis, long maxIdleInMillis) {
|
|
|
|
@ -50,14 +52,19 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void onValueRead(CachedValue<K, V> value) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void onValueRemove(CachedValue<K, V> value) {
|
|
|
|
|
|
|
|
|
|
if (removalListener != null) {
|
|
|
|
|
removalListener.accept(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public final void removalListener(Consumer<CachedValue<K, V>> removalListener) {
|
|
|
|
|
this.removalListener = removalListener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (non-Javadoc)
|
|
|
|
|
* @see java.util.Map#size()
|
|
|
|
@ -85,7 +92,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
if (key == null) {
|
|
|
|
|
throw new NullPointerException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CachedValue<K, V> entry = map.get(key);
|
|
|
|
|
if (entry == null) {
|
|
|
|
|
return false;
|
|
|
|
@ -147,7 +154,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
if (key == null) {
|
|
|
|
|
throw new NullPointerException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CachedValue<K, V> entry = map.get(key);
|
|
|
|
|
if (entry == null) {
|
|
|
|
|
return null;
|
|
|
|
@ -166,7 +173,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
onValueRead(entry);
|
|
|
|
|
return (V) entry.getValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (non-Javadoc)
|
|
|
|
|
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
|
|
|
|
@ -175,7 +182,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
public V put(K key, V value) {
|
|
|
|
|
return put(key, value, timeToLiveInMillis, TimeUnit.MILLISECONDS, maxIdleInMillis, TimeUnit.MILLISECONDS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private V put(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
|
|
|
|
|
CachedValue<K, V> entry = create(key, value, ttlUnit.toMillis(ttl), maxIdleUnit.toMillis(maxIdleTime));
|
|
|
|
|
if (isFull(key)) {
|
|
|
|
@ -197,7 +204,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
protected CachedValue<K, V> create(K key, V value, long ttl, long maxIdleTime) {
|
|
|
|
|
return new StdCachedValue<K, V>(key, value, ttl, maxIdleTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void onValueCreate(CachedValue<K, V> entry) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -211,7 +218,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
for (CachedValue<K, V> value : map.values()) {
|
|
|
|
|
if (isValueExpired(value)) {
|
|
|
|
|
if (map.remove(value.getKey(), value)) {
|
|
|
|
|
onValueRemove(value);
|
|
|
|
|
onValueRemove(value);
|
|
|
|
|
removed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -230,7 +237,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (non-Javadoc)
|
|
|
|
|
* @see java.util.Map#remove(java.lang.Object)
|
|
|
|
@ -246,7 +253,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (non-Javadoc)
|
|
|
|
|
* @see java.util.Map#putAll(java.util.Map)
|
|
|
|
@ -297,13 +304,13 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
removeExpiredEntries();
|
|
|
|
|
return new EntrySet();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
abstract class MapIterator<M> implements Iterator<M> {
|
|
|
|
|
|
|
|
|
|
private final Iterator<Map.Entry<K, CachedValue<K, V>>> keyIterator = map.entrySet().iterator();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map.Entry<K, CachedValue<K, V>> mapEntry;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean hasNext() {
|
|
|
|
|
if (mapEntry != null) {
|
|
|
|
@ -313,7 +320,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
while (keyIterator.hasNext()) {
|
|
|
|
|
Map.Entry<K, CachedValue<K, V>> entry = keyIterator.next();
|
|
|
|
|
if (isValueExpired(entry.getValue())) {
|
|
|
|
|
continue;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
mapEntry = entry;
|
|
|
|
|
break;
|
|
|
|
@ -339,7 +346,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
if (mapEntry == null) {
|
|
|
|
|
throw new NoSuchElementException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
K key = mapEntry.getKey();
|
|
|
|
|
mapEntry = null;
|
|
|
|
|
return key;
|
|
|
|
@ -388,7 +395,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
if (mapEntry == null) {
|
|
|
|
|
throw new NoSuchElementException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V value = readValue(mapEntry.getValue());
|
|
|
|
|
mapEntry = null;
|
|
|
|
|
return value;
|
|
|
|
@ -431,7 +438,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
if (mapEntry == null) {
|
|
|
|
|
throw new NoSuchElementException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SimpleEntry<K, V> result = new SimpleEntry<K, V>(mapEntry.getKey(), readValue(mapEntry.getValue()));
|
|
|
|
|
mapEntry = null;
|
|
|
|
|
return result;
|
|
|
|
@ -572,4 +579,4 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|