Skip to content

Commit 88cf9bc

Browse files
atakavcisazzad16
andauthored
Adding CacheConfig (#3919)
* add cacheconfig * remove empty file * -modify constructors with cache as public - trim guava caffeine * remove cachetype * - add getCache to UnifiedJedis - add builder method to CacheConfig * add evictionpolicy to cacheconfig * - unifiedjedis constructor with cacheconfig - wrap IOException on protocol read error * fix merge issue --------- Co-authored-by: M Sazzadul Hoque <[email protected]>
1 parent e96e2e3 commit 88cf9bc

15 files changed

+186
-41
lines changed

Diff for: src/main/java/redis/clients/jedis/JedisCluster.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import redis.clients.jedis.executors.ClusterCommandExecutor;
1212
import redis.clients.jedis.providers.ClusterConnectionProvider;
1313
import redis.clients.jedis.csc.Cache;
14+
import redis.clients.jedis.csc.CacheConfig;
15+
import redis.clients.jedis.csc.CacheProvider;
1416
import redis.clients.jedis.util.JedisClusterCRC16;
1517

1618
public class JedisCluster extends UnifiedJedis {
@@ -225,10 +227,16 @@ public JedisCluster(Set<HostAndPort> clusterNodes, JedisClientConfig clientConfi
225227
Duration.ofMillis(DEFAULT_MAX_ATTEMPTS * clientConfig.getSocketTimeoutMillis()));
226228
}
227229

230+
@Experimental
231+
public JedisCluster(Set<HostAndPort> hnp, JedisClientConfig jedisClientConfig, CacheConfig cacheConfig) {
232+
this(hnp, jedisClientConfig, new CacheProvider().getCache(cacheConfig));
233+
}
234+
228235
@Experimental
229236
public JedisCluster(Set<HostAndPort> clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache,
230237
int maxAttempts, Duration maxTotalRetriesDuration) {
231-
this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache), maxAttempts, maxTotalRetriesDuration,
238+
this(new ClusterConnectionProvider(clusterNodes, clientConfig, clientSideCache), maxAttempts,
239+
maxTotalRetriesDuration,
232240
clientConfig.getRedisProtocol(), clientSideCache);
233241
}
234242

Diff for: src/main/java/redis/clients/jedis/JedisPooled.java

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
1010
import redis.clients.jedis.annots.Experimental;
1111
import redis.clients.jedis.csc.Cache;
12+
import redis.clients.jedis.csc.CacheConfig;
13+
import redis.clients.jedis.csc.CacheProvider;
1214
import redis.clients.jedis.providers.PooledConnectionProvider;
1315
import redis.clients.jedis.util.JedisURIHelper;
1416
import redis.clients.jedis.util.Pool;
@@ -82,6 +84,11 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client
8284
super(hostAndPort, clientConfig, clientSideCache);
8385
}
8486

87+
@Experimental
88+
public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, CacheConfig cacheConfig) {
89+
this(hostAndPort, clientConfig, new CacheProvider().getCache(cacheConfig));
90+
}
91+
8592
public JedisPooled(PooledObjectFactory<Connection> factory) {
8693
this(new PooledConnectionProvider(factory));
8794
}
@@ -389,6 +396,12 @@ public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig client
389396
clientConfig.getRedisProtocol(), clientSideCache);
390397
}
391398

