From 736338d48fe26daa4ce43a436fc108165490d59e Mon Sep 17 00:00:00 2001 From: lyrric Date: Wed, 18 Sep 2024 13:37:11 +0800 Subject: [PATCH] Feature - add computeIfAbsent with TTL method to RMapCache #6136 Signed-off-by: lyrric --- .../java/org/redisson/RedissonMapCache.java | 29 +++++++++++++++++++ .../main/java/org/redisson/api/RMapCache.java | 16 +++++++++- .../org/redisson/api/RMapCacheReactive.java | 16 +++++++++- .../java/org/redisson/api/RMapCacheRx.java | 16 +++++++++- .../org/redisson/RedissonMapCacheTest.java | 16 ++++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonMapCache.java b/redisson/src/main/java/org/redisson/RedissonMapCache.java index 30c294197..4b7b62128 100644 --- a/redisson/src/main/java/org/redisson/RedissonMapCache.java +++ b/redisson/src/main/java/org/redisson/RedissonMapCache.java @@ -128,6 +128,35 @@ public class RedissonMapCache extends RedissonMap implements RMapCac Collections.singletonList(optionsName), maxSize, mode); } + @Override + public V computeIfAbsent(K key, Duration ttl, Function mappingFunction) { + checkNotBatch(); + + checkKey(key); + Objects.requireNonNull(mappingFunction); + + V value = get(key); + if (value != null) { + return value; + } + RLock lock = getLock(key); + lock.lock(); + try { + value = get(key); + if (value == null) { + V newValue = mappingFunction.apply(key); + if (newValue != null) { + fastPut(key, newValue, ttl.toMillis(), TimeUnit.MILLISECONDS); + return newValue; + } + return null; + } + return value; + } finally { + lock.unlock(); + } + } + @Override public void setMaxSize(int maxSize) { get(setMaxSizeAsync(maxSize)); diff --git a/redisson/src/main/java/org/redisson/api/RMapCache.java b/redisson/src/main/java/org/redisson/api/RMapCache.java index 559980090..f3c31d0bc 100644 --- a/redisson/src/main/java/org/redisson/api/RMapCache.java +++ b/redisson/src/main/java/org/redisson/api/RMapCache.java @@ -23,6 +23,7 @@ import java.time.Duration; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** *

Map-based cache with ability to set TTL for each entry via @@ -81,7 +82,20 @@ public interface RMapCache extends RMap, RMapCacheAsync { * @return true if max size has been successfully set, otherwise false. */ boolean trySetMaxSize(int maxSize, EvictionMode mode); - + /** + * If the specified key is not already associated + * with a value, attempts to compute its value using the given mapping function and enters it into this map . + *

+ * Stores value mapped by key with specified time to live. + * Entry expires after specified time to live. + * + * @param key - map key + * @param ttl - time to live for key\value entry. + * If 0 then stores infinitely. + * @param mappingFunction the mapping function to compute a value + * @return current associated value + */ + V computeIfAbsent(K key, Duration ttl, Function mappingFunction); /** * If the specified key is not already associated * with a value, associate it with the given value. diff --git a/redisson/src/main/java/org/redisson/api/RMapCacheReactive.java b/redisson/src/main/java/org/redisson/api/RMapCacheReactive.java index 3ffafdd0f..937637b16 100644 --- a/redisson/src/main/java/org/redisson/api/RMapCacheReactive.java +++ b/redisson/src/main/java/org/redisson/api/RMapCacheReactive.java @@ -24,6 +24,7 @@ import java.time.Duration; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** *

Map-based cache with ability to set TTL for each entry via @@ -126,7 +127,20 @@ public interface RMapCacheReactive extends RMapReactive, RDestroyabl * @return previous associated value */ Mono putIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit); - + /** + * If the specified key is not already associated + * with a value, attempts to compute its value using the given mapping function and enters it into this map . + *

+ * Stores value mapped by key with specified time to live. + * Entry expires after specified time to live. + * + * @param key - map key + * @param ttl - time to live for key\value entry. + * If 0 then stores infinitely. + * @param mappingFunction the mapping function to compute a value + * @return current associated value + */ + Mono computeIfAbsentAsync(K key, Duration ttl, Function mappingFunction); /** * Stores value mapped by key with specified time to live. * Entry expires after specified time to live. diff --git a/redisson/src/main/java/org/redisson/api/RMapCacheRx.java b/redisson/src/main/java/org/redisson/api/RMapCacheRx.java index c65a81716..810391b22 100644 --- a/redisson/src/main/java/org/redisson/api/RMapCacheRx.java +++ b/redisson/src/main/java/org/redisson/api/RMapCacheRx.java @@ -26,6 +26,7 @@ import java.time.Duration; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** *

Map-based cache with ability to set TTL for each entry via @@ -128,7 +129,20 @@ public interface RMapCacheRx extends RMapRx, RDestroyable { * @return previous associated value */ Maybe putIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit); - + /** + * If the specified key is not already associated + * with a value, attempts to compute its value using the given mapping function and enters it into this map . + *

+ * Stores value mapped by key with specified time to live. + * Entry expires after specified time to live. + * + * @param key - map key + * @param ttl - time to live for key\value entry. + * If 0 then stores infinitely. + * @param mappingFunction the mapping function to compute a value + * @return current associated value + */ + Maybe computeIfAbsentAsync(K key, Duration ttl, Function mappingFunction); /** * Stores value mapped by key with specified time to live. * Entry expires after specified time to live. diff --git a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java index 3802e0e42..ab22cca34 100644 --- a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java +++ b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java @@ -1470,5 +1470,21 @@ public class RedissonMapCacheTest extends BaseMapTest { map.destroy(); } + + @Test + public void testComputeIfAbsentWithTTL() throws Exception{ + RMapCache map = redisson.getMapCache("testMap"); + map.delete(); + Duration duration = Duration.ofSeconds(1); + String value = map.computeIfAbsent("key1",duration, (t1) -> "value1"); + assertThat("value1".equals(value)).isTrue(); + value = map.computeIfAbsent("key1", duration, (t1) -> "value2"); + assertThat("value2".equals(value)).isFalse(); + Thread.sleep(1100); + value = map.computeIfAbsent("key1", duration, (t1) -> "value3"); + assertThat("value3".equals(value)).isTrue(); + map.destroy(); + + } }