From 15dd47ef6396c1e0df826185677aacf54116b751 Mon Sep 17 00:00:00 2001 From: godotg Date: Wed, 27 Mar 2024 14:46:20 +0800 Subject: [PATCH] perf[cache]: use back pressure to remove caches that exceed the maximum size in batches --- .../com/zfoo/scheduler/util/LazyCache.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scheduler/src/main/java/com/zfoo/scheduler/util/LazyCache.java b/scheduler/src/main/java/com/zfoo/scheduler/util/LazyCache.java index 8f673f3c..8ba558cb 100644 --- a/scheduler/src/main/java/com/zfoo/scheduler/util/LazyCache.java +++ b/scheduler/src/main/java/com/zfoo/scheduler/util/LazyCache.java @@ -15,6 +15,8 @@ import java.util.function.BiConsumer; */ public class LazyCache { + private static final float DEFAULT_BACK_PRESSURE_FACTOR = 0.11f; + private static class CacheValue { public volatile V value; public volatile long expireTime; @@ -49,6 +51,7 @@ public class LazyCache { private int maximumSize; + private int backPressureSize; private long expireAfterAccessMillis; private long expireCheckIntervalMillis; private volatile long minExpireTime; @@ -59,6 +62,7 @@ public class LazyCache { public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer, RemovalCause> removeListener) { this.maximumSize = maximumSize; + this.backPressureSize = maximumSize + (int) (maximumSize * DEFAULT_BACK_PRESSURE_FACTOR); this.expireAfterAccessMillis = expireAfterAccessMillis; this.expireCheckIntervalMillis = expireCheckIntervalMillis; this.minExpireTime = TimeUtils.now(); @@ -126,18 +130,15 @@ public class LazyCache { // ----------------------------------------------------------------------------------------------------------------- private void checkMaximumSize() { - if (cacheMap.size() <= maximumSize) { + if (cacheMap.size() <= backPressureSize) { return; } - K minKey = null; - var minTimestamp = Long.MAX_VALUE; - for (var entry : cacheMap.entrySet()) { - if (entry.getValue().expireTime < minTimestamp) { - minKey = entry.getKey(); - minTimestamp = entry.getValue().expireTime; - } - } - removeForCause(minKey, RemovalCause.SIZE); + var exceedList = cacheMap.entrySet() + .stream() + .sorted((a, b) -> Long.compare(a.getValue().expireTime, b.getValue().expireTime)) + .limit(cacheMap.size() - maximumSize) + .toList(); + exceedList.forEach(it -> removeForCause(it.getKey(), RemovalCause.SIZE)); } private void checkExpire() {