From 96fa2ecd70e2ab14d42c3142303088f74abd625f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 19 Jan 2021 10:48:48 +0100 Subject: [PATCH] Introduce LettuceInvoker. We now use LettuceInvoker to call Lettuce API methods for synchronous, pipelining, and transactional execution models. LettuceInvoker captures the method invocation as functional utility and allows conversion of results: Long result = invoker.just(RedisGeoAsyncCommands::geoadd, key, point.getX(), point.getY(), member); List result = invoker.fromMany(RedisGeoAsyncCommands::geohash, key, members) .toList(it -> it.getValueOrElse(null)); Closes #1797 Original Pull Request #1948 --- .../redis/connection/RedisListCommands.java | 1 + .../LettuceClusterHyperLogLogCommands.java | 19 +- .../connection/lettuce/LettuceConnection.java | 417 +++++------ .../connection/lettuce/LettuceConverters.java | 2 +- .../lettuce/LettuceGeoCommands.java | 192 +---- .../lettuce/LettuceHashCommands.java | 239 +------ .../lettuce/LettuceHyperLogLogCommands.java | 84 +-- .../connection/lettuce/LettuceInvoker.java | 665 ++++++++++++++++++ .../lettuce/LettuceKeyCommands.java | 439 +----------- .../lettuce/LettuceListCommands.java | 311 +------- .../lettuce/LettuceScriptingCommands.java | 147 +--- .../lettuce/LettuceServerCommands.java | 365 ++-------- .../lettuce/LettuceSetCommands.java | 260 +------ .../lettuce/LettuceStreamCommands.java | 428 ++--------- .../lettuce/LettuceStringCommands.java | 503 ++----------- .../lettuce/LettuceZSetCommands.java | 604 ++-------------- .../LettuceClusterConnectionUnitTests.java | 19 +- .../LettuceConnectionFactoryTests.java | 1 - 18 files changed, 1257 insertions(+), 3439 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceInvoker.java diff --git a/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java index 1d69e18f3..12ac4432e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java @@ -75,6 +75,7 @@ public interface RedisListCommands { * @see Redis Documentation: LPOS * @since 2.4 */ + @Nullable List lPos(byte[] key, byte[] element, @Nullable Integer rank, @Nullable Integer count); /** diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java index db641048c..3464949db 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java @@ -38,14 +38,9 @@ class LettuceClusterHyperLogLogCommands extends LettuceHyperLogLogCommands { public Long pfCount(byte[]... keys) { if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - - try { - return super.pfCount(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - + return super.pfCount(keys); } + throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfcount in cluster mode."); } @@ -59,14 +54,10 @@ class LettuceClusterHyperLogLogCommands extends LettuceHyperLogLogCommands { byte[][] allKeys = ByteUtils.mergeArrays(destinationKey, sourceKeys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - super.pfMerge(destinationKey, sourceKeys); - return; - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - + super.pfMerge(destinationKey, sourceKeys); + return; } + throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfmerge in cluster mode."); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index 16d5707c7..e89e0c3ee 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -20,7 +20,6 @@ import static io.lettuce.core.protocol.CommandType.*; import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.LettuceFutures; import io.lettuce.core.RedisClient; -import io.lettuce.core.RedisException; import io.lettuce.core.RedisFuture; import io.lettuce.core.RedisURI; import io.lettuce.core.TransactionResult; @@ -53,7 +52,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; import java.util.function.Supplier; import org.springframework.beans.BeanUtils; @@ -108,7 +106,7 @@ public class LettuceConnection extends AbstractRedisConnection { private boolean isClosed = false; private boolean isMulti = false; private boolean isPipelined = false; - private @Nullable List ppline; + private @Nullable List> ppline; private @Nullable PipeliningFlushState flushState; private final Queue> txResults = new LinkedList<>(); private volatile @Nullable LettuceSubscription subscription; @@ -116,22 +114,20 @@ public class LettuceConnection extends AbstractRedisConnection { private boolean convertPipelineAndTxResults = true; private PipeliningFlushPolicy pipeliningFlushPolicy = PipeliningFlushPolicy.flushEachCommand(); - LettuceResult newLettuceResult(Future resultHolder) { + LettuceResult newLettuceResult(Future resultHolder) { return newLettuceResult(resultHolder, (val) -> val); } - @SuppressWarnings("unchecked") LettuceResult newLettuceResult(Future resultHolder, Converter converter) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) + return LettuceResultBuilder. forResponse(resultHolder).mappedWith(converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).build(); } - @SuppressWarnings("unchecked") LettuceResult newLettuceResult(Future resultHolder, Converter converter, Supplier defaultValue) { - return LettuceResultBuilder.forResponse(resultHolder).mappedWith((Converter) converter) + return LettuceResultBuilder. forResponse(resultHolder).mappedWith(converter) .convertPipelineAndTxResults(convertPipelineAndTxResults).defaultNullTo(defaultValue).build(); } @@ -372,17 +368,6 @@ public class LettuceConnection extends AbstractRedisConnection { return new LettuceZSetCommands(this); } - @Nullable - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Object await(RedisFuture cmd) { - - if (isMulti) { - return null; - } - - return LettuceFutures.awaitOrCancel(cmd, timeout, TimeUnit.MILLISECONDS); - } - @Override public Object execute(String command, byte[]... args) { return execute(command, null, args); @@ -402,40 +387,22 @@ public class LettuceConnection extends AbstractRedisConnection { public Object execute(String command, @Nullable CommandOutput commandOutputTypeHint, byte[]... args) { Assert.hasText(command, "a valid command needs to be specified"); - try { - String name = command.trim().toUpperCase(); - CommandType commandType = CommandType.valueOf(name); + String name = command.trim().toUpperCase(); + CommandType commandType = CommandType.valueOf(name); - validateCommandIfRunningInTransactionMode(commandType, args); + validateCommandIfRunningInTransactionMode(commandType, args); - CommandArgs cmdArg = new CommandArgs<>(CODEC); - if (!ObjectUtils.isEmpty(args)) { - cmdArg.addKeys(args); - } - - RedisClusterAsyncCommands connectionImpl = getAsyncConnection(); - - CommandOutput expectedOutput = commandOutputTypeHint != null ? commandOutputTypeHint - : typeHints.getTypeHint(commandType); - Command cmd = new Command(commandType, expectedOutput, cmdArg); - - if (isPipelined()) { - - pipeline(newLettuceResult(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs()))); - return null; - } - - if (isQueueing()) { - - transaction(newLettuceResult(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs()))); - return null; - } - - return await(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs())); - } catch (RedisException ex) { - throw convertLettuceAccessException(ex); + CommandArgs cmdArg = new CommandArgs<>(CODEC); + if (!ObjectUtils.isEmpty(args)) { + cmdArg.addKeys(args); } + + CommandOutput expectedOutput = commandOutputTypeHint != null ? commandOutputTypeHint + : typeHints.getTypeHint(commandType); + Command cmd = new Command(commandType, expectedOutput, cmdArg); + + return invoke().just(RedisClusterAsyncCommands::dispatch, cmd.getType(), cmd.getOutput(), cmd.getArgs()); } /* @@ -600,36 +567,12 @@ public class LettuceConnection extends AbstractRedisConnection { */ @Override public byte[] echo(byte[] message) { - try { - if (isPipelined()) { - pipeline(newLettuceResult(getAsyncConnection().echo(message))); - return null; - } - if (isQueueing()) { - transaction(newLettuceResult(getAsyncConnection().echo(message))); - return null; - } - return getConnection().echo(message); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return invoke().just(RedisClusterAsyncCommands::echo, message); } @Override public String ping() { - try { - if (isPipelined()) { - pipeline(newLettuceResult(getAsyncConnection().ping())); - return null; - } - if (isQueueing()) { - transaction(newLettuceResult(getAsyncConnection().ping())); - return null; - } - return getConnection().ping(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return invoke().just(RedisClusterAsyncCommands::ping); } @Override @@ -703,29 +646,15 @@ public class LettuceConnection extends AbstractRedisConnection { + "Use separate ConnectionFactorys to work with multiple databases"); } - try { + this.dbIndex = dbIndex; - this.dbIndex = dbIndex; - - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().dispatch(CommandType.SELECT, - new StatusOutput<>(ByteArrayCodec.INSTANCE), new CommandArgs<>(ByteArrayCodec.INSTANCE).add(dbIndex)))); - return; - } - - if (isQueueing()) { - transaction(newLettuceStatusResult(getAsyncConnection().dispatch(CommandType.SELECT, - new StatusOutput<>(ByteArrayCodec.INSTANCE), new CommandArgs<>(ByteArrayCodec.INSTANCE).add(dbIndex)))); - return; - } - ((RedisCommands) getConnection()).select(dbIndex); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + invokeStatus().just(RedisClusterAsyncCommands::dispatch, CommandType.SELECT, + new StatusOutput<>(ByteArrayCodec.INSTANCE), new CommandArgs<>(ByteArrayCodec.INSTANCE).add(dbIndex)); } @Override public void unwatch() { + try { if (isPipelined()) { pipeline(newLettuceStatusResult(getAsyncDedicatedRedisCommands().unwatch())); @@ -771,23 +700,7 @@ public class LettuceConnection extends AbstractRedisConnection { */ @Override public Long publish(byte[] channel, byte[] message) { - - try { - - if (isPipelined()) { - pipeline(newLettuceResult(getAsyncConnection().publish(channel, message))); - return null; - } - - if (isQueueing()) { - transaction(newLettuceResult(getAsyncConnection().publish(channel, message))); - return null; - } - - return getConnection().publish(channel, message); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return invoke().just(RedisClusterAsyncCommands::publish, channel, message); } /* @@ -887,13 +800,6 @@ public class LettuceConnection extends AbstractRedisConnection { this.pipeliningFlushPolicy = pipeliningFlushPolicy; } - private void checkSubscription() { - if (isSubscribed()) { - throw new RedisSubscribedConnectionException( - "Connection already subscribed; use the connection Subscription to cancel or add new channels"); - } - } - /** * {@link #close()} the current connection and open a new pub/sub connection to the Redis server. * @@ -906,10 +812,6 @@ public class LettuceConnection extends AbstractRedisConnection { return connectionProvider.getConnection(StatefulRedisPubSubConnection.class); } - private LettuceSubscription initSubscription(MessageListener listener) { - return doCreateSubscription(listener, switchToPubSub(), connectionProvider); - } - /** * Customization hook to create a {@link LettuceSubscription}. * @@ -924,7 +826,7 @@ public class LettuceConnection extends AbstractRedisConnection { return new LettuceSubscription(listener, connection, connectionProvider); } - void pipeline(LettuceResult result) { + void pipeline(LettuceResult result) { if (flushState != null) { flushState.onCommand(getOrCreateDedicatedConnection()); @@ -937,77 +839,90 @@ public class LettuceConnection extends AbstractRedisConnection { } } - void executeInPipeline(Function> command, - Converter converter) { - - try { - pipeline(newLettuceResult(command.apply(getAsyncConnection()), converter)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + /** + * Obtain a {@link LettuceInvoker} to call Lettuce methods using the default {@link #getAsyncConnection() connection}. + * + * @return the {@link LettuceInvoker}. + * @since 2.5 + */ + LettuceInvoker invoke() { + return invoke(getAsyncConnection()); } - void executeInTx(Function> command, Converter converter) { - - try { - transaction(newLettuceResult(command.apply(getAsyncConnection()), converter)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + /** + * Obtain a {@link LettuceInvoker} to call Lettuce methods using the given {@link RedisClusterAsyncCommands + * connection}. + * + * @param connection the connection to use. + * @return the {@link LettuceInvoker}. + * @since 2.5 + */ + LettuceInvoker invoke(RedisClusterAsyncCommands connection) { + return doInvoke(connection, false); } - NullableResult execute(Function command) { - - try { - - T result = command.apply(getConnection()); - return NullableResult.of(result); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + /** + * Obtain a {@link LettuceInvoker} to call Lettuce methods returning a status response using the default + * {@link #getAsyncConnection() connection}. Status responses are not included in transactional and pipeline results. + * + * @return the {@link LettuceInvoker}. + * @since 2.5 + */ + LettuceInvoker invokeStatus() { + return doInvoke(getAsyncConnection(), true); } - RedisFuture executeAsync(Function> command) { - - try { - return command.apply(getAsyncConnection()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - T invoke(RedisFuture future, Converter converter) { + private LettuceInvoker doInvoke(RedisClusterAsyncCommands connection, boolean statusCommand) { if (isPipelined()) { - pipeline(newLettuceResult(future, converter)); - return null; + + return new LettuceInvoker(connection, (future, converter, nullDefault) -> { + + try { + if (statusCommand) { + pipeline(newLettuceStatusResult(future.get())); + } else { + pipeline(newLettuceResult(future.get(), converter, nullDefault)); + } + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + return null; + }); } + if (isQueueing()) { - transaction(newLettuceResult(future, converter)); - return null; - } - return NullableResult.of((S) await(future)).convert(converter).get(); - } - T execute(Function sync, Function> async) { - return execute(sync, async, val -> val); - } + return new LettuceInvoker(connection, (future, converter, nullDefault) -> { + try { + if (statusCommand) { + transaction(newLettuceStatusResult(future.get())); + } else { + transaction(newLettuceResult(future.get(), converter, nullDefault)); + } - // use a future here and only async. - T execute(Function sync, Function> async, - Converter converter) { - - if (isPipelined()) { - executeInPipeline(async, converter); - return null; - } - if (isQueueing()) { - executeInTx(async, converter); - return null; + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + return null; + }); } - // return execute(sync).convert(converter).get(); - return NullableResult.of((S) await(executeAsync(async))).convert(converter).get(); + return new LettuceInvoker(connection, (future, converter, nullDefault) -> { + + try { + + Object result = await(future.get()); + + if (result == null) { + return nullDefault.get(); + } + + return converter.convert(result); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + }); } void transaction(FutureResult result) { @@ -1015,14 +930,19 @@ public class LettuceConnection extends AbstractRedisConnection { } RedisClusterAsyncCommands getAsyncConnection() { + if (isQueueing()) { return getAsyncDedicatedConnection(); } + if (asyncSharedConn != null) { if (asyncSharedConn instanceof StatefulRedisConnection) { return ((StatefulRedisConnection) asyncSharedConn).async(); } + if (asyncSharedConn instanceof StatefulRedisClusterConnection) { + return ((StatefulRedisClusterConnection) asyncSharedConn).async(); + } } return getAsyncDedicatedConnection(); } @@ -1032,6 +952,7 @@ public class LettuceConnection extends AbstractRedisConnection { if (isQueueing()) { return getDedicatedConnection(); } + if (asyncSharedConn != null) { if (asyncSharedConn instanceof StatefulRedisConnection) { @@ -1041,12 +962,8 @@ public class LettuceConnection extends AbstractRedisConnection { return ((StatefulRedisClusterConnection) asyncSharedConn).sync(); } } - return getDedicatedConnection(); - } - @SuppressWarnings("unchecked") - private RedisAsyncCommands getAsyncDedicatedRedisCommands() { - return (RedisAsyncCommands) getAsyncDedicatedConnection(); + return getDedicatedConnection(); } RedisClusterCommands getDedicatedConnection() { @@ -1079,6 +996,69 @@ public class LettuceConnection extends AbstractRedisConnection { String.format("%s is not a supported connection type.", connection.getClass().getName())); } + @SuppressWarnings("unchecked") + protected StatefulConnection doGetAsyncDedicatedConnection() { + + StatefulConnection connection = connectionProvider.getConnection(StatefulConnection.class); + + if (customizedDatabaseIndex()) { + potentiallySelectDatabase(dbIndex); + } + + return connection; + } + + @Override + protected boolean isActive(RedisNode node) { + + StatefulRedisSentinelConnection connection = null; + try { + connection = getConnection(node); + return connection.sync().ping().equalsIgnoreCase("pong"); + } catch (Exception e) { + return false; + } finally { + if (connection != null) { + connectionProvider.release(connection); + } + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.AbstractRedisConnection#getSentinelConnection(org.springframework.data.redis.connection.RedisNode) + */ + @Override + protected RedisSentinelConnection getSentinelConnection(RedisNode sentinel) { + + StatefulRedisSentinelConnection connection = getConnection(sentinel); + return new LettuceSentinelConnection(connection); + } + + LettuceConnectionProvider getConnectionProvider() { + return connectionProvider; + } + + @SuppressWarnings("unchecked") + private StatefulRedisSentinelConnection getConnection(RedisNode sentinel) { + return ((TargetAware) connectionProvider).getConnection(StatefulRedisSentinelConnection.class, + getRedisURI(sentinel)); + } + + @Nullable + private T await(RedisFuture cmd) { + + if (isMulti) { + return null; + } + + try { + return LettuceFutures.awaitOrCancel(cmd, timeout, TimeUnit.MILLISECONDS); + } catch (RuntimeException e) { + throw convertLettuceAccessException(e); + } + } + private StatefulConnection getOrCreateDedicatedConnection() { if (asyncDedicatedConn == null) { @@ -1094,15 +1074,23 @@ public class LettuceConnection extends AbstractRedisConnection { } @SuppressWarnings("unchecked") - protected StatefulConnection doGetAsyncDedicatedConnection() { + private RedisAsyncCommands getAsyncDedicatedRedisCommands() { + return (RedisAsyncCommands) getAsyncDedicatedConnection(); + } - StatefulConnection connection = connectionProvider.getConnection(StatefulConnection.class); - - if (customizedDatabaseIndex()) { - potentiallySelectDatabase(dbIndex); + private void checkSubscription() { + if (isSubscribed()) { + throw new RedisSubscribedConnectionException( + "Connection already subscribed; use the connection Subscription to cancel or add new channels"); } + } - return connection; + private LettuceSubscription initSubscription(MessageListener listener) { + return doCreateSubscription(listener, switchToPubSub(), connectionProvider); + } + + private RedisURI getRedisURI(RedisNode node) { + return RedisURI.Builder.redis(node.getHost(), node.getPort()).build(); } private boolean customizedDatabaseIndex() { @@ -1138,47 +1126,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - @Override - protected boolean isActive(RedisNode node) { - - StatefulRedisSentinelConnection connection = null; - try { - connection = getConnection(node); - return connection.sync().ping().equalsIgnoreCase("pong"); - } catch (Exception e) { - return false; - } finally { - if (connection != null) { - connectionProvider.release(connection); - } - } - } - - private RedisURI getRedisURI(RedisNode node) { - return RedisURI.Builder.redis(node.getHost(), node.getPort()).build(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.AbstractRedisConnection#getSentinelConnection(org.springframework.data.redis.connection.RedisNode) - */ - @Override - protected RedisSentinelConnection getSentinelConnection(RedisNode sentinel) { - - StatefulRedisSentinelConnection connection = getConnection(sentinel); - return new LettuceSentinelConnection(connection); - } - - @SuppressWarnings("unchecked") - private StatefulRedisSentinelConnection getConnection(RedisNode sentinel) { - return ((TargetAware) connectionProvider).getConnection(StatefulRedisSentinelConnection.class, - getRedisURI(sentinel)); - } - - LettuceConnectionProvider getConnectionProvider() { - return connectionProvider; - } - /** * {@link TypeHints} provide {@link CommandOutput} information for a given {@link CommandType}. * @@ -1481,7 +1428,7 @@ public class LettuceConnection extends AbstractRedisConnection { /** * State object associated with flushing of the currently ongoing pipeline. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1514,7 +1461,7 @@ public class LettuceConnection extends AbstractRedisConnection { /** * Implementation to flush on each command. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1539,7 +1486,7 @@ public class LettuceConnection extends AbstractRedisConnection { /** * Implementation to flush on closing the pipeline. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1571,7 +1518,7 @@ public class LettuceConnection extends AbstractRedisConnection { /** * Pipeline state for buffered flushing. - * + * * @author Mark Paluch * @since 2.3 */ diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index a9c71f9a5..6d334f17d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -104,7 +104,7 @@ abstract public class LettuceConverters extends Converters { private static final Converter> PARTITIONS_TO_CLUSTER_NODES; private static Converter CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER; private static final Converter, Long> BYTES_LIST_TO_TIME_CONVERTER; - private static final Converter GEO_COORDINATE_TO_POINT_CONVERTER; + public static final Converter GEO_COORDINATE_TO_POINT_CONVERTER; private static final ListConverter GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER; private static final Converter, Object> KEY_VALUE_UNWRAPPER; private static final ListConverter, Object> KEY_VALUE_LIST_UNWRAPPER; diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java index 915fd1918..5822cd36c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java @@ -16,10 +16,8 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.GeoArgs; -import io.lettuce.core.GeoCoordinates; import io.lettuce.core.GeoWithin; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisGeoAsyncCommands; import java.util.ArrayList; import java.util.Collection; @@ -27,18 +25,14 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; -import org.springframework.dao.DataAccessException; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; -import org.springframework.data.redis.connection.NullableResult; import org.springframework.data.redis.connection.RedisGeoCommands; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -66,19 +60,7 @@ class LettuceGeoCommands implements RedisGeoCommands { Assert.notNull(point, "Point must not be null!"); Assert.notNull(member, "Member must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geoadd(key, point.getX(), point.getY(), member))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().geoadd(key, point.getX(), point.getY(), member))); - return null; - } - return getConnection().geoadd(key, point.getX(), point.getY(), member); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisGeoAsyncCommands::geoadd, key, point.getX(), point.getY(), member); } /* @@ -125,21 +107,7 @@ class LettuceGeoCommands implements RedisGeoCommands { @Nullable private Long geoAdd(byte[] key, Collection values) { - - try { - - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geoadd(key, values.toArray()))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().geoadd(key, values.toArray()))); - return null; - } - return getConnection().geoadd(key, values.toArray()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(it -> it.geoadd(key, values.toArray())); } /* @@ -166,12 +134,8 @@ class LettuceGeoCommands implements RedisGeoCommands { GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(metric); Converter distanceConverter = LettuceConverters.distanceConverterForMetric(metric); -// return connection.execute( -// sync -> sync.geodist(key, member1, member2, geoUnit), -// async -> async.geodist(key, member1, member2, geoUnit), -// distanceConverter); - - return connection.invoke(connection.getAsyncConnection().geodist(key, member1, member2, geoUnit), distanceConverter); + return connection.invoke().from(RedisGeoAsyncCommands::geodist, key, member1, member2, geoUnit) + .get(distanceConverter); } /* @@ -185,20 +149,8 @@ class LettuceGeoCommands implements RedisGeoCommands { Assert.notNull(members, "Members must not be null!"); Assert.noNullElements(members, "Members must not contain null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geohash(key, members))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().geohash(key, members))); - return null; - } - return getConnection().geohash(key, members).stream().map(value -> value.getValueOrElse(null)) - .collect(Collectors.toList()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisGeoAsyncCommands::geohash, key, members) + .toList(it -> it.getValueOrElse(null)); } /* @@ -212,21 +164,8 @@ class LettuceGeoCommands implements RedisGeoCommands { Assert.notNull(members, "Members must not be null!"); Assert.noNullElements(members, "Members must not contain null!"); - ListConverter converter = LettuceConverters.geoCoordinatesToPointConverter(); - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geopos(key, members), converter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().geopos(key, members), converter)); - return null; - } - return converter.convert(getConnection().geopos(key, members)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisGeoAsyncCommands::geopos, key, members) + .toList(LettuceConverters.GEO_COORDINATE_TO_POINT_CONVERTER); } /* @@ -242,27 +181,10 @@ class LettuceGeoCommands implements RedisGeoCommands { Converter, GeoResults>> geoResultsConverter = LettuceConverters .bytesSetToGeoResultsConverter(); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric())), - geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric())), - geoResultsConverter)); - return null; - } - return geoResultsConverter - .convert(getConnection().georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke() + .from(it -> it.georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()))) + .get(geoResultsConverter); } /* @@ -280,25 +202,10 @@ class LettuceGeoCommands implements RedisGeoCommands { Converter>, GeoResults>> geoResultsConverter = LettuceConverters .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().georadius(key, within.getCenter().getX(), - within.getCenter().getY(), within.getRadius().getValue(), - LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()), geoArgs), geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().georadius(key, within.getCenter().getX(), - within.getCenter().getY(), within.getRadius().getValue(), - LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()), geoArgs), geoResultsConverter)); - return null; - } - return geoResultsConverter - .convert(getConnection().georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()), geoArgs)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke() + .from(it -> it.georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()), geoArgs)) + .get(geoResultsConverter); } /* @@ -325,21 +232,8 @@ class LettuceGeoCommands implements RedisGeoCommands { Converter, GeoResults>> converter = LettuceConverters .bytesSetToGeoResultsConverter(); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit), converter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit), converter)); - return null; - } - return converter.convert(getConnection().georadiusbymember(key, member, radius.getValue(), geoUnit)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisGeoAsyncCommands::georadiusbymember, key, member, radius.getValue(), geoUnit) + .get(converter); } /* @@ -360,24 +254,9 @@ class LettuceGeoCommands implements RedisGeoCommands { Converter>, GeoResults>> geoResultsConverter = LettuceConverters .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit, geoArgs), - geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit, geoArgs), - geoResultsConverter)); - return null; - } - return geoResultsConverter - .convert(getConnection().georadiusbymember(key, member, radius.getValue(), geoUnit, geoArgs)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke() + .from(RedisGeoAsyncCommands::georadiusbymember, key, member, radius.getValue(), geoUnit, geoArgs) + .get(geoResultsConverter); } /* @@ -389,31 +268,4 @@ class LettuceGeoCommands implements RedisGeoCommands { return connection.zSetCommands().zRem(key, values); } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java index 873f429db..627e107c9 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java @@ -17,15 +17,13 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.MapScanCursor; import io.lettuce.core.ScanArgs; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisHashAsyncCommands; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisHashCommands; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; @@ -58,19 +56,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(field, "Field must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hset(key, field, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hset(key, field, value))); - return null; - } - return getConnection().hset(key, field, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hset, key, field, value); } /* @@ -84,19 +70,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(field, "Field must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hsetnx(key, field, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hsetnx(key, field, value))); - return null; - } - return getConnection().hsetnx(key, field, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hsetnx, key, field, value); } /* @@ -109,19 +83,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(fields, "Fields must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hdel(key, fields))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hdel(key, fields))); - return null; - } - return getConnection().hdel(key, fields); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hdel, key, fields); } /* @@ -134,19 +96,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Fields must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hexists(key, field))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hexists(key, field))); - return null; - } - return getConnection().hexists(key, field); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hexists, key, field); } /* @@ -159,19 +109,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hget(key, field))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hget(key, field))); - return null; - } - return getConnection().hget(key, field); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hget, key, field); } /* @@ -183,19 +121,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hgetall(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hgetall(key))); - return null; - } - return getConnection().hgetall(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hgetall, key); } /* @@ -208,19 +134,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hincrby(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hincrby(key, field, delta))); - return null; - } - return getConnection().hincrby(key, field, delta); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hincrby, key, field, delta); } /* @@ -233,19 +147,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); - return null; - } - return getConnection().hincrbyfloat(key, field, delta); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hincrbyfloat, key, field, delta); } /* @@ -257,20 +159,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().hkeys(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisHashAsyncCommands::hkeys, key).get(LettuceConverters.bytesListToBytesSet()); } /* @@ -282,19 +171,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hlen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hlen(key))); - return null; - } - return getConnection().hlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hlen, key); } /* @@ -307,21 +184,8 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(fields, "Fields must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hmget(key, fields), - LettuceConverters.keyValueListUnwrapper())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hmget(key, fields), - LettuceConverters.keyValueListUnwrapper())); - return null; - } - return LettuceConverters. keyValueListUnwrapper().convert(getConnection().hmget(key, fields)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisHashAsyncCommands::hmget, key, fields) + .toList(source -> source.getValueOrElse(null)); } /* @@ -334,19 +198,7 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(hashes, "Hashes must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, hashes))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, hashes))); - return; - } - getConnection().hmset(key, hashes); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisHashAsyncCommands::hmset, key, hashes); } /* @@ -358,22 +210,11 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hvals(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hvals(key))); - return null; - } - return getConnection().hvals(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHashAsyncCommands::hvals, key); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) */ @Override @@ -397,14 +238,15 @@ class LettuceHashCommands implements RedisHashCommands { @Override protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { - if (isQueueing() || isPipelined()) { + if (connection.isQueueing() || connection.isPipelined()) { throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); ScanArgs scanArgs = LettuceConverters.toScanArgs(options); - MapScanCursor mapScanCursor = getConnection().hscan(key, scanCursor, scanArgs); + MapScanCursor mapScanCursor = connection.invoke().just(RedisHashAsyncCommands::hscan, key, + scanCursor, scanArgs); String nextCursorId = mapScanCursor.getCursor(); Map values = mapScanCursor.getMap(); @@ -429,47 +271,8 @@ class LettuceHashCommands implements RedisHashCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(field, "Field must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().hstrlen(key, field))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().hstrlen(key, field))); - return null; - } - return getConnection().hstrlen(key, field); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + return connection.invoke().just(RedisHashAsyncCommands::hstrlen, key, field); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java index 6e8bb1269..bb981df2f 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java @@ -15,11 +15,8 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.api.sync.RedisHLLCommands; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisHLLAsyncCommands; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisHyperLogLogCommands; import org.springframework.util.Assert; @@ -46,22 +43,7 @@ class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { Assert.notEmpty(values, "PFADD requires at least one non 'null' value."); Assert.noNullElements(values, "Values for PFADD must not contain 'null'."); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pfadd(key, values))); - return null; - } - - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pfadd(key, values))); - return null; - } - - RedisHLLCommands connection = getConnection(); - return connection.pfadd(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHLLAsyncCommands::pfadd, key, values); } /* @@ -74,22 +56,7 @@ class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); Assert.noNullElements(keys, "Keys for PFCOUNT must not contain 'null'."); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pfcount(keys))); - return null; - } - - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pfcount(keys))); - return null; - } - - RedisHLLCommands connection = getConnection(); - return connection.pfcount(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisHLLAsyncCommands::pfcount, keys); } /* @@ -103,49 +70,6 @@ class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { Assert.notNull(sourceKeys, "Source keys must not be null"); Assert.noNullElements(sourceKeys, "Keys for PFMERGE must not contain 'null'."); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pfmerge(destinationKey, sourceKeys))); - return; - } - - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pfmerge(destinationKey, sourceKeys))); - return; - } - - RedisHLLCommands connection = getConnection(); - connection.pfmerge(destinationKey, sourceKeys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - protected DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + connection.invoke().just(RedisHLLAsyncCommands::pfmerge, destinationKey, sourceKeys); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceInvoker.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceInvoker.java new file mode 100644 index 000000000..83af96084 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceInvoker.java @@ -0,0 +1,665 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis.connection.lettuce; + +import io.lettuce.core.RedisFuture; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * Utility for functional invocation of {@link RedisClusterAsyncCommands Lettuce methods}. Typically used to express the + * method call as method reference and passing method arguments through one of the {@code just} or {@code from} methods. + *

