diff --git a/pom.xml b/pom.xml index 2ab4a03a1f..06db944d42 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,13 @@ - + 4.0.0 org.springframework.data spring-data-redis - 2.5.0-SNAPSHOT + 2.5.0-DATAREDIS-1224-SNAPSHOT Spring Data Redis 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 1d69e18f3e..12ac4432e6 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 @@ default Long lPos(byte[] key, byte[] element) { * @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/convert/LongToBooleanConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java index a6cc0d513b..8acccc6311 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java @@ -25,6 +25,8 @@ */ public class LongToBooleanConverter implements Converter { + public static final LongToBooleanConverter INSTANCE = new LongToBooleanConverter(); + /* * (non-Javadoc) * @see org.springframework.core.convert.converter.Converter#convert(Object) diff --git a/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java index 1986fea283..7da91f26df 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java @@ -35,6 +35,8 @@ */ public class StringToRedisClientInfoConverter implements Converter> { + public static final StringToRedisClientInfoConverter INSTANCE = new StringToRedisClientInfoConverter(); + /* * (non-Javadoc) * @see org.springframework.core.convert.converter.Converter#convert(Object) 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 db641048c3..3464949dbf 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 @@ public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { 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 7fe86121a7..d808cee848 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 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; @@ -107,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; @@ -115,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(); } @@ -371,17 +368,6 @@ public RedisZSetCommands zSetCommands() { 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); @@ -401,40 +387,22 @@ public Object execute(String command, byte[]... args) { 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); - validateCommandIfRunningInTransactionMode(commandType, args); + String name = command.trim().toUpperCase(); + CommandType commandType = CommandType.valueOf(name); - CommandArgs cmdArg = new CommandArgs<>(CODEC); - if (!ObjectUtils.isEmpty(args)) { - cmdArg.addKeys(args); - } - - RedisClusterAsyncCommands connectionImpl = getAsyncConnection(); + validateCommandIfRunningInTransactionMode(commandType, args); - 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()) { + CommandArgs cmdArg = new CommandArgs<>(CODEC); + if (!ObjectUtils.isEmpty(args)) { + cmdArg.addKeys(args); + } - transaction(newLettuceResult(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs()))); - return null; - } + CommandOutput expectedOutput = commandOutputTypeHint != null ? commandOutputTypeHint + : typeHints.getTypeHint(commandType); + Command cmd = new Command(commandType, expectedOutput, cmdArg); - return await(connectionImpl.dispatch(cmd.getType(), cmd.getOutput(), cmd.getArgs())); - } catch (RedisException ex) { - throw convertLettuceAccessException(ex); - } + return invoke().just(RedisClusterAsyncCommands::dispatch, cmd.getType(), cmd.getOutput(), cmd.getArgs()); } /* @@ -599,36 +567,12 @@ public List closePipeline() { */ @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 @@ -654,21 +598,23 @@ public List exec() { isMulti = false; try { + Converter exceptionConverter = this::convertLettuceAccessException; + if (isPipelined()) { RedisFuture exec = getAsyncDedicatedRedisCommands().exec(); LettuceTransactionResultConverter resultConverter = new LettuceTransactionResultConverter( - new LinkedList<>(txResults), LettuceConverters.exceptionConverter()); + new LinkedList<>(txResults), exceptionConverter); pipeline(newLettuceResult(exec, source -> resultConverter - .convert(LettuceConverters.transactionResultUnwrapper().convert((TransactionResult) source)))); + .convert(LettuceConverters.transactionResultUnwrapper().convert(source)))); return null; } - TransactionResult transactionResult = (getDedicatedRedisCommands()).exec(); + TransactionResult transactionResult = getDedicatedRedisCommands().exec(); List results = LettuceConverters.transactionResultUnwrapper().convert(transactionResult); return convertPipelineAndTxResults - ? new LettuceTransactionResultConverter(txResults, LettuceConverters.exceptionConverter()).convert(results) + ? new LettuceTransactionResultConverter(txResults, exceptionConverter).convert(results) : results; } catch (Exception ex) { throw convertLettuceAccessException(ex); @@ -702,29 +648,15 @@ public void select(int dbIndex) { + "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())); @@ -770,23 +702,7 @@ public void watch(byte[]... keys) { */ @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); } /* @@ -886,13 +802,6 @@ public void setPipeliningFlushPolicy(PipeliningFlushPolicy pipeliningFlushPolicy 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. * @@ -905,10 +814,6 @@ protected StatefulRedisPubSubConnection switchToPubSub() { return connectionProvider.getConnection(StatefulRedisPubSubConnection.class); } - private LettuceSubscription initSubscription(MessageListener listener) { - return doCreateSubscription(listener, switchToPubSub(), connectionProvider); - } - /** * Customization hook to create a {@link LettuceSubscription}. * @@ -923,7 +828,7 @@ protected LettuceSubscription doCreateSubscription(MessageListener listener, return new LettuceSubscription(listener, connection, connectionProvider); } - void pipeline(LettuceResult result) { + void pipeline(LettuceResult result) { if (flushState != null) { flushState.onCommand(getOrCreateDedicatedConnection()); @@ -936,19 +841,110 @@ void pipeline(LettuceResult result) { } } + /** + * 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()); + } + + /** + * 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); + } + + /** + * 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); + } + + private LettuceInvoker doInvoke(RedisClusterAsyncCommands connection, boolean statusCommand) { + + if (isPipelined()) { + + 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()) { + + return new LettuceInvoker(connection, (future, converter, nullDefault) -> { + try { + if (statusCommand) { + transaction(newLettuceStatusResult(future.get())); + } else { + transaction(newLettuceResult(future.get(), converter, nullDefault)); + } + + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + return null; + }); + } + + 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) { txResults.add(result); } 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(); } @@ -958,6 +954,7 @@ protected RedisClusterCommands getConnection() { if (isQueueing()) { return getDedicatedConnection(); } + if (asyncSharedConn != null) { if (asyncSharedConn instanceof StatefulRedisConnection) { @@ -967,12 +964,8 @@ protected RedisClusterCommands getConnection() { return ((StatefulRedisClusterConnection) asyncSharedConn).sync(); } } - return getDedicatedConnection(); - } - @SuppressWarnings("unchecked") - private RedisAsyncCommands getAsyncDedicatedRedisCommands() { - return (RedisAsyncCommands) getAsyncDedicatedConnection(); + return getDedicatedConnection(); } RedisClusterCommands getDedicatedConnection() { @@ -1005,6 +998,69 @@ protected RedisClusterAsyncCommands getAsyncDedicatedConnection( 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) { @@ -1020,15 +1076,23 @@ private RedisCommands getDedicatedRedisCommands() { } @SuppressWarnings("unchecked") - protected StatefulConnection doGetAsyncDedicatedConnection() { - - StatefulConnection connection = connectionProvider.getConnection(StatefulConnection.class); + private RedisAsyncCommands getAsyncDedicatedRedisCommands() { + return (RedisAsyncCommands) getAsyncDedicatedConnection(); + } - 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() { @@ -1064,47 +1128,6 @@ private void validateCommand(CommandType cmd, @Nullable byte[]... args) { } } - @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}. * @@ -1407,7 +1430,7 @@ static PipeliningFlushPolicy buffered(int bufferSize) { /** * State object associated with flushing of the currently ongoing pipeline. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1440,7 +1463,7 @@ public interface PipeliningFlushState { /** * Implementation to flush on each command. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1465,7 +1488,7 @@ public void onClose(StatefulConnection connection) {} /** * Implementation to flush on closing the pipeline. - * + * * @author Mark Paluch * @since 2.3 */ @@ -1497,7 +1520,7 @@ public void onClose(StatefulConnection connection) { /** * 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 a9c71f9a59..60177e2ac5 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 @@ -84,31 +84,11 @@ * @author Ninad Divadkar * @author dengliming */ -abstract public class LettuceConverters extends Converters { - - private static final Converter DATE_TO_LONG; - private static final Converter, Set> BYTES_LIST_TO_BYTES_SET; - private static final Converter BYTES_TO_STRING; - private static final Converter STRING_TO_BYTES; - private static final Converter, List> BYTES_SET_TO_BYTES_LIST; - private static final Converter, List> BYTES_COLLECTION_TO_BYTES_LIST; - private static final Converter, List> KEY_VALUE_TO_BYTES_LIST; - private static final Converter>, Set> SCORED_VALUES_TO_TUPLE_SET; - private static final Converter>, List> SCORED_VALUES_TO_TUPLE_LIST; - private static final Converter, Tuple> SCORED_VALUE_TO_TUPLE; +public abstract class LettuceConverters extends Converters { + private static final Converter EXCEPTION_CONVERTER = new LettuceExceptionConverter(); - private static final Converter LONG_TO_BOOLEAN = new LongToBooleanConverter(); - private static final Converter, Map> BYTES_LIST_TO_MAP; - private static final Converter, List> BYTES_LIST_TO_TUPLE_LIST_CONVERTER; - private static final Converter> STRING_TO_LIST_OF_CLIENT_INFO = new StringToRedisClientInfoConverter(); - 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; 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; - private static final Converter> TRANSACTION_RESULT_UNWRAPPER; public static final byte[] PLUS_BYTES; public static final byte[] MINUS_BYTES; @@ -120,258 +100,101 @@ abstract public class LettuceConverters extends Converters { static { - DATE_TO_LONG = source -> source != null ? source.getTime() : null; - - BYTES_LIST_TO_BYTES_SET = results -> results != null ? new LinkedHashSet<>(results) : null; - - BYTES_TO_STRING = source -> { - if (source == null || Arrays.equals(source, new byte[0])) { - return null; - } - return new String(source); - }; - - STRING_TO_BYTES = source -> { - if (source == null) { - return null; - } - return source.getBytes(); - }; - - BYTES_SET_TO_BYTES_LIST = results -> results != null ? new ArrayList<>(results) : null; - - BYTES_COLLECTION_TO_BYTES_LIST = results -> { - - if (results instanceof List) { - return (List) results; - } - return results != null ? new ArrayList<>(results) : null; - }; - - KEY_VALUE_TO_BYTES_LIST = source -> { - - if (source == null) { - return null; - } - List list = new ArrayList<>(2); - list.add(source.getKey()); - list.add(source.getValue()); - - return list; - }; - BYTES_LIST_TO_MAP = source -> { - - if (CollectionUtils.isEmpty(source)) { - return Collections.emptyMap(); - } - - Map target = new LinkedHashMap<>(); - - Iterator kv = source.iterator(); - while (kv.hasNext()) { - target.put(kv.next(), kv.hasNext() ? kv.next() : null); - } - - return target; - }; - - SCORED_VALUES_TO_TUPLE_SET = source -> { - - if (source == null) { - return null; - } - Set tuples = new LinkedHashSet<>(source.size()); - for (ScoredValue value : source) { - tuples.add(LettuceConverters.toTuple(value)); - } - return tuples; - }; - - SCORED_VALUES_TO_TUPLE_LIST = source -> { - - if (source == null) { - return null; - } - List tuples = new ArrayList<>(source.size()); - for (ScoredValue value : source) { - tuples.add(LettuceConverters.toTuple(value)); - } - return tuples; - }; - - SCORED_VALUE_TO_TUPLE = source -> source != null - ? new DefaultTuple(source.getValue(), Double.valueOf(source.getScore())) - : null; - - BYTES_LIST_TO_TUPLE_LIST_CONVERTER = source -> { - - if (CollectionUtils.isEmpty(source)) { - return Collections.emptyList(); - } - - List tuples = new ArrayList<>(); - Iterator it = source.iterator(); - while (it.hasNext()) { - tuples.add(new DefaultTuple(it.next(), it.hasNext() ? Double.valueOf(toString(it.next())) : null)); - } - return tuples; - }; - - PARTITIONS_TO_CLUSTER_NODES = new Converter>() { - - @Override - public List convert(Partitions source) { - - if (source == null) { - return Collections.emptyList(); - } - List nodes = new ArrayList<>(); - for (io.lettuce.core.cluster.models.partitions.RedisClusterNode node : source) { - nodes.add(CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER.convert(node)); - } - - return nodes; - }; - - }; - - CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER = new Converter() { - - @Override - public RedisClusterNode convert(io.lettuce.core.cluster.models.partitions.RedisClusterNode source) { - - Set flags = parseFlags(source.getFlags()); - - return RedisClusterNode.newRedisClusterNode().listeningAt(source.getUri().getHost(), source.getUri().getPort()) - .withId(source.getNodeId()).promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.SLAVE) - .serving(new SlotRange(source.getSlots())).withFlags(flags) - .linkState(source.isConnected() ? LinkState.CONNECTED : LinkState.DISCONNECTED).slaveOf(source.getSlaveOf()) - .build(); - } - - private Set parseFlags(Set source) { - - Set flags = new LinkedHashSet<>(source != null ? source.size() : 8, 1); - for (NodeFlag flag : source) { - switch (flag) { - case NOFLAGS: - flags.add(Flag.NOFLAGS); - break; - case EVENTUAL_FAIL: - flags.add(Flag.PFAIL); - break; - case FAIL: - flags.add(Flag.FAIL); - break; - case HANDSHAKE: - flags.add(Flag.HANDSHAKE); - break; - case MASTER: - flags.add(Flag.MASTER); - break; - case MYSELF: - flags.add(Flag.MYSELF); - break; - case NOADDR: - flags.add(Flag.NOADDR); - break; - case SLAVE: - flags.add(Flag.SLAVE); - break; - } - } - return flags; - } - - }; - PLUS_BYTES = toBytes("+"); MINUS_BYTES = toBytes("-"); POSITIVE_INFINITY_BYTES = toBytes("+inf"); NEGATIVE_INFINITY_BYTES = toBytes("-inf"); - BYTES_LIST_TO_TIME_CONVERTER = source -> { - - Assert.notEmpty(source, "Received invalid result from server. Expected 2 items in collection."); - Assert.isTrue(source.size() == 2, - "Received invalid nr of arguments from redis server. Expected 2 received " + source.size()); - - return toTimeMillis(toString(source.get(0)), toString(source.get(1))); - }; + GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER = new ListConverter<>(LettuceConverters::geoCoordinatesToPoint); - GEO_COORDINATE_TO_POINT_CONVERTER = geoCoordinate -> geoCoordinate != null - ? new Point(geoCoordinate.getX().doubleValue(), geoCoordinate.getY().doubleValue()) - : null; - GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER = new ListConverter<>(GEO_COORDINATE_TO_POINT_CONVERTER); - - KEY_VALUE_UNWRAPPER = source -> source.getValueOrElse(null); + KEY_VALUE_LIST_UNWRAPPER = new ListConverter<>(source -> source.getValueOrElse(null)); + } - KEY_VALUE_LIST_UNWRAPPER = new ListConverter<>(KEY_VALUE_UNWRAPPER); + @Deprecated + public static List toTuple(List source) { - TRANSACTION_RESULT_UNWRAPPER = transactionResult -> transactionResult.stream().collect(Collectors.toList()); + if (CollectionUtils.isEmpty(source)) { + return Collections.emptyList(); + } - } + List tuples = new ArrayList<>(); + Iterator it = source.iterator(); + while (it.hasNext()) { + tuples.add(new DefaultTuple(it.next(), it.hasNext() ? Double.valueOf(toString(it.next())) : null)); + } - public static List toTuple(List list) { - return BYTES_LIST_TO_TUPLE_LIST_CONVERTER.convert(list); + return tuples; } + @Deprecated public static Converter, List> bytesListToTupleListConverter() { - return BYTES_LIST_TO_TUPLE_LIST_CONVERTER; + return LettuceConverters::toTuple; } - public static Point geoCoordinatesToPoint(GeoCoordinates geoCoordinates) { - return GEO_COORDINATE_TO_POINT_CONVERTER.convert(geoCoordinates); + public static Point geoCoordinatesToPoint(@Nullable GeoCoordinates geoCoordinate) { + return geoCoordinate != null ? new Point(geoCoordinate.getX().doubleValue(), geoCoordinate.getY().doubleValue()) + : null; } public static Converter> stringToRedisClientListConverter() { - - return source -> { - - if (!StringUtils.hasText(source)) { - return Collections.emptyList(); - } - - return STRING_TO_LIST_OF_CLIENT_INFO.convert(source.split("\\r?\\n")); - }; + return LettuceConverters::toListOfRedisClientInformation; } + @Deprecated public static Converter dateToLong() { - return DATE_TO_LONG; + return LettuceConverters::toLong; } + @Deprecated public static Converter, Set> bytesListToBytesSet() { - return BYTES_LIST_TO_BYTES_SET; + return LettuceConverters::toBytesSet; } + @Deprecated public static Converter bytesToString() { - return BYTES_TO_STRING; + return LettuceConverters::toString; } + @Deprecated public static Converter, List> keyValueToBytesList() { - return KEY_VALUE_TO_BYTES_LIST; + return LettuceConverters::toBytesList; } + @Deprecated public static Converter, List> bytesSetToBytesList() { - return BYTES_COLLECTION_TO_BYTES_LIST; + return LettuceConverters::toBytesList; } + @Deprecated public static Converter, List> bytesCollectionToBytesList() { - return BYTES_COLLECTION_TO_BYTES_LIST; + return LettuceConverters::toBytesList; } + @Deprecated public static Converter>, Set> scoredValuesToTupleSet() { - return SCORED_VALUES_TO_TUPLE_SET; + return LettuceConverters::toTupleSet; } public static Converter>, List> scoredValuesToTupleList() { - return SCORED_VALUES_TO_TUPLE_LIST; + return source -> { + + if (source == null) { + return null; + } + List tuples = new ArrayList<>(source.size()); + for (ScoredValue value : source) { + tuples.add(LettuceConverters.toTuple(value)); + } + return tuples; + }; } + @Deprecated public static Converter, Tuple> scoredValueToTuple() { - return SCORED_VALUE_TO_TUPLE; + return LettuceConverters::toTuple; } + @Deprecated public static Converter exceptionConverter() { return EXCEPTION_CONVERTER; } @@ -381,35 +204,57 @@ public static Converter exceptionConverter() { * @sice 1.3 */ public static Converter longToBooleanConverter() { - return LONG_TO_BOOLEAN; + return LongToBooleanConverter.INSTANCE; } - public static Long toLong(Date source) { - return DATE_TO_LONG.convert(source); + public static Long toLong(@Nullable Date source) { + return source != null ? source.getTime() : null; } - public static Set toBytesSet(List source) { - return BYTES_LIST_TO_BYTES_SET.convert(source); + public static Set toBytesSet(@Nullable List source) { + return source != null ? new LinkedHashSet<>(source) : null; } public static List toBytesList(KeyValue source) { - return KEY_VALUE_TO_BYTES_LIST.convert(source); + + if (source == null) { + return null; + } + List list = new ArrayList<>(2); + list.add(source.getKey()); + list.add(source.getValue()); + + return list; } public static List toBytesList(Collection source) { - return BYTES_COLLECTION_TO_BYTES_LIST.convert(source); + if (source instanceof List) { + return (List) source; + } + return source != null ? new ArrayList<>(source) : null; } - public static Set toTupleSet(List> source) { - return SCORED_VALUES_TO_TUPLE_SET.convert(source); + @Deprecated + public static Set toTupleSet(@Nullable List> source) { + if (source == null) { + return null; + } + Set tuples = new LinkedHashSet<>(source.size()); + for (ScoredValue value : source) { + tuples.add(LettuceConverters.toTuple(value)); + } + return tuples; } - public static Tuple toTuple(ScoredValue source) { - return SCORED_VALUE_TO_TUPLE.convert(source); + public static Tuple toTuple(@Nullable ScoredValue source) { + return source != null ? new DefaultTuple(source.getValue(), Double.valueOf(source.getScore())) : null; } - public static String toString(byte[] source) { - return BYTES_TO_STRING.convert(source); + public static String toString(@Nullable byte[] source) { + if (source == null || Arrays.equals(source, new byte[0])) { + return null; + } + return new String(source); } public static ScriptOutputType toScriptOutputType(ReturnType returnType) { @@ -440,11 +285,23 @@ public static int toInt(boolean value) { } public static Map toMap(List source) { - return BYTES_LIST_TO_MAP.convert(source); + if (CollectionUtils.isEmpty(source)) { + return Collections.emptyMap(); + } + + Map target = new LinkedHashMap<>(); + + Iterator kv = source.iterator(); + while (kv.hasNext()) { + target.put(kv.next(), kv.hasNext() ? kv.next() : null); + } + + return target; } + @Deprecated public static Converter, Map> bytesListToMapConverter() { - return BYTES_LIST_TO_MAP; + return LettuceConverters::toMap; } public static SortArgs toSortArgs(SortParameters params) { @@ -480,9 +337,15 @@ public static SortArgs toSortArgs(SortParameters params) { } public static List toListOfRedisClientInformation(String clientList) { - return stringToRedisClientListConverter().convert(clientList); + + if (!StringUtils.hasText(clientList)) { + return Collections.emptyList(); + } + + return StringToRedisClientInfoConverter.INSTANCE.convert(clientList.split("\\r?\\n")); } + @Deprecated public static byte[][] subarray(byte[][] input, int index) { if (input.length > index) { @@ -494,6 +357,7 @@ public static byte[][] subarray(byte[][] input, int index) { return null; } + @Deprecated public static String boundaryToStringForZRange(Boundary boundary, String defaultValue) { if (boundary == null || boundary.getValue() == null) { @@ -668,8 +532,11 @@ public static RedisURI sentinelConfigurationToRedisURI(RedisSentinelConfiguratio return builder.build(); } - public static byte[] toBytes(String source) { - return STRING_TO_BYTES.convert(source); + public static byte[] toBytes(@Nullable String source) { + if (source == null) { + return null; + } + return source.getBytes(); } public static byte[] toBytes(Integer source) { @@ -698,6 +565,7 @@ public static byte[] toBytes(Double source) { * @return * @since 1.6 */ + @Deprecated public static String boundaryToBytesForZRange(Boundary boundary, byte[] defaultValue) { if (boundary == null || boundary.getValue() == null) { @@ -714,6 +582,7 @@ public static String boundaryToBytesForZRange(Boundary boundary, byte[] defaultV * @return * @since 1.6 */ + @Deprecated public static String boundaryToBytesForZRangeByLex(Boundary boundary, byte[] defaultValue) { if (boundary == null || boundary.getValue() == null) { @@ -747,8 +616,19 @@ private static String boundaryToBytes(Boundary boundary, byte[] inclPrefix, byte return toString(ByteUtils.getBytes(buffer)); } - public static List partitionsToClusterNodes(Partitions partitions) { - return PARTITIONS_TO_CLUSTER_NODES.convert(partitions); + public static List partitionsToClusterNodes(@Nullable Partitions source) { + + if (source == null) { + return Collections.emptyList(); + } + + List nodes = new ArrayList<>(); + + for (io.lettuce.core.cluster.models.partitions.RedisClusterNode node : source) { + nodes.add(toRedisClusterNode(node)); + } + + return nodes; } /** @@ -757,7 +637,48 @@ public static List partitionsToClusterNodes(Partitions partiti * @since 1.7 */ public static RedisClusterNode toRedisClusterNode(io.lettuce.core.cluster.models.partitions.RedisClusterNode source) { - return CLUSTER_NODE_TO_CLUSTER_NODE_CONVERTER.convert(source); + + Set flags = parseFlags(source.getFlags()); + + return RedisClusterNode.newRedisClusterNode().listeningAt(source.getUri().getHost(), source.getUri().getPort()) + .withId(source.getNodeId()).promotedAs(flags.contains(Flag.MASTER) ? NodeType.MASTER : NodeType.SLAVE) + .serving(new SlotRange(source.getSlots())).withFlags(flags) + .linkState(source.isConnected() ? LinkState.CONNECTED : LinkState.DISCONNECTED).slaveOf(source.getSlaveOf()) + .build(); + } + + private static Set parseFlags(@Nullable Set source) { + + Set flags = new LinkedHashSet<>(source != null ? source.size() : 8, 1); + for (NodeFlag flag : source) { + switch (flag) { + case NOFLAGS: + flags.add(Flag.NOFLAGS); + break; + case EVENTUAL_FAIL: + flags.add(Flag.PFAIL); + break; + case FAIL: + flags.add(Flag.FAIL); + break; + case HANDSHAKE: + flags.add(Flag.HANDSHAKE); + break; + case MASTER: + flags.add(Flag.MASTER); + break; + case MYSELF: + flags.add(Flag.MYSELF); + break; + case NOADDR: + flags.add(Flag.NOADDR); + break; + case SLAVE: + flags.add(Flag.SLAVE); + break; + } + } + return flags; } /** @@ -805,7 +726,15 @@ public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOp } static Converter, Long> toTimeConverter() { - return BYTES_LIST_TO_TIME_CONVERTER; + + return source -> { + + Assert.notEmpty(source, "Received invalid result from server. Expected 2 items in collection."); + Assert.isTrue(source.size() == 2, + "Received invalid nr of arguments from redis server. Expected 2 received " + source.size()); + + return toTimeMillis(toString(source.get(0)), toString(source.get(1))); + }; } /** @@ -989,6 +918,7 @@ public static Converter>, GeoResults> * @return * @since 1.8 */ + @Deprecated public static ListConverter geoCoordinatesToPointConverter() { return GEO_COORDINATE_LIST_TO_POINT_LIST_CONVERTER; } @@ -998,12 +928,13 @@ public static ListConverter geoCoordinate * @since 2.0 */ @SuppressWarnings("unchecked") + @Deprecated public static ListConverter, V> keyValueListUnwrapper() { return (ListConverter) KEY_VALUE_LIST_UNWRAPPER; } public static Converter> transactionResultUnwrapper() { - return TRANSACTION_RESULT_UNWRAPPER; + return transactionResult -> transactionResult.stream().collect(Collectors.toList()); } /** @@ -1115,7 +1046,7 @@ public GeoResultConverter(Metric metric) { @Override public GeoResult> convert(GeoWithin source) { - Point point = GEO_COORDINATE_TO_POINT_CONVERTER.convert(source.getCoordinates()); + Point point = geoCoordinatesToPoint(source.getCoordinates()); return new GeoResult<>(new GeoLocation<>(source.getMember(), point), new Distance(source.getDistance() != null ? source.getDistance() : 0D, metric)); 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 0dc4b0b693..9b8c3b0f0d 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,17 +25,14 @@ 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.RedisGeoCommands; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -65,19 +60,7 @@ public Long geoAdd(byte[] key, Point point, byte[] member) { 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); } /* @@ -124,21 +107,7 @@ public Long geoAdd(byte[] key, Iterable> locations) { @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())); } /* @@ -165,23 +134,8 @@ public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metri GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(metric); Converter distanceConverter = LettuceConverters.distanceConverterForMetric(metric); - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geodist(key, member1, member2, geoUnit), - distanceConverter)); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceResult(getAsyncConnection().geodist(key, member1, member2, geoUnit), - distanceConverter)); - return null; - } - - Double distance = getConnection().geodist(key, member1, member2, geoUnit); - return distance != null ? distanceConverter.convert(distance) : null; - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + return connection.invoke().from(RedisGeoAsyncCommands::geodist, key, member1, member2, geoUnit) + .get(distanceConverter); } /* @@ -195,20 +149,8 @@ public List geoHash(byte[] key, byte[]... members) { 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)); } /* @@ -222,21 +164,8 @@ public List geoPos(byte[] key, byte[]... members) { 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::geoCoordinatesToPoint); } /* @@ -252,27 +181,10 @@ public GeoResults> geoRadius(byte[] key, Circle within) { 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); } /* @@ -290,25 +202,10 @@ public GeoResults> geoRadius(byte[] key, Circle within, GeoR 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); } /* @@ -335,21 +232,8 @@ public GeoResults> geoRadiusByMember(byte[] key, byte[] memb 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); } /* @@ -370,24 +254,9 @@ public GeoResults> geoRadiusByMember(byte[] key, byte[] memb 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); } /* @@ -399,31 +268,4 @@ public Long geoRemove(byte[] key, byte[]... values) { 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 873f429db0..dd210fad74 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 @@ 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 @@ public Boolean hSet(byte[] key, byte[] field, byte[] value) { 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 @@ public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { 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 @@ public Long hDel(byte[] key, byte[]... fields) { 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 @@ public Boolean hExists(byte[] key, byte[] field) { 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 @@ public byte[] hGet(byte[] key, byte[] field) { 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 @@ public Map hGetAll(byte[] key) { 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 @@ public Long hIncrBy(byte[] key, byte[] field, long delta) { 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 @@ public Double hIncrBy(byte[] key, byte[] field, double delta) { 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 @@ public Set hKeys(byte[] key) { 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().fromMany(RedisHashAsyncCommands::hkeys, key).toSet(); } /* @@ -282,19 +171,7 @@ public Long hLen(byte[] key) { 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 @@ public List hMGet(byte[] key, byte[]... fields) { 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 @@ public void hMSet(byte[] key, Map hashes) { 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 @@ public List hVals(byte[] key) { 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 @@ public Cursor> hScan(byte[] key, long cursorId, ScanOption @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 @@ public Long hStrLen(byte[] key, byte[] field) { 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 6e8bb1269d..bb981df2fc 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 @@ public Long pfAdd(byte[] key, byte[]... values) { 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 @@ public Long pfCount(byte[]... keys) { 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 @@ public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { 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 0000000000..83af96084c --- /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 f0b562a4b1..1fd74e3261 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.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 @@ public Boolean exists(byte[] key) { 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 @@ public Long exists(byte[]... keys) { 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 @@ public Long del(byte[]... keys) { 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 @@ public Long unlink(byte[]... keys) { 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 @@ public DataType type(byte[] key) { 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 @@ public Long touch(byte[]... keys) { 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 @@ public Set keys(byte[] pattern) { 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().fromMany(RedisKeyAsyncCommands::keys, pattern).toSet(); } /** @@ -257,13 +167,12 @@ private Cursor doScan(ScanOptions options) { @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 @@ protected void doClose() { */ @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 @@ public void rename(byte[] sourceKey, byte[] targetKey) { 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 @@ public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { 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 @@ public Boolean expire(byte[] key, long seconds) { 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 @@ public Boolean pExpire(byte[] key, long millis) { 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 @@ public Boolean expireAt(byte[] key, long unixTime) { 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 @@ public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { 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 @@ public Boolean persist(byte[] key) { 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 @@ public Boolean move(byte[] key, int dbIndex) { 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 @@ public Long ttl(byte[] key) { 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 @@ public Long ttl(byte[] key, TimeUnit timeUnit) { 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 @@ public Long pTtl(byte[] key) { 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 @@ public Long pTtl(byte[] key, TimeUnit timeUnit) { 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 @@ public List sort(byte[] key, SortParameters params) { 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 @@ public Long sort(byte[] key, SortParameters params, byte[] sortKey) { 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 @@ public byte[] dump(byte[] key) { 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 @@ public void restore(byte[] key, long ttlInMillis, byte[] serializedValue, boolea 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); - - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().restore(key, serializedValue, restoreArgs))); - return; - } - - if (isQueueing()) { - transaction(connection.newLettuceStatusResult(getAsyncConnection().restore(key, serializedValue, restoreArgs))); - return; - } + RestoreArgs restoreArgs = RestoreArgs.Builder.ttl(ttlInMillis).replace(replace); - getConnection().restore(key, serializedValue, restoreArgs); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } + connection.invokeStatus().just(RedisKeyAsyncCommands::restore, key, serializedValue, restoreArgs); } /* @@ -711,22 +406,8 @@ public ValueEncoding encodingOf(byte[] key) { 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.invoke().from(RedisKeyAsyncCommands::objectEncoding, key).getOrElse(ValueEncoding::of, + () -> RedisValueEncoding.VACANT); } /* @@ -739,21 +420,7 @@ public Duration idletime(byte[] key) { 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 @@ public Long refcount(byte[] key) { 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); - } - } - - 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(); + return connection.invoke().just(RedisKeyAsyncCommands::objectRefcount, key); } - - 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 c183a7b4c2..5ba9aaae95 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 @@ -15,14 +15,14 @@ */ package org.springframework.data.redis.connection.lettuce; +import io.lettuce.core.KeyValue; 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.ArrayList; 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 +49,7 @@ public Long rPush(byte[] key, byte[]... values) { 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 +66,12 @@ public List lPos(byte[] key, byte[] element, @Nullable Integer rank, @Null 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 +85,7 @@ public Long lPush(byte[] key, byte[]... values) { 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 +98,7 @@ public Long rPushX(byte[] key, byte[] value) { 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 +111,7 @@ public Long lPushX(byte[] key, byte[] value) { 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 +123,7 @@ public Long lLen(byte[] key) { 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 +135,7 @@ public List lRange(byte[] key, long start, long end) { 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 +147,7 @@ public void lTrim(byte[] key, long start, long end) { 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 +159,7 @@ public byte[] lIndex(byte[] key, long index) { 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 +171,8 @@ public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { 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 +185,7 @@ public void lSet(byte[] key, long index, byte[] value) { 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 +198,7 @@ public Long lRem(byte[] key, long count, byte[] value) { 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 +210,7 @@ public byte[] lPop(byte[] key) { 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 +222,7 @@ public byte[] rPop(byte[] key) { 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 +235,17 @@ public List bLPop(int timeout, byte[]... keys) { 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(LettuceListCommands::toBytesList); + } + + private static List toBytesList(KeyValue source) { + + List list = new ArrayList<>(2); + list.add(source.getKey()); + list.add(source.getValue()); + + return list; } /* @@ -440,21 +258,8 @@ public List bRPop(int timeout, byte[]... keys) { 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(LettuceListCommands::toBytesList); } /* @@ -467,19 +272,7 @@ public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { 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 +285,8 @@ public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { 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 0008f3b5d8..91aeaef75d 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 @@ public void scriptFlush() { @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 @@ public String scriptLoad(byte[] script) { 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 @@ public List scriptExists(String... scriptSha1) { 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 @@ public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... k 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 @@ public T evalSha(String scriptSha1, ReturnType returnType, int numKeys, byte 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 @@ public T evalSha(byte[] scriptSha1, ReturnType returnType, int numKeys, byte 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 @@ private static byte[][] extractScriptArgs(int numKeys, byte[]... keysAndArgs) { } private class LettuceEvalResultsConverter implements Converter { - private ReturnType returnType; + + private final ReturnType returnType; public LettuceEvalResultsConverter(ReturnType returnType) { this.returnType = returnType; @@ -263,7 +162,7 @@ public T convert(Object source) { 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 911395a45c..68fe9fbda9 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 @@ public void bgReWriteAof() { */ @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 @@ public void bgSave() { */ @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::toLong); } /* @@ -113,20 +77,7 @@ public Long lastSave() { */ @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 @@ public void save() { */ @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 @@ public Long dbSize() { */ @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 @@ public void flushDb() { */ @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 @@ public void flushAll() { */ @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 @@ public Properties info(String section) { 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 @@ public Properties info(String section) { */ @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 @@ public void shutdown(ShutdownOption option) { } 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 @@ public Properties getConfig(String pattern) { 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 @@ public void setConfig(String param, String value) { 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 @@ public void setConfig(String param, String value) { */ @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 @@ public void resetConfigStats() { */ @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 @@ public void killClient(String host, int port) { 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 @@ public void setClientName(byte[] name) { 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 @@ public void setClientName(byte[] name) { */ @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::toString); } /* @@ -450,16 +251,12 @@ public String getClientName() { @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 @@ public void slaveOf(String host, int port) { 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 @@ public void slaveOf(String host, int port) { */ @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 @@ public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable Migrate 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); - } + connection.invoke().just(RedisKeyAsyncCommands::migrate, target.getHost(), target.getPort(), key, dbIndex, timeout); } - private boolean isPipelined() { - return connection.isPipelined(); - } - - private boolean isQueueing() { - return connection.isQueueing(); - } - - private void pipeline(LettuceResult result) { - connection.pipeline(result); + public RedisClusterCommands getConnection() { + return connection.getConnection(); } - private void transaction(LettuceResult result) { - connection.transaction(result); - } + static class CompletedRedisFuture extends CompletableFuture implements RedisFuture { - private RedisClusterAsyncCommands getAsyncConnection() { - return connection.getAsyncConnection(); - } + public CompletedRedisFuture(T value) { + complete(value); + } - public RedisClusterCommands getConnection() { - return connection.getConnection(); - } + @Override + public String getError() { + return ""; + } - private DataAccessException convertLettuceAccessException(Exception ex) { - return connection.convertLettuceAccessException(ex); + @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 b86b33e9e8..802288a022 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 @@ 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 @@ public Long sAdd(byte[] key, byte[]... values) { 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 @@ public Long sCard(byte[] key) { 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 @@ public Set sDiff(byte[]... keys) { 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 @@ public Long sDiffStore(byte[] destKey, byte[]... keys) { 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 @@ public Set sInter(byte[]... keys) { 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 @@ public Long sInterStore(byte[] destKey, byte[]... keys) { 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 @@ public Boolean sIsMember(byte[] key, byte[] value) { 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 @@ public Set sMembers(byte[] key) { 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 @@ public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { 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 @@ public byte[] sPop(byte[] key) { 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 @@ public List sPop(byte[] key, long count) { 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 @@ public byte[] sRandMember(byte[] key) { 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 @@ public List sRandMember(byte[] key, long count) { 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 @@ public Long sRem(byte[] key, byte[]... values) { 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 @@ public Set sUnion(byte[]... keys) { 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 @@ public Long sUnionStore(byte[] destKey, byte[]... keys) { 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 @@ public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { @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 @@ protected void doClose() { }.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 ed5860da9d..35e59b9ead 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.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 @@ public Long xAck(byte[] key, String group, RecordId... recordIds) { 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 @@ public RecordId xAdd(MapRecord record, XAddOptions optio 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 @@ public List xClaimJustId(byte[] key, String group, String newOwner, XC 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 @@ public List xClaim(byte[] key, String group, String newOwner, XClaim 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 @@ public Long xDel(byte[] key, RecordId... recordIds) { 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 @@ public String xGroupCreate(byte[] key, String groupName, ReadOffset readOffset, 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()); - - 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); - } + XReadArgs.StreamOffset streamOffset = XReadArgs.StreamOffset.from(key, readOffset.getOffset()); + + return connection.invoke().just(RedisStreamAsyncCommands::xgroupCreate, streamOffset, + LettuceConverters.toBytes(groupName), XGroupCreateArgs.Builder.mkstream(mkSteam)); } /* @@ -262,23 +176,10 @@ public Boolean xGroupDelConsumer(byte[] key, Consumer consumer) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(consumer, "Consumer must not be null!"); - try { - 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); - } + io.lettuce.core.Consumer lettuceConsumer = toConsumer(consumer); + + return connection.invoke().from(RedisStreamAsyncCommands::xgroupDelconsumer, key, lettuceConsumer) + .get(Objects::nonNull); } /* @@ -291,21 +192,7 @@ public Boolean xGroupDestroy(byte[] key, String groupName) { 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 @@ public XInfoStream xInfo(byte[] key) { 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 @@ public XInfoGroups xInfoGroups(byte[] key) { 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 @@ public XInfoConsumers xInfoConsumers(byte[] key, String groupName) { 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 @@ public Long xLen(byte[] key) { 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 @@ public Long xLen(byte[] key) { 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 @@ public PendingMessagesSummary xPending(byte[] key, String groupName) { 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 (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); + if (options.hasConsumer()) { + + 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 @@ public List xRange(byte[] key, Range range, Limit limit) { 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 @@ public List xRead(StreamReadOptions readOptions, StreamOffset xReadGroup(Consumer consumer, StreamReadOptions readOpti 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 @@ public List xRevRange(byte[] key, Range range, Limit limit) 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 @@ public Long xTrim(byte[] key, long count) { 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 0f448b44a1..1a563187ce 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 @@ public byte[] get(byte[] key) { 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 @@ public byte[] getSet(byte[] key, byte[] value) { 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 @@ public List mGet(byte[]... keys) { 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 @@ public Boolean set(byte[] key, byte[] value) { 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 @@ public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption op 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 @@ public Boolean setNX(byte[] key, byte[] value) { 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 @@ public Boolean setEx(byte[] key, long seconds, byte[] value) { 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 @@ public Boolean pSetEx(byte[] key, long milliseconds, byte[] value) { 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 @@ public Boolean mSet(Map tuples) { 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 @@ public Boolean mSetNX(Map tuples) { 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 @@ public Long incr(byte[] key) { 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 @@ public Long incrBy(byte[] key, long value) { 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 @@ public Double incrBy(byte[] key, double value) { 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 @@ public Long decr(byte[] key) { 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 @@ public Long decrBy(byte[] key, long value) { 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 @@ public Long append(byte[] key, byte[] value) { 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 @@ public byte[] getRange(byte[] key, long start, long end) { 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 @@ public void setRange(byte[] key, byte[] value, long offset) { 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 @@ public Boolean getBit(byte[] key, long offset) { 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 @@ public Boolean setBit(byte[] key, long offset, boolean value) { 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 @@ public Long bitCount(byte[] key) { 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 @@ public Long bitCount(byte[] key, long start, long end) { 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 @@ public List bitField(byte[] key, BitFieldSubCommands subCommands) { 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 @@ public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { 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"); - } - } - 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"); - } + return connection.invoke().just(it -> { + + 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 @@ public Long bitPos(byte[] key, boolean bit, Range range) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null! Use Range.unbounded() instead."); - try { - if (isPipelined() || isQueueing()) { - - 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.getLowerBound().isBounded()) { - if (range.getLowerBound().isBounded()) { - if (range.getUpperBound().isBounded()) { - return getConnection().bitpos(key, bit, getLowerValue(range), getUpperValue(range)); - } - return getConnection().bitpos(key, bit, getLowerValue(range)); + if (range.getUpperBound().isBounded()) { + return connection.invoke().just(RedisStringAsyncCommands::bitpos, key, bit, getLowerValue(range), + getUpperValue(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 @@ public Long strLen(byte[] key) { 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 c704759da0..a3d1bb643a 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.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 @@ public Boolean zAdd(byte[] key, double score, byte[] value) { 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 @@ public Long zAdd(byte[] key, Set tuples) { 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 @@ public Long zRem(byte[] key, byte[]... values) { 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 @@ public Double zIncrBy(byte[] key, double increment, byte[] value) { 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 @@ public Long zRank(byte[] key, byte[] value) { 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 @@ public Long zRevRank(byte[] key, byte[] value) { 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 @@ public Set zRange(byte[] key, long start, long end) { 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 @@ public Set zRangeWithScores(byte[] key, long start, long end) { 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 @@ public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) 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 @@ public Set zRevRange(byte[] key, long start, long end) { 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 @@ public Set zRevRangeWithScores(byte[] key, long start, long end) { 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 @@ public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { 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 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 connection.invoke() + .fromMany(RedisSortedSetAsyncCommands::zrevrangebyscore, key, LettuceConverters. toRange(range)) + .toSet(); } - 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 @@ public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limi 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 @@ public Long zCount(byte[] key, Range range) { 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 @@ public Long zLexCount(byte[] key, Range range) { 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 @@ public Long zCard(byte[] key) { 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 @@ public Double zScore(byte[] key, byte[] value) { 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 @@ public Long zRemRange(byte[] key, long start, long end) { 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 @@ public Long zRemRangeByScore(byte[] key, Range range) { 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 @@ public Long zUnionStore(byte[] destKey, Aggregate aggregate, Weights weights, by 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 @@ public Long zUnionStore(byte[] destKey, byte[]... sets) { 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 @@ public Long zInterStore(byte[] destKey, Aggregate aggregate, Weights weights, by 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 @@ public Long zInterStore(byte[] destKey, byte[]... sets) { 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 @@ public Cursor zScan(byte[] key, long cursorId, ScanOptions options) { @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 @@ public Set zRangeByScore(byte[] key, String min, String max) { 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 @@ public Set zRangeByScore(byte[] key, String min, String max, long offset 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 @@ public Set zRangeByScore(byte[] key, Range range, Limit limit) { 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 @@ public Set zRangeByLex(byte[] key, Range range, Limit limit) { 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 @@ public Set zRevRangeByLex(byte[] key, Range range, Limit limit) { 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 a288165794..eb5f5e97e3 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.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 @@ void resetConfigStatsShouldBeExecutedOnSingleNodeCorrectly() { @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 c8da2fa6b2..9f05183179 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 @@ void factoryUsesElastiCacheMasterWithoutMaster() { 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 {