Skip to content

Commit 2075633

Browse files
jxblumchristophstrobl
authored andcommitted
Upgrade to Jedis 5.0
Adapt to API changes in the Jedis 5.0 driver. Fix bzPopMaxShouldWorkCorrectly() and bzPopMinShouldWorkCorrectly() tests in JedisClusterConnectionTests. Jedis 5.0 changed the bzpopmax and bzpopmin Redis commands to no longer return an empty (Array)List internally when evaluating and popping from an empty sorted set. A NullPointerException will be thrown if either bzpopmax or bzpopmin commands are executd on an empty Redis sorted set in Jedis 5.0 (vs. Jedis 4.x): Closes #2612 Original pull request: #2716
1 parent d63fd19 commit 2075633

14 files changed

+257
-143
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<xstream>1.4.20</xstream>
2626
<pool>2.11.1</pool>
2727
<lettuce>6.2.6.RELEASE</lettuce>
28-
<jedis>4.4.5</jedis>
28+
<jedis>5.0.1</jedis>
2929
<multithreadedtc>1.01</multithreadedtc>
3030
<netty>4.1.96.Final</netty>
3131
<java-module-name>spring.data.redis</java-module-name>

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
import org.springframework.data.redis.core.ScanCursor;
3131
import org.springframework.data.redis.core.ScanIteration;
3232
import org.springframework.data.redis.core.ScanOptions;
33-
import org.springframework.data.util.Streamable;
3433
import org.springframework.lang.Nullable;
3534
import org.springframework.util.Assert;
3635