+ * {@code just} methods record the method call and evaluate the method result immediately. {@code from} methods allows + * composing a functional pipeline to transform the result using a {@link Converter}. + *

+ * Usage example: + * + *

+ * LettuceInvoker invoker = …;
+ *
+ * Long result = invoker.just(RedisGeoAsyncCommands::geoadd, key, point.getX(), point.getY(), member);
+ *
+ * List<byte[]> result = invoker.fromMany(RedisGeoAsyncCommands::geohash, key, members)
+ * 				.toList(it -> it.getValueOrElse(null));
+ * 
+ *

+ * The actual translation from {@link RedisFuture} is delegated to {@link Synchronizer} which can either await + * completion or record the future along {@link Converter} for further processing. + * + * @author Mark Paluch + * @since 2.5 + */ +class LettuceInvoker { + + private final RedisClusterAsyncCommands connection; + private final Synchronizer synchronizer; + + LettuceInvoker(RedisClusterAsyncCommands connection, Synchronizer synchronizer) { + this.connection = connection; + this.synchronizer = synchronizer; + } + + /** + * Returns a {@link Converter} that always returns its input argument. + * + * @param the type of the input and output objects to the function + * @return a function that always returns its input argument + */ + static Converter identityConverter() { + return t -> t; + } + + /** + * Invoke the {@link ConnectionFunction0} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction0 function) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection), identityConverter(), () -> null); + } + + /** + * Invoke the {@link ConnectionFunction1} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction1 function, T1 t1) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection, t1)); + } + + /** + * Invoke the {@link ConnectionFunction2} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction2 function, T1 t1, T2 t2) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection, t1, t2)); + } + + /** + * Invoke the {@link ConnectionFunction3} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction3 function, T1 t1, T2 t2, T3 t3) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection, t1, t2, t3)); + } + + /** + * Invoke the {@link ConnectionFunction4} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction4 function, T1 t1, T2 t2, T3 t3, T4 t4) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection, t1, t2, t3, t4)); + } + + /** + * Invoke the {@link ConnectionFunction5} and return its result. + * + * @param function must not be {@literal null}. + */ + @Nullable + R just(ConnectionFunction5 function, T1 t1, T2 t2, T3 t3, T4 t4, + T5 t5) { + Assert.notNull(function, "ConnectionFunction must not be null"); + + return synchronizer.invoke(() -> function.apply(connection, t1, t2, t3, t4, t5)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction0} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction0 function) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return new DefaultSingleInvocationSpec<>(() -> function.apply(connection), synchronizer); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction1} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction1 function, T1 t1) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return from(it -> function.apply(it, t1)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction2} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction2 function, T1 t1, T2 t2) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return from(it -> function.apply(it, t1, t2)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction3} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction3 function, T1 t1, T2 t2, T3 t3) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return from(it -> function.apply(it, t1, t2, t3)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction4} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction4 function, T1 t1, T2 t2, T3 t3, + T4 t4) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return from(it -> function.apply(it, t1, t2, t3, t4)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction5} and return a {@link SingleInvocationSpec} for + * further composition. + * + * @param function must not be {@literal null}. + */ + SingleInvocationSpec from(ConnectionFunction5 function, T1 t1, + T2 t2, T3 t3, T4 t4, T5 t5) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return from(it -> function.apply(it, t1, t2, t3, t4, t5)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction0} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E> ManyInvocationSpec fromMany(ConnectionFunction0 function) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return new DefaultManyInvocationSpec<>(() -> function.apply(connection), synchronizer); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction1} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E, T1> ManyInvocationSpec fromMany(ConnectionFunction1 function, T1 t1) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return fromMany(it -> function.apply(it, t1)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction2} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E, T1, T2> ManyInvocationSpec fromMany(ConnectionFunction2 function, T1 t1, + T2 t2) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return fromMany(it -> function.apply(it, t1, t2)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction3} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E, T1, T2, T3> ManyInvocationSpec fromMany(ConnectionFunction3 function, + T1 t1, T2 t2, T3 t3) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return fromMany(it -> function.apply(it, t1, t2, t3)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction4} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E, T1, T2, T3, T4> ManyInvocationSpec fromMany( + ConnectionFunction4 function, T1 t1, T2 t2, T3 t3, T4 t4) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return fromMany(it -> function.apply(it, t1, t2, t3, t4)); + } + + /** + * Compose a invocation pipeline from the {@link ConnectionFunction5} that returns a {@link Collection}-like result + * and return a {@link ManyInvocationSpec} for further composition. + * + * @param function must not be {@literal null}. + */ + , E, T1, T2, T3, T4, T5> ManyInvocationSpec fromMany( + ConnectionFunction5 function, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { + + Assert.notNull(function, "ConnectionFunction must not be null"); + + return fromMany(it -> function.apply(it, t1, t2, t3, t4, t5)); + } + + /** + * Represents an element in the invocation pipleline allowing consuming the result by applying a {@link Converter}. + * + * @param + */ + public interface SingleInvocationSpec { + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result after applying + * {@link Converter}. + * + * @param converter must not be {@literal null}. + * @param target type. + * @return the converted result, can be {@literal null}. + */ + @Nullable + T get(Converter converter); + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result after applying + * {@link Converter}. + * + * @param converter must not be {@literal null}. + * @param nullDefault must not be {@literal null}. + * @param target type. + * @return the converted result, can be {@literal null}. + */ + @Nullable + T getOrElse(Converter converter, Supplier nullDefault); + } + + /** + * Represents an element in the invocation pipleline for methods returning {@link Collection}-like results allowing + * consuming the result by applying a {@link Converter}. + * + * @param + */ + public interface ManyInvocationSpec { + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result. + * + * @return the result as {@link List}. + */ + default List toList() { + return toList(identityConverter()); + } + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result after applying + * {@link Converter}. + * + * @param converter must not be {@literal null}. + * @param target type. + * @return the converted {@link List}. + */ + List toList(Converter converter); + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result. + * + * @return the result as {@link Set}. + */ + default Set toSet() { + return toSet(identityConverter()); + } + + /** + * Materialize the pipeline by invoking the {@code ConnectionFunction} and returning the result after applying + * {@link Converter}. + * + * @param converter must not be {@literal null}. + * @param target type. + * @return the converted {@link Set}. + */ + Set toSet(Converter converter); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 0 arguments. + * + * @param + */ + @FunctionalInterface + public interface ConnectionFunction0 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 1 argument. + * + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction1 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 2 arguments. + * + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction2 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 3 arguments. + * + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction3 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 4 arguments. + * + * @param + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction4 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3, T4 t4); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 5 arguments. + * + * @param + * @param + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction5 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 6 arguments. + * + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction6 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, + T6 t6); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 7 arguments. + * + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction7 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, + T7 t7); + } + + /** + * A function accepting {@link RedisClusterAsyncCommands} with 8 arguments. + * + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + @FunctionalInterface + public interface ConnectionFunction8 { + + /** + * Apply this function to the arguments and return a {@link RedisFuture}. + */ + RedisFuture apply(RedisClusterAsyncCommands connection, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, + T7 t7, T8 t8); + } + + static class DefaultSingleInvocationSpec implements SingleInvocationSpec { + + private final Supplier> parent; + private final Synchronizer synchronizer; + + public DefaultSingleInvocationSpec(Supplier> parent, Synchronizer synchronizer) { + this.parent = parent; + this.synchronizer = synchronizer; + } + + @Override + public T get(Converter converter) { + + Assert.notNull(converter, "Converter must not be null"); + + return synchronizer.invoke(parent, converter, () -> null); + } + + @Nullable + @Override + public T getOrElse(Converter converter, Supplier nullDefault) { + + Assert.notNull(converter, "Converter must not be null"); + + return synchronizer.invoke(parent, converter, nullDefault); + } + } + + static class DefaultManyInvocationSpec implements ManyInvocationSpec { + + private final Supplier>> parent; + private final Synchronizer synchronizer; + + public DefaultManyInvocationSpec(Supplier>> parent, Synchronizer synchronizer) { + this.parent = (Supplier) parent; + this.synchronizer = synchronizer; + } + + @Override + public List toList(Converter converter) { + + Assert.notNull(converter, "Converter must not be null"); + + return synchronizer.invoke(parent, source -> { + + if (source.isEmpty()) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(source.size()); + + for (S s : source) { + result.add(converter.convert(s)); + } + + return result; + }, Collections::emptyList); + } + + @Override + public Set toSet(Converter converter) { + + Assert.notNull(converter, "Converter must not be null"); + + return synchronizer.invoke(parent, source -> { + + if (source.isEmpty()) { + return Collections.emptySet(); + } + + Set result = new LinkedHashSet<>(source.size()); + + for (S s : source) { + result.add(converter.convert(s)); + } + + return result; + }, Collections::emptySet); + } + } + + /** + * Interface to define a synchronization function to evaluate {@link RedisFuture}. + */ + interface Synchronizer { + + @Nullable + @SuppressWarnings({ "unchecked", "rawtypes" }) + default T invoke(Supplier> futureSupplier) { + return (T) doInvoke((Supplier) futureSupplier, identityConverter(), () -> null); + } + + @Nullable + @SuppressWarnings({ "unchecked", "rawtypes" }) + default T invoke(Supplier> futureSupplier, Converter converter, + Supplier nullDefault) { + return (T) doInvoke((Supplier) futureSupplier, (Converter) converter, + (Supplier) nullDefault); + } + + @Nullable + Object doInvoke(Supplier> futureSupplier, Converter converter, + Supplier nullDefault); + + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java index f0b562a4b..5b8edfbbf 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java @@ -20,15 +20,13 @@ import io.lettuce.core.RestoreArgs; import io.lettuce.core.ScanArgs; import io.lettuce.core.ScanCursor; import io.lettuce.core.SortArgs; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisKeyAsyncCommands; import java.time.Duration; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisKeyCommands; import org.springframework.data.redis.connection.SortParameters; @@ -62,21 +60,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().exists(new byte[][] { key }), - LettuceConverters.longToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().exists(new byte[][] { key }), - LettuceConverters.longToBooleanConverter())); - return null; - } - return LettuceConverters.longToBooleanConverter().convert(getConnection().exists(new byte[][] { key })); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::exists, key).get(LettuceConverters.longToBooleanConverter()); } /* @@ -90,19 +74,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().exists(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().exists(keys))); - return null; - } - return getConnection().exists(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::exists, keys); } /* @@ -115,19 +87,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().del(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().del(keys))); - return null; - } - return getConnection().del(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::del, keys); } /* @@ -139,19 +99,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(keys, "Keys must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().unlink(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().unlink(keys))); - return null; - } - return getConnection().unlink(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::unlink, keys); } /* @@ -163,19 +111,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - return LettuceConverters.toDataType(getConnection().type(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::type, key).get(LettuceConverters.stringToDataType()); } /* @@ -187,19 +123,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(keys, "Keys must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().touch(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().touch(keys))); - return null; - } - return getConnection().touch(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::touch, keys); } /* @@ -211,21 +135,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(pattern, "Pattern must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().keys(pattern)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::keys, pattern).get(LettuceConverters.bytesListToBytesSet()); } /** @@ -257,13 +167,12 @@ class LettuceKeyCommands implements RedisKeyCommands { @Override protected LettuceScanIteration doScan(ScanCursor cursor, ScanOptions options) { - if (isQueueing() || isPipelined()) { + if (connection.isQueueing() || connection.isPipelined()) { throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); } ScanArgs scanArgs = LettuceConverters.toScanArgs(options); - - KeyScanCursor keyScanCursor = getConnection().scan(cursor, scanArgs); + KeyScanCursor keyScanCursor = connection.invoke().just(RedisKeyAsyncCommands::scan, cursor, scanArgs); List keys = keyScanCursor.getKeys(); return new LettuceScanIteration<>(keyScanCursor, keys); @@ -283,20 +192,7 @@ class LettuceKeyCommands implements RedisKeyCommands { */ @Override public byte[] randomKey() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().randomkey())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().randomkey())); - return null; - } - return getConnection().randomkey(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::randomkey); } /* @@ -309,19 +205,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(sourceKey, "Source key must not be null!"); Assert.notNull(targetKey, "Target key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().rename(sourceKey, targetKey))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().rename(sourceKey, targetKey))); - return; - } - getConnection().rename(sourceKey, targetKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisKeyAsyncCommands::rename, sourceKey, targetKey); } /* @@ -334,19 +218,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(sourceKey, "Source key must not be null!"); Assert.notNull(targetKey, "Target key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().renamenx(sourceKey, targetKey))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().renamenx(sourceKey, targetKey))); - return null; - } - return (getConnection().renamenx(sourceKey, targetKey)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::renamenx, sourceKey, targetKey); } /* @@ -358,19 +230,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().expire(key, seconds))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().expire(key, seconds))); - return null; - } - return getConnection().expire(key, seconds); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::expire, key, seconds); } /* @@ -382,19 +242,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pexpire(key, millis))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pexpire(key, millis))); - return null; - } - return getConnection().pexpire(key, millis); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::pexpire, key, millis); } /* @@ -406,19 +254,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().expireat(key, unixTime))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().expireat(key, unixTime))); - return null; - } - return getConnection().expireat(key, unixTime); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::expireat, key, unixTime); } /* @@ -430,19 +266,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pexpireat(key, unixTimeInMillis))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pexpireat(key, unixTimeInMillis))); - return null; - } - return getConnection().pexpireat(key, unixTimeInMillis); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::pexpireat, key, unixTimeInMillis); } /* @@ -454,19 +278,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().persist(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().persist(key))); - return null; - } - return getConnection().persist(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::persist, key); } /* @@ -478,19 +290,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().move(key, dbIndex))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().move(key, dbIndex))); - return null; - } - return getConnection().move(key, dbIndex); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::move, key, dbIndex); } /* @@ -502,20 +302,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().ttl(key))); - return null; - } - - return getConnection().ttl(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::ttl, key); } /* @@ -527,20 +314,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.secondsToTimeUnit(getConnection().ttl(key), timeUnit); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::ttl, key).get(Converters.secondsToTimeUnit(timeUnit)); } /* @@ -552,20 +326,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().pttl(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().pttl(key))); - return null; - } - - return getConnection().pttl(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::pttl, key); } /* @@ -577,22 +338,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.millisecondsToTimeUnit(getConnection().pttl(key), timeUnit); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::pttl, key).get(Converters.millisecondsToTimeUnit(timeUnit)); } /* @@ -606,19 +352,7 @@ class LettuceKeyCommands implements RedisKeyCommands { SortArgs args = LettuceConverters.toSortArgs(params); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sort(key, args))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sort(key, args))); - return null; - } - return getConnection().sort(key, args); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::sort, key, args); } /* @@ -632,19 +366,7 @@ class LettuceKeyCommands implements RedisKeyCommands { SortArgs args = LettuceConverters.toSortArgs(params); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sortStore(key, args, sortKey))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sortStore(key, args, sortKey))); - return null; - } - return getConnection().sortStore(key, args, sortKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::sortStore, key, args, sortKey); } /* @@ -656,19 +378,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().dump(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().dump(key))); - return null; - } - return getConnection().dump(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::dump, key); } /* @@ -681,24 +391,9 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(serializedValue, "Serialized value must not be null!"); - try { + RestoreArgs restoreArgs = RestoreArgs.Builder.ttl(ttlInMillis).replace(replace); - RestoreArgs restoreArgs = RestoreArgs.Builder.ttl(ttlInMillis).replace(replace); - - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().restore(key, serializedValue, restoreArgs))); - return; - } - - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().restore(key, serializedValue, restoreArgs))); - return; - } - - getConnection().restore(key, serializedValue, restoreArgs); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisKeyAsyncCommands::restore, key, serializedValue, restoreArgs); } /* @@ -711,22 +406,8 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().objectEncoding(key), ValueEncoding::of, - () -> RedisValueEncoding.VACANT)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().objectEncoding(key), ValueEncoding::of, - () -> RedisValueEncoding.VACANT)); - return null; - } - - return ValueEncoding.of(getConnection().objectEncoding(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invokeStatus().from(RedisKeyAsyncCommands::objectEncoding, key).getOrElse(ValueEncoding::of, + () -> RedisValueEncoding.VACANT); } /* @@ -739,21 +420,7 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().objectIdletime(key), Converters::secondsToDuration)); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().objectIdletime(key), Converters::secondsToDuration)); - return null; - } - - return Converters.secondsToDuration(getConnection().objectIdletime(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisKeyAsyncCommands::objectIdletime, key).get(Converters::secondsToDuration); } /* @@ -766,48 +433,6 @@ class LettuceKeyCommands implements RedisKeyCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().objectRefcount(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().objectRefcount(key))); - return null; - } - - return getConnection().objectRefcount(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisKeyAsyncCommands::objectRefcount, key); } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } - } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java index c183a7b4c..68850272c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java @@ -16,13 +16,11 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.LPosArgs; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisListAsyncCommands; import java.util.Collections; import java.util.List; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -49,19 +47,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().rpush(key, values))); - return null; - } - return getConnection().rpush(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::rpush, key, values); } /* @@ -78,33 +64,12 @@ class LettuceListCommands implements RedisListCommands { if (rank != null) { args.rank(rank); } - try { - if (isPipelined()) { - if (count != null) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpos(key, element, count, args))); - } else { - pipeline( - connection.newLettuceResult(getAsyncConnection().lpos(key, element, args), Collections::singletonList)); - } - return null; - } - if (isQueueing()) { - if (count != null) { - transaction(connection.newLettuceResult(getAsyncConnection().lpos(key, element, count, args))); - } else { - transaction( - connection.newLettuceResult(getAsyncConnection().lpos(key, element, args), Collections::singletonList)); - } - return null; - } - if (count != null) { - return getConnection().lpos(key, element, count, args); - } - return Collections.singletonList(getConnection().lpos(key, element, args)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + if (count != null) { + return connection.invoke().just(RedisListAsyncCommands::lpos, key, element, count, args); } + + return connection.invoke().from(RedisListAsyncCommands::lpos, key, element, args).get(Collections::singletonList); } /* @@ -118,19 +83,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lpush(key, values))); - return null; - } - return getConnection().lpush(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lpush, key, values); } /* @@ -143,19 +96,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().rpushx(key, value))); - return null; - } - return getConnection().rpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::rpushx, key, value); } /* @@ -168,19 +109,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lpushx(key, value))); - return null; - } - return getConnection().lpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lpushx, key, value); } /* @@ -192,19 +121,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().llen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().llen(key))); - return null; - } - return getConnection().llen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::llen, key); } /* @@ -216,19 +133,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lrange(key, start, end))); - return null; - } - return getConnection().lrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lrange, key, start, end); } /* @@ -240,19 +145,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); - return; - } - getConnection().ltrim(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisListAsyncCommands::ltrim, key, start, end); } /* @@ -264,19 +157,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lindex(key, index))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lindex(key, index))); - return null; - } - return getConnection().lindex(key, index); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lindex, key, index); } /* @@ -288,21 +169,8 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection - .newLettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - if (isQueueing()) { - transaction(connection - .newLettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - return getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::linsert, key, LettuceConverters.toBoolean(where), pivot, + value); } /* @@ -315,19 +183,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().lset(key, index, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().lset(key, index, value))); - return; - } - getConnection().lset(key, index, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisListAsyncCommands::lset, key, index, value); } /* @@ -340,19 +196,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lrem(key, count, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lrem(key, count, value))); - return null; - } - return getConnection().lrem(key, count, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lrem, key, count, value); } /* @@ -364,19 +208,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpop(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lpop(key))); - return null; - } - return getConnection().lpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::lpop, key); } /* @@ -388,19 +220,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpop(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().rpop(key))); - return null; - } - return getConnection().rpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::rpop, key); } /* @@ -413,21 +233,8 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(keys, "Key must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().blpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(connection.getAsyncDedicatedConnection().blpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - return LettuceConverters.toBytesList(connection.getDedicatedConnection().blpop(timeout, keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke(connection.getAsyncDedicatedConnection()) + .from(RedisListAsyncCommands::blpop, timeout, keys).get(LettuceConverters.keyValueToBytesList()); } /* @@ -440,21 +247,8 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(keys, "Key must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - return LettuceConverters.toBytesList(connection.getDedicatedConnection().brpop(timeout, keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke(connection.getAsyncDedicatedConnection()) + .from(RedisListAsyncCommands::brpop, timeout, keys).get(LettuceConverters.keyValueToBytesList()); } /* @@ -467,19 +261,7 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(srcKey, "Source key must not be null!"); Assert.notNull(dstKey, "Destination key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpoplpush(srcKey, dstKey))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().rpoplpush(srcKey, dstKey))); - return null; - } - return getConnection().rpoplpush(srcKey, dstKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisListAsyncCommands::rpoplpush, srcKey, dstKey); } /* @@ -492,49 +274,8 @@ class LettuceListCommands implements RedisListCommands { Assert.notNull(srcKey, "Source key must not be null!"); Assert.notNull(dstKey, "Destination key must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); - return null; - } - return connection.getDedicatedConnection().brpoplpush(timeout, srcKey, dstKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + return connection.invoke(connection.getAsyncDedicatedConnection()).just(RedisListAsyncCommands::brpoplpush, timeout, + srcKey, dstKey); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java index 0008f3b5d..91aeaef75 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java @@ -15,14 +15,12 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisScriptingAsyncCommands; import java.util.Arrays; import java.util.List; import org.springframework.core.convert.converter.Converter; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisScriptingCommands; import org.springframework.data.redis.connection.ReturnType; import org.springframework.util.Assert; @@ -45,20 +43,7 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public void scriptFlush() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().scriptFlush())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().scriptFlush())); - return; - } - getConnection().scriptFlush(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invoke().just(RedisScriptingAsyncCommands::scriptFlush); } /* @@ -68,19 +53,11 @@ class LettuceScriptingCommands implements RedisScriptingCommands { @Override public void scriptKill() { - if (isQueueing()) { + if (connection.isQueueing()) { throw new UnsupportedOperationException("Script kill not permitted in a transaction"); } - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().scriptKill())); - return; - } - getConnection().scriptKill(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invoke().just(RedisScriptingAsyncCommands::scriptKill); } /* @@ -92,19 +69,7 @@ class LettuceScriptingCommands implements RedisScriptingCommands { Assert.notNull(script, "Script must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().scriptLoad(script))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().scriptLoad(script))); - return null; - } - return getConnection().scriptLoad(script); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisScriptingAsyncCommands::scriptLoad, script); } /* @@ -117,19 +82,7 @@ class LettuceScriptingCommands implements RedisScriptingCommands { Assert.notNull(scriptSha1, "Script digests must not be null!"); Assert.noNullElements(scriptSha1, "Script digests must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().scriptExists(scriptSha1))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().scriptExists(scriptSha1))); - return null; - } - return getConnection().scriptExists(scriptSha1); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisScriptingAsyncCommands::scriptExists, scriptSha1); } /* @@ -141,27 +94,14 @@ class LettuceScriptingCommands implements RedisScriptingCommands { Assert.notNull(script, "Script must not be null!"); - try { - byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); - byte[][] args = extractScriptArgs(numKeys, keysAndArgs); - String convertedScript = LettuceConverters.toString(script); - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().eval(convertedScript, LettuceConverters.toScriptOutputType(returnType), keys, args), - new LettuceEvalResultsConverter(returnType))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().eval(convertedScript, LettuceConverters.toScriptOutputType(returnType), keys, args), - new LettuceEvalResultsConverter(returnType))); - return null; - } - return new LettuceEvalResultsConverter(returnType) - .convert(getConnection().eval(convertedScript, LettuceConverters.toScriptOutputType(returnType), keys, args)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); + byte[][] args = extractScriptArgs(numKeys, keysAndArgs); + String convertedScript = LettuceConverters.toString(script); + + return connection + .invoke().from(RedisScriptingAsyncCommands::eval, convertedScript, + LettuceConverters.toScriptOutputType(returnType), keys, args) + .get(new LettuceEvalResultsConverter(returnType)); } /* @@ -173,27 +113,13 @@ class LettuceScriptingCommands implements RedisScriptingCommands { Assert.notNull(scriptSha1, "Script digest must not be null!"); - try { - byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); - byte[][] args = extractScriptArgs(numKeys, keysAndArgs); + byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); + byte[][] args = extractScriptArgs(numKeys, keysAndArgs); - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().evalsha(scriptSha1, LettuceConverters.toScriptOutputType(returnType), keys, args), - new LettuceEvalResultsConverter(returnType))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().evalsha(scriptSha1, LettuceConverters.toScriptOutputType(returnType), keys, args), - new LettuceEvalResultsConverter(returnType))); - return null; - } - return new LettuceEvalResultsConverter(returnType) - .convert(getConnection().evalsha(scriptSha1, LettuceConverters.toScriptOutputType(returnType), keys, args)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection + .invoke().from(RedisScriptingAsyncCommands::evalsha, scriptSha1, + LettuceConverters.toScriptOutputType(returnType), keys, args) + .get(new LettuceEvalResultsConverter(returnType)); } /* @@ -208,34 +134,6 @@ class LettuceScriptingCommands implements RedisScriptingCommands { return evalSha(LettuceConverters.toString(scriptSha1), returnType, numKeys, keysAndArgs); } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } - private static byte[][] extractScriptKeys(int numKeys, byte[]... keysAndArgs) { if (numKeys > 0) { return Arrays.copyOfRange(keysAndArgs, 0, numKeys); @@ -251,7 +149,8 @@ class LettuceScriptingCommands implements RedisScriptingCommands { } private class LettuceEvalResultsConverter implements Converter { - private ReturnType returnType; + + private final ReturnType returnType; public LettuceEvalResultsConverter(ReturnType returnType) { this.returnType = returnType; @@ -263,7 +162,7 @@ class LettuceScriptingCommands implements RedisScriptingCommands { List resultList = (List) source; for (Object obj : resultList) { if (obj instanceof Exception) { - throw convertLettuceAccessException((Exception) obj); + throw connection.convertLettuceAccessException((Exception) obj); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java index 911395a45..0bcf82c87 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceServerCommands.java @@ -15,16 +15,19 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.LettuceFutures; +import io.lettuce.core.RedisFuture; +import io.lettuce.core.api.async.RedisKeyAsyncCommands; +import io.lettuce.core.api.async.RedisServerAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import java.util.List; import java.util.Properties; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisServerCommands; -import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -47,20 +50,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void bgReWriteAof() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().bgrewriteaof())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().bgrewriteaof())); - return; - } - getConnection().bgrewriteaof(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::bgrewriteaof); } /* @@ -69,20 +59,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void bgSave() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().bgsave())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().bgsave())); - return; - } - getConnection().bgsave(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::bgsave); } /* @@ -91,20 +68,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Long lastSave() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lastsave(), LettuceConverters.dateToLong())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().lastsave(), LettuceConverters.dateToLong())); - return null; - } - return LettuceConverters.toLong(getConnection().lastsave()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::lastsave).get(LettuceConverters.dateToLong()); } /* @@ -113,20 +77,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void save() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().save())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().save())); - return; - } - getConnection().save(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::save); } /* @@ -135,20 +86,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Long dbSize() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().dbsize())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().dbsize())); - return null; - } - return getConnection().dbsize(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisServerAsyncCommands::dbsize); } /* @@ -157,20 +95,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void flushDb() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().flushdb())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().flushdb())); - return; - } - getConnection().flushdb(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::flushdb); } /* @@ -179,20 +104,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void flushAll() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().flushall())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().flushall())); - return; - } - getConnection().flushall(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::flushall); } /* @@ -201,20 +113,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Properties info() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().info(), LettuceConverters.stringToProps())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().info(), LettuceConverters.stringToProps())); - return null; - } - return LettuceConverters.toProperties(getConnection().info()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::info).get(LettuceConverters.stringToProps()); } /* @@ -226,19 +125,7 @@ class LettuceServerCommands implements RedisServerCommands { Assert.hasText(section, "Section must not be null or empty!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().info(section), LettuceConverters.stringToProps())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().info(section), LettuceConverters.stringToProps())); - return null; - } - return LettuceConverters.toProperties(getConnection().info(section)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::info, section).get(LettuceConverters.stringToProps()); } /* @@ -247,16 +134,12 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void shutdown() { + connection.invokeStatus().just(it -> { - try { - if (isPipelined()) { - getAsyncConnection().shutdown(true); - return; - } - getConnection().shutdown(true); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + it.shutdown(true); + + return new CompletedRedisFuture<>(null); + }); } /* @@ -272,15 +155,13 @@ class LettuceServerCommands implements RedisServerCommands { } boolean save = ShutdownOption.SAVE.equals(option); - try { - if (isPipelined()) { - getAsyncConnection().shutdown(save); - return; - } - getConnection().shutdown(save); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + connection.invokeStatus().just(it -> { + + it.shutdown(save); + + return new CompletedRedisFuture<>(null); + }); } /* @@ -292,21 +173,8 @@ class LettuceServerCommands implements RedisServerCommands { Assert.hasText(pattern, "Pattern must not be null or empty!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().configGet(pattern), - Converters.mapToPropertiesConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().configGet(pattern), - Converters.mapToPropertiesConverter())); - return null; - } - return Converters.toProperties(getConnection().configGet(pattern)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::configGet, pattern) + .get(LettuceConverters.mapToPropertiesConverter()); } /* @@ -319,19 +187,8 @@ class LettuceServerCommands implements RedisServerCommands { Assert.hasText(param, "Parameter must not be null or empty!"); Assert.hasText(value, "Value must not be null or empty!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().configSet(param, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().configSet(param, value))); - return; - } - getConnection().configSet(param, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::configSet, param, value); + } /* @@ -340,20 +197,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void resetConfigStats() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().configResetstat())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().configResetstat())); - return; - } - getConnection().configResetstat(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisServerAsyncCommands::configResetstat); } /* @@ -362,20 +206,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Long time() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().time(), LettuceConverters.toTimeConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().time(), LettuceConverters.toTimeConverter())); - return null; - } - return LettuceConverters.toTimeConverter().convert(getConnection().time()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::time).get(LettuceConverters.toTimeConverter()); } /* @@ -388,15 +219,8 @@ class LettuceServerCommands implements RedisServerCommands { Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'."); String client = String.format("%s:%s", host, port); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().clientKill(client))); - return; - } - getConnection().clientKill(client); - } catch (Exception e) { - throw convertLettuceAccessException(e); - } + + connection.invoke().just(RedisServerAsyncCommands::clientKill, client); } /* @@ -408,16 +232,7 @@ class LettuceServerCommands implements RedisServerCommands { Assert.notNull(name, "Name must not be null!"); - if (isQueueing()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().clientSetname(name))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().clientSetname(name))); - return; - } - - getAsyncConnection().clientSetname(name); + connection.invoke().just(RedisServerAsyncCommands::clientSetname, name); } /* @@ -426,21 +241,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public String getClientName() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().clientGetname(), LettuceConverters.bytesToString())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().clientGetname(), LettuceConverters.bytesToString())); - return null; - } - return LettuceConverters.toString(getConnection().clientGetname()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisServerAsyncCommands::clientGetname).get(LettuceConverters.bytesToString()); } /* @@ -450,16 +251,12 @@ class LettuceServerCommands implements RedisServerCommands { @Override public List getClientList() { - if (isPipelined()) { + if (connection.isPipelined()) { throw new UnsupportedOperationException("Cannot be called in pipeline mode."); } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().clientList(), - LettuceConverters.stringToRedisClientListConverter())); - return null; - } - return LettuceConverters.toListOfRedisClientInformation(getConnection().clientList()); + return connection.invoke().from(RedisServerAsyncCommands::clientList) + .get(LettuceConverters.stringToRedisClientListConverter()); } /* @@ -471,19 +268,7 @@ class LettuceServerCommands implements RedisServerCommands { Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().slaveof(host, port))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().slaveof(host, port))); - return; - } - getConnection().slaveof(host, port); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invoke().just(RedisServerAsyncCommands::slaveof, host, port); } /* @@ -492,20 +277,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void slaveOfNoOne() { - - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().slaveofNoOne())); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().slaveofNoOne())); - return; - } - getConnection().slaveofNoOne(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invoke().just(RedisServerAsyncCommands::slaveofNoOne); } /* @@ -527,48 +299,27 @@ class LettuceServerCommands implements RedisServerCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(target, "Target node must not be null!"); - try { - if (isPipelined()) { - pipeline(connection - .newLettuceResult(getAsyncConnection().migrate(target.getHost(), target.getPort(), key, dbIndex, timeout))); - return; - } - if (isQueueing()) { - transaction(connection - .newLettuceResult(getAsyncConnection().migrate(target.getHost(), target.getPort(), key, dbIndex, timeout))); - return; - } - getConnection().migrate(target.getHost(), target.getPort(), key, dbIndex, timeout); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); + connection.invoke().just(RedisKeyAsyncCommands::migrate, target.getHost(), target.getPort(), key, dbIndex, timeout); } public RedisClusterCommands getConnection() { return connection.getConnection(); } - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + static class CompletedRedisFuture extends CompletableFuture implements RedisFuture { + + public CompletedRedisFuture(T value) { + complete(value); + } + + @Override + public String getError() { + return ""; + } + + @Override + public boolean await(long timeout, TimeUnit unit) throws InterruptedException { + return LettuceFutures.awaitAll(timeout, unit, this); + } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java index b86b33e9e..802288a02 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java @@ -17,15 +17,13 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.ScanArgs; import io.lettuce.core.ValueScanCursor; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.api.async.RedisSetAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.springframework.core.convert.converter.Converter; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisSetCommands; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; @@ -57,19 +55,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sadd(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sadd(key, values))); - return null; - } - return getConnection().sadd(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sadd, key, values); } /* @@ -81,19 +67,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().scard(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().scard(key))); - return null; - } - return getConnection().scard(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::scard, key); } /* @@ -106,19 +80,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sdiff(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sdiff(keys))); - return null; - } - return getConnection().sdiff(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sdiff, keys); } /* @@ -132,19 +94,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sdiffstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sdiffstore(destKey, keys))); - return null; - } - return getConnection().sdiffstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sdiffstore, destKey, keys); } /* @@ -157,19 +107,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sinter(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sinter(keys))); - return null; - } - return getConnection().sinter(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sinter, keys); } /* @@ -183,19 +121,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sinterstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sinterstore(destKey, keys))); - return null; - } - return getConnection().sinterstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sinterstore, destKey, keys); } /* @@ -208,19 +134,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sismember(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sismember(key, value))); - return null; - } - return getConnection().sismember(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sismember, key, value); } /* @@ -232,19 +146,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().smembers(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().smembers(key))); - return null; - } - return getConnection().smembers(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::smembers, key); } /* @@ -258,19 +160,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(destKey, "Destination key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().smove(srcKey, destKey, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().smove(srcKey, destKey, value))); - return null; - } - return getConnection().smove(srcKey, destKey, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::smove, srcKey, destKey, value); } /* @@ -282,19 +172,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().spop(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().spop(key))); - return null; - } - return getConnection().spop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::spop, key); } /* @@ -306,20 +184,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().spop(key, count), ArrayList::new)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().spop(key, count), - (Converter, List>) ArrayList::new)); - return null; - } - return new ArrayList<>(getConnection().spop(key, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisSetAsyncCommands::spop, key, count).get(ArrayList::new); } /* @@ -331,19 +196,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().srandmember(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().srandmember(key))); - return null; - } - return getConnection().srandmember(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::srandmember, key); } /* @@ -355,19 +208,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().srandmember(key, count))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().srandmember(key, count))); - return null; - } - return LettuceConverters.toBytesList(getConnection().srandmember(key, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::srandmember, key, count); } /* @@ -381,19 +222,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().srem(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().srem(key, values))); - return null; - } - return getConnection().srem(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::srem, key, values); } /* @@ -406,19 +235,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sunion(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sunion(keys))); - return null; - } - return getConnection().sunion(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sunion, keys); } /* @@ -432,19 +249,7 @@ class LettuceSetCommands implements RedisSetCommands { Assert.notNull(keys, "Source keys must not be null!"); Assert.noNullElements(keys, "Source keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().sunionstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().sunionstore(destKey, keys))); - return null; - } - return getConnection().sunionstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSetAsyncCommands::sunionstore, destKey, keys); } /* @@ -472,14 +277,15 @@ class LettuceSetCommands implements RedisSetCommands { @Override protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - if (isQueueing() || isPipelined()) { + if (connection.isQueueing() || connection.isPipelined()) { throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); ScanArgs scanArgs = LettuceConverters.toScanArgs(options); - ValueScanCursor valueScanCursor = getConnection().sscan(key, scanCursor, scanArgs); + ValueScanCursor valueScanCursor = connection.invoke().just(RedisSetAsyncCommands::sscan, key, + scanCursor, scanArgs); String nextCursorId = valueScanCursor.getCursor(); List values = connection.failsafeReadScanValues(valueScanCursor.getValues(), null); @@ -493,32 +299,8 @@ class LettuceSetCommands implements RedisSetCommands { }.open(); } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { + public RedisClusterCommands getCommands() { return connection.getConnection(); } - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } - } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java index ed5860da9..35e59b9ea 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStreamCommands.java @@ -19,15 +19,14 @@ import io.lettuce.core.XAddArgs; import io.lettuce.core.XClaimArgs; import io.lettuce.core.XGroupCreateArgs; import io.lettuce.core.XReadArgs; +import io.lettuce.core.api.async.RedisStreamAsyncCommands; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Function; -import org.springframework.dao.DataAccessException; import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.RedisStreamCommands; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; @@ -73,19 +72,7 @@ class LettuceStreamCommands implements RedisStreamCommands { String[] ids = entryIdsToString(recordIds); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xack(key, LettuceConverters.toBytes(group), ids))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xack(key, LettuceConverters.toBytes(group), ids))); - return null; - } - return getConnection().xack(key, LettuceConverters.toBytes(group), ids); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStreamAsyncCommands::xack, key, LettuceConverters.toBytes(group), ids); } /* @@ -104,25 +91,8 @@ class LettuceStreamCommands implements RedisStreamCommands { args.maxlen(options.getMaxlen()); } - try { - if (isPipelined()) { - - pipeline(connection.newLettuceResult(getAsyncConnection().xadd(record.getStream(), args, record.getValue()), - RecordId::of)); - return null; - } - if (isQueueing()) { - - transaction(connection.newLettuceResult(getAsyncConnection().xadd(record.getStream(), args, record.getValue()), - RecordId::of)); - return null; - } - - return RecordId.of(getConnection().xadd(record.getStream(), args, record.getValue())); - - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStreamAsyncCommands::xadd, record.getStream(), args, record.getValue()) + .get(RecordId::of); } /* @@ -137,25 +107,8 @@ class LettuceStreamCommands implements RedisStreamCommands { LettuceConverters.toBytes(newOwner)); XClaimArgs args = StreamConverters.toXClaimArgs(options).justid(); - try { - if (isPipelined()) { - - pipeline(connection.newLettuceResult(getAsyncConnection().xclaim(key, from, args, ids), - StreamConverters.messagesToIds())); - return null; - } - if (isQueueing()) { - - transaction(connection.newLettuceResult(getAsyncConnection().xclaim(key, from, args, ids), - StreamConverters.messagesToIds())); - return null; - } - - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - - return StreamConverters.messagesToIds().convert(getConnection().xclaim(key, from, args, ids)); + return connection.invoke().fromMany(RedisStreamAsyncCommands::xclaim, key, from, args, ids) + .toList(it -> RecordId.of(it.getId())); } /* @@ -170,21 +123,8 @@ class LettuceStreamCommands implements RedisStreamCommands { LettuceConverters.toBytes(newOwner)); XClaimArgs args = StreamConverters.toXClaimArgs(options); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xclaim(key, from, args, ids), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xclaim(key, from, args, ids), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter().convert(getConnection().xclaim(key, from, args, ids)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisStreamAsyncCommands::xclaim, key, from, args, ids) + .toList(StreamConverters.byteRecordConverter()); } /* @@ -197,19 +137,7 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(recordIds, "recordIds must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xdel(key, entryIdsToString(recordIds)))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xdel(key, entryIdsToString(recordIds)))); - return null; - } - return getConnection().xdel(key, entryIdsToString(recordIds)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStreamAsyncCommands::xdel, key, entryIdsToString(recordIds)); } /* @@ -232,24 +160,10 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.hasText(groupName, "Group name must not be null or empty!"); Assert.notNull(readOffset, "ReadOffset must not be null!"); - try { - XReadArgs.StreamOffset streamOffset = XReadArgs.StreamOffset.from(key, readOffset.getOffset()); + XReadArgs.StreamOffset streamOffset = XReadArgs.StreamOffset.from(key, readOffset.getOffset()); - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xgroupCreate(streamOffset, - LettuceConverters.toBytes(groupName), XGroupCreateArgs.Builder.mkstream(mkSteam)))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xgroupCreate(streamOffset, - LettuceConverters.toBytes(groupName), XGroupCreateArgs.Builder.mkstream(mkSteam)))); - return null; - } - return getConnection().xgroupCreate(streamOffset, LettuceConverters.toBytes(groupName), - XGroupCreateArgs.Builder.mkstream(mkSteam)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStreamAsyncCommands::xgroupCreate, streamOffset, + LettuceConverters.toBytes(groupName), XGroupCreateArgs.Builder.mkstream(mkSteam)); } /* @@ -262,23 +176,10 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(consumer, "Consumer must not be null!"); - try { - io.lettuce.core.Consumer lettuceConsumer = toConsumer(consumer); + io.lettuce.core.Consumer lettuceConsumer = toConsumer(consumer); - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xgroupDelconsumer(key, lettuceConsumer), - Objects::nonNull)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xgroupDelconsumer(key, lettuceConsumer), - Objects::nonNull)); - return null; - } - return Objects.nonNull(getConnection().xgroupDelconsumer(key, lettuceConsumer)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStreamAsyncCommands::xgroupDelconsumer, key, lettuceConsumer) + .get(Objects::nonNull); } /* @@ -291,21 +192,7 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); Assert.hasText(groupName, "Group name must not be null or empty!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().xgroupDestroy(key, LettuceConverters.toBytes(groupName)))); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().xgroupDestroy(key, LettuceConverters.toBytes(groupName)))); - return null; - } - return getConnection().xgroupDestroy(key, LettuceConverters.toBytes(groupName)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStreamAsyncCommands::xgroupDestroy, key, LettuceConverters.toBytes(groupName)); } /* @@ -317,19 +204,7 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xinfoStream(key), XInfoStream::fromList)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xinfoStream(key), XInfoStream::fromList)); - return null; - } - return XInfoStream.fromList(getConnection().xinfoStream(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStreamAsyncCommands::xinfoStream, key).get(XInfoStream::fromList); } /* @@ -341,19 +216,7 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xinfoGroups(key), XInfoGroups::fromList)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xinfoGroups(key), XInfoGroups::fromList)); - return null; - } - return XInfoGroups.fromList(getConnection().xinfoGroups(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStreamAsyncCommands::xinfoGroups, key).get(XInfoGroups::fromList); } /* @@ -366,23 +229,8 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(groupName, "GroupName must not be null!"); - byte[] binaryGroupName = LettuceConverters.toBytes(groupName); - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xinfoConsumers(key, binaryGroupName), - it -> XInfoConsumers.fromList(groupName, it))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xinfoConsumers(key, binaryGroupName), - it -> XInfoConsumers.fromList(groupName, it))); - return null; - } - return XInfoConsumers.fromList(groupName, getConnection().xinfoConsumers(key, binaryGroupName)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStreamAsyncCommands::xinfoConsumers, key, LettuceConverters.toBytes(groupName)) + .get(it -> XInfoConsumers.fromList(groupName, it)); } /* @@ -394,19 +242,7 @@ class LettuceStreamCommands implements RedisStreamCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xlen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xlen(key))); - return null; - } - return getConnection().xlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStreamAsyncCommands::xlen, key); } /* @@ -417,21 +253,9 @@ class LettuceStreamCommands implements RedisStreamCommands { public PendingMessagesSummary xPending(byte[] key, String groupName) { byte[] group = LettuceConverters.toBytes(groupName); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xpending(key, group), - it -> StreamConverters.toPendingMessagesInfo(groupName, it))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xpending(key, group), - it -> StreamConverters.toPendingMessagesInfo(groupName, it))); - return null; - } - return StreamConverters.toPendingMessagesInfo(groupName, getConnection().xpending(key, group)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return connection.invoke().from(RedisStreamAsyncCommands::xpending, key, group) + .get(it -> StreamConverters.toPendingMessagesInfo(groupName, it)); } /* @@ -442,46 +266,21 @@ class LettuceStreamCommands implements RedisStreamCommands { public PendingMessages xPending(byte[] key, String groupName, XPendingOptions options) { byte[] group = LettuceConverters.toBytes(groupName); - io.lettuce.core.Range range = RangeConverter.toRangeWithDefault(options.getRange(), "-", "+", Function.identity()); + io.lettuce.core.Range range = RangeConverter.toRangeWithDefault(options.getRange(), "-", "+", + Function.identity()); io.lettuce.core.Limit limit = options.isLimited() ? io.lettuce.core.Limit.from(options.getCount()) : io.lettuce.core.Limit.unlimited(); - try { - if (options.hasConsumer()) { + if (options.hasConsumer()) { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xpending(key, - io.lettuce.core.Consumer.from(group, LettuceConverters.toBytes(options.getConsumerName())), range, limit), - it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xpending(key, - io.lettuce.core.Consumer.from(group, LettuceConverters.toBytes(options.getConsumerName())), range, limit), - it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it))); - return null; - } - return StreamConverters.toPendingMessages(groupName, options.getRange(), getConnection().xpending(key, - io.lettuce.core.Consumer.from(group, LettuceConverters.toBytes(options.getConsumerName())), range, limit)); - - } else { - - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xpending(key, group, range, limit), - it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xpending(key, group, range, limit), - it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it))); - return null; - } - return StreamConverters.toPendingMessages(groupName, options.getRange(), - getConnection().xpending(key, group, range, limit)); - } - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + return connection.invoke() + .from(RedisStreamAsyncCommands::xpending, key, + io.lettuce.core.Consumer.from(group, LettuceConverters.toBytes(options.getConsumerName())), range, limit) + .get(it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it)); } + + return connection.invoke().from(RedisStreamAsyncCommands::xpending, key, group, range, limit) + .get(it -> StreamConverters.toPendingMessages(groupName, options.getRange(), it)); } /* @@ -497,24 +296,9 @@ class LettuceStreamCommands implements RedisStreamCommands { io.lettuce.core.Range lettuceRange = RangeConverter.toRange(range, Function.identity()); io.lettuce.core.Limit lettuceLimit = LettuceConverters.toLimit(limit); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xrange(key, lettuceRange, lettuceLimit), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xrange(key, lettuceRange, lettuceLimit), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter() - .convert(getConnection().xrange(key, lettuceRange, lettuceLimit)); - - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisStreamAsyncCommands::xrange, key, lettuceRange, lettuceLimit) + .toList(StreamConverters.byteRecordConverter()); } /* @@ -532,38 +316,13 @@ class LettuceStreamCommands implements RedisStreamCommands { if (readOptions.isBlocking()) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncDedicatedConnection().xread(args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncDedicatedConnection().xread(args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter().convert(getDedicatedConnection().xread(args, streamOffsets)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke(getAsyncDedicatedConnection()) + .fromMany(RedisStreamAsyncCommands::xread, args, streamOffsets) + .toList(StreamConverters.byteRecordConverter()); } - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xread(args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xread(args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter().convert(getConnection().xread(args, streamOffsets)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisStreamAsyncCommands::xread, args, streamOffsets) + .toList(StreamConverters.byteRecordConverter()); } /* @@ -584,42 +343,13 @@ class LettuceStreamCommands implements RedisStreamCommands { if (readOptions.isBlocking()) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncDedicatedConnection().xreadgroup(lettuceConsumer, args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncDedicatedConnection().xreadgroup(lettuceConsumer, args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter() - .convert(getDedicatedConnection().xreadgroup(lettuceConsumer, args, streamOffsets)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke(getAsyncDedicatedConnection()) + .fromMany(RedisStreamAsyncCommands::xreadgroup, lettuceConsumer, args, streamOffsets) + .toList(StreamConverters.byteRecordConverter()); } - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xreadgroup(lettuceConsumer, args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xreadgroup(lettuceConsumer, args, streamOffsets), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter() - .convert(getConnection().xreadgroup(lettuceConsumer, args, streamOffsets)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisStreamAsyncCommands::xreadgroup, lettuceConsumer, args, streamOffsets) + .toList(StreamConverters.byteRecordConverter()); } /* @@ -635,22 +365,10 @@ class LettuceStreamCommands implements RedisStreamCommands { io.lettuce.core.Range lettuceRange = RangeConverter.toRange(range, Function.identity()); io.lettuce.core.Limit lettuceLimit = LettuceConverters.toLimit(limit); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xrevrange(key, lettuceRange, lettuceLimit), - StreamConverters.byteRecordListConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xrevrange(key, lettuceRange, lettuceLimit), - StreamConverters.byteRecordListConverter())); - return null; - } - return StreamConverters.byteRecordListConverter() - .convert(getConnection().xrevrange(key, lettuceRange, lettuceLimit)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return connection.invoke(getAsyncDedicatedConnection()) + .fromMany(RedisStreamAsyncCommands::xrevrange, key, lettuceRange, lettuceLimit) + .toList(StreamConverters.byteRecordConverter()); } /* @@ -670,57 +388,13 @@ class LettuceStreamCommands implements RedisStreamCommands { public Long xTrim(byte[] key, long count, boolean approximateTrimming) { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().xtrim(key, approximateTrimming, count))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().xtrim(key, approximateTrimming, count))); - return null; - } - return getConnection().xtrim(key, approximateTrimming, count); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - RedisClusterCommands getConnection() { - return connection.getConnection(); + return connection.invoke().just(RedisStreamAsyncCommands::xtrim, key, approximateTrimming, count); } RedisClusterAsyncCommands getAsyncDedicatedConnection() { return connection.getAsyncDedicatedConnection(); } - RedisClusterCommands getDedicatedConnection() { - return connection.getDedicatedConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } - @SuppressWarnings("unchecked") private static XReadArgs.StreamOffset[] toStreamOffsets(StreamOffset[] streams) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java index 0f448b44a..1a563187c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java @@ -16,15 +16,11 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.BitFieldArgs; -import io.lettuce.core.RedisFuture; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.api.async.RedisStringAsyncCommands; import java.util.List; import java.util.Map; -import java.util.concurrent.Future; -import org.springframework.dao.DataAccessException; import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.BitFieldSubCommands; import org.springframework.data.redis.connection.RedisStringCommands; @@ -56,19 +52,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().get(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().get(key))); - return null; - } - return getConnection().get(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::get, key); } /* @@ -81,19 +65,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().getset(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().getset(key, value))); - return null; - } - return getConnection().getset(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::getset, key, value); } /* @@ -106,22 +78,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - - return LettuceConverters. keyValueListUnwrapper().convert(getConnection().mget(keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisStringAsyncCommands::mget, keys) + .toList(source -> source.getValueOrElse(null)); } /* @@ -134,21 +92,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().set(key, value), Converters.stringToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().set(key, value), Converters.stringToBooleanConverter())); - return null; - } - return Converters.stringToBoolean(getConnection().set(key, value)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::set, key, value) + .get(Converters.stringToBooleanConverter()); } /* @@ -163,24 +108,9 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(expiration, "Expiration must not be null!"); Assert.notNull(option, "Option must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)), - Converters.stringToBooleanConverter(), () -> false)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult( - getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)), - Converters.stringToBooleanConverter(), () -> false)); - return null; - } - return Converters - .stringToBoolean(getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke() + .from(RedisStringAsyncCommands::set, key, value, LettuceConverters.toSetArgs(expiration, option)) + .getOrElse(LettuceConverters.stringToBooleanConverter(), () -> false); } /* @@ -193,19 +123,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().setnx(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().setnx(key, value))); - return null; - } - return getConnection().setnx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::setnx, key, value); } /* @@ -218,21 +136,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().setex(key, seconds, value), - Converters.stringToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().setex(key, seconds, value), - Converters.stringToBooleanConverter())); - return null; - } - return Converters.stringToBoolean(getConnection().setex(key, seconds, value)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::setex, key, seconds, value) + .get(Converters.stringToBooleanConverter()); } /* @@ -245,21 +150,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().psetex(key, milliseconds, value), - Converters.stringToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().psetex(key, milliseconds, value), - Converters.stringToBooleanConverter())); - return null; - } - return Converters.stringToBoolean(getConnection().psetex(key, milliseconds, value)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::psetex, key, milliseconds, value) + .get(Converters.stringToBooleanConverter()); } /* @@ -271,20 +163,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(tuples, "Tuples must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().mset(tuples), Converters.stringToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().mset(tuples), Converters.stringToBooleanConverter())); - return null; - } - return Converters.stringToBoolean(getConnection().mset(tuples)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::mset, tuples).get(Converters.stringToBooleanConverter()); } /* @@ -296,19 +175,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(tuples, "Tuples must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().msetnx(tuples))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().msetnx(tuples))); - return null; - } - return getConnection().msetnx(tuples); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::msetnx, tuples); } /* @@ -320,19 +187,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().incr(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().incr(key))); - return null; - } - return getConnection().incr(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::incr, key); } /* @@ -344,19 +199,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().incrby(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().incrby(key, value))); - return null; - } - return getConnection().incrby(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::incrby, key, value); } /* @@ -368,19 +211,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().incrbyfloat(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().incrbyfloat(key, value))); - return null; - } - return getConnection().incrbyfloat(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::incrbyfloat, key, value); } /* @@ -392,19 +223,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().decr(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().decr(key))); - return null; - } - return getConnection().decr(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::decr, key); } /* @@ -416,19 +235,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().decrby(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().decrby(key, value))); - return null; - } - return getConnection().decrby(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::decrby, key, value); } /* @@ -441,19 +248,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().append(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().append(key, value))); - return null; - } - return getConnection().append(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::append, key, value); } /* @@ -465,19 +260,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().getrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().getrange(key, start, end))); - return null; - } - return getConnection().getrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::getrange, key, start, end); } /* @@ -490,19 +273,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().setrange(key, offset, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().setrange(key, offset, value))); - return; - } - getConnection().setrange(key, offset, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisStringAsyncCommands::setrange, key, offset, value); } /* @@ -514,21 +285,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().getbit(key, offset), LettuceConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().getbit(key, offset), LettuceConverters.longToBoolean())); - return null; - } - return LettuceConverters.toBoolean(getConnection().getbit(key, offset)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::getbit, key, offset) + .get(LettuceConverters.longToBoolean()); } /* @@ -540,23 +298,8 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().setbit(key, offset, LettuceConverters.toInt(value)), - LettuceConverters.longToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().setbit(key, offset, LettuceConverters.toInt(value)), - LettuceConverters.longToBooleanConverter())); - return null; - } - return LettuceConverters.longToBooleanConverter() - .convert(getConnection().setbit(key, offset, LettuceConverters.toInt(value))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisStringAsyncCommands::setbit, key, offset, LettuceConverters.toInt(value)) + .get(LettuceConverters.longToBoolean()); } /* @@ -568,19 +311,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().bitcount(key))); - return null; - } - return getConnection().bitcount(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::bitcount, key); } /* @@ -592,19 +323,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().bitcount(key, start, end))); - return null; - } - return getConnection().bitcount(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::bitcount, key, start, end); } /* @@ -619,19 +338,7 @@ class LettuceStringCommands implements RedisStringCommands { BitFieldArgs args = LettuceConverters.toBitFieldArgs(subCommands); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().bitfield(key, args))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().bitfield(key, args))); - return null; - } - return getConnection().bitfield(key, args); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisStringAsyncCommands::bitfield, key, args); } /* @@ -647,57 +354,25 @@ class LettuceStringCommands implements RedisStringCommands { if (op == BitOperation.NOT && keys.length > 1) { throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); } - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(asyncBitOp(op, destination, keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(asyncBitOp(op, destination, keys))); - return null; - } - return syncBitOp(op, destination, keys); - } catch (UnsupportedOperationException ex) { - throw ex; - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - private Future asyncBitOp(BitOperation op, byte[] destination, byte[]... keys) { - switch (op) { - case AND: - return getAsyncConnection().bitopAnd(destination, keys); - case OR: - return getAsyncConnection().bitopOr(destination, keys); - case XOR: - return getAsyncConnection().bitopXor(destination, keys); - case NOT: - if (keys.length != 1) { - throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); - } - return getAsyncConnection().bitopNot(destination, keys[0]); - default: - throw new UnsupportedOperationException("Bit operation " + op + " is not supported"); - } - } + return connection.invoke().just(it -> { - private Long syncBitOp(BitOperation op, byte[] destination, byte[]... keys) { - switch (op) { - case AND: - return getConnection().bitopAnd(destination, keys); - case OR: - return getConnection().bitopOr(destination, keys); - case XOR: - return getConnection().bitopXor(destination, keys); - case NOT: - if (keys.length != 1) { - throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); - } - return getConnection().bitopNot(destination, keys[0]); - default: - throw new UnsupportedOperationException("Bit operation " + op + " is not supported"); - } + switch (op) { + case AND: + return it.bitopAnd(destination, keys); + case OR: + return it.bitopOr(destination, keys); + case XOR: + return it.bitopXor(destination, keys); + case NOT: + if (keys.length != 1) { + throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + } + return it.bitopNot(destination, keys[0]); + default: + throw new UnsupportedOperationException("Bit operation " + op + " is not supported"); + } + }); } /* @@ -711,41 +386,17 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null! Use Range.unbounded() instead."); - try { - if (isPipelined() || isQueueing()) { + if (range.getLowerBound().isBounded()) { - RedisFuture futureResult; - RedisClusterAsyncCommands connection = getAsyncConnection(); - - if (range.getLowerBound().isBounded()) { - if (range.getUpperBound().isBounded()) { - futureResult = connection.bitpos(key, bit, getLowerValue(range), getUpperValue(range)); - } else { - futureResult = connection.bitpos(key, bit, getLowerValue(range)); - } - } else { - futureResult = connection.bitpos(key, bit); - } - - if (isPipelined()) { - pipeline(this.connection.newLettuceResult(futureResult)); - } else if (isQueueing()) { - transaction(this.connection.newLettuceResult(futureResult)); - } - return null; + if (range.getUpperBound().isBounded()) { + return connection.invoke().just(RedisStringAsyncCommands::bitpos, key, bit, getLowerValue(range), + getUpperValue(range)); } - if (range.getLowerBound().isBounded()) { - if (range.getUpperBound().isBounded()) { - return getConnection().bitpos(key, bit, getLowerValue(range), getUpperValue(range)); - } - return getConnection().bitpos(key, bit, getLowerValue(range)); - } - - return getConnection().bitpos(key, bit); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + return connection.invoke().just(RedisStringAsyncCommands::bitpos, key, bit, getLowerValue(range)); } + + return connection.invoke().just(RedisStringAsyncCommands::bitpos, key, bit); } /* @@ -757,47 +408,7 @@ class LettuceStringCommands implements RedisStringCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().strlen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().strlen(key))); - return null; - } - return getConnection().strlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } - - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } - - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + return connection.invoke().just(RedisStringAsyncCommands::strlen, key); } private static > T getUpperValue(Range range) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java index c704759da..a3d1bb643 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java @@ -19,13 +19,12 @@ import io.lettuce.core.ScanArgs; import io.lettuce.core.ScoredValue; import io.lettuce.core.ScoredValueScanCursor; import io.lettuce.core.ZStoreArgs; -import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.api.async.RedisSortedSetAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import java.util.List; import java.util.Set; -import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; @@ -58,21 +57,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zadd(key, score, value), - LettuceConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zadd(key, score, value), - LettuceConverters.longToBoolean())); - return null; - } - return LettuceConverters.toBoolean(getConnection().zadd(key, score, value)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisSortedSetAsyncCommands::zadd, key, score, value) + .get(LettuceConverters.longToBoolean()); } /* @@ -85,21 +71,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(tuples, "Tuples must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); - return null; - } - return getConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zadd, key, + LettuceConverters.toObjects(tuples).toArray()); } /* @@ -113,19 +86,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(values, "Values must not be null!"); Assert.noNullElements(values, "Values must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrem(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrem(key, values))); - return null; - } - return getConnection().zrem(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zrem, key, values); } /* @@ -138,19 +99,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zincrby(key, increment, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zincrby(key, increment, value))); - return null; - } - return getConnection().zincrby(key, increment, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zincrby, key, increment, value); } /* @@ -163,19 +112,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrank(key, value))); - return null; - } - return getConnection().zrank(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zrank, key, value); } /* @@ -187,19 +124,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrevrank(key, value))); - return null; - } - return getConnection().zrevrank(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zrevrank, key, value); } /* @@ -211,21 +136,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrange(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrange, key, start, end).toSet(); } /* @@ -237,21 +148,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangeWithScores, key, start, end) + .toSet(LettuceConverters::toTuple); } /* @@ -265,40 +163,16 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { if (limit.isUnlimited()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangebyscoreWithScores, key, + LettuceConverters. toRange(range)).toSet(LettuceConverters::toTuple); } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction(connection.newLettuceResult( - getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } else { - transaction(connection.newLettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (limit.isUnlimited()) { - return LettuceConverters - .toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range))); - } - return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrangebyscoreWithScores, key, + LettuceConverters. toRange(range), LettuceConverters.toLimit(limit)) + .toSet(LettuceConverters::toTuple); + } /* @@ -310,21 +184,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrevrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrevrange(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrevrange, key, start, end) + .toSet(LettuceInvoker.identityConverter()); } /* @@ -336,21 +197,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrevrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrevrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrevrangeWithScores, key, start, end) + .toSet(LettuceConverters::toTuple); } /* @@ -364,39 +212,16 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { if (limit.isUnlimited()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); + + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrevrangebyscore, key, LettuceConverters. toRange(range)) + .toSet(); } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction( - connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction( - connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (limit.isUnlimited()) { - return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range))); - } - return LettuceConverters.toBytesSet( - getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrevrangebyscore, key, + LettuceConverters. toRange(range), LettuceConverters.toLimit(limit)).toSet(); + } /* @@ -410,41 +235,16 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { if (limit.isUnlimited()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrevrangebyscoreWithScores, key, + LettuceConverters. toRange(range)).toSet(LettuceConverters::toTuple); } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction(connection.newLettuceResult( - getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } else { - transaction(connection.newLettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (limit.isUnlimited()) { - return LettuceConverters - .toTupleSet(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range))); - } - return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrevrangebyscoreWithScores, key, + LettuceConverters. toRange(range), LettuceConverters.toLimit(limit)) + .toSet(LettuceConverters::toTuple); + } /* @@ -456,19 +256,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zcount(key, LettuceConverters.toRange(range)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zcount, key, + LettuceConverters. toRange(range)); } /* @@ -481,19 +270,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zlexcount(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zlexcount(key, LettuceConverters.toRange(range, true)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zlexcount, key, + LettuceConverters. toRange(range, true)); } /* @@ -505,19 +283,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zcard(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zcard(key))); - return null; - } - return getConnection().zcard(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zcard, key); } /* @@ -530,19 +296,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zscore(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zscore(key, value))); - return null; - } - return getConnection().zscore(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zscore, key, value); } /* @@ -554,19 +308,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zremrangebyrank(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zremrangebyrank(key, start, end))); - return null; - } - return getConnection().zremrangebyrank(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zremrangebyrank, key, start, end); } /* @@ -579,21 +321,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREMRANGEBYSCORE must not be null!"); - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zremrangebyscore(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceResult(getAsyncConnection().zremrangebyscore(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zremrangebyscore(key, LettuceConverters.toRange(range)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zremrangebyscore, key, + LettuceConverters. toRange(range)); } /* @@ -611,19 +340,7 @@ class LettuceZSetCommands implements RedisZSetCommands { ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, storeArgs, sets))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, storeArgs, sets))); - return null; - } - return getConnection().zunionstore(destKey, storeArgs, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zunionstore, destKey, storeArgs, sets); } /* @@ -637,19 +354,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(sets, "Source sets must not be null!"); Assert.noNullElements(sets, "Source sets must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, sets))); - return null; - } - return getConnection().zunionstore(destKey, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zunionstore, destKey, sets); } /* @@ -667,19 +372,7 @@ class LettuceZSetCommands implements RedisZSetCommands { ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); - return null; - } - return getConnection().zinterstore(destKey, storeArgs, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zinterstore, destKey, storeArgs, sets); } /* @@ -693,19 +386,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(sets, "Source sets must not be null!"); Assert.noNullElements(sets, "Source sets must not contain null elements!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, sets))); - return null; - } - return getConnection().zinterstore(destKey, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().just(RedisSortedSetAsyncCommands::zinterstore, destKey, sets); } /* @@ -733,14 +414,15 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - if (isQueueing() || isPipelined()) { + if (connection.isQueueing() || connection.isPipelined()) { throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); } io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); ScanArgs scanArgs = LettuceConverters.toScanArgs(options); - ScoredValueScanCursor scoredValueScanCursor = getConnection().zscan(key, scanCursor, scanArgs); + ScoredValueScanCursor scoredValueScanCursor = connection.invoke() + .just(RedisSortedSetAsyncCommands::zscan, key, scanCursor, scanArgs); String nextCursorId = scoredValueScanCursor.getCursor(); List> result = scoredValueScanCursor.getValues(); @@ -766,21 +448,7 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangebyscore, key, min, max).toSet(); } /* @@ -792,21 +460,8 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(key, "Key must not be null!"); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max, offset, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangebyscore, key, min, max, offset, count) + .toSet(); } /* @@ -820,38 +475,13 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { - if (limit.isUnlimited()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction( - connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction( - connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (limit.isUnlimited()) { - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); - } - return LettuceConverters.toBytesSet( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + if (limit.isUnlimited()) { + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrangebyscore, key, LettuceConverters. toRange(range)).toSet(); } + + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangebyscore, key, + LettuceConverters. toRange(range), LettuceConverters.toLimit(limit)).toSet(); } /* @@ -865,42 +495,14 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZRANGEBYLEX must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { - if (limit.isUnlimited()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range, true)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range, true), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction( - connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range, true)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction( - connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range, true), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - - if (limit.isUnlimited()) { - return LettuceConverters.bytesListToBytesSet() - .convert(getConnection().zrangebylex(key, LettuceConverters.toRange(range, true))); - } - return LettuceConverters.bytesListToBytesSet().convert( - getConnection().zrangebylex(key, LettuceConverters.toRange(range, true), LettuceConverters.toLimit(limit))); - - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + if (limit.isUnlimited()) { + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrangebylex, key, LettuceConverters. toRange(range, true)) + .toSet(); } + + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrangebylex, key, + LettuceConverters. toRange(range, true), LettuceConverters.toLimit(limit)).toSet(); } /* @@ -914,72 +516,20 @@ class LettuceZSetCommands implements RedisZSetCommands { Assert.notNull(range, "Range for ZREVRANGEBYLEX must not be null!"); Assert.notNull(limit, "Limit must not be null!"); - try { - if (isPipelined()) { - if (limit.isUnlimited()) { - pipeline(connection.newLettuceResult( - getAsyncConnection().zrevrangebylex(key, LettuceConverters.toRange(range, true)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangebylex(key, - LettuceConverters.toRange(range, true), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction(connection.newLettuceResult( - getAsyncConnection().zrevrangebylex(key, LettuceConverters.toRange(range, true)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction(connection.newLettuceResult(getAsyncConnection().zrevrangebylex(key, - LettuceConverters.toRange(range, true), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - - if (limit.isUnlimited()) { - return LettuceConverters.bytesListToBytesSet() - .convert(getConnection().zrevrangebylex(key, LettuceConverters.toRange(range, true))); - } - return LettuceConverters.bytesListToBytesSet().convert(getConnection().zrevrangebylex(key, - LettuceConverters.toRange(range, true), LettuceConverters.toLimit(limit))); - - } catch (Exception ex) { - throw convertLettuceAccessException(ex); + if (limit.isUnlimited()) { + return connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrevrangebylex, key, LettuceConverters. toRange(range, true)) + .toSet(); } - } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); - } - - private void transaction(LettuceResult result) { - connection.transaction(result); - } - - RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); + return connection.invoke().fromMany(RedisSortedSetAsyncCommands::zrevrangebylex, key, + LettuceConverters. toRange(range, true), LettuceConverters.toLimit(limit)).toSet(); } public RedisClusterCommands getConnection() { return connection.getConnection(); } - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); - } - private static ZStoreArgs zStoreArgs(@Nullable Aggregate aggregate, Weights weights) { ZStoreArgs args = new ZStoreArgs(); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java index a28816579..eb5f5e97e 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionUnitTests.java @@ -20,14 +20,15 @@ import static org.mockito.Mockito.*; import static org.springframework.data.redis.connection.ClusterTestVariables.*; import static org.springframework.data.redis.test.util.MockitoUtils.*; +import io.lettuce.core.RedisFuture; import io.lettuce.core.RedisURI; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.api.StatefulRedisConnection; -import io.lettuce.core.api.sync.RedisCommands; +import io.lettuce.core.api.async.RedisAsyncCommands; import io.lettuce.core.cluster.RedisClusterClient; import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; +import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; -import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; import io.lettuce.core.cluster.models.partitions.Partitions; import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag; @@ -361,34 +362,36 @@ class LettuceClusterConnectionUnitTests { @Test // DATAREDIS-731, DATAREDIS-545 void shouldExecuteOnSharedConnection() { - RedisAdvancedClusterCommands sync = mock(RedisAdvancedClusterCommands.class); + RedisAdvancedClusterAsyncCommands async = mock(RedisAdvancedClusterAsyncCommands.class); - when(sharedConnectionMock.sync()).thenReturn(sync); + when(sharedConnectionMock.async()).thenReturn(async); + when(async.del(any())).thenReturn(mock(RedisFuture.class)); LettuceClusterConnection connection = new LettuceClusterConnection(sharedConnectionMock, connectionProviderMock, topologyProviderMock, executorMock, Duration.ZERO); connection.keyCommands().del(KEY_1_BYTES); - verify(sync).del(KEY_1_BYTES); + verify(async).del(KEY_1_BYTES); verifyNoMoreInteractions(connectionProviderMock); } @Test // DATAREDIS-731, DATAREDIS-545 void shouldExecuteOnDedicatedConnection() { - RedisCommands sync = mock(RedisCommands.class); + RedisAsyncCommands async = mock(RedisAsyncCommands.class); StatefulRedisConnection dedicatedConnection = mock(StatefulRedisConnection.class); when(connectionProviderMock.getConnection(StatefulConnection.class)).thenReturn(dedicatedConnection); - when(dedicatedConnection.sync()).thenReturn(sync); + when(dedicatedConnection.async()).thenReturn(async); + when(async.blpop(anyLong(), any())).thenReturn(mock(RedisFuture.class)); LettuceClusterConnection connection = new LettuceClusterConnection(sharedConnectionMock, connectionProviderMock, topologyProviderMock, executorMock, Duration.ZERO); connection.listCommands().bLPop(1, KEY_1_BYTES); - verify(sync).blpop(1, KEY_1_BYTES); + verify(async).blpop(1, KEY_1_BYTES); verify(connectionProviderMock).getConnection(StatefulConnection.class); verifyNoMoreInteractions(connectionProviderMock); verifyZeroInteractions(sharedConnectionMock); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index c8da2fa6b..9f0518317 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -491,7 +491,6 @@ class LettuceConnectionFactoryTests { connection.ping(); fail("Expected RedisException: Master is currently unknown"); } catch (RedisSystemException e) { - assertThat(e.getCause()).isInstanceOf(RedisException.class); assertThat(e.getCause().getMessage()).contains("Master is currently unknown"); } finally {