perf[LazyCache]: remove cache reason

This commit is contained in:
godotg
2024-03-25 19:38:16 +08:00
parent 66d5735bff
commit 5ca773121b
2 changed files with 71 additions and 25 deletions
@@ -1,5 +1,6 @@
package com.zfoo.orm.util;
import com.zfoo.protocol.model.Pair;
import com.zfoo.scheduler.util.TimeUtils;
import java.util.concurrent.ConcurrentHashMap;
@@ -14,22 +15,49 @@ import java.util.function.BiConsumer;
*/
public class LazyCache<K, V> {
private static class ValueCache<V> {
private static class CacheValue<V> {
public volatile V value;
public volatile long expireTime;
}
public static enum RemovalCause {
/**
* The entry was manually removed by the user. This can result from the user invoking any of the
* following methods on the cache or map view.
* remove()
*/
EXPLICIT,
private AtomicLong expireCheckTimeAtomic;
private volatile long minExpireTime;
/**
* The entry itself was not actually removed, but its value was replaced by the user. This can
* result from the user invoking any of the following methods on the cache or map view.
* put()
*/
REPLACED,
/**
* The entry's expiration timestamp has passed.
*/
EXPIRED,
/**
* The entry was evicted due to size constraints.
*/
SIZE;
}
private int maximumSize;
private long expireAfterAccessMillis;
private long expireCheckInterval;
private int maximumSize;
private ConcurrentMap<K, ValueCache<V>> cacheMap;
private BiConsumer<K, V> removeCallback = (k, v) -> {
private AtomicLong expireCheckTimeAtomic;
private volatile long minExpireTime;
private ConcurrentMap<K, CacheValue<V>> cacheMap;
private BiConsumer<Pair<K, V>, RemovalCause> removeCallback = (pair, removalCause) -> {
};
public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<K, V> removeCallback) {
public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<Pair<K, V>, RemovalCause> removeCallback) {
this.maximumSize = maximumSize;
this.expireAfterAccessMillis = expireAfterAccessMillis;
this.expireCheckInterval = expireCheckIntervalMillis;
@@ -44,10 +72,13 @@ public class LazyCache<K, V> {
* If the cache previously contained a value associated with the key, the old value is replaced by the new value.
*/
public void put(K key, V value) {
var valueCache = new ValueCache<V>();
valueCache.value = value;
valueCache.expireTime = TimeUtils.now();
cacheMap.put(key, valueCache);
var cacheValue = new CacheValue<V>();
cacheValue.value = value;
cacheValue.expireTime = TimeUtils.now();
var oldCacheValue = cacheMap.put(key, cacheValue);
if (oldCacheValue != null) {
removeCallback.accept(new Pair<>(key, oldCacheValue.value), RemovalCause.REPLACED);
}
checkMaximumSize();
checkExpire();
}
@@ -55,29 +86,43 @@ public class LazyCache<K, V> {
public V get(K key) {
checkExpire();
var valueCache = cacheMap.get(key);
if (valueCache == null) {
var cacheValue = cacheMap.get(key);
if (cacheValue == null) {
return null;
}
if (valueCache.expireTime < TimeUtils.now()) {
remove(key);
if (cacheValue.expireTime < TimeUtils.now()) {
remove(key, RemovalCause.EXPIRED);
return null;
}
valueCache.expireTime = TimeUtils.now() + expireAfterAccessMillis;
return valueCache.value;
cacheValue.expireTime = TimeUtils.now() + expireAfterAccessMillis;
return cacheValue.value;
}
public void remove(K key) {
remove(key, RemovalCause.EXPLICIT);
}
public void remove(K key, RemovalCause removalCause) {
if (key == null) {
return;
}
var valueCache = cacheMap.remove(key);
if (valueCache != null) {
removeCallback.accept(key, valueCache.value);
var cacheValue = cacheMap.remove(key);
if (cacheValue != null) {
removeCallback.accept(new Pair<>(key, cacheValue.value), removalCause);
}
}
public void forEach(BiConsumer<K, V> biConsumer) {
for (var entry : cacheMap.entrySet()) {
biConsumer.accept(entry.getKey(), entry.getValue().value);
}
}
public int size() {
return cacheMap.size();
}
// -----------------------------------------------------------------------------------------------------------------
private void checkMaximumSize() {
@@ -93,7 +138,7 @@ public class LazyCache<K, V> {
}
}
this.minExpireTime = minTimestamp;
remove(minKey);
remove(minKey, RemovalCause.SIZE);
checkMaximumSize();
}
@@ -107,7 +152,7 @@ public class LazyCache<K, V> {
for (var entry : cacheMap.entrySet()) {
var expireTime = entry.getValue().expireTime;
if (expireTime < now) {
remove(entry.getKey());
remove(entry.getKey(), RemovalCause.EXPIRED);
}
if (expireTime < minTimestamp) {
minTimestamp = expireTime;
+4 -3
View File
@@ -1,6 +1,7 @@
package com.zfoo.orm.cache;
import com.zfoo.orm.util.LazyCache;
import com.zfoo.protocol.model.Pair;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.protocol.util.ThreadUtils;
import com.zfoo.scheduler.util.TimeUtils;
@@ -15,10 +16,10 @@ import java.util.function.BiConsumer;
@Ignore
public class LazyCacheTest {
private static final BiConsumer<Integer, String> myRemoveCallback = new BiConsumer<Integer, String>() {
private static final BiConsumer<Pair<Integer, String>, LazyCache.RemovalCause> myRemoveCallback = new BiConsumer<Pair<Integer, String>, LazyCache.RemovalCause>() {
@Override
public void accept(Integer key, String value) {
System.out.println(StringUtils.format("remove key:[{}] value:[{}]", key, value));
public void accept(Pair<Integer, String> pair, LazyCache.RemovalCause removalCause) {
System.out.println(StringUtils.format("remove key:[{}] value:[{}] removalCause:[{}]", pair.getKey(), pair.getValue(), removalCause));
}
};