Skip to content

Commit 9bddabd

Browse files
authored
Jedis test plan coverage for CSC (#3918)
* initial changes * cover tests for JedisPooled and functionality * fix javadoc * cover new tests for JedisCluster and JedisSentineled * Fix CSC allow-and-deny-list and rename Cacheable interface * Tag CommandArguments#getKeys() as Internal * cover lruEvictionTest * Address code reviews and more updates * fix format and more minor changes * format Connection * modify WeakReference usage
1 parent f78fc08 commit 9bddabd

30 files changed

+894
-1073
lines changed

pom.xml

-13
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,6 @@
7676
</dependency>
7777

7878
<!-- Optional dependencies -->
79-
<!-- Client-side caching -->
80-
<dependency>
81-
<groupId>com.google.guava</groupId>
82-
<artifactId>guava</artifactId>
83-
<version>33.2.1-jre</version>
84-
<optional>true</optional>
85-
</dependency>
86-
<dependency>
87-
<groupId>com.github.ben-manes.caffeine</groupId>
88-
<artifactId>caffeine</artifactId>
89-
<version>2.9.3</version>
90-
<optional>true</optional>
91-
</dependency>
9279

9380
<!-- UNIX socket connection support -->
9481
<dependency>

src/main/java/redis/clients/jedis/CommandArguments.java

+32-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
import java.util.ArrayList;
44
import java.util.Arrays;
55
import java.util.Collection;
6+
import java.util.Collections;
67
import java.util.Iterator;
8+
import java.util.List;
79

10+
import redis.clients.jedis.annots.Internal;
811
import redis.clients.jedis.args.Rawable;
912
import redis.clients.jedis.args.RawableFactory;
1013
import redis.clients.jedis.commands.ProtocolCommand;
@@ -14,14 +17,20 @@
1417
public class CommandArguments implements Iterable<Rawable> {
1518

1619
private final ArrayList<Rawable> args;
17-
private final ArrayList<Object> keys;
20+
21+
private List<Object> keys;
1822

1923
private boolean blocking;
2024

25+
private CommandArguments() {
26+
throw new InstantiationError();
27+
}
28+
2129
public CommandArguments(ProtocolCommand command) {
2230
args = new ArrayList<>();
2331
args.add(command);
24-
keys = new ArrayList<>();
32+
33+
keys = Collections.emptyList();
2534
}
2635

2736
public ProtocolCommand getCommand() {
@@ -113,10 +122,25 @@ public CommandArguments key(Object key) {
113122
} else {
114123
throw new IllegalArgumentException("\"" + key.toString() + "\" is not a valid argument.");
115124
}
116-
keys.add(key);
125+
126+
addKeyInKeys(key);
127+
117128
return this;
118129
}
119130

131+
private void addKeyInKeys(Object key) {
132+
if (keys.isEmpty()) {
133+
keys = Collections.singletonList(key);
134+
} else if (keys.size() == 1) {
135+
List oldKeys = keys;
136+
keys = new ArrayList();
137+
keys.addAll(oldKeys);
138+
keys.add(key);
139+
} else {
140+
keys.add(key);
141+
}
142+
}
143+
120144
public final CommandArguments keys(Object... keys) {
121145
Arrays.stream(keys).forEach(this::key);
122146
return this;
@@ -133,6 +157,7 @@ public final CommandArguments addParams(IParams params) {
133157
}
134158

135159
protected CommandArguments processKey(byte[] key) {
160+
// do nothing
136161
return this;
137162
}
138163

@@ -144,6 +169,7 @@ protected final CommandArguments processKeys(byte[]... keys) {
144169
}
145170

146171
protected CommandArguments processKey(String key) {
172+
// do nothing
147173
return this;
148174
}
149175

@@ -163,8 +189,9 @@ public Iterator<Rawable> iterator() {
163189
return args.iterator();
164190
}
165191

166-
public Object[] getKeys() {
167-
return keys.toArray();
192+
@Internal
193+
public List<Object> getKeys() {
194+
return keys;
168195
}
169196

170197
public boolean isBlocking() {

src/main/java/redis/clients/jedis/Connection.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public String toIdentityString() {
102102
.append(id)
103103
.append(", L:")
104104
.append(localAddr)
105-
.append(broken? " ! " : " - ")
105+
.append(broken ? " ! " : " - ")
106106
.append("R:")
107107
.append(remoteAddr)
108108
.append(']');
@@ -455,7 +455,7 @@ public List<Object> getMany(final int count) {
455455

456456
/**
457457
* Check if the client name libname, libver, characters are legal
458-
*
458+
*
459459
* @param info the name
460460
* @return Returns true if legal, false throws exception
461461
* @throws JedisException if characters illegal
@@ -499,8 +499,9 @@ protected void initializeFromClientConfig(final JedisClientConfig config) {
499499
}
500500

501501
ClientSetInfoConfig setInfoConfig = config.getClientSetInfoConfig();
502-
if (setInfoConfig == null)
502+
if (setInfoConfig == null) {
503503
setInfoConfig = ClientSetInfoConfig.DEFAULT;
504+
}
504505

505506
if (!setInfoConfig.isDisabled()) {
506507
String libName = JedisMetaInfo.getArtifactId();

src/main/java/redis/clients/jedis/csc/AbstractCache.java

+11-13
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,23 @@
1414
import redis.clients.jedis.util.SafeEncoder;
1515

1616
/**
17-
* The class to manage the client-side caching. User can provide any of implementation of this class
18-
* to the client object; e.g. {@link redis.clients.jedis.csc.CaffeineClientSideCache
19-
* CaffeineClientSideCache} or {@link redis.clients.jedis.csc.GuavaClientSideCache
20-
* GuavaClientSideCache} or a custom implementation of their own.
17+
* The class to manage the client-side caching. User can provide an of implementation of this class
18+
* to the client object.
2119
*/
2220
@Experimental
2321
public abstract class AbstractCache implements Cache {
2422

25-
private ClientSideCacheable cacheable;
23+
private Cacheable cacheable;
2624
private final Map<ByteBuffer, Set<CacheKey<?>>> redisKeysToCacheKeys = new ConcurrentHashMap<>();
2725
private final int maximumSize;
2826
private ReentrantLock lock = new ReentrantLock();
2927
private volatile CacheStats stats = new CacheStats();
3028

3129
protected AbstractCache(int maximumSize) {
32-
this(maximumSize, DefaultClientSideCacheable.INSTANCE);
30+
this(maximumSize, DefaultCacheable.INSTANCE);
3331
}
3432

35-
protected AbstractCache(int maximumSize, ClientSideCacheable cacheable) {
33+
protected AbstractCache(int maximumSize, Cacheable cacheable) {
3634
this.maximumSize = maximumSize;
3735
this.cacheable = cacheable;
3836
}
@@ -89,7 +87,7 @@ public CacheEntry set(CacheKey cacheKey, CacheEntry entry) {
8987
}
9088

9189
@Override
92-
public Boolean delete(CacheKey cacheKey) {
90+
public boolean delete(CacheKey cacheKey) {
9391
lock.lock();
9492
try {
9593
boolean removed = removeFromStore(cacheKey);
@@ -171,12 +169,12 @@ public int flush() {
171169
}
172170

173171
@Override
174-
public Boolean isCacheable(CacheKey cacheKey) {
175-
return cacheable.isCacheable(cacheKey.getCommand().getArguments().getCommand(), cacheKey.getRedisKeys());
172+
public boolean isCacheable(CacheKey cacheKey) {
173+
return cacheable.isCacheable(cacheKey.getRedisCommand(), cacheKey.getRedisKeys());
176174
}
177175

178176
@Override
179-
public Boolean hasCacheKey(CacheKey cacheKey) {
177+
public boolean hasCacheKey(CacheKey cacheKey) {
180178
return containsKeyInStore(cacheKey);
181179
}
182180

@@ -202,13 +200,13 @@ public CacheStats getAndResetStats() {
202200

203201
protected abstract CacheEntry putIntoStore(CacheKey cacheKey, CacheEntry entry);
204202

205-
protected abstract Boolean removeFromStore(CacheKey cacheKey);
203+
protected abstract boolean removeFromStore(CacheKey cacheKey);
206204

207205
// protected abstract Collection<CacheKey> remove(Set<CacheKey<?>> commands);
208206

209207
protected abstract void clearStore();
210208

211-
protected abstract Boolean containsKeyInStore(CacheKey cacheKey);
209+
protected abstract boolean containsKeyInStore(CacheKey cacheKey);
212210

213211
// End of abstract methods to be implemented by the concrete classes
214212

src/main/java/redis/clients/jedis/csc/Cache.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public interface Cache {
4545
* @param cacheKey The cache key of the entry in the cache
4646
* @return True if the entry could be deleted, false if the entry wasn't found.
4747
*/
48-
Boolean delete(CacheKey cacheKey);
48+
boolean delete(CacheKey cacheKey);
4949

5050
/**
5151
* Delete entries by cache key from the cache
@@ -82,14 +82,14 @@ public interface Cache {
8282
* @param cacheKey The key of the cache entry
8383
* @return True if the entry is cachable, false otherwise
8484
*/
85-
Boolean isCacheable(CacheKey cacheKey);
85+
boolean isCacheable(CacheKey cacheKey);
8686

8787
/**
8888
*
8989
* @param cacheKey The key of the cache entry
9090
* @return True if the cache already contains the key
9191
*/
92-
Boolean hasCacheKey(CacheKey cacheKey);
92+
boolean hasCacheKey(CacheKey cacheKey);
9393

9494
/**
9595
* @return The eviction policy that is used by the cache
@@ -99,10 +99,10 @@ public interface Cache {
9999
/**
100100
* @return The statistics of the cache
101101
*/
102-
public CacheStats getStats();
102+
CacheStats getStats();
103103

104104
/**
105105
* @return The statistics of the cache
106106
*/
107-
public CacheStats getAndResetStats();
107+
CacheStats getAndResetStats();
108108
}

src/main/java/redis/clients/jedis/csc/CacheConnection.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package redis.clients.jedis.csc;
22

3-
import java.lang.ref.WeakReference;
43
import java.util.Objects;
54
import java.util.concurrent.locks.ReentrantLock;
5+
66
import redis.clients.jedis.CommandObject;
77
import redis.clients.jedis.Connection;
88
import redis.clients.jedis.JedisClientConfig;
@@ -84,7 +84,7 @@ public <T> T executeCommand(final CommandObject<T> commandObject) {
8484
clientSideCache.getStats().miss();
8585
T value = super.executeCommand(commandObject);
8686
if (value != null) {
87-
cacheEntry = new CacheEntry<T>(cacheKey, value, new WeakReference(this));
87+
cacheEntry = new CacheEntry<>(cacheKey, value, this);
8888
clientSideCache.set(cacheKey, cacheEntry);
8989
// this line actually provides a deep copy of cached object instance
9090
value = cacheEntry.getValue();
@@ -101,7 +101,7 @@ private void initializeClientSideCache() {
101101
}
102102

103103
private CacheEntry validateEntry(CacheEntry cacheEntry) {
104-
CacheConnection cacheOwner = (CacheConnection) cacheEntry.getConnection().get();
104+
CacheConnection cacheOwner = cacheEntry.getConnection();
105105
if (cacheOwner == null || cacheOwner.isBroken() || !cacheOwner.isConnected()) {
106106
clientSideCache.delete(cacheEntry.getCacheKey());
107107
return null;

src/main/java/redis/clients/jedis/csc/CacheEntry.java

+6-11
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@
77
import java.io.ObjectOutputStream;
88
import java.lang.ref.WeakReference;
99

10-
import redis.clients.jedis.Connection;
11-
import redis.clients.jedis.annots.Internal;
1210
import redis.clients.jedis.exceptions.JedisCacheException;
1311

14-
@Internal
1512
public class CacheEntry<T> {
1613

1714
private final CacheKey<T> cacheKey;
18-
private final WeakReference<Connection> connection;
15+
private final WeakReference<CacheConnection> connection;
1916
private final byte[] bytes;
2017

21-
public CacheEntry(CacheKey<T> cacheKey, T value, WeakReference<Connection> connection) {
18+
public CacheEntry(CacheKey<T> cacheKey, T value, CacheConnection connection) {
2219
this.cacheKey = cacheKey;
23-
this.connection = connection;
20+
this.connection = new WeakReference<>(connection);
2421
this.bytes = toBytes(value);
2522
}
2623

@@ -32,8 +29,8 @@ public T getValue() {
3229
return toObject(bytes);
3330
}
3431

35-
public WeakReference<Connection> getConnection() {
36-
return connection;
32+
public CacheConnection getConnection() {
33+
return connection.get();
3734
}
3835

3936
private static byte[] toBytes(Object object) {
@@ -52,9 +49,7 @@ private T toObject(byte[] data) {
5249
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
5350
ObjectInputStream ois = new ObjectInputStream(bais)) {
5451
return (T) ois.readObject();
55-
} catch (IOException e) {
56-
throw new JedisCacheException("Failed to deserialize object", e);
57-
} catch (ClassNotFoundException e) {
52+
} catch (IOException | ClassNotFoundException e) {
5853
throw new JedisCacheException("Failed to deserialize object", e);
5954
}
6055
}

src/main/java/redis/clients/jedis/csc/CacheKey.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package redis.clients.jedis.csc;
22

3+
import java.util.List;
34
import java.util.Objects;
5+
46
import redis.clients.jedis.CommandObject;
5-
import redis.clients.jedis.annots.Internal;
7+
import redis.clients.jedis.commands.ProtocolCommand;
68

7-
@Internal
89
public class CacheKey<T> {
910

1011
private final CommandObject<T> command;
@@ -26,11 +27,11 @@ public boolean equals(Object obj) {
2627
return Objects.equals(this.command, other.command);
2728
}
2829

29-
public Object[] getRedisKeys() {
30+
public List<Object> getRedisKeys() {
3031
return command.getArguments().getKeys();
3132
}
3233

33-
public CommandObject<T> getCommand() {
34-
return command;
34+
public ProtocolCommand getRedisCommand() {
35+
return command.getArguments().getCommand();
3536
}
3637
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package redis.clients.jedis.csc;
2+
3+
import java.util.List;
4+
import redis.clients.jedis.commands.ProtocolCommand;
5+
6+
public interface Cacheable {
7+
8+
boolean isCacheable(ProtocolCommand command, List<Object> keys);
9+
}

0 commit comments

Comments
 (0)