perf[cache]: expire check

This commit is contained in:
godotg
2024-03-25 23:12:01 +08:00
parent c701dd8e6e
commit 6b62bda613
@@ -51,21 +51,22 @@ public class LazyCache<K, V> {
private int maximumSize;
private long expireAfterAccessMillis;
private long expireCheckInterval;
private AtomicLong expireCheckTimeAtomic;
private long expireCheckIntervalMillis;
private volatile long minExpireTime;
private AtomicLong expireCheckTimeAtomic;
private ConcurrentMap<K, CacheValue<V>> cacheMap;
private BiConsumer<Pair<K, V>, RemovalCause> removeCallback = (pair, removalCause) -> {
private BiConsumer<Pair<K, V>, RemovalCause> removeListener = (pair, removalCause) -> {
};
public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<Pair<K, V>, RemovalCause> removeCallback) {
public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<Pair<K, V>, RemovalCause> removeListener) {
this.maximumSize = maximumSize;
this.expireAfterAccessMillis = expireAfterAccessMillis;
this.expireCheckInterval = expireCheckIntervalMillis;
this.expireCheckTimeAtomic = new AtomicLong(TimeUtils.now() + expireCheckInterval);
this.expireCheckIntervalMillis = expireCheckIntervalMillis;
this.minExpireTime = TimeUtils.now();
this.expireCheckTimeAtomic = new AtomicLong(TimeUtils.now() + expireCheckIntervalMillis);
this.cacheMap = new ConcurrentHashMap<>(Math.max(maximumSize / 16, 512));
if (removeCallback != null) {
this.removeCallback = removeCallback;
if (removeListener != null) {
this.removeListener = removeListener;
}
}
@@ -78,10 +79,9 @@ public class LazyCache<K, V> {
cacheValue.expireTime = TimeUtils.now();
var oldCacheValue = cacheMap.put(key, cacheValue);
if (oldCacheValue != null) {
removeCallback.accept(new Pair<>(key, oldCacheValue.value), RemovalCause.REPLACED);
removeListener.accept(new Pair<>(key, oldCacheValue.value), RemovalCause.REPLACED);
}
checkMaximumSize();
checkExpire();
}
public V get(K key) {
@@ -92,7 +92,7 @@ public class LazyCache<K, V> {
return null;
}
if (cacheValue.expireTime < TimeUtils.now()) {
remove(key, RemovalCause.EXPIRED);
removeForCause(key, RemovalCause.EXPIRED);
return null;
}
cacheValue.expireTime = TimeUtils.now() + expireAfterAccessMillis;
@@ -101,16 +101,16 @@ public class LazyCache<K, V> {
public void remove(K key) {
remove(key, RemovalCause.EXPLICIT);
removeForCause(key, RemovalCause.EXPLICIT);
}
public void remove(K key, RemovalCause removalCause) {
private void removeForCause(K key, RemovalCause removalCause) {
if (key == null) {
return;
}
var cacheValue = cacheMap.remove(key);
if (cacheValue != null) {
removeCallback.accept(new Pair<>(key, cacheValue.value), removalCause);
removeListener.accept(new Pair<>(key, cacheValue.value), removalCause);
}
}
@@ -138,16 +138,14 @@ public class LazyCache<K, V> {
minTimestamp = entry.getValue().expireTime;
}
}
this.minExpireTime = minTimestamp;
remove(minKey, RemovalCause.SIZE);
checkMaximumSize();
removeForCause(minKey, RemovalCause.SIZE);
}
private void checkExpire() {
var now = TimeUtils.now();
var expireCheckTime = expireCheckTimeAtomic.get();
if (now > expireCheckTime) {
if (expireCheckTimeAtomic.compareAndSet(expireCheckTime, now + expireCheckInterval)) {
if (expireCheckTimeAtomic.compareAndSet(expireCheckTime, now + expireCheckIntervalMillis)) {
if (now > this.minExpireTime) {
var minTimestamp = Long.MAX_VALUE;
var removeList = new ArrayList<K>();
@@ -155,13 +153,16 @@ public class LazyCache<K, V> {
var expireTime = entry.getValue().expireTime;
if (expireTime < now) {
removeList.add(entry.getKey());
continue;
}
if (expireTime < minTimestamp) {
minTimestamp = expireTime;
}
}
removeList.forEach(it -> remove(it, RemovalCause.EXPIRED));
this.minExpireTime = minTimestamp;
removeList.forEach(it -> removeForCause(it, RemovalCause.EXPIRED));
if (this.minExpireTime < Long.MAX_VALUE) {
this.minExpireTime = minTimestamp;
}
}
}
}