399+
@Experimental
400+
public JedisPooled(final HostAndPort hostAndPort, final JedisClientConfig clientConfig, CacheConfig cacheConfig,
401+
final GenericObjectPoolConfig<Connection> poolConfig) {
402+
this(hostAndPort, clientConfig, new CacheProvider().getCache(cacheConfig), poolConfig);
403+
}
404+
392405
public JedisPooled(final GenericObjectPoolConfig<Connection> poolConfig,
393406
final JedisSocketFactory jedisSocketFactory, final JedisClientConfig clientConfig) {
394407
super(new PooledConnectionProvider(new ConnectionFactory(jedisSocketFactory, clientConfig), poolConfig),

Diff for: src/main/java/redis/clients/jedis/JedisSentineled.java

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
55
import redis.clients.jedis.annots.Experimental;
66
import redis.clients.jedis.csc.Cache;
7+
import redis.clients.jedis.csc.CacheConfig;
8+
import redis.clients.jedis.csc.CacheProvider;
79
import redis.clients.jedis.providers.SentineledConnectionProvider;
810

911
public class JedisSentineled extends UnifiedJedis {
@@ -21,6 +23,13 @@ public JedisSentineled(String masterName, final JedisClientConfig masterClientCo
2123
sentinels, sentinelClientConfig), masterClientConfig.getRedisProtocol(), clientSideCache);
2224
}
2325

26+
@Experimental
27+
public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig, CacheConfig cacheConfig,
28+
Set<HostAndPort> sentinels, final JedisClientConfig sentinelClientConfig) {
29+
this(masterName, masterClientConfig, new CacheProvider().getCache(cacheConfig),
30+
sentinels, sentinelClientConfig);
31+
}
32+
2433
public JedisSentineled(String masterName, final JedisClientConfig masterClientConfig,
2534
final GenericObjectPoolConfig<Connection> poolConfig,
2635
Set<HostAndPort> sentinels, final JedisClientConfig sentinelClientConfig) {

Diff for: src/main/java/redis/clients/jedis/Protocol.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,8 @@ public static void readPushes(final RedisInputStream is, final Cache cache, bool
235235
is.readByte();
236236
processPush(is, cache);
237237
}
238-
} catch (JedisConnectionException e) {
239-
// TODO handle it properly
240238
} catch (IOException e) {
241-
// TODO handle it properly
239+
throw new JedisConnectionException("Failed to read pending buffer for push messages !", e);
242240
}
243241
} else {
244242
while (is.peek(GREATER_THAN_BYTE)) {

Diff for: src/main/java/redis/clients/jedis/UnifiedJedis.java

+28-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import redis.clients.jedis.commands.SampleKeyedCommands;
2121
import redis.clients.jedis.commands.RedisModuleCommands;
2222
import redis.clients.jedis.csc.Cache;
23+
import redis.clients.jedis.csc.CacheConfig;
24+
import redis.clients.jedis.csc.CacheConnection;
25+
import redis.clients.jedis.csc.CacheProvider;
2326
import redis.clients.jedis.exceptions.JedisException;
2427
import redis.clients.jedis.executors.*;
2528
import redis.clients.jedis.gears.TFunctionListParams;
@@ -58,6 +61,7 @@ public class UnifiedJedis implements JedisCommands, JedisBinaryCommands,
5861
protected final CommandObjects commandObjects;
5962
private final GraphCommandObjects graphCommandObjects;
6063
private JedisBroadcastAndRoundRobinConfig broadcastAndRoundRobinConfig = null;
64+
private final Cache cache;
6165

6266
public UnifiedJedis() {
6367
this(new HostAndPort(Protocol.DEFAULT_HOST, Protocol.DEFAULT_PORT));
@@ -95,9 +99,14 @@ public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig) {
9599
}
96100

97101
@Experimental
98-
public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache clientSideCache) {
99-
this(new PooledConnectionProvider(hostAndPort, clientConfig, clientSideCache), clientConfig.getRedisProtocol(),
100-
clientSideCache);
102+
public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig, Cache cache) {
103+
this(new PooledConnectionProvider(hostAndPort, clientConfig, cache), clientConfig.getRedisProtocol(),
104+
cache);
105+
}
106+
107+
@Experimental
108+
public UnifiedJedis(HostAndPort hostAndPort, JedisClientConfig clientConfig, CacheConfig cacheConfig) {
109+
this(hostAndPort, clientConfig, new CacheProvider().getCache(cacheConfig));
101110
}
102111

103112
public UnifiedJedis(ConnectionProvider provider) {
@@ -109,8 +118,8 @@ protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol) {
109118
}
110119

111120
@Experimental
112-
protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol, Cache clientSideCache) {
113-
this(new DefaultCommandExecutor(provider), provider, new CommandObjects(), protocol, clientSideCache);
121+
protected UnifiedJedis(ConnectionProvider provider, RedisProtocol protocol, Cache cache) {
122+
this(new DefaultCommandExecutor(provider), provider, new CommandObjects(), protocol, cache);
114123
}
115124

116125
/**
@@ -147,6 +156,11 @@ public UnifiedJedis(Connection connection) {
147156
if (proto != null)
148157
this.commandObjects.setProtocol(proto);
149158
this.graphCommandObjects = new GraphCommandObjects(this);
159+
if (connection instanceof CacheConnection) {
160+
this.cache = ((CacheConnection) connection).getCache();
161+
} else {
162+
this.cache = null;
163+
}
150164
}
151165

152166
@Deprecated
@@ -183,9 +197,9 @@ protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Dura
183197

184198
@Experimental
185199
protected UnifiedJedis(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration,
186-
RedisProtocol protocol, Cache clientSideCache) {
200+
RedisProtocol protocol, Cache cache) {
187201
this(new ClusterCommandExecutor(provider, maxAttempts, maxTotalRetriesDuration), provider,
188-
new ClusterCommandObjects(), protocol, clientSideCache);
202+
new ClusterCommandObjects(), protocol, cache);
189203
}
190204

191205
/**
@@ -259,9 +273,9 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, Comm
259273

260274
@Experimental
261275
private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects,
262-
RedisProtocol protocol, Cache clientSideCache) {
276+
RedisProtocol protocol, Cache cache) {
263277

264-
if (clientSideCache != null && protocol != RedisProtocol.RESP3) {
278+
if (cache != null && protocol != RedisProtocol.RESP3) {
265279
throw new IllegalArgumentException("Client-side caching is only supported with RESP3.");
266280
}
267281

@@ -274,7 +288,7 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, Comm
274288

275289
this.graphCommandObjects = new GraphCommandObjects(this);
276290
this.graphCommandObjects.setBaseCommandArgumentsCreator((comm) -> this.commandObjects.commandArguments(comm));
277-
291+
this.cache = cache;
278292
}
279293

280294
@Override
@@ -314,6 +328,10 @@ public void setBroadcastAndRoundRobinConfig(JedisBroadcastAndRoundRobinConfig co
314328
this.commandObjects.setBroadcastAndRoundRobinConfig(this.broadcastAndRoundRobinConfig);
315329
}
316330

331+
public Cache getCache() {
332+
return cache;
333+
}
334+
317335
public String ping() {
318336
return checkAndBroadcastCommand(commandObjects.ping());
319337
}
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package redis.clients.jedis.csc;
2+
3+
public class CacheConfig {
4+
5+
private int maxSize;
6+
private Cacheable cacheable;
7+
private EvictionPolicy evictionPolicy;
8+
9+
public int getMaxSize() {
10+
return maxSize;
11+
}
12+
13+
public Cacheable getCacheable() {
14+
return cacheable;
15+
}
16+
17+
public EvictionPolicy getEvictionPolicy() {
18+
return evictionPolicy;
19+
}
20+
21+
public static Builder builder() {
22+
return new Builder();
23+
}
24+
25+
public static class Builder {
26+
private int maxSize;
27+
private Cacheable cacheable = DefaultCacheable.INSTANCE;
28+
private EvictionPolicy evictionPolicy;
29+
30+
public Builder maxSize(int maxSize) {
31+
this.maxSize = maxSize;
32+
return this;
33+
}
34+
35+
public Builder evictionPolicy(EvictionPolicy policy) {
36+
this.evictionPolicy = policy;
37+
return this;
38+
}
39+
40+
public Builder cacheable(Cacheable cacheable) {
41+
this.cacheable = cacheable;
42+
return this;
43+
}
44+
45+
public CacheConfig build() {
46+
CacheConfig cacheConfig = new CacheConfig();
47+
cacheConfig.maxSize = this.maxSize;
48+
cacheConfig.cacheable = this.cacheable;
49+
cacheConfig.evictionPolicy = this.evictionPolicy;
50+
return cacheConfig;
51+
}
52+
}
53+
}

Diff for: src/main/java/redis/clients/jedis/csc/CacheConnection.java

+19-15
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414

1515
public class CacheConnection extends Connection {
1616

17-
private final Cache clientSideCache;
17+
private final Cache cache;
1818
private ReentrantLock lock;
1919

20-
public CacheConnection(final JedisSocketFactory socketFactory, JedisClientConfig clientConfig, Cache clientSideCache) {
20+
public CacheConnection(final JedisSocketFactory socketFactory, JedisClientConfig clientConfig, Cache cache) {
2121
super(socketFactory, clientConfig);
2222

2323
if (protocol != RedisProtocol.RESP3) {
2424
throw new JedisException("Client side caching is only supported with RESP3.");
2525
}
26-
this.clientSideCache = Objects.requireNonNull(clientSideCache);
26+
this.cache = Objects.requireNonNull(cache);
2727
initializeClientSideCache();
2828
}
2929

@@ -37,7 +37,7 @@ protected void initializeFromClientConfig(JedisClientConfig config) {
3737
protected Object protocolRead(RedisInputStream inputStream) {
3838
lock.lock();
3939
try {
40-
return Protocol.read(inputStream, clientSideCache);
40+
return Protocol.read(inputStream, cache);
4141
} finally {
4242
lock.unlock();
4343
}
@@ -47,7 +47,7 @@ protected Object protocolRead(RedisInputStream inputStream) {
4747
protected void protocolReadPushes(RedisInputStream inputStream) {
4848
if (lock.tryLock()) {
4949
try {
50-
Protocol.readPushes(inputStream, clientSideCache, true);
50+
Protocol.readPushes(inputStream, cache, true);
5151
} finally {
5252
lock.unlock();
5353
}
@@ -57,37 +57,41 @@ protected void protocolReadPushes(RedisInputStream inputStream) {
5757
@Override
5858
public void disconnect() {
5959
super.disconnect();
60-
clientSideCache.flush();
60+
cache.flush();
6161
}
6262

6363
@Override
6464
public <T> T executeCommand(final CommandObject<T> commandObject) {
6565
final CacheKey cacheKey = new CacheKey(commandObject);
66-
if (!clientSideCache.isCacheable(cacheKey)) {
67-
clientSideCache.getStats().nonCacheable();
66+
if (!cache.isCacheable(cacheKey)) {
67+
cache.getStats().nonCacheable();
6868
return super.executeCommand(commandObject);
6969
}
7070

71-
CacheEntry<T> cacheEntry = clientSideCache.get(cacheKey);
71+
CacheEntry<T> cacheEntry = cache.get(cacheKey);
7272
if (cacheEntry != null) { // (probable) CACHE HIT !!
7373
cacheEntry = validateEntry(cacheEntry);
7474
if (cacheEntry != null) {
7575
// CACHE HIT confirmed !!!
76-
clientSideCache.getStats().hit();
76+
cache.getStats().hit();
7777
return cacheEntry.getValue();
7878
}
7979
}
8080

8181
// CACHE MISS !!
82-
clientSideCache.getStats().miss();
82+
cache.getStats().miss();
8383
T value = super.executeCommand(commandObject);
8484
cacheEntry = new CacheEntry<>(cacheKey, value, this);
85-
clientSideCache.set(cacheKey, cacheEntry);
85+
cache.set(cacheKey, cacheEntry);
8686
// this line actually provides a deep copy of cached object instance
8787
value = cacheEntry.getValue();
8888
return value;
8989
}
9090

91+
public Cache getCache() {
92+
return cache;
93+
}
94+
9195
private void initializeClientSideCache() {
9296
sendCommand(Protocol.Command.CLIENT, "TRACKING", "ON");
9397
String reply = getStatusCodeReply();
@@ -99,17 +103,17 @@ private void initializeClientSideCache() {
99103
private CacheEntry validateEntry(CacheEntry cacheEntry) {
100104
CacheConnection cacheOwner = cacheEntry.getConnection();
101105
if (cacheOwner == null || cacheOwner.isBroken() || !cacheOwner.isConnected()) {
102-
clientSideCache.delete(cacheEntry.getCacheKey());
106+
cache.delete(cacheEntry.getCacheKey());
103107
return null;
104108
} else {
105109
try {
106110
cacheOwner.readPushesWithCheckingBroken();
107111
} catch (JedisException e) {
108-
clientSideCache.delete(cacheEntry.getCacheKey());
112+
cache.delete(cacheEntry.getCacheKey());
109113
return null;
110114
}
111115

112-
return clientSideCache.get(cacheEntry.getCacheKey());
116+
return cache.get(cacheEntry.getCacheKey());
113117
}
114118
}
115119
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package redis.clients.jedis.csc;
2+
3+
import java.util.HashMap;
4+
5+
public class CacheProvider {
6+
7+
public Cache getCache(CacheConfig config) {
8+
return getCache(config, new HashMap<CacheKey, CacheEntry>());
9+
}
10+
11+
public Cache getCache(CacheConfig config, HashMap<CacheKey, CacheEntry> map) {
12+
return new DefaultCache(config.getMaxSize(), map, config.getCacheable(),
13+
getEvictionPolicy(config));
14+
}
15+
16+
private EvictionPolicy getEvictionPolicy(CacheConfig config) {
17+
if (config.getEvictionPolicy() == null) {
18+
// It will be default to LRUEviction, until we have other eviction implementations
19+
return new LRUEviction(config.getMaxSize());
20+
}
21+
return config.getEvictionPolicy();
22+
}
23+
}

0 commit comments

Comments
 (0)