diff --git a/pom.xml b/pom.xml
index c9fd15d2cb..96a4e122f7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,12 @@
gson
2.10.1
+
+ com.github.ben-manes.caffeine
+ caffeine
+ 2.9.3
+ true
+
diff --git a/src/main/java/redis/clients/jedis/ClientSideCache.java b/src/main/java/redis/clients/jedis/ClientSideCache.java
index 62c5be28c2..482c9c0681 100644
--- a/src/main/java/redis/clients/jedis/ClientSideCache.java
+++ b/src/main/java/redis/clients/jedis/ClientSideCache.java
@@ -1,63 +1,47 @@
package redis.clients.jedis;
import java.nio.ByteBuffer;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.util.SafeEncoder;
-public class ClientSideCache {
+public abstract class ClientSideCache {
- private final Map cache;
+ protected ClientSideCache() { }
- public ClientSideCache() {
- this.cache = new HashMap<>();
- }
+ public abstract void clear();
- /**
- * For testing purpose only.
- * @param map
- */
- ClientSideCache(Map map) {
- this.cache = map;
- }
+ protected abstract void remove(ByteBuffer key);
- public final void clear() {
- cache.clear();
- }
+ protected abstract void put(ByteBuffer key, Object value);
+
+ protected abstract Object get(ByteBuffer key);
- public final void invalidateKeys(List list) {
+ final void invalidateKeys(List list) {
if (list == null) {
clear();
- return;
+ } else {
+ list.forEach(this::invalidateKey);
}
-
- list.forEach(this::invalidateKey);
}
private void invalidateKey(Object key) {
if (key instanceof byte[]) {
- cache.remove(convertKey((byte[]) key));
+ remove(convertKey((byte[]) key));
} else {
throw new JedisException("" + key.getClass().getSimpleName() + " is not supported. Value: " + String.valueOf(key));
}
}
- protected void setKey(Object key, Object value) {
- cache.put(getMapKey(key), value);
- }
-
- protected T getValue(Object key) {
- return (T) getMapValue(key);
+ final void set(Object key, Object value) {
+ put(makeKey(key), value);
}
- private Object getMapValue(Object key) {
- return cache.get(getMapKey(key));
+ final T get(Object key) {
+ return (T) get(makeKey(key));
}
- private ByteBuffer getMapKey(Object key) {
+ private ByteBuffer makeKey(Object key) {
if (key instanceof byte[]) {
return convertKey((byte[]) key);
} else {
diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java
index ba7b36b134..343b24c842 100644
--- a/src/main/java/redis/clients/jedis/UnifiedJedis.java
+++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java
@@ -750,11 +750,11 @@ public String set(String key, String value, SetParams params) {
@Override
public String get(String key) {
if (clientSideCache != null) {
- String cachedValue = clientSideCache.getValue(key);
+ String cachedValue = clientSideCache.get(key);
if (cachedValue != null) return cachedValue;
String value = executeCommand(commandObjects.get(key));
- if (value != null) clientSideCache.setKey(key, value);
+ if (value != null) clientSideCache.set(key, value);
return value;
}
return executeCommand(commandObjects.get(key));
diff --git a/src/main/java/redis/clients/jedis/util/CaffeineCSC.java b/src/main/java/redis/clients/jedis/util/CaffeineCSC.java
new file mode 100644
index 0000000000..7a205f40ab
--- /dev/null
+++ b/src/main/java/redis/clients/jedis/util/CaffeineCSC.java
@@ -0,0 +1,50 @@
+package redis.clients.jedis.util;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+import redis.clients.jedis.ClientSideCache;
+
+public class CaffeineCSC extends ClientSideCache {
+
+ private static final int DEFAULT_MAXIMUM_SIZE = 10_000;
+
+ private final Cache cache;
+
+ public CaffeineCSC() {
+ this(DEFAULT_MAXIMUM_SIZE);
+ }
+
+ public CaffeineCSC(int maximumSize) {
+ this(Caffeine.newBuilder().maximumSize(maximumSize).build());
+ }
+
+ public CaffeineCSC(int maximumSize, int ttlSeconds) {
+ this(Caffeine.newBuilder().maximumSize(maximumSize).expireAfterWrite(ttlSeconds, TimeUnit.SECONDS).build());
+ }
+
+ public CaffeineCSC(Cache caffeineCache) {
+ this.cache = caffeineCache;
+ }
+
+ @Override
+ public final void clear() {
+ cache.invalidateAll();
+ }
+
+ @Override
+ protected void remove(ByteBuffer key) {
+ cache.invalidate(key);
+ }
+
+ @Override
+ protected void put(ByteBuffer key, Object value) {
+ cache.put(key, value);
+ }
+
+ @Override
+ protected Object get(ByteBuffer key) {
+ return cache.getIfPresent(key);
+ }
+}
diff --git a/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java
index 3c8bc18c5c..8e276d9665 100644
--- a/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java
+++ b/src/test/java/redis/clients/jedis/JedisClusterClientSideCacheTest.java
@@ -14,6 +14,7 @@
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.hamcrest.Matchers;
import org.junit.Test;
+import redis.clients.jedis.util.MapCSC;
public class JedisClusterClientSideCacheTest extends JedisClusterTestBase {
@@ -31,7 +32,7 @@ public class JedisClusterClientSideCacheTest extends JedisClusterTestBase {
@Test
public void simple() {
- try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache())) {
+ try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapCSC())) {
jedis.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
jedis.del("foo");
@@ -42,7 +43,7 @@ public void simple() {
@Test
public void simpleWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) {
+ try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapCSC(map), singleConnectionPoolConfig.get())) {
jedis.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
@@ -60,7 +61,7 @@ public void simpleWithSimpleMap() {
@Test
public void flushAll() {
- try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache())) {
+ try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapCSC())) {
jedis.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
jedis.flushAll();
@@ -71,7 +72,7 @@ public void flushAll() {
@Test
public void flushAllWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) {
+ try (JedisCluster jedis = new JedisCluster(hnp, clientConfig.get(), new MapCSC(map), singleConnectionPoolConfig.get())) {
jedis.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
diff --git a/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java
index ad4313a4b7..805d9738d7 100644
--- a/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java
+++ b/src/test/java/redis/clients/jedis/JedisPooledClientSideCacheTest.java
@@ -12,6 +12,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import redis.clients.jedis.util.MapCSC;
public class JedisPooledClientSideCacheTest {
@@ -42,7 +43,7 @@ public void tearDown() throws Exception {
@Test
public void simple() {
- try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache())) {
+ try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapCSC())) {
control.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
control.del("foo");
@@ -53,7 +54,7 @@ public void simple() {
@Test
public void simpleWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) {
+ try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapCSC(map), singleConnectionPoolConfig.get())) {
control.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
@@ -71,7 +72,7 @@ public void simpleWithSimpleMap() {
@Test
public void flushAll() {
- try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache())) {
+ try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapCSC())) {
control.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
control.flushAll();
@@ -82,7 +83,7 @@ public void flushAll() {
@Test
public void flushAllWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new ClientSideCache(map), singleConnectionPoolConfig.get())) {
+ try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), new MapCSC(map), singleConnectionPoolConfig.get())) {
control.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
diff --git a/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java
index 9af243ffc7..5fa5a36f4b 100644
--- a/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java
+++ b/src/test/java/redis/clients/jedis/JedisSentineledClientSideCacheTest.java
@@ -8,12 +8,11 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
-import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.hamcrest.Matchers;
import org.junit.Test;
+import redis.clients.jedis.util.MapCSC;
public class JedisSentineledClientSideCacheTest {
@@ -28,16 +27,9 @@ public class JedisSentineledClientSideCacheTest {
private static final JedisClientConfig sentinelClientConfig = DefaultJedisClientConfig.builder().resp3().build();
- private static final Supplier> singleConnectionPoolConfig
- = () -> {
- ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
- poolConfig.setMaxTotal(1);
- return poolConfig;
- };
-
@Test
public void simple() {
- try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(), sentinels, sentinelClientConfig)) {
+ try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapCSC(), sentinels, sentinelClientConfig)) {
jedis.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
jedis.del("foo");
@@ -48,7 +40,7 @@ public void simple() {
@Test
public void simpleWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(map), sentinels, sentinelClientConfig)) {
+ try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapCSC(map), sentinels, sentinelClientConfig)) {
jedis.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
@@ -66,7 +58,7 @@ public void simpleWithSimpleMap() {
@Test
public void flushAll() {
- try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(), sentinels, sentinelClientConfig)) {
+ try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapCSC(), sentinels, sentinelClientConfig)) {
jedis.set("foo", "bar");
assertEquals("bar", jedis.get("foo"));
jedis.flushAll();
@@ -77,7 +69,7 @@ public void flushAll() {
@Test
public void flushAllWithSimpleMap() {
HashMap map = new HashMap<>();
- try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new ClientSideCache(map), sentinels, sentinelClientConfig)) {
+ try (JedisSentineled jedis = new JedisSentineled(MASTER_NAME, masterClientConfig, new MapCSC(map), sentinels, sentinelClientConfig)) {
jedis.set("foo", "bar");
assertThat(map, Matchers.aMapWithSize(0));
assertEquals("bar", jedis.get("foo"));
diff --git a/src/test/java/redis/clients/jedis/util/MapCSC.java b/src/test/java/redis/clients/jedis/util/MapCSC.java
new file mode 100644
index 0000000000..a9d1ef6f37
--- /dev/null
+++ b/src/test/java/redis/clients/jedis/util/MapCSC.java
@@ -0,0 +1,39 @@
+package redis.clients.jedis.util;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import redis.clients.jedis.ClientSideCache;
+
+public class MapCSC extends ClientSideCache {
+
+ private final Map cache;
+
+ public MapCSC() {
+ this(new HashMap<>());
+ }
+
+ public MapCSC(Map map) {
+ this.cache = map;
+ }
+
+ @Override
+ public final void clear() {
+ cache.clear();
+ }
+
+ @Override
+ protected void remove(ByteBuffer key) {
+ cache.remove(key);
+ }
+
+ @Override
+ protected void put(ByteBuffer key, Object value) {
+ cache.put(key, value);
+ }
+
+ @Override
+ protected Object get(ByteBuffer key) {
+ return cache.get(key);
+ }
+}