From d1db84c4d8a7571eef14351281983dfbad63a899 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Mon, 24 Feb 2025 09:02:52 +0300 Subject: [PATCH 1/5] Update CHANGELOG.md --- CHANGELOG.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b42e3a23e..281bdea27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,62 @@ Redisson Releases History Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**. +### 21-Feb-2025 + +Feature - added `max-size` setting for Quarkus Cache +Feature - `RedissonSpringCacheV2Manager` and `RedissonSpringLocalCachedCacheV2Manager` support maxSize setting +Feature - `RedissonRegionV2Factory` and `RedissonLocalCachedV2RegionFactory` in Hibernate support eviction.max_entries setting +Feature - `RedissonCacheV2` and `RedissonLocalCachedCacheV2` in MyBatis support `maxSize` settings +Feature - `maxSize` setting support by `redisson.caches-v2.*` and `redisson.local-caches-v2.*` cache configurations in Micronaut +Feature - `RMapCacheV2.setMaxSize()` method added +Feature - `RClusteredLocalCachedMapCacheNative` object added with data partitioning, local cache and native eviction +Feature - `RedissonClusteredSpringLocalCachedCacheNativeManager` object added with data partitioning, local cache and native eviction +Feature - added Micronaut `redisson.clustered-local-caches-native.*` cache with data partitioning, local cache and native eviction +Feature - added Hibernate `RedissonClusteredLocalCachedNativeRegionFactory` cache with data partitioning, local cache and native eviction +Feature - added Quarkus `CLUSTERED_LOCALCACHE_NATIVE` cache with data partitioning, local cache and native eviction +Feature - added MyBatis `RedissonClusteredLocalCachedCacheNative` cache with data partitioning, local cache and native eviction +Feature - added JCache implementation with local cache and advanced eviction +Feature - added JCache implementation with local cache and native eviction +Feature - added JCache implementation with data partitioning, local cache and native eviction +Feature - ability to set eviction mode via Spring `CacheConfig` object (thanks to @JKord) +Feature - RBitSet.get(long...) method added (thanks to @seakider) +Feature - RBlockingQueue.pollLastFromAnyWithName() method added (thanks to @seakider) +Feature - getReferenceCount(), getAccessFrequency(), getInternalEncoding() methods added to RObject interface (thanks to @seakider) +Feature - RExecutorService.deregisterWorkers() method added +Feature - `valuesAsync()` and `entrySetAsync` methods added to `RMap` interface (thanks to @seakider) + +Improvement - validate PARAMS in `RSearch.search()` method (thanks to @seakider) + +Fixed - delete() method doesn't work in non-clustered mode for `RLocalCachedJsonStore`, `RLocalCachedMapCacheV2` objects +Fixed - clustered local cached JCache doesn't use `storeCacheMiss` setting +Fixed - JCache with native and advanced eviction don't work in cluster mode +Fixed - clustered local cached `JCache.put()` method may throw a CROSSLOT error +Fixed - `put()` method of local cached JCache instance may not update local cache +Fixed - `remove()` and `removeAll()` methods of local cached JCache instance don't update the local cache of other instances +Fixed - `putAll()` and `clear()` methods of JCacheV2 may not work +Fixed - `RedissonClusteredSpringCacheNativeManager` properties validation +Fixed - `RedissonSpringLocalCachedCacheV2Manager` properties validation +Fixed - `RedissonSpringLocalCachedCacheNativeManager` can't be created using a yaml configuration file +Fixed - `RedissonSpringLocalCachedCacheNativeManager` throws an `ClassCastException` if cache wasn't defined in the configuration +Fixed - `RLocalCachedMapCache.getAll()` method may return an incorrect result +Fixed - `RLocalCachedMapCacheNative.getAll()` method may return an incorrect result +Fixed - missed implementation of `expireEntriesIfNotSet()`, `expireEntriesIfLess()` and `expireEntriesIfGreater()` methods of RClusteredMapCacheNative +Fixed - missed implementation of `expireEntriesIfLess()` and `expireEntriesIfGreater()` methods of RLocalCachedMapCacheNative +Fixed - `RJsonStore.isExists()` method doesn't work +Fixed - JCacheV2 entry name generation fixed +Fixed - `RMapCacheV2.isExists()` method optimization +Fixed - `RedissonSpringLocalCachedCacheV2Manager` throws an ClassCastException if cache wasn't defined in the configuration +Fixed - `RedissonSpringLocalCachedCacheV2Manager` can't be created using a yaml configuration file +Fixed - `RLocalCachedMapCacheV2`, `RLocalCachedJsonStore`, `RSetV2`, `RSetCacheV2`, `JCacheV2`, `RMapCacheV2` don't work if `useScriptCache = true` +Fixed - LUA error when `RedissonMapCache.putAll(Map)` is invoked with listeners (thanks to @max.huang) +Fixed - `ProtobufCodec` compatibility with the latest protobuf version (thanks to @zzhlhc) +Fixed - `RFairLock` attempt to compare nil with number (thanks to @seakider) +Fixed - incorrect parsing of `PubSubType.UNSUBSCRIBE` command with non-English locale +Fixed - `RRemoteExecutorService` `expiration` sorted set is growing indefinitely (thanks to @seakider) +Fixed - Quarkus shutdown process fails if version 3.18 or higher +Fixed - `notifyUpdate()` and `notifyInvalidate()` methods of `LocalCacheListener` might throw NPE +Fixed - `RBatchRx` may work incorrectly if `useScriptCache = true` + ### 27-Jan-2025 - 3.44.0 released Feature - native eviction implemented for [JCache](https://redisson.org/docs/cache-api-implementations/#local-cache-and-data-partitioning) API From c600011dc96371ba501a5e0a93ca98aebd7d7744 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Mon, 24 Feb 2025 09:03:38 +0300 Subject: [PATCH 2/5] Update CHANGELOG.md --- CHANGELOG.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 281bdea27..0ee332a16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,27 +3,27 @@ Redisson Releases History Upgrade to __[Redisson PRO](https://redisson.pro)__ with **advanced features**. -### 21-Feb-2025 - -Feature - added `max-size` setting for Quarkus Cache -Feature - `RedissonSpringCacheV2Manager` and `RedissonSpringLocalCachedCacheV2Manager` support maxSize setting -Feature - `RedissonRegionV2Factory` and `RedissonLocalCachedV2RegionFactory` in Hibernate support eviction.max_entries setting -Feature - `RedissonCacheV2` and `RedissonLocalCachedCacheV2` in MyBatis support `maxSize` settings -Feature - `maxSize` setting support by `redisson.caches-v2.*` and `redisson.local-caches-v2.*` cache configurations in Micronaut -Feature - `RMapCacheV2.setMaxSize()` method added -Feature - `RClusteredLocalCachedMapCacheNative` object added with data partitioning, local cache and native eviction -Feature - `RedissonClusteredSpringLocalCachedCacheNativeManager` object added with data partitioning, local cache and native eviction -Feature - added Micronaut `redisson.clustered-local-caches-native.*` cache with data partitioning, local cache and native eviction -Feature - added Hibernate `RedissonClusteredLocalCachedNativeRegionFactory` cache with data partitioning, local cache and native eviction -Feature - added Quarkus `CLUSTERED_LOCALCACHE_NATIVE` cache with data partitioning, local cache and native eviction -Feature - added MyBatis `RedissonClusteredLocalCachedCacheNative` cache with data partitioning, local cache and native eviction -Feature - added JCache implementation with local cache and advanced eviction -Feature - added JCache implementation with local cache and native eviction -Feature - added JCache implementation with data partitioning, local cache and native eviction -Feature - ability to set eviction mode via Spring `CacheConfig` object (thanks to @JKord) -Feature - RBitSet.get(long...) method added (thanks to @seakider) -Feature - RBlockingQueue.pollLastFromAnyWithName() method added (thanks to @seakider) -Feature - getReferenceCount(), getAccessFrequency(), getInternalEncoding() methods added to RObject interface (thanks to @seakider) +### 21-Feb-2025 - 3.45.0 released + +Feature - added `max-size` setting for Quarkus Cache +Feature - `RedissonSpringCacheV2Manager` and `RedissonSpringLocalCachedCacheV2Manager` support maxSize setting +Feature - `RedissonRegionV2Factory` and `RedissonLocalCachedV2RegionFactory` in Hibernate support eviction.max_entries setting +Feature - `RedissonCacheV2` and `RedissonLocalCachedCacheV2` in MyBatis support `maxSize` settings +Feature - `maxSize` setting support by `redisson.caches-v2.*` and `redisson.local-caches-v2.*` cache configurations in Micronaut +Feature - `RMapCacheV2.setMaxSize()` method added +Feature - `RClusteredLocalCachedMapCacheNative` object added with data partitioning, local cache and native eviction +Feature - `RedissonClusteredSpringLocalCachedCacheNativeManager` object added with data partitioning, local cache and native eviction +Feature - added Micronaut `redisson.clustered-local-caches-native.*` cache with data partitioning, local cache and native eviction +Feature - added Hibernate `RedissonClusteredLocalCachedNativeRegionFactory` cache with data partitioning, local cache and native eviction +Feature - added Quarkus `CLUSTERED_LOCALCACHE_NATIVE` cache with data partitioning, local cache and native eviction +Feature - added MyBatis `RedissonClusteredLocalCachedCacheNative` cache with data partitioning, local cache and native eviction +Feature - added JCache implementation with local cache and advanced eviction +Feature - added JCache implementation with local cache and native eviction +Feature - added JCache implementation with data partitioning, local cache and native eviction +Feature - ability to set eviction mode via Spring `CacheConfig` object (thanks to @JKord) +Feature - RBitSet.get(long...) method added (thanks to @seakider) +Feature - RBlockingQueue.pollLastFromAnyWithName() method added (thanks to @seakider) +Feature - getReferenceCount(), getAccessFrequency(), getInternalEncoding() methods added to RObject interface (thanks to @seakider) Feature - RExecutorService.deregisterWorkers() method added Feature - `valuesAsync()` and `entrySetAsync` methods added to `RMap` interface (thanks to @seakider) From 6fdbd58afdc98388e6bed12225afbbc41a906402 Mon Sep 17 00:00:00 2001 From: seakider Date: Tue, 25 Feb 2025 19:04:11 +0800 Subject: [PATCH 3/5] Fixed - Issue with asynchronous @Cacheable methods Signed-off-by: seakider --- .../micronaut/cache/RedissonAsyncCache.java | 2 +- .../redisson/micronaut/RedissonCacheTest.java | 29 +++++++++++++++++++ .../micronaut/cache/RedissonAsyncCache.java | 2 +- .../redisson/micronaut/RedissonCacheTest.java | 29 +++++++++++++++++++ .../micronaut/cache/RedissonAsyncCache.java | 2 +- .../redisson/micronaut/RedissonCacheTest.java | 28 ++++++++++++++++++ 6 files changed, 89 insertions(+), 3 deletions(-) diff --git a/redisson-micronaut/redisson-micronaut-20/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java b/redisson-micronaut/redisson-micronaut-20/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java index 2c80bbe6c..8977808e9 100644 --- a/redisson-micronaut/redisson-micronaut-20/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java +++ b/redisson-micronaut/redisson-micronaut-20/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java @@ -56,7 +56,7 @@ public class RedissonAsyncCache implements AsyncCache> { return map.getAsync(key) .thenApply(v -> { if (v != null) { - return Optional.of((T)conversionService.convert(v, ConversionContext.of(requiredType))); + return conversionService.convert(v, ConversionContext.of(requiredType)); } return Optional.empty(); }) diff --git a/redisson-micronaut/redisson-micronaut-20/src/test/java/org/redisson/micronaut/RedissonCacheTest.java b/redisson-micronaut/redisson-micronaut-20/src/test/java/org/redisson/micronaut/RedissonCacheTest.java index 57a0bcc25..d30dfac35 100644 --- a/redisson-micronaut/redisson-micronaut-20/src/test/java/org/redisson/micronaut/RedissonCacheTest.java +++ b/redisson-micronaut/redisson-micronaut-20/src/test/java/org/redisson/micronaut/RedissonCacheTest.java @@ -1,5 +1,6 @@ package org.redisson.micronaut; +import io.micronaut.cache.AsyncCache; import io.micronaut.context.ApplicationContext; import io.micronaut.inject.qualifiers.Qualifiers; import org.junit.jupiter.api.Test; @@ -8,6 +9,9 @@ import org.redisson.micronaut.cache.RedissonSyncCache; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import static org.assertj.core.api.Assertions.assertThat; @@ -42,4 +46,29 @@ public class RedissonCacheTest { assertThat(cache.get(3, Integer.class).isPresent()).isTrue(); } + @Test + public void testAsyncCache() throws ExecutionException, InterruptedException { + Map map = new HashMap<>(); + map.put("redisson.threads", "10"); + map.put("redisson.single-server-config.address", "redis://127.0.0.1:6379"); + map.put("redisson.caches.test.expire-after-write", "3s"); + map.put("redisson.caches.test.expire-after-access", "3s"); + ApplicationContext ac = ApplicationContext.run(map); + + RedissonClient client = ac.getBean(RedissonClient.class); + assertThat(client).isNotNull(); + + client.getKeys().flushall(); + + RedissonSyncCache cache = ac.getBean(RedissonSyncCache.class, Qualifiers.byName("test")); + AsyncCache asyncCache = cache.async(); + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.empty()); + + CompletableFuture f = asyncCache.put(3, 4).toCompletableFuture(); + f.join(); + + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.of(4)); + + } + } diff --git a/redisson-micronaut/redisson-micronaut-30/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java b/redisson-micronaut/redisson-micronaut-30/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java index 2c80bbe6c..8977808e9 100644 --- a/redisson-micronaut/redisson-micronaut-30/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java +++ b/redisson-micronaut/redisson-micronaut-30/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java @@ -56,7 +56,7 @@ public class RedissonAsyncCache implements AsyncCache> { return map.getAsync(key) .thenApply(v -> { if (v != null) { - return Optional.of((T)conversionService.convert(v, ConversionContext.of(requiredType))); + return conversionService.convert(v, ConversionContext.of(requiredType)); } return Optional.empty(); }) diff --git a/redisson-micronaut/redisson-micronaut-30/src/test/java/org/redisson/micronaut/RedissonCacheTest.java b/redisson-micronaut/redisson-micronaut-30/src/test/java/org/redisson/micronaut/RedissonCacheTest.java index 57a0bcc25..d30dfac35 100644 --- a/redisson-micronaut/redisson-micronaut-30/src/test/java/org/redisson/micronaut/RedissonCacheTest.java +++ b/redisson-micronaut/redisson-micronaut-30/src/test/java/org/redisson/micronaut/RedissonCacheTest.java @@ -1,5 +1,6 @@ package org.redisson.micronaut; +import io.micronaut.cache.AsyncCache; import io.micronaut.context.ApplicationContext; import io.micronaut.inject.qualifiers.Qualifiers; import org.junit.jupiter.api.Test; @@ -8,6 +9,9 @@ import org.redisson.micronaut.cache.RedissonSyncCache; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import static org.assertj.core.api.Assertions.assertThat; @@ -42,4 +46,29 @@ public class RedissonCacheTest { assertThat(cache.get(3, Integer.class).isPresent()).isTrue(); } + @Test + public void testAsyncCache() throws ExecutionException, InterruptedException { + Map map = new HashMap<>(); + map.put("redisson.threads", "10"); + map.put("redisson.single-server-config.address", "redis://127.0.0.1:6379"); + map.put("redisson.caches.test.expire-after-write", "3s"); + map.put("redisson.caches.test.expire-after-access", "3s"); + ApplicationContext ac = ApplicationContext.run(map); + + RedissonClient client = ac.getBean(RedissonClient.class); + assertThat(client).isNotNull(); + + client.getKeys().flushall(); + + RedissonSyncCache cache = ac.getBean(RedissonSyncCache.class, Qualifiers.byName("test")); + AsyncCache asyncCache = cache.async(); + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.empty()); + + CompletableFuture f = asyncCache.put(3, 4).toCompletableFuture(); + f.join(); + + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.of(4)); + + } + } diff --git a/redisson-micronaut/redisson-micronaut-40/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java b/redisson-micronaut/redisson-micronaut-40/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java index 728efe8be..b5be0cbc1 100644 --- a/redisson-micronaut/redisson-micronaut-40/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java +++ b/redisson-micronaut/redisson-micronaut-40/src/main/java/org/redisson/micronaut/cache/RedissonAsyncCache.java @@ -56,7 +56,7 @@ public class RedissonAsyncCache implements AsyncCache> { return map.getAsync(key) .thenApply(v -> { if (v != null) { - return Optional.of((T)conversionService.convert(v, ConversionContext.of(requiredType))); + return conversionService.convert(v, ConversionContext.of(requiredType)); } return Optional.empty(); }) diff --git a/redisson-micronaut/redisson-micronaut-40/src/test/java/org/redisson/micronaut/RedissonCacheTest.java b/redisson-micronaut/redisson-micronaut-40/src/test/java/org/redisson/micronaut/RedissonCacheTest.java index c2b1cf579..fa73230f2 100644 --- a/redisson-micronaut/redisson-micronaut-40/src/test/java/org/redisson/micronaut/RedissonCacheTest.java +++ b/redisson-micronaut/redisson-micronaut-40/src/test/java/org/redisson/micronaut/RedissonCacheTest.java @@ -1,5 +1,6 @@ package org.redisson.micronaut; +import io.micronaut.cache.AsyncCache; import io.micronaut.context.ApplicationContext; import io.micronaut.inject.qualifiers.Qualifiers; import org.junit.jupiter.api.Test; @@ -12,6 +13,9 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import static org.assertj.core.api.Assertions.assertThat; @@ -49,6 +53,30 @@ public class RedissonCacheTest { cache.get(3, Integer.class); Thread.sleep(2000); assertThat(cache.get(3, Integer.class).isPresent()).isTrue(); + + } + + @Test + public void testAsyncCache() throws ExecutionException, InterruptedException { + Map map = new HashMap<>(); + map.put("redisson.threads", "10"); + map.put("redisson.single-server-config.address", "redis://127.0.0.1:" + REDIS.getFirstMappedPort()); + map.put("redisson.caches.test.expire-after-write", "10s"); + map.put("redisson.caches.test.expire-after-access", "10s"); + ApplicationContext ac = ApplicationContext.run(map); + + RedissonClient client = ac.getBean(RedissonClient.class); + assertThat(client).isNotNull(); + + RedissonSyncCache cache = ac.getBean(RedissonSyncCache.class, Qualifiers.byName("test")); + AsyncCache asyncCache = cache.async(); + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.empty()); + + CompletableFuture f = asyncCache.put(3, 4).toCompletableFuture(); + f.join(); + + assertThat(asyncCache.get(3, Integer.class).get()).isEqualTo(Optional.of(4)); + } @Test From 91923d78a52007765f8b6acbb8f1f557ae120e58 Mon Sep 17 00:00:00 2001 From: seakider Date: Tue, 25 Feb 2025 22:50:54 +0800 Subject: [PATCH 4/5] Fixed - submitAsync is reporting script error: ERR invalid expire time in set Signed-off-by: seakider --- redisson/src/main/java/org/redisson/RedissonExecutorService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/redisson/src/main/java/org/redisson/RedissonExecutorService.java b/redisson/src/main/java/org/redisson/RedissonExecutorService.java index d1775ebe7..398a0f47f 100644 --- a/redisson/src/main/java/org/redisson/RedissonExecutorService.java +++ b/redisson/src/main/java/org/redisson/RedissonExecutorService.java @@ -1150,6 +1150,7 @@ public class RedissonExecutorService implements RScheduledExecutorService { MasterSlaveServersConfig config = commandExecutor.getServiceManager().getConfig(); int timeout = (config.getTimeout() + config.getRetryInterval()) * config.getRetryAttempts(); + timeout = Math.max(timeout, 1); String taskName = tasksLatchName + ":" + id; From 81dc6aded335cf7409f9f1bccb991abc30e8d070 Mon Sep 17 00:00:00 2001 From: seakider Date: Thu, 27 Feb 2025 23:22:40 +0800 Subject: [PATCH 5/5] Fixed - Adding a new slave node in redis-cluster, isSlaveNotUsed does not take effect Signed-off-by: seakider --- .../org/redisson/connection/ClusterConnectionManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/redisson/src/main/java/org/redisson/connection/ClusterConnectionManager.java b/redisson/src/main/java/org/redisson/connection/ClusterConnectionManager.java index 8ec102088..aa98e65c0 100644 --- a/redisson/src/main/java/org/redisson/connection/ClusterConnectionManager.java +++ b/redisson/src/main/java/org/redisson/connection/ClusterConnectionManager.java @@ -641,6 +641,10 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager { futures.add(slaveUpFuture); continue; } + + if (config.isSlaveNotUsed()) { + continue; + } CompletableFuture slaveUpFuture = entry.addSlave(uri, configEndpointHostName); CompletableFuture f = slaveUpFuture.thenAccept(res -> {