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 {