From 944a97516d6ebcf3f473700f854ff8f0219385b9 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal002@users.noreply.github.com> Date: Sun, 18 Aug 2024 09:43:50 +0200 Subject: Fix: Time Limited Cache Lock (#2370) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../hannibal2/skyhanni/utils/TimeLimitedCache.kt | 38 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'src/main/java/at/hannibal2') diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt index 018c858fa..4c96c9b3c 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt @@ -1,7 +1,9 @@ package at.hannibal2.skyhanni.utils import com.google.common.cache.CacheBuilder +import java.util.concurrent.ConcurrentMap import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.time.Duration class TimeLimitedCache( @@ -9,9 +11,18 @@ class TimeLimitedCache( private val removalListener: (K?, V?) -> Unit = { _, _ -> }, ) : Iterable> { + private val cacheLock = ReentrantReadWriteLock() + private val cache = CacheBuilder.newBuilder() .expireAfterWrite(expireAfterWrite.inWholeMilliseconds, TimeUnit.MILLISECONDS) - .removalListener { removalListener(it.key, it.value) } + .removalListener { + cacheLock.writeLock().lock() + try { + removalListener(it.key, it.value) + } finally { + cacheLock.writeLock().unlock() + } + } .build() // TODO IntelliJ cant replace this, find another way? @@ -27,11 +38,30 @@ class TimeLimitedCache( fun remove(key: K) = cache.invalidate(key) - fun entries(): Set> = cache.asMap().entries + fun entries(): Set> = getMap().entries + + fun values(): Collection = getMap().values + + fun keys(): Set = getMap().keys - fun values(): Collection = cache.asMap().values + /** + * Modifications to the returned map are not supported and may lead to unexpected behavior. + * This method is intended for read-only operations such as iteration or retrieval of values. + * + * @return A read-only view of the cache's underlying map. + */ + private fun getMap(): ConcurrentMap { + val asMap: ConcurrentMap - fun keys(): Set = cache.asMap().keys + cacheLock.readLock().lock() + try { + asMap = cache.asMap() + } finally { + cacheLock.readLock().unlock() + } + + return asMap + } fun containsKey(key: K): Boolean = cache.getIfPresent(key) != null -- cgit