3736
/**
37+
* Cluster {@link RedisHashCommands} implementation for Jedis.
38+
*
3839
* @author Christoph Strobl
3940
* @author Mark Paluch
41+
* @author John Blum
4042
* @since 2.0
4143
*/
4244
class JedisClusterHashCommands implements RedisHashCommands {
@@ -160,8 +162,8 @@ public Entry<byte[], byte[]> hRandFieldWithValues(byte[] key) {
160162
Assert.notNull(key, "Key must not be null");
161163

162164
try {
163-
Map<byte[], byte[]> map = connection.getCluster().hrandfieldWithValues(key, 1);
164-
return map.isEmpty() ? null : map.entrySet().iterator().next();
165+
List<Entry<byte[], byte[]>> mapEntryList = connection.getCluster().hrandfieldWithValues(key, 1);
166+
return mapEntryList.isEmpty() ? null : mapEntryList.get(0);
165167
} catch (Exception ex) {
166168
throw convertJedisAccessException(ex);
167169
}
@@ -185,8 +187,7 @@ public List<byte[]> hRandField(byte[] key, long count) {
185187
public List<Entry<byte[], byte[]>> hRandFieldWithValues(byte[] key, long count) {
186188

187189
try {
188-
Map<byte[], byte[]> map = connection.getCluster().hrandfieldWithValues(key, count);
189-
return Streamable.of(() -> map.entrySet().iterator()).toList();
190+
return connection.getCluster().hrandfieldWithValues(key, count);
190191
} catch (Exception ex) {
191192
throw convertJedisAccessException(ex);
192193
}

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java

+15-9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Collection;
2222
import java.util.Collections;
2323
import java.util.List;
24+
import java.util.Map;
2425
import java.util.Map.Entry;
2526
import java.util.Properties;
2627
import java.util.concurrent.TimeUnit;
@@ -249,21 +250,26 @@ public Properties getConfig(String pattern) {
249250

250251
Assert.notNull(pattern, "Pattern must not be null");
251252

252-
List<NodeResult<List<String>>> mapResult = connection.getClusterCommandExecutor()
253-
.executeCommandOnAllNodes((JedisClusterCommandCallback<List<String>>) client -> client.configGet(pattern))
253+
JedisClusterCommandCallback<Map<String, String>> command = jedis -> jedis.configGet(pattern);
254+
255+
List<NodeResult<Map<String, String>>> nodeResults = connection.getClusterCommandExecutor()
256+
.executeCommandOnAllNodes(command)
254257
.getResults();
255258

256-
List<String> result = new ArrayList<>();
257-
for (NodeResult<List<String>> entry : mapResult) {
259+
Properties nodesConfiguration = new Properties();
260+
261+
for (NodeResult<Map<String, String>> nodeResult : nodeResults) {
262+
263+
String prefix = nodeResult.getNode().asString();
258264

259-
String prefix = entry.getNode().asString();
260-
int i = 0;
261-
for (String value : entry.getValue()) {
262-
result.add((i++ % 2 == 0 ? (prefix + ".") : "") + value);
265+
for (Entry<String, String> entry : nodeResult.getValue().entrySet()) {
266+
String newKey = prefix.concat(".").concat(entry.getKey());
267+
String value = entry.getValue();
268+
nodesConfiguration.setProperty(newKey, value);
263269
}
264270
}
265271

266-
return Converters.toProperties(result);
272+
return nodesConfiguration;
267273
}
268274

269275
@Override

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStreamCommands.java

+15-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
import static org.springframework.data.redis.connection.jedis.StreamConverters.*;
1919

20+
import org.springframework.util.StringUtils;
2021
import redis.clients.jedis.BuilderFactory;
2122
import redis.clients.jedis.params.XAddParams;
2223
import redis.clients.jedis.params.XClaimParams;
24+
import redis.clients.jedis.params.XPendingParams;
2325
import redis.clients.jedis.params.XReadGroupParams;
2426
import redis.clients.jedis.params.XReadParams;
2527

@@ -269,9 +271,19 @@ public PendingMessages xPending(byte[] key, String groupName, XPendingOptions op
269271

270272
try {
271273

272-
List<Object> response = connection.getCluster().xpending(key, group,
273-
JedisConverters.toBytes(getLowerValue(range)), JedisConverters.toBytes(getUpperValue(range)),
274-
options.getCount().intValue(), JedisConverters.toBytes(options.getConsumerName()));
274+
@SuppressWarnings("all")
275+
XPendingParams pendingParams = new XPendingParams(
276+
JedisConverters.toBytes(StreamConverters.getLowerValue(range)),
277+
JedisConverters.toBytes(StreamConverters.getUpperValue(range)),
278+
options.getCount().intValue());
279+
280+
String consumerName = options.getConsumerName();
281+
282+
if (StringUtils.hasText(consumerName)) {
283+
pendingParams = pendingParams.consumer(consumerName);
284+
}
285+
286+
List<Object> response = connection.getCluster().xpending(key, group, pendingParams);
275287

276288
return StreamConverters.toPendingMessages(groupName, range,
277289
BuilderFactory.STREAM_PENDING_ENTRY_LIST.build(response));

src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java

+25-25
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import redis.clients.jedis.params.ZParams;
2121
import redis.clients.jedis.params.ZRangeParams;
2222
import redis.clients.jedis.resps.ScanResult;
23+
import redis.clients.jedis.util.KeyValue;
2324

2425
import java.util.ArrayList;
2526
import java.util.LinkedHashSet;
@@ -34,7 +35,6 @@
3435
import org.springframework.data.redis.connection.RedisZSetCommands;
3536
import org.springframework.data.redis.connection.convert.SetConverter;
3637
import org.springframework.data.redis.connection.zset.Aggregate;
37-
import org.springframework.data.redis.connection.zset.DefaultTuple;
3838
import org.springframework.data.redis.connection.zset.Tuple;
3939
import org.springframework.data.redis.connection.zset.Weights;
4040
import org.springframework.data.redis.core.Cursor;
@@ -46,18 +46,22 @@
4646
import org.springframework.util.Assert;
4747

4848
/**
49+
* Cluster {@link RedisZSetCommands} implementation for Jedis.
50+
*
4951
* @author Christoph Strobl
5052
* @author Mark Paluch
5153
* @author Clement Ong
5254
* @author Andrey Shlykov
5355
* @author Jens Deppe
5456
* @author Shyngys Sapraliyev
57+
* @author John Blum
5558
* @since 2.0
5659
*/
5760
class JedisClusterZSetCommands implements RedisZSetCommands {
5861

59-
private static final SetConverter<redis.clients.jedis.resps.Tuple, Tuple> TUPLE_SET_CONVERTER = new SetConverter<>(
60-
JedisConverters::toTuple);
62+
private static final SetConverter<redis.clients.jedis.resps.Tuple, Tuple> TUPLE_SET_CONVERTER =
63+
new SetConverter<>(JedisConverters::toTuple);
64+
6165
private final JedisClusterConnection connection;
6266

6367
JedisClusterZSetCommands(JedisClusterConnection connection) {
@@ -818,7 +822,7 @@ public Set<byte[]> zDiff(byte[]... sets) {
818822
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
819823

820824
try {
821-
return connection.getCluster().zdiff(sets);
825+
return JedisConverters.toSet(connection.getCluster().zdiff(sets));
822826
} catch (Exception ex) {
823827
throw convertJedisAccessException(ex);
824828
}
@@ -835,7 +839,7 @@ public Set<Tuple> zDiffWithScores(byte[]... sets) {
835839
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
836840

837841
try {
838-
return JedisConverters.toTupleSet(connection.getCluster().zdiffWithScores(sets));
842+
return JedisConverters.toSet(JedisConverters.toTupleList(connection.getCluster().zdiffWithScores(sets)));
839843
} catch (Exception ex) {
840844
throw convertJedisAccessException(ex);
841845
}
@@ -872,7 +876,7 @@ public Set<byte[]> zInter(byte[]... sets) {
872876
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
873877

874878
try {
875-
return connection.getCluster().zinter(new ZParams(), sets);
879+
return JedisConverters.toSet(connection.getCluster().zinter(new ZParams(), sets));
876880
} catch (Exception ex) {
877881
throw convertJedisAccessException(ex);
878882
}
@@ -889,7 +893,8 @@ public Set<Tuple> zInterWithScores(byte[]... sets) {
889893
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
890894

891895
try {
892-
return JedisConverters.toTupleSet(connection.getCluster().zinterWithScores(new ZParams(), sets));
896+
return JedisConverters.toSet(JedisConverters.toTupleList(connection.getCluster()
897+
.zinterWithScores(new ZParams(), sets)));
893898
} catch (Exception ex) {
894899
throw convertJedisAccessException(ex);
895900
}
@@ -909,8 +914,8 @@ public Set<Tuple> zInterWithScores(Aggregate aggregate, Weights weights, byte[].
909914
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
910915

911916
try {
912-
return JedisConverters
913-
.toTupleSet(connection.getCluster().zinterWithScores(toZParams(aggregate, weights), sets));
917+
return JedisConverters.toSet(JedisConverters.toTupleList(connection.getCluster()
918+
.zinterWithScores(toZParams(aggregate, weights), sets)));
914919
} catch (Exception ex) {
915920
throw convertJedisAccessException(ex);
916921
}
@@ -971,7 +976,7 @@ public Set<byte[]> zUnion(byte[]... sets) {
971976
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
972977

973978
try {
974-
return connection.getCluster().zunion(new ZParams(), sets);
979+
return JedisConverters.toSet(connection.getCluster().zunion(new ZParams(), sets));
975980
} catch (Exception ex) {
976981
throw convertJedisAccessException(ex);
977982
}
@@ -988,7 +993,8 @@ public Set<Tuple> zUnionWithScores(byte[]... sets) {
988993
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
989994

990995
try {
991-
return JedisConverters.toTupleSet(connection.getCluster().zunionWithScores(new ZParams(), sets));
996+
return JedisConverters.toSet(JedisConverters.toTupleList(connection.getCluster()
997+
.zunionWithScores(new ZParams(), sets)));
992998
} catch (Exception ex) {
993999
throw convertJedisAccessException(ex);
9941000
}
@@ -1008,10 +1014,11 @@ public Set<Tuple> zUnionWithScores(Aggregate aggregate, Weights weights, byte[].
10081014
if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {
10091015

10101016
try {
1011-
return JedisConverters
1012-
.toTupleSet(connection.getCluster().zunionWithScores(toZParams(aggregate, weights), sets));
1017+
return JedisConverters.toSet(JedisConverters.toTupleList(connection.getCluster()
1018+
.zunionWithScores(toZParams(aggregate, weights), sets)));
10131019
} catch (Exception ex) {
10141020
throw convertJedisAccessException(ex);
1021+
10151022
}
10161023
}
10171024

@@ -1126,21 +1133,14 @@ private static ZParams toZParams(Aggregate aggregate, Weights weights) {
11261133
return new ZParams().weights(weights.toArray()).aggregate(ZParams.Aggregate.valueOf(aggregate.name()));
11271134
}
11281135

1129-
/**
1130-
* Workaround for broken Jedis BZPOP signature.
1131-
*
1132-
* @param bytes
1133-
* @return
1134-
*/
11351136
@Nullable
1136-
@SuppressWarnings("unchecked")
1137-
private static Tuple toTuple(@Nullable List<?> bytes) {
1137+
private static Tuple toTuple(@Nullable KeyValue<?, redis.clients.jedis.resps.Tuple> keyValue) {
11381138

1139-
if (bytes == null || bytes.isEmpty()) {
1140-
return null;
1139+
if (keyValue != null) {
1140+
redis.clients.jedis.resps.Tuple tuple = keyValue.getValue();
1141+
return tuple != null ? JedisConverters.toTuple(tuple) : null;
11411142
}
11421143

1143-
return new DefaultTuple((byte[]) bytes.get(1), Double.parseDouble(new String((byte[]) bytes.get(2))));
1144+
return null;
11441145
}
1145-
11461146
}

src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@
5959
import org.springframework.util.Assert;
6060
import org.springframework.util.CollectionUtils;
6161

62-
import org.apache.commons.logging.Log;
63-
import org.apache.commons.logging.LogFactory;
64-
6562
import redis.clients.jedis.BuilderFactory;
6663
import redis.clients.jedis.CommandArguments;
6764
import redis.clients.jedis.CommandObject;
@@ -130,6 +127,7 @@ public class JedisConnection extends AbstractRedisConnection {
130127

131128
private final Log LOGGER = LogFactory.getLog(getClass());
132129

130+
@SuppressWarnings("rawtypes")
133131
private List<JedisResult> pipelinedResults = new ArrayList<>();
134132

135133
private final @Nullable Pool<Jedis> pool;
@@ -348,7 +346,6 @@ public void close() throws DataAccessException {
348346
jedis.close();
349347
}
350348
else {
351-
doExceptionThrowingOperationSafely(jedis::quit, "Failed to quit during close");
352349
doExceptionThrowingOperationSafely(jedis::disconnect, "Failed to disconnect during close");
353350
}
354351
}
@@ -480,6 +477,7 @@ public void discard() {
480477
public List<Object> exec() {
481478

482479
try {
480+
483481
if (transaction == null) {
484482
throw new InvalidDataAccessApiUsageException("No ongoing transaction; Did you forget to call multi");
485483
}
@@ -489,6 +487,7 @@ public List<Object> exec() {
489487
return !CollectionUtils.isEmpty(results)
490488
? new TransactionResultConverter<>(txResults, JedisExceptionConverter.INSTANCE).convert(results)
491489
: results;
490+
492491
} catch (Exception cause) {
493492
throw convertJedisAccessException(cause);
494493
} finally {

0 commit comments

Comments
 (0)