From c636400104be8fd7d09b2032a97e7f0fbf0100a5 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 18 Apr 2017 15:21:47 +0200 Subject: [PATCH] DATAREDIS-626 - Refactor RedisConnection implementations to Redis feature-specific interfaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We refactored JedisConnection and LettuceConnection from monolithic connection classes into modular classes that organize methods according the Redis feature group and created segregated interfaces per Redis feature group. Segregated interfaces reduce the number of methods available on the interface to the used data type. This refactoring reduces the responsibility of JedisConnection/LettuceConnection and JedisClusterConnection/LettuceClusterConnection to a minimum of commands. To preserve backwards-compatibility with users of the connection classes, we introduced DefaultedRedisConnection and DefaultedRedisClusterConnection to forward calls from the connection facade to the specific implementation. Deprecation of connection facade method assists migration off these methods towards using methods on the feature group interface. LettuceConnection connection = … connection.keyCommands().del(key); connection.hashCommands().hSet(key, field, value); Original pull request: #247. --- .../connection/AbstractRedisConnection.java | 2 +- .../DefaultStringRedisConnection.java | 6 +- .../DefaultedRedisClusterConnection.java | 24 + .../connection/DefaultedRedisConnection.java | 1015 +++++ .../data/redis/connection/RedisCommands.java | 2 +- .../redis/connection/RedisConnection.java | 81 +- .../redis/connection/RedisGeoCommands.java | 18 +- ...nds.java => RedisHyperLogLogCommands.java} | 2 +- .../redis/connection/RedisStringCommands.java | 4 +- .../redis/connection/RedisZSetCommands.java | 82 +- .../connection/StringRedisConnection.java | 6 +- .../jedis/JedisClusterConnection.java | 2681 +------------ .../jedis/JedisClusterGeoCommands.java | 284 ++ .../jedis/JedisClusterHashCommands.java | 250 ++ .../JedisClusterHyperLogLogCommands.java | 93 + .../jedis/JedisClusterKeyCommands.java | 482 +++ .../jedis/JedisClusterListCommands.java | 313 ++ .../jedis/JedisClusterSetCommands.java | 393 ++ .../jedis/JedisClusterStringCommands.java | 463 +++ .../jedis/JedisClusterZSetCommands.java | 681 ++++ .../connection/jedis/JedisConnection.java | 3383 ++--------------- .../connection/jedis/JedisGeoCommands.java | 433 +++ .../connection/jedis/JedisHashCommands.java | 396 ++ .../jedis/JedisHyperLogLogCommands.java | 126 + .../connection/jedis/JedisKeyCommands.java | 634 +++ .../connection/jedis/JedisListCommands.java | 443 +++ .../connection/jedis/JedisSetCommands.java | 419 ++ .../connection/jedis/JedisStringCommands.java | 580 +++ .../connection/jedis/JedisZSetCommands.java | 853 +++++ .../lettuce/LettuceClusterConnection.java | 595 +-- .../lettuce/LettuceClusterGeoCommands.java | 27 + .../lettuce/LettuceClusterHashCommands.java | 27 + .../LettuceClusterHyperLogLogCommands.java | 71 + .../lettuce/LettuceClusterKeyCommands.java | 235 ++ .../lettuce/LettuceClusterListCommands.java | 125 + .../lettuce/LettuceClusterSetCommands.java | 220 ++ .../lettuce/LettuceClusterStringCommands.java | 55 + .../lettuce/LettuceClusterZSetCommands.java | 27 + .../connection/lettuce/LettuceConnection.java | 3018 +-------------- .../lettuce/LettuceGeoCommands.java | 452 +++ .../lettuce/LettuceHashCommands.java | 395 ++ .../lettuce/LettuceHyperLogLogCommands.java | 157 + .../lettuce/LettuceKeyCommands.java | 604 +++ .../lettuce/LettuceListCommands.java | 433 +++ .../lettuce/LettuceSetCommands.java | 437 +++ .../lettuce/LettuceStringCommands.java | 514 +++ .../lettuce/LettuceZSetCommands.java | 841 ++++ .../jedis/JedisConnectionUnitTestSuite.java | 4 +- 48 files changed, 13183 insertions(+), 9203 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java create mode 100644 src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java rename src/main/java/org/springframework/data/redis/connection/{HyperLogLogCommands.java => RedisHyperLogLogCommands.java} (97%) create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterGeoCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHashCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterZSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java create mode 100644 src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java diff --git a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java index c7e324ab7..9ce3a20b9 100644 --- a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java @@ -27,7 +27,7 @@ import org.springframework.data.redis.RedisSystemException; * @author Christoph Strobl * @since 1.4 */ -public abstract class AbstractRedisConnection implements RedisConnection { +public abstract class AbstractRedisConnection implements DefaultedRedisConnection { private RedisSentinelConfiguration sentinelConfiguration; private ConcurrentHashMap connectionCache = new ConcurrentHashMap(); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index f0ce25f8f..73095226a 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -3034,7 +3034,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfAdd(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfAdd(byte[], byte[][]) */ @Override public Long pfAdd(byte[] key, byte[]... values) { @@ -3052,7 +3052,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfCount(byte[][]) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfCount(byte[][]) */ @Override public Long pfCount(byte[]... keys) { @@ -3070,7 +3070,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfMerge(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfMerge(byte[], byte[][]) */ @Override public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java new file mode 100644 index 000000000..9695324bf --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisClusterConnection.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017 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 + * + * http://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; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +public interface DefaultedRedisClusterConnection extends RedisClusterConnection, DefaultedRedisConnection { + +} diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java new file mode 100644 index 000000000..4a558cffe --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -0,0 +1,1015 @@ +/* + * Copyright 2017 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 + * + * http://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; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +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.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.types.Expiration; + +/** + * {@link DefaultedRedisConnection} provides method delegates to {@code Redis*Command} interfaces accessible via {@link RedisConnection}. + * This allows us to maintain backwards compatibility while moving the actual implementation and stay in sync with {@link ReactiveRedisConnection}. + * Going forward the {@link RedisCommands} extension is likely to be removed from {@link RedisConnection}. + * @author Christoph Strobl + * @since 2.0 + */ +public interface DefaultedRedisConnection extends RedisConnection { + + // KEY COMMANDS + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean exists(byte[] key) { + return keyCommands().exists(key); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long del(byte[]... keys) { + return keyCommands().del(keys); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default DataType type(byte[] pattern) { + return keyCommands().type(pattern); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Set keys(byte[] pattern) { + return keyCommands().keys(pattern); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Cursor scan(ScanOptions options) { + return keyCommands().scan(options); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default byte[] randomKey() { + return keyCommands().randomKey(); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default void rename(byte[] oldName, byte[] newName) { + keyCommands().rename(oldName, newName); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean renameNX(byte[] oldName, byte[] newName) { + return keyCommands().renameNX(oldName, newName); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean expire(byte[] key, long seconds) { + return keyCommands().expire(key, seconds); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean persist(byte[] key) { + return keyCommands().persist(key); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean move(byte[] key, int dbIndex) { + return keyCommands().move(key, dbIndex); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + keyCommands().restore(key, ttlInMillis, serializedValue); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long pTtl(byte[] key) { + return keyCommands().pTtl(key); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long pTtl(byte[] key, TimeUnit timeUnit) { + return keyCommands().pTtl(key, timeUnit); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean pExpire(byte[] key, long millis) { + return keyCommands().pExpire(key, millis); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + return keyCommands().pExpireAt(key, unixTimeInMillis); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Boolean expireAt(byte[] key, long unixTime) { + return keyCommands().expireAt(key, unixTime); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long ttl(byte[] key) { + return keyCommands().ttl(key); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long ttl(byte[] key, TimeUnit timeUnit) { + return keyCommands().ttl(key, timeUnit); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default byte[] dump(byte[] key) { + return keyCommands().dump(key); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default List sort(byte[] key, SortParameters params) { + return keyCommands().sort(key, params); + } + + /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ + @Override + @Deprecated + default Long sort(byte[] key, SortParameters params, byte[] sortKey) { + return keyCommands().sort(key, params, sortKey); + } + + // STRING COMMANDS + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default byte[] get(byte[] key) { + return stringCommands().get(key); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default byte[] getSet(byte[] key, byte[] value) { + return stringCommands().getSet(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default List mGet(byte[]... keys) { + return stringCommands().mGet(keys); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void set(byte[] key, byte[] value) { + stringCommands().set(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + stringCommands().set(key, value, expiration, option); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Boolean setNX(byte[] key, byte[] value) { + return stringCommands().setNX(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void setEx(byte[] key, long seconds, byte[] value) { + stringCommands().setEx(key, seconds, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void pSetEx(byte[] key, long milliseconds, byte[] value) { + stringCommands().pSetEx(key, milliseconds, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void mSet(Map tuple) { + stringCommands().mSet(tuple); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Boolean mSetNX(Map tuple) { + return stringCommands().mSetNX(tuple); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long incr(byte[] key) { + return stringCommands().incr(key); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Double incrBy(byte[] key, double value) { + return stringCommands().incrBy(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long incrBy(byte[] key, long value) { + return stringCommands().incrBy(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long decr(byte[] key) { + return stringCommands().decr(key); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long decrBy(byte[] key, long value) { + return stringCommands().decrBy(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long append(byte[] key, byte[] value) { + return stringCommands().append(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default byte[] getRange(byte[] key, long begin, long end) { + return stringCommands().getRange(key, begin, end); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default void setRange(byte[] key, byte[] value, long offset) { + stringCommands().setRange(key, value, offset); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Boolean getBit(byte[] key, long offset) { + return stringCommands().getBit(key, offset); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Boolean setBit(byte[] key, long offset, boolean value) { + return stringCommands().setBit(key, offset, value); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long bitCount(byte[] key) { + return stringCommands().bitCount(key); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long bitCount(byte[] key, long begin, long end) { + return stringCommands().bitCount(key, begin, end); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + return stringCommands().bitOp(op, destination, keys); + } + + /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ + @Override + @Deprecated + default Long strLen(byte[] key) { + return stringCommands().strLen(key); + } + + // LIST COMMANDS + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long rPush(byte[] key, byte[]... values) { + return listCommands().rPush(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long lPush(byte[] key, byte[]... values) { + return listCommands().lPush(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long rPushX(byte[] key, byte[] value) { + return listCommands().rPushX(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long lPushX(byte[] key, byte[] value) { + return listCommands().lPushX(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long lLen(byte[] key) { + return listCommands().lLen(key); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default List lRange(byte[] key, long start, long end) { + return listCommands().lRange(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default void lTrim(byte[] key, long start, long end) { + listCommands().lTrim(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default byte[] lIndex(byte[] key, long index) { + return listCommands().lIndex(key, index); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + return listCommands().lInsert(key, where, pivot, value); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default void lSet(byte[] key, long index, byte[] value) { + listCommands().lSet(key, index, value); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default Long lRem(byte[] key, long count, byte[] value) { + return listCommands().lRem(key, count, value); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default byte[] lPop(byte[] key) { + return listCommands().lPop(key); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default byte[] rPop(byte[] key) { + return listCommands().rPop(key); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default List bLPop(int timeout, byte[]... keys) { + return listCommands().bLPop(timeout, keys); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default List bRPop(int timeout, byte[]... keys) { + return listCommands().bRPop(timeout, keys); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + return listCommands().rPopLPush(srcKey, dstKey); + } + + /** @deprecated in favor of {@link RedisConnection#listCommands()}}. */ + @Override + @Deprecated + default byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + return listCommands().bRPopLPush(timeout, srcKey, dstKey); + } + + // SET COMMANDS + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sAdd(byte[] key, byte[]... values) { + return setCommands().sAdd(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sCard(byte[] key) { + return setCommands().sCard(key); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Set sDiff(byte[]... keys) { + return setCommands().sDiff(keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sDiffStore(byte[] destKey, byte[]... keys) { + return setCommands().sDiffStore(destKey, keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Set sInter(byte[]... keys) { + return setCommands().sInter(keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sInterStore(byte[] destKey, byte[]... keys) { + return setCommands().sInterStore(destKey, keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Boolean sIsMember(byte[] key, byte[] value) { + return setCommands().sIsMember(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Set sMembers(byte[] key) { + return setCommands().sMembers(key); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + return setCommands().sMove(srcKey, destKey, value); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default byte[] sPop(byte[] key) { + return setCommands().sPop(key); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default byte[] sRandMember(byte[] key) { + return setCommands().sRandMember(key); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default List sRandMember(byte[] key, long count) { + return setCommands().sRandMember(key, count); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sRem(byte[] key, byte[]... values) { + return setCommands().sRem(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Set sUnion(byte[]... keys) { + return setCommands().sUnion(keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Long sUnionStore(byte[] destKey, byte[]... keys) { + return setCommands().sUnionStore(destKey, keys); + } + + /** @deprecated in favor of {@link RedisConnection#setCommands()}}. */ + @Override + @Deprecated + default Cursor sScan(byte[] key, ScanOptions options) { + return setCommands().sScan(key, options); + } + + // ZSET COMMANDS + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Boolean zAdd(byte[] key, double score, byte[] value) { + return zSetCommands().zAdd(key, score, value); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zAdd(byte[] key, Set tuples) { + return zSetCommands().zAdd(key, tuples); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zCard(byte[] key) { + return zSetCommands().zCard(key); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zCount(byte[] key, double min, double max) { + return zSetCommands().zCount(key, min, max); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zCount(byte[] key, Range range) { + return zSetCommands().zCount(key, range); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Double zIncrBy(byte[] key, double increment, byte[] value) { + return zSetCommands().zIncrBy(key, increment, value); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + return zSetCommands().zInterStore(destKey, aggregate, weights, sets); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zInterStore(byte[] destKey, byte[]... sets) { + return zSetCommands().zInterStore(destKey, sets); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRange(byte[] key, long start, long end) { + return zSetCommands().zRange(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeWithScores(byte[] key, long start, long end) { + return zSetCommands().zRangeWithScores(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeByLex(byte[] key, Range range, Limit limit) { + return zSetCommands().zRangeByLex(key, range, limit); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeByScore(byte[] key, Range range, Limit limit) { + return zSetCommands().zRangeByScore(key, range, limit); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + return zSetCommands().zRangeByScoreWithScores(key, range, limit); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRevRangeWithScores(byte[] key, long start, long end) { + return zSetCommands().zRevRangeWithScores(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + return zSetCommands().zRevRangeByScore(key, range, limit); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + return zSetCommands().zRevRangeByScoreWithScores(key, range, limit); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRank(byte[] key, byte[] value) { + return zSetCommands().zRank(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRem(byte[] key, byte[]... values) { + return zSetCommands().zRem(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRemRange(byte[] key, long start, long end) { + return zSetCommands().zRemRange(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRemRangeByScore(byte[] key, Range range) { + return zSetCommands().zRemRangeByScore(key, range); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRemRangeByScore(byte[] key, double min, double max) { + return zSetCommands().zRemRangeByScore(key, min, max); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRevRange(byte[] key, long start, long end) { + return zSetCommands().zRevRange(key, start, end); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zRevRank(byte[] key, byte[] value) { + return zSetCommands().zRevRank(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Double zScore(byte[] key, byte[] value) { + return zSetCommands().zScore(key, value); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + return zSetCommands().zUnionStore(destKey, aggregate, weights, sets); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Long zUnionStore(byte[] destKey, byte[]... sets) { + return zSetCommands().zUnionStore(destKey, sets); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Cursor zScan(byte[] key, ScanOptions options) { + return zSetCommands().zScan(key, options); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeByScore(byte[] key, String min, String max) { + return zSetCommands().zRangeByScore(key, min, max); + } + + /** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */ + @Override + @Deprecated + default Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + return zSetCommands().zRangeByScore(key, min, max, offset, count); + } + + // HASH COMMANDS + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Boolean hSet(byte[] key, byte[] field, byte[] value) { + return hashCommands().hSet(key, field, value); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + return hashCommands().hSetNX(key, field, value); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Long hDel(byte[] key, byte[]... fields) { + return hashCommands().hDel(key, fields); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Boolean hExists(byte[] key, byte[] field) { + return hashCommands().hExists(key, field); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default byte[] hGet(byte[] key, byte[] field) { + return hashCommands().hGet(key, field); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Map hGetAll(byte[] key) { + return hashCommands().hGetAll(key); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Double hIncrBy(byte[] key, byte[] field, double delta) { + return hashCommands().hIncrBy(key, field, delta); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Long hIncrBy(byte[] key, byte[] field, long delta) { + return hashCommands().hIncrBy(key, field, delta); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Set hKeys(byte[] key) { + return hashCommands().hKeys(key); + } + + @Override + default Long hLen(byte[] key) { + return hashCommands().hLen(key); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default List hMGet(byte[] key, byte[]... fields) { + return hashCommands().hMGet(key, fields); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default void hMSet(byte[] key, Map hashes) { + hashCommands().hMSet(key, hashes); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default List hVals(byte[] key) { + return hashCommands().hVals(key); + } + + /** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */ + @Override + @Deprecated + default Cursor> hScan(byte[] key, ScanOptions options) { + return hashCommands().hScan(key, options); + } + + // GEO COMMANDS + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Long geoAdd(byte[] key, Point point, byte[] member) { + return geoCommands().geoAdd(key, point, member); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Long geoAdd(byte[] key, Map memberCoordinateMap) { + return geoCommands().geoAdd(key, memberCoordinateMap); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Long geoAdd(byte[] key, Iterable> locations) { + return geoCommands().geoAdd(key, locations); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Distance geoDist(byte[] key, byte[] member1, byte[] member2) { + return geoCommands().geoDist(key, member1, member2); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { + return geoCommands().geoDist(key, member1, member2, metric); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default List geoHash(byte[] key, byte[]... members) { + return geoCommands().geoHash(key, members); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default List geoPos(byte[] key, byte[]... members) { + return geoCommands().geoPos(key, members); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default GeoResults> geoRadius(byte[] key, Circle within) { + return geoCommands().geoRadius(key, within); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { + return geoCommands().geoRadius(key, within, args); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { + return geoCommands().geoRadiusByMember(key, member, radius); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, + GeoRadiusCommandArgs args) { + return geoCommands().geoRadiusByMember(key, member, radius, args); + } + + /** @deprecated in favor of {@link RedisConnection#geoCommands()}}. */ + @Override + @Deprecated + default Long geoRemove(byte[] key, byte[]... members) { + return geoCommands().geoRemove(key, members); + } + + // HLL COMMANDS + + /** @deprecated in favor of {@link RedisConnection#hyperLogLogCommands()}. */ + @Override + @Deprecated + default Long pfAdd(byte[] key, byte[]... values) { + return hyperLogLogCommands().pfAdd(key, values); + } + + /** @deprecated in favor of {@link RedisConnection#hyperLogLogCommands()}. */ + @Override + @Deprecated + default Long pfCount(byte[]... keys) { + return hyperLogLogCommands().pfCount(keys); + } + + /** @deprecated in favor of {@link RedisConnection#hyperLogLogCommands()}. */ + @Override + @Deprecated + default void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + hyperLogLogCommands().pfMerge(destinationKey, sourceKeys); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/RedisCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisCommands.java index ee3725617..f0b3020e4 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisCommands.java @@ -24,7 +24,7 @@ package org.springframework.data.redis.connection; */ public interface RedisCommands extends RedisKeyCommands, RedisStringCommands, RedisListCommands, RedisSetCommands, RedisZSetCommands, RedisHashCommands, RedisTxCommands, RedisPubSubCommands, RedisConnectionCommands, - RedisServerCommands, RedisScriptingCommands, RedisGeoCommands, HyperLogLogCommands { + RedisServerCommands, RedisScriptingCommands, RedisGeoCommands, RedisHyperLogLogCommands { /** * 'Native' or 'raw' execution of the given command along-side the given arguments. The command is executed as is, diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java index 2171ca5dd..148b067e9 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2017 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. @@ -26,9 +26,88 @@ import org.springframework.dao.DataAccessException; * The methods follow as much as possible the Redis names and conventions. * * @author Costin Leau + * @author Christoph Strobl */ public interface RedisConnection extends RedisCommands { + /** + * Get {@link RedisGeoCommands}. + * + * @return never {@literal null}. + */ + default RedisGeoCommands geoCommands() { + return this; + } + + /** + * Get {@link RedisHashCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisHashCommands hashCommands() { + return this; + } + + /** + * Get {@link RedisHyperLogLogCommands}. + * + * @return never {@literal null}. + */ + default RedisHyperLogLogCommands hyperLogLogCommands() { + return this; + } + + /** + * Get {@link RedisKeyCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisKeyCommands keyCommands() { + return this; + } + + /** + * Get {@link RedisListCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisListCommands listCommands() { + return this; + } + + /** + * Get {@link RedisSetCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisSetCommands setCommands() { + return this; + } + + /** + * Get {@link RedisStringCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisStringCommands stringCommands() { + return this; + } + + /** + * Get {@link RedisZSetCommands}. + * + * @return never {@literal null}. + * @since 2.0 + */ + default RedisZSetCommands zSetCommands() { + return this; + } + /** * Closes (or quits) the connection. * diff --git a/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java index c60755fb2..830ed1c85 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java @@ -60,7 +60,13 @@ public interface RedisGeoCommands { * @return Number of elements added. * @see Redis Documentation: GEOADD */ - Long geoAdd(byte[] key, GeoLocation location); + default Long geoAdd(byte[] key, GeoLocation location) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(location, "Location must not be null!"); + + return geoAdd(key, location.getPoint(), location.getName()); + } /** * Add {@link Map} of member / {@link Point} pairs to {@literal key}. @@ -156,7 +162,9 @@ public interface RedisGeoCommands { * @return never {@literal null}. * @see Redis Documentation: GEORADIUSBYMEMBER */ - GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius); + default GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { + return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); + } /** * Get the {@literal member}s within the circle defined by the {@literal members} coordinates and given @@ -201,7 +209,7 @@ public interface RedisGeoCommands { * @author Christoph Strobl * @since 1.8 */ - public class GeoRadiusCommandArgs implements Cloneable { + class GeoRadiusCommandArgs implements Cloneable { Set flags = new LinkedHashSet(2, 1); Long limit; @@ -332,7 +340,7 @@ public interface RedisGeoCommands { */ @Data @RequiredArgsConstructor - public static class GeoLocation { + class GeoLocation { private final T name; private final Point point; @@ -344,7 +352,7 @@ public interface RedisGeoCommands { * @author Christoph Strobl * @since 1.8 */ - public static enum DistanceUnit implements Metric { + enum DistanceUnit implements Metric { METERS(6378137, "m"), KILOMETERS(6378.137, "km"), MILES(3963.191, "mi"), FEET(20925646.325, "ft"); diff --git a/src/main/java/org/springframework/data/redis/connection/HyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java similarity index 97% rename from src/main/java/org/springframework/data/redis/connection/HyperLogLogCommands.java rename to src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java index 7869202f1..d05c83047 100644 --- a/src/main/java/org/springframework/data/redis/connection/HyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java @@ -22,7 +22,7 @@ package org.springframework.data.redis.connection; * @author Mark Paluch * @since 1.5 */ -public interface HyperLogLogCommands { +public interface RedisHyperLogLogCommands { /** * Adds given {@literal values} to the HyperLogLog stored at given {@literal key}. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java index 3e7bda6a6..489c46f3e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java @@ -29,7 +29,7 @@ import org.springframework.data.redis.core.types.Expiration; */ public interface RedisStringCommands { - public enum BitOperation { + enum BitOperation { AND, OR, XOR, NOT; } @@ -278,7 +278,7 @@ public interface RedisStringCommands { * @author Christoph Strobl * @since 1.7 */ - public static enum SetOption { + enum SetOption { /** * Do not set any additional command argument. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java index 7f872dd34..d16b544fa 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -35,14 +35,14 @@ public interface RedisZSetCommands { /** * Sort aggregation operations. */ - public enum Aggregate { + enum Aggregate { SUM, MIN, MAX; } /** * ZSet tuple. */ - public interface Tuple extends Comparable { + interface Tuple extends Comparable { byte[] getValue(); @@ -55,7 +55,7 @@ public interface RedisZSetCommands { * @author Christoph Strobl * @since 1.6 */ - public class Range { + class Range { Boundary min; Boundary max; @@ -177,7 +177,7 @@ public interface RedisZSetCommands { * @author Christoph Strobl * @since 1.6 */ - public class Limit { + class Limit { int offset; int count; @@ -298,7 +298,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScore(byte[] key, double min, double max); + default Set zRangeByScore(byte[] key, double min, double max) { + return zRangeByScore(key, new Range().gte(min).lte(max)); + } /** * Get set of {@link Tuple}s where score is between {@code Range#min} and {@code Range#max} from sorted set. @@ -309,7 +311,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScoreWithScores(byte[] key, Range range); + default Set zRangeByScoreWithScores(byte[] key, Range range) { + return zRangeByScoreWithScores(key, range, null); + } /** * Get set of {@link Tuple}s where score is between {@code min} and {@code max} from sorted set. @@ -320,7 +324,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScoreWithScores(byte[] key, double min, double max); + default Set zRangeByScoreWithScores(byte[] key, double min, double max) { + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); + } /** * Get elements in range from {@code start} to {@code end} where score is between {@code min} and {@code max} from @@ -334,7 +340,10 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScore(byte[] key, double min, double max, long offset, long count); + default Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { + return zRangeByScore(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } /** * Get set of {@link Tuple}s in range from {@code start} to {@code end} where score is between {@code min} and @@ -348,7 +357,10 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count); + default Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } /** * Get set of {@link Tuple}s in range from {@code Limit#offset} to {@code Limit#offset + Limit#count} where score is @@ -394,7 +406,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZREVRANGE */ - Set zRevRangeByScore(byte[] key, double min, double max); + default Set zRevRangeByScore(byte[] key, double min, double max) { + return zRevRangeByScore(key, new Range().gte(min).lte(max)); + } /** * Get elements where score is between {@code Range#min} and {@code Range#max} from sorted set ordered from high to @@ -406,7 +420,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ - Set zRevRangeByScore(byte[] key, Range range); + default Set zRevRangeByScore(byte[] key, Range range) { + return zRevRangeByScore(key, range, null); + } /** * Get set of {@link Tuple} where score is between {@code min} and {@code max} from sorted set ordered from high to @@ -418,7 +434,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZREVRANGEBYSCORE */ - Set zRevRangeByScoreWithScores(byte[] key, double min, double max); + default Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), null); + } /** * Get elements in range from {@code start} to {@code end} where score is between {@code min} and {@code max} from @@ -432,7 +450,11 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZREVRANGEBYSCORE */ - Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count); + default Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { + + return zRevRangeByScore(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } /** * Get elements in range from {@code Limit#offset} to {@code Limit#offset + Limit#count} where score is between @@ -459,7 +481,11 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZREVRANGEBYSCORE */ - Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count); + default Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), + new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); + } /** * Get set of {@link Tuple} where score is between {@code Range#min} and {@code Range#max} from sorted set ordered @@ -471,7 +497,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ - Set zRevRangeByScoreWithScores(byte[] key, Range range); + default Set zRevRangeByScoreWithScores(byte[] key, Range range) { + return zRevRangeByScoreWithScores(key, range, null); + } /** * Get set of {@link Tuple} in range from {@code Limit#offset} to {@code Limit#count} where score is between @@ -495,7 +523,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZCOUNT */ - Long zCount(byte[] key, double min, double max); + default Long zCount(byte[] key, double min, double max) { + return zCount(key, new Range().gte(min).lte(max)); + } /** * Count number of elements within sorted set with scores between {@code Range#min} and {@code Range#max}. @@ -547,7 +577,9 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZREMRANGEBYSCORE */ - Long zRemRangeByScore(byte[] key, double min, double max); + default Long zRemRangeByScore(byte[] key, double min, double max) { + return zRemRangeByScore(key, new Range().gte(min).lte(max)); + } /** * Remove elements with scores between {@code Range#min} and {@code Range#max} from sorted set with {@code key}. @@ -625,7 +657,9 @@ public interface RedisZSetCommands { * @since 1.5 * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScore(byte[] key, String min, String max); + default Set zRangeByScore(byte[] key, String min, String max) { + return zRangeByScore(key, new Range().gte(min).lte(max)); + } /** * Get elements where score is between {@code Range#min} and {@code Range#max} from sorted set. @@ -636,7 +670,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ - Set zRangeByScore(byte[] key, Range range); + default Set zRangeByScore(byte[] key, Range range) { + return zRangeByScore(key, range, null); + } /** * Get elements in range from {@code start} to {@code end} where score is between {@code min} and {@code max} from @@ -674,7 +710,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZRANGEBYLEX */ - Set zRangeByLex(byte[] key); + default Set zRangeByLex(byte[] key) { + return zRangeByLex(key, Range.unbounded()); + } /** * Get all the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. @@ -685,7 +723,9 @@ public interface RedisZSetCommands { * @since 1.6 * @see Redis Documentation: ZRANGEBYLEX */ - Set zRangeByLex(byte[] key, Range range); + default Set zRangeByLex(byte[] key, Range range) { + return zRangeByLex(key, range, null); + } /** * Get all the elements in {@link Range} from the sorted set at {@literal key} in lexicographical ordering. Result is diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index e9f6208db..714c9c4f7 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -1502,7 +1502,7 @@ public interface StringRedisConnection extends RedisConnection { * @return * @since 1.5 * @see Redis Documentation: PFADD - * @see HyperLogLogCommands#pfAdd(byte[], byte[]...) + * @see RedisHyperLogLogCommands#pfAdd(byte[], byte[]...) */ Long pfAdd(String key, String... values); @@ -1512,7 +1512,7 @@ public interface StringRedisConnection extends RedisConnection { * @param keys must not be {@literal null}. * @return * @see Redis Documentation: PFCOUNT - * @see HyperLogLogCommands#pfCount(byte[]...) + * @see RedisHyperLogLogCommands#pfCount(byte[]...) */ Long pfCount(String... keys); @@ -1522,7 +1522,7 @@ public interface StringRedisConnection extends RedisConnection { * @param destinationKey must not be {@literal null}. * @param sourceKeys must not be {@literal null}. * @see Redis Documentation: PFMERGE - * @see HyperLogLogCommands#pfMerge(byte[], byte[]...) + * @see RedisHyperLogLogCommands#pfMerge(byte[], byte[]...) */ void pfMerge(String destinationKey, String... sourceKeys); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java index e6e614ff0..b8ffb96ae 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java @@ -15,30 +15,25 @@ */ package org.springframework.data.redis.connection.jedis; +import redis.clients.jedis.BinaryJedisPubSub; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPool; + import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.Random; import java.util.Set; -import java.util.concurrent.TimeUnit; import org.springframework.beans.DirectFieldAccessor; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; -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.ClusterStateFailureException; import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; @@ -48,43 +43,31 @@ import org.springframework.data.redis.connection.ClusterCommandExecutor.MultiKey import org.springframework.data.redis.connection.ClusterCommandExecutor.NodeResult; import org.springframework.data.redis.connection.ClusterInfo; import org.springframework.data.redis.connection.ClusterNodeResourceProvider; -import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.ClusterTopology; import org.springframework.data.redis.connection.ClusterTopologyProvider; -import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.DefaultedRedisClusterConnection; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisClusterConnection; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.RedisHashCommands; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisPipelineException; import org.springframework.data.redis.connection.RedisSentinelConnection; +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.RedisSubscribedConnectionException; +import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.util.ByteArraySet; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.ScanCursor; -import org.springframework.data.redis.core.ScanIteration; -import org.springframework.data.redis.core.ScanOptions; -import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; -import org.springframework.data.redis.util.ByteUtils; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; - -import redis.clients.jedis.BinaryJedisPubSub; -import redis.clients.jedis.GeoCoordinate; -import redis.clients.jedis.GeoUnit; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ZParams; -import redis.clients.jedis.params.geo.GeoRadiusParam; /** * {@link RedisClusterConnection} implementation on top of {@link JedisCluster}.
@@ -96,7 +79,7 @@ import redis.clients.jedis.params.geo.GeoRadiusParam; * @author Ninad Divadkar * @since 1.7 */ -public class JedisClusterConnection implements RedisClusterConnection { +public class JedisClusterConnection implements DefaultedRedisClusterConnection { private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( JedisConverters.exceptionConverter()); @@ -164,126 +147,53 @@ public class JedisClusterConnection implements RedisClusterConnection { throw new UnsupportedOperationException("Execute is currently not supported in cluster mode."); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) - */ @Override - public Long del(byte[]... keys) { - - Assert.noNullElements(keys, "Keys must not be null or contain null key!"); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - try { - return cluster.del(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - return Long - .valueOf(this.clusterCommandExecutor.executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback() { - - @Override - public Long doInCluster(Jedis client, byte[] key) { - return client.del(key); - } - }, Arrays.asList(keys)).resultsAsList().size()); + public RedisGeoCommands geoCommands() { + return new JedisClusterGeoCommands(this); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) - */ @Override - public DataType type(byte[] key) { - - try { - return JedisConverters.toDataType(cluster.type(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + public RedisHashCommands hashCommands() { + return new JedisClusterHashCommands(this); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) - */ @Override - public Set keys(final byte[] pattern) { - - Assert.notNull(pattern, "Pattern must not be null!"); - - Collection> keysPerNode = clusterCommandExecutor - .executeCommandOnAllNodes(new JedisClusterCommandCallback>() { - - @Override - public Set doInCluster(Jedis client) { - return client.keys(pattern); - } - }).resultsAsList(); - - Set keys = new HashSet(); - for (Set keySet : keysPerNode) { - keys.addAll(keySet); - } - return keys; + public RedisHyperLogLogCommands hyperLogLogCommands() { + return new JedisClusterHyperLogLogCommands(this); + } + + @Override + public RedisKeyCommands keyCommands() { + return doGetKeyCommands(); + } + + @Override + public RedisStringCommands stringCommands() { + return new JedisClusterStringCommands(this); + } + + @Override + public RedisListCommands listCommands() { + return new JedisClusterListCommands(this); + } + + @Override + public RedisSetCommands setCommands() { + return new JedisClusterSetCommands(this); + } + + @Override + public RedisZSetCommands zSetCommands() { + return new JedisClusterZSetCommands(this); + } + + private JedisClusterKeyCommands doGetKeyCommands() { + return new JedisClusterKeyCommands(this); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) - */ @Override public Set keys(RedisClusterNode node, final byte[] pattern) { - - Assert.notNull(pattern, "Pattern must not be null!"); - - return clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback>() { - - @Override - public Set doInCluster(Jedis client) { - return client.keys(pattern); - } - }, node).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor scan(ScanOptions options) { - throw new InvalidDataAccessApiUsageException("Scan is not supported accros multiple nodes within a cluster"); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() - */ - @Override - public byte[] randomKey() { - - List nodes = new ArrayList( - topologyProvider.getTopology().getActiveMasterNodes()); - Set inspectedNodes = new HashSet(nodes.size()); - - do { - - RedisClusterNode node = nodes.get(new Random().nextInt(nodes.size())); - - while (inspectedNodes.contains(node)) { - node = nodes.get(new Random().nextInt(nodes.size())); - } - inspectedNodes.add(node); - byte[] key = randomKey(node); - - if (key != null && key.length > 0) { - return key; - } - } while (nodes.size() != inspectedNodes.size()); - - return null; + return doGetKeyCommands().keys(node, pattern); } /* @@ -292,2160 +202,7 @@ public class JedisClusterConnection implements RedisClusterConnection { */ @Override public byte[] randomKey(RedisClusterNode node) { - - return clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public byte[] doInCluster(Jedis client) { - return client.randomBinaryKey(); - } - }, node).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) - */ - @Override - public void rename(final byte[] sourceKey, final byte[] targetKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { - - try { - cluster.rename(sourceKey, targetKey); - return; - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - byte[] value = dump(sourceKey); - - if (value != null && value.length > 0) { - - restore(targetKey, 0, value); - del(sourceKey); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) - */ - @Override - public Boolean renameNX(final byte[] sourceKey, final byte[] targetKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { - - try { - return JedisConverters.toBoolean(cluster.renamenx(sourceKey, targetKey)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - byte[] value = dump(sourceKey); - - if (value != null && value.length > 0 && !exists(targetKey)) { - - restore(targetKey, 0, value); - del(sourceKey); - return Boolean.TRUE; - } - return Boolean.FALSE; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#expire(byte[], long) - */ - @Override - public Boolean expire(byte[] key, long seconds) { - - if (seconds > Integer.MAX_VALUE) { - throw new UnsupportedOperationException("Jedis does not support seconds exceeding Integer.MAX_VALUE."); - } - try { - return JedisConverters.toBoolean(cluster.expire(key, Long.valueOf(seconds).intValue())); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) - */ - @Override - public Boolean pExpire(final byte[] key, final long millis) { - - try { - return JedisConverters.toBoolean(cluster.pexpire(key, millis)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) - */ - @Override - public Boolean expireAt(byte[] key, long unixTime) { - - try { - return JedisConverters.toBoolean(cluster.expireAt(key, unixTime)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) - */ - @Override - public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { - - try { - return JedisConverters.toBoolean(cluster.pexpireAt(key, unixTimeInMillis)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) - */ - @Override - public Boolean persist(byte[] key) { - - try { - return JedisConverters.toBoolean(cluster.persist(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) - */ - @Override - public Boolean move(byte[] key, int dbIndex) { - throw new UnsupportedOperationException("Cluster mode does not allow moving keys."); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) - */ - @Override - public Long ttl(byte[] key) { - - try { - return cluster.ttl(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long ttl(byte[] key, TimeUnit timeUnit) { - - try { - return Converters.secondsToTimeUnit(cluster.ttl(key), timeUnit); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) - */ - @Override - public Long pTtl(final byte[] key) { - - return clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public Long doInCluster(Jedis client) { - return client.pttl(key); - } - }, topologyProvider.getTopology().getKeyServingMasterNode(key)).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long pTtl(final byte[] key, final TimeUnit timeUnit) { - - return clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public Long doInCluster(Jedis client) { - return Converters.millisecondsToTimeUnit(client.pttl(key), timeUnit); - } - }, topologyProvider.getTopology().getKeyServingMasterNode(key)).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) - */ - @Override - public List sort(byte[] key, SortParameters params) { - - try { - return cluster.sort(key, JedisConverters.toSortingParams(params)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) - */ - @Override - public Long sort(byte[] key, SortParameters params, byte[] storeKey) { - - List sorted = sort(key, params); - if (!CollectionUtils.isEmpty(sorted)) { - - byte[][] arr = new byte[sorted.size()][]; - switch (type(key)) { - - case SET: - sAdd(storeKey, sorted.toArray(arr)); - return 1L; - case LIST: - lPush(storeKey, sorted.toArray(arr)); - return 1L; - default: - throw new IllegalArgumentException("sort and store is only supported for SET and LIST"); - } - } - return 0L; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) - */ - @Override - public byte[] dump(final byte[] key) { - - return clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public byte[] doInCluster(Jedis client) { - return client.dump(key); - } - }, topologyProvider.getTopology().getKeyServingMasterNode(key)).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) - */ - @Override - public void restore(final byte[] key, final long ttlInMillis, final byte[] serializedValue) { - - if (ttlInMillis > Integer.MAX_VALUE) { - throw new UnsupportedOperationException("Jedis does not support ttlInMillis exceeding Integer.MAX_VALUE."); - } - - this.clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public String doInCluster(Jedis client) { - return client.restore(key, Long.valueOf(ttlInMillis).intValue(), serializedValue); - } - }, clusterGetNodeForKey(key)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[]) - */ - @Override - public byte[] get(byte[] key) { - - try { - return cluster.get(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[]) - */ - @Override - public byte[] getSet(byte[] key, byte[] value) { - - try { - return cluster.getSet(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#mGet(byte[][]) - */ - @Override - public List mGet(byte[]... keys) { - - Assert.noNullElements(keys, "Keys must not contain null elements!"); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return cluster.mget(keys); - } - - return this.clusterCommandExecutor.executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback() { - - @Override - public byte[] doInCluster(Jedis client, byte[] key) { - return client.get(key); - } - }, Arrays.asList(keys)).resultsAsListSortBy(keys); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[]) - */ - @Override - public void set(byte[] key, byte[] value) { - - try { - cluster.set(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions) - */ - @Override - public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { - - if (expiration == null || expiration.isPersistent()) { - - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { - set(key, value); - } else { - - // BinaryCluster does not support set with nxxx and binary key/value pairs. - if (ObjectUtils.nullSafeEquals(SetOption.SET_IF_PRESENT, option)) { - throw new UnsupportedOperationException("Jedis does not support SET XX without PX or EX on BinaryCluster."); - } - - setNX(key, value); - } - } else { - - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { - - if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) { - pSetEx(key, expiration.getExpirationTime(), value); - } else { - setEx(key, expiration.getExpirationTime(), value); - } - } else { - - byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); - byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration); - - try { - cluster.set(key, value, nxxx, expx, expiration.getExpirationTime()); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#setNX(byte[], byte[]) - */ - @Override - public Boolean setNX(byte[] key, byte[] value) { - - try { - return JedisConverters.toBoolean(cluster.setnx(key, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#setEx(byte[], long, byte[]) - */ - @Override - public void setEx(byte[] key, long seconds, byte[] value) { - - if (seconds > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Seconds have cannot exceed Integer.MAX_VALUE!"); - } - - try { - cluster.setex(key, Long.valueOf(seconds).intValue(), value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) - */ - @Override - public void pSetEx(final byte[] key, final long milliseconds, final byte[] value) { - - if (milliseconds > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Milliseconds have cannot exceed Integer.MAX_VALUE!"); - } - - this.clusterCommandExecutor.executeCommandOnSingleNode(new JedisClusterCommandCallback() { - - @Override - public String doInCluster(Jedis client) { - return client.psetex(key, milliseconds, value); - } - }, topologyProvider.getTopology().getKeyServingMasterNode(key)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#mSet(java.util.Map) - */ - @Override - public void mSet(Map tuples) { - - Assert.notNull(tuples, "Tuples must not be null!"); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { - try { - cluster.mset(JedisConverters.toByteArrays(tuples)); - return; - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - for (Map.Entry entry : tuples.entrySet()) { - set(entry.getKey(), entry.getValue()); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#mSetNX(java.util.Map) - */ - @Override - public Boolean mSetNX(Map tuples) { - - Assert.notNull(tuples, "Tuple must not be null!"); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { - try { - return JedisConverters.toBoolean(cluster.msetnx(JedisConverters.toByteArrays(tuples))); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - boolean result = true; - for (Map.Entry entry : tuples.entrySet()) { - if (!setNX(entry.getKey(), entry.getValue()) && result) { - result = false; - } - } - return result; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#incr(byte[]) - */ - @Override - public Long incr(byte[] key) { - - try { - return cluster.incr(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], long) - */ - @Override - public Long incrBy(byte[] key, long value) { - - try { - return cluster.incrBy(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], double) - */ - @Override - public Double incrBy(byte[] key, double value) { - - try { - return cluster.incrByFloat(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#decr(byte[]) - */ - @Override - public Long decr(byte[] key) { - - try { - return cluster.decr(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#decrBy(byte[], long) - */ - @Override - public Long decrBy(byte[] key, long value) { - - try { - return cluster.decrBy(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#append(byte[], byte[]) - */ - @Override - public Long append(byte[] key, byte[] value) { - - try { - return cluster.append(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#getRange(byte[], long, long) - */ - @Override - public byte[] getRange(byte[] key, long begin, long end) { - - try { - return cluster.getrange(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#setRange(byte[], byte[], long) - */ - @Override - public void setRange(byte[] key, byte[] value, long offset) { - - try { - cluster.setrange(key, offset, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Boolean getBit(byte[] key, long offset) { - - try { - return cluster.getbit(key, offset); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Boolean setBit(byte[] key, long offset, boolean value) { - - try { - return cluster.setbit(key, offset, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Long bitCount(byte[] key) { - - try { - return cluster.bitcount(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Long bitCount(byte[] key, long begin, long end) { - - try { - return cluster.bitcount(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destination, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - return cluster.bitop(JedisConverters.toBitOp(op), destination, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new InvalidDataAccessApiUsageException("BITOP is only supported for same slot keys in cluster mode."); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#strLen(byte[]) - */ - @Override - public Long strLen(byte[] key) { - - try { - return cluster.strlen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPush(byte[], byte[][]) - */ - @Override - public Long rPush(byte[] key, byte[]... values) { - - try { - return cluster.rpush(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) - */ - @Override - public Long lPush(byte[] key, byte[]... values) { - - try { - return cluster.lpush(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) - */ - @Override - public Long rPushX(byte[] key, byte[] value) { - - try { - return cluster.rpushx(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) - */ - @Override - public Long lPushX(byte[] key, byte[] value) { - - try { - return cluster.lpushx(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) - */ - @Override - public Long lLen(byte[] key) { - - try { - return cluster.llen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) - */ - @Override - public List lRange(byte[] key, long begin, long end) { - - try { - return cluster.lrange(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) - */ - @Override - public void lTrim(final byte[] key, final long begin, final long end) { - - try { - cluster.ltrim(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) - */ - @Override - public byte[] lIndex(byte[] key, long index) { - - try { - return cluster.lindex(key, index); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) - */ - @Override - public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { - - try { - return cluster.linsert(key, JedisConverters.toListPosition(where), pivot, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) - */ - @Override - public void lSet(byte[] key, long index, byte[] value) { - - try { - cluster.lset(key, index, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) - */ - @Override - public Long lRem(byte[] key, long count, byte[] value) { - - try { - return cluster.lrem(key, count, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) - */ - @Override - public byte[] lPop(byte[] key) { - - try { - return cluster.lpop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) - */ - @Override - public byte[] rPop(byte[] key) { - - try { - return cluster.rpop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) - */ - @Override - public List bLPop(final int timeout, final byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - try { - return cluster.blpop(timeout, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - return this.clusterCommandExecutor.executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { - - @Override - public List doInCluster(Jedis client, byte[] key) { - return client.blpop(timeout, key); - } - }, Arrays.asList(keys)).getFirstNonNullNotEmptyOrDefault(Collections. emptyList()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#bRPop(int, byte[][]) - */ - @Override - public List bRPop(final int timeout, byte[]... keys) { - - return this.clusterCommandExecutor.executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { - - @Override - public List doInCluster(Jedis client, byte[] key) { - return client.brpop(timeout, key); - } - }, Arrays.asList(keys)).getFirstNonNullNotEmptyOrDefault(Collections. emptyList()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPopLPush(byte[], byte[]) - */ - @Override - public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { - try { - return cluster.rpoplpush(srcKey, dstKey); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - byte[] val = rPop(srcKey); - lPush(dstKey, val); - return val; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#bRPopLPush(int, byte[], byte[]) - */ - @Override - public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { - try { - return cluster.brpoplpush(srcKey, dstKey, timeout); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - List val = bRPop(timeout, srcKey); - if (!CollectionUtils.isEmpty(val)) { - lPush(dstKey, val.get(1)); - return val.get(1); - } - - return null; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sAdd(byte[], byte[][]) - */ - @Override - public Long sAdd(byte[] key, byte[]... values) { - - try { - return cluster.sadd(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sRem(byte[], byte[][]) - */ - @Override - public Long sRem(byte[] key, byte[]... values) { - - try { - return cluster.srem(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sPop(byte[]) - */ - @Override - public byte[] sPop(byte[] key) { - try { - return cluster.spop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sMove(byte[], byte[], byte[]) - */ - @Override - public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { - try { - return JedisConverters.toBoolean(cluster.smove(srcKey, destKey, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - if (exists(srcKey)) { - if (sRem(srcKey, value) > 0 && !sIsMember(destKey, value)) { - return JedisConverters.toBoolean(sAdd(destKey, value)); - } - } - return Boolean.FALSE; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sCard(byte[]) - */ - @Override - public Long sCard(byte[] key) { - - try { - return cluster.scard(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sIsMember(byte[], byte[]) - */ - @Override - public Boolean sIsMember(byte[] key, byte[] value) { - - try { - return cluster.sismember(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sInter(byte[][]) - */ - @Override - public Set sInter(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - try { - return cluster.sinter(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - Collection> resultList = this.clusterCommandExecutor - .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(Jedis client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(keys)).resultsAsList(); - - ByteArraySet result = null; - - for (Set value : resultList) { - - ByteArraySet tmp = new ByteArraySet(value); - if (result == null) { - result = tmp; - } else { - result.retainAll(tmp); - if (result.isEmpty()) { - break; - } - } - } - - if (result.isEmpty()) { - return Collections.emptySet(); - } - - return result.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sInterStore(byte[], byte[][]) - */ - @Override - public Long sInterStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - return cluster.sinterstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - Set result = sInter(keys); - if (result.isEmpty()) { - return 0L; - } - return sAdd(destKey, result.toArray(new byte[result.size()][])); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sUnion(byte[][]) - */ - @Override - public Set sUnion(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - try { - return cluster.sunion(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - Collection> resultList = this.clusterCommandExecutor - .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(Jedis client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(keys)).resultsAsList(); - - ByteArraySet result = new ByteArraySet(); - for (Set entry : resultList) { - result.addAll(entry); - } - - if (result.isEmpty()) { - return Collections.emptySet(); - } - - return result.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sUnionStore(byte[], byte[][]) - */ - @Override - public Long sUnionStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - return cluster.sunionstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - Set result = sUnion(keys); - if (result.isEmpty()) { - return 0L; - } - return sAdd(destKey, result.toArray(new byte[result.size()][])); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sDiff(byte[][]) - */ - @Override - public Set sDiff(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - try { - return cluster.sdiff(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - byte[] source = keys[0]; - byte[][] others = Arrays.copyOfRange(keys, 1, keys.length - 1); - - ByteArraySet values = new ByteArraySet(sMembers(source)); - Collection> resultList = clusterCommandExecutor - .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(Jedis client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(others)).resultsAsList(); - - if (values.isEmpty()) { - return Collections.emptySet(); - } - - for (Set singleNodeValue : resultList) { - values.removeAll(singleNodeValue); - } - - return values.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sDiffStore(byte[], byte[][]) - */ - @Override - public Long sDiffStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - return cluster.sdiffstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - Set diff = sDiff(keys); - if (diff.isEmpty()) { - return 0L; - } - - return sAdd(destKey, diff.toArray(new byte[diff.size()][])); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sMembers(byte[]) - */ - @Override - public Set sMembers(byte[] key) { - - try { - return cluster.smembers(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[]) - */ - @Override - public byte[] sRandMember(byte[] key) { - - try { - return cluster.srandmember(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[], long) - */ - @Override - public List sRandMember(byte[] key, long count) { - - if (count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count cannot exceed Integer.MAX_VALUE!"); - } - - try { - return cluster.srandmember(key, Long.valueOf(count).intValue()); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor sScan(final byte[] key, ScanOptions options) { - - return new ScanCursor(options) { - - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - - ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = cluster.sscan(key, JedisConverters.toBytes(cursorId), params); - return new ScanIteration(Long.valueOf(result.getStringCursor()), result.getResult()); - } - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[]) - */ - @Override - public Boolean zAdd(byte[] key, double score, byte[] value) { - - try { - return JedisConverters.toBoolean(cluster.zadd(key, score, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Long zAdd(byte[] key, Set tuples) { - - // TODO: need to move the tuple conversion form jedisconnection. - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) - */ - @Override - public Long zRem(byte[] key, byte[]... values) { - - try { - return cluster.zrem(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zIncrBy(byte[], double, byte[]) - */ - @Override - public Double zIncrBy(byte[] key, double increment, byte[] value) { - try { - return cluster.zincrby(key, increment, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) - */ - @Override - public Long zRank(byte[] key, byte[] value) { - - try { - return cluster.zrank(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) - */ - @Override - public Long zRevRank(byte[] key, byte[] value) { - - try { - return cluster.zrevrank(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRange(byte[], long, long) - */ - @Override - public Set zRange(byte[] key, long begin, long end) { - - try { - return cluster.zrange(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range) { - return zRangeByScoreWithScores(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (limit != null) { - return JedisConverters - .toTupleSet(cluster.zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); - } - return JedisConverters.toTupleSet(cluster.zrangeByScoreWithScores(key, min, max)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRevRangeByScore(byte[] key, Range range) { - return zRevRangeByScore(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (limit != null) { - return cluster.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); - } - return cluster.zrevrangeByScore(key, max, min); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range) { - return zRevRangeByScoreWithScores(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (limit != null) { - return JedisConverters - .toTupleSet(cluster.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); - } - return JedisConverters.toTupleSet(cluster.zrevrangeByScoreWithScores(key, max, min)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zCount(byte[] key, Range range) { - - Assert.notNull(range, "Range cannot be null for ZCOUNT."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - return cluster.zcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zRemRangeByScore(byte[] key, Range range) { - - Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - return cluster.zremrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByScore(byte[] key, Range range) { - return zRangeByScore(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (limit != null) { - return cluster.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); - } - return cluster.zrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) - */ - @Override - public Set zRangeByLex(byte[] key) { - return zRangeByLex(key, Range.unbounded()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByLex(byte[] key, Range range) { - return zRangeByLex(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); - - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.toBytes("-")); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.toBytes("+")); - - try { - if (limit != null) { - return cluster.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); - } - return cluster.zrangeByLex(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeWithScores(byte[], long, long) - */ - @Override - public Set zRangeWithScores(byte[] key, long begin, long end) { - - try { - return JedisConverters.toTupleSet(cluster.zrangeWithScores(key, begin, end)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double) - */ - @Override - public Set zRangeByScore(byte[] key, double min, double max) { - - try { - return cluster.zrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, double min, double max) { - - try { - return JedisConverters.toTupleSet(cluster.zrangeByScoreWithScores(key, min, max)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double, long, long) - */ - @Override - public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); - } - - try { - return cluster.zrangeByScore(key, min, max, Long.valueOf(offset).intValue(), Long.valueOf(count).intValue()); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double, long, long) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); - } - - try { - return JedisConverters.toTupleSet(cluster.zrangeByScoreWithScores(key, min, max, Long.valueOf(offset).intValue(), - Long.valueOf(count).intValue())); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) - */ - @Override - public Set zRevRange(byte[] key, long begin, long end) { - - try { - return cluster.zrevrange(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) - */ - @Override - public Set zRevRangeWithScores(byte[] key, long begin, long end) { - - try { - return JedisConverters.toTupleSet(cluster.zrevrangeWithScores(key, begin, end)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double) - */ - @Override - public Set zRevRangeByScore(byte[] key, double min, double max) { - - try { - return cluster.zrevrangeByScore(key, max, min); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { - - try { - return JedisConverters.toTupleSet(cluster.zrevrangeByScoreWithScores(key, max, min)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double, long, long) - */ - @Override - public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); - } - - try { - return cluster.zrevrangeByScore(key, max, min, Long.valueOf(offset).intValue(), Long.valueOf(count).intValue()); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double, long, long) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); - } - - try { - return JedisConverters.toTupleSet(cluster.zrevrangeByScoreWithScores(key, max, min, - Long.valueOf(offset).intValue(), Long.valueOf(count).intValue())); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], double, double) - */ - @Override - public Long zCount(byte[] key, double min, double max) { - - try { - return cluster.zcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) - */ - @Override - public Long zCard(byte[] key) { - - try { - return cluster.zcard(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) - */ - @Override - public Double zScore(byte[] key, byte[] value) { - - try { - return cluster.zscore(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) - */ - @Override - public Long zRemRange(byte[] key, long begin, long end) { - - try { - return cluster.zremrangeByRank(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], double, double) - */ - @Override - public Long zRemRangeByScore(byte[] key, double min, double max) { - - try { - return cluster.zremrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], byte[][]) - */ - @Override - public Long zUnionStore(byte[] destKey, byte[]... sets) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - - try { - return cluster.zunionstore(destKey, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new InvalidDataAccessApiUsageException("ZUNIONSTORE can only be executed when all keys map to the same slot"); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) - */ - @Override - public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - - ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); - - try { - return cluster.zunionstore(destKey, zparams, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new InvalidDataAccessApiUsageException("ZUNIONSTORE can only be executed when all keys map to the same slot"); - } - - @Override - public Long zInterStore(byte[] destKey, byte[]... sets) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - - try { - return cluster.zinterstore(destKey, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new InvalidDataAccessApiUsageException("ZINTERSTORE can only be executed when all keys map to the same slot"); - } - - @Override - public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - - ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); - - try { - return cluster.zinterstore(destKey, zparams, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new IllegalArgumentException("ZINTERSTORE can only be executed when all keys map to the same slot"); - } - - @Override - public Cursor zScan(final byte[] key, final ScanOptions options) { - return new ScanCursor(options) { - - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - - ScanParams params = JedisConverters.toScanParams(options); - - redis.clients.jedis.ScanResult result = cluster.zscan(key, - JedisConverters.toBytes(cursorId), params); - return new ScanIteration(Long.valueOf(result.getStringCursor()), - JedisConverters.tuplesToTuples().convert(result.getResult())); - } - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String) - */ - @Override - public Set zRangeByScore(byte[] key, String min, String max) { - - try { - return cluster.zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String, long, long) - */ - @Override - public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); - } - - try { - return cluster.zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max), - Long.valueOf(offset).intValue(), Long.valueOf(count).intValue()); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hSet(byte[], byte[], byte[]) - */ - @Override - public Boolean hSet(byte[] key, byte[] field, byte[] value) { - - try { - return JedisConverters.toBoolean(cluster.hset(key, field, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hSetNX(byte[], byte[], byte[]) - */ - @Override - public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { - - try { - return JedisConverters.toBoolean(cluster.hsetnx(key, field, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hGet(byte[], byte[]) - */ - @Override - public byte[] hGet(byte[] key, byte[] field) { - - try { - return cluster.hget(key, field); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hMGet(byte[], byte[][]) - */ - @Override - public List hMGet(byte[] key, byte[]... fields) { - - try { - return cluster.hmget(key, fields); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) - */ - @Override - public void hMSet(byte[] key, Map hashes) { - - try { - cluster.hmset(key, hashes); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], long) - */ - @Override - public Long hIncrBy(byte[] key, byte[] field, long delta) { - - try { - return cluster.hincrBy(key, field, delta); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], double) - */ - @Override - public Double hIncrBy(byte[] key, byte[] field, double delta) { - try { - return cluster.hincrByFloat(key, field, delta); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hExists(byte[], byte[]) - */ - @Override - public Boolean hExists(byte[] key, byte[] field) { - - try { - return cluster.hexists(key, field); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hDel(byte[], byte[][]) - */ - @Override - public Long hDel(byte[] key, byte[]... fields) { - - try { - return cluster.hdel(key, fields); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hLen(byte[]) - */ - @Override - public Long hLen(byte[] key) { - - try { - return cluster.hlen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hKeys(byte[]) - */ - @Override - public Set hKeys(byte[] key) { - - try { - return cluster.hkeys(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hVals(byte[]) - */ - @Override - public List hVals(byte[] key) { - - try { - return new ArrayList(cluster.hvals(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hGetAll(byte[]) - */ - @Override - public Map hGetAll(byte[] key) { - - try { - return cluster.hgetAll(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor> hScan(final byte[] key, ScanOptions options) { - - return new ScanCursor>(options) { - - @Override - protected ScanIteration> doScan(long cursorId, ScanOptions options) { - - ScanParams params = JedisConverters.toScanParams(options); - - redis.clients.jedis.ScanResult> result = cluster.hscan(key, - JedisConverters.toBytes(cursorId), params); - return new ScanIteration>(Long.valueOf(result.getStringCursor()), result.getResult()); - } - }.open(); + return doGetKeyCommands().randomKey(node); } /* @@ -2552,261 +309,6 @@ public class JedisClusterConnection implements RedisClusterConnection { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) - */ - @Override - public Long geoAdd(byte[] key, Point point, byte[] member) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(point, "Point must not be null!"); - Assert.notNull(member, "Member must not be null!"); - - try { - return cluster.geoadd(key, point.getX(), point.getY(), member); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation) - */ - public Long geoAdd(byte[] key, GeoLocation location) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(location, "Location must not be null!"); - - return geoAdd(key, location.getPoint(), location.getName()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) - */ - @Override - public Long geoAdd(byte[] key, Map memberCoordinateMap) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); - - Map redisGeoCoordinateMap = new HashMap(); - for (byte[] mapKey : memberCoordinateMap.keySet()) { - redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey))); - } - - try { - return cluster.geoadd(key, redisGeoCoordinateMap); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) - */ - @Override - public Long geoAdd(byte[] key, Iterable> locations) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(locations, "Locations must not be null!"); - - Map redisGeoCoordinateMap = new HashMap(); - for (GeoLocation location : locations) { - redisGeoCoordinateMap.put(location.getName(), JedisConverters.toGeoCoordinate(location.getPoint())); - } - - try { - return cluster.geoadd(key, redisGeoCoordinateMap); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member1, "Member1 must not be null!"); - Assert.notNull(member2, "Member2 must not be null!"); - - try { - return JedisConverters.distanceConverterForMetric(DistanceUnit.METERS) - .convert(cluster.geodist(key, member1, member2)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member1, "Member1 must not be null!"); - Assert.notNull(member2, "Member2 must not be null!"); - Assert.notNull(metric, "Metric must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(metric); - try { - return JedisConverters.distanceConverterForMetric(metric) - .convert(cluster.geodist(key, member1, member2, geoUnit)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) - */ - @Override - public List geoHash(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - try { - return JedisConverters.toStrings(cluster.geohash(key, members)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) - */ - @Override - public List geoPos(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - try { - return JedisConverters.geoCoordinateToPointConverter().convert(cluster.geopos(key, members)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - - try { - return JedisConverters.geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()) - .convert(cluster.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()))); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - - try { - return JedisConverters.geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()) - .convert(cluster.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), - geoRadiusParam)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { - return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - try { - return JedisConverters.geoRadiusResponseToGeoResultsConverter(radius.getMetric()) - .convert(cluster.georadiusByMember(key, member, radius.getValue(), geoUnit)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.core.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, - GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - - try { - return JedisConverters.geoRadiusResponseToGeoResultsConverter(radius.getMetric()) - .convert(cluster.georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam)); - - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) - */ - @Override - public Long geoRemove(byte[] key, byte[]... members) { - return zRem(key, members); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int) @@ -3570,74 +1072,6 @@ public class JedisClusterConnection implements RedisClusterConnection { throw new InvalidDataAccessApiUsageException("EvalSha is not supported in cluster environment."); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfAdd(byte[], byte[][]) - */ - @Override - public Long pfAdd(byte[] key, byte[]... values) { - - try { - return cluster.pfadd(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfCount(byte[][]) - */ - @Override - public Long pfCount(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - - try { - return cluster.pfcount(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - - } - throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfcount in cluster mode."); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfMerge(byte[], byte[][]) - */ - @Override - public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destinationKey, sourceKeys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - try { - cluster.pfmerge(destinationKey, sourceKeys); - return; - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfmerge in cluster mode."); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#exists(byte[]) - */ - @Override - public Boolean exists(final byte[] key) { - - try { - return cluster.exists(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - /* * --> Cluster Commands */ @@ -4207,4 +1641,15 @@ public class JedisClusterConnection implements RedisClusterConnection { } } + protected JedisCluster getCluster() { + return cluster; + } + + protected ClusterCommandExecutor getClusterCommandExecutor() { + return clusterCommandExecutor; + } + + protected JedisClusterTopologyProvider getTopologyProvider() { + return topologyProvider; + } } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java new file mode 100644 index 000000000..5a631d6fb --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterGeoCommands.java @@ -0,0 +1,284 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.GeoCoordinate; +import redis.clients.jedis.GeoUnit; +import redis.clients.jedis.params.geo.GeoRadiusParam; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterGeoCommands implements RedisGeoCommands { + + private final JedisClusterConnection connection; + + public JedisClusterGeoCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) + */ + @Override + public Long geoAdd(byte[] key, Point point, byte[] member) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(point, "Point must not be null!"); + Assert.notNull(member, "Member must not be null!"); + + try { + return connection.getCluster().geoadd(key, point.getX(), point.getY(), member); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) + */ + @Override + public Long geoAdd(byte[] key, Map memberCoordinateMap) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); + + Map redisGeoCoordinateMap = new HashMap(); + for (byte[] mapKey : memberCoordinateMap.keySet()) { + redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey))); + } + + try { + return connection.getCluster().geoadd(key, redisGeoCoordinateMap); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) + */ + @Override + public Long geoAdd(byte[] key, Iterable> locations) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(locations, "Locations must not be null!"); + + Map redisGeoCoordinateMap = new HashMap(); + for (GeoLocation location : locations) { + redisGeoCoordinateMap.put(location.getName(), JedisConverters.toGeoCoordinate(location.getPoint())); + } + + try { + return connection.getCluster().geoadd(key, redisGeoCoordinateMap); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member1, "Member1 must not be null!"); + Assert.notNull(member2, "Member2 must not be null!"); + + try { + return JedisConverters.distanceConverterForMetric(DistanceUnit.METERS) + .convert(connection.getCluster().geodist(key, member1, member2)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member1, "Member1 must not be null!"); + Assert.notNull(member2, "Member2 must not be null!"); + Assert.notNull(metric, "Metric must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(metric); + try { + return JedisConverters.distanceConverterForMetric(metric) + .convert(connection.getCluster().geodist(key, member1, member2, geoUnit)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) + */ + @Override + public List geoHash(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(members, "Members must not be null!"); + Assert.noNullElements(members, "Members must not contain null!"); + + try { + return JedisConverters.toStrings(connection.getCluster().geohash(key, members)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) + */ + @Override + public List geoPos(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(members, "Members must not be null!"); + Assert.noNullElements(members, "Members must not contain null!"); + + try { + return JedisConverters.geoCoordinateToPointConverter().convert(connection.getCluster().geopos(key, members)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + + try { + return JedisConverters.geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()) + .convert(connection.getCluster().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()))); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); + + try { + return JedisConverters.geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()) + .convert(connection.getCluster().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), + geoRadiusParam)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); + try { + return JedisConverters.geoRadiusResponseToGeoResultsConverter(radius.getMetric()) + .convert(connection.getCluster().georadiusByMember(key, member, radius.getValue(), geoUnit)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.core.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, + GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); + redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); + + try { + return JedisConverters.geoRadiusResponseToGeoResultsConverter(radius.getMetric()) + .convert(connection.getCluster().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam)); + + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) + */ + @Override + public Long geoRemove(byte[] key, byte[]... members) { + return connection.zRem(key, members); + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java new file mode 100644 index 000000000..7c68c18da --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java @@ -0,0 +1,250 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; + +import java.util.ArrayList; +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.ScanCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterHashCommands implements RedisHashCommands { + + private final JedisClusterConnection connection; + + public JedisClusterHashCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSet(byte[], byte[], byte[]) + */ + @Override + public Boolean hSet(byte[] key, byte[] field, byte[] value) { + + try { + return JedisConverters.toBoolean(connection.getCluster().hset(key, field, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSetNX(byte[], byte[], byte[]) + */ + @Override + public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + + try { + return JedisConverters.toBoolean(connection.getCluster().hsetnx(key, field, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGet(byte[], byte[]) + */ + @Override + public byte[] hGet(byte[] key, byte[] field) { + + try { + return connection.getCluster().hget(key, field); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMGet(byte[], byte[][]) + */ + @Override + public List hMGet(byte[] key, byte[]... fields) { + + try { + return connection.getCluster().hmget(key, fields); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) + */ + @Override + public void hMSet(byte[] key, Map hashes) { + + try { + connection.getCluster().hmset(key, hashes); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], long) + */ + @Override + public Long hIncrBy(byte[] key, byte[] field, long delta) { + + try { + return connection.getCluster().hincrBy(key, field, delta); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], double) + */ + @Override + public Double hIncrBy(byte[] key, byte[] field, double delta) { + try { + return connection.getCluster().hincrByFloat(key, field, delta); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hExists(byte[], byte[]) + */ + @Override + public Boolean hExists(byte[] key, byte[] field) { + + try { + return connection.getCluster().hexists(key, field); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hDel(byte[], byte[][]) + */ + @Override + public Long hDel(byte[] key, byte[]... fields) { + + try { + return connection.getCluster().hdel(key, fields); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hLen(byte[]) + */ + @Override + public Long hLen(byte[] key) { + + try { + return connection.getCluster().hlen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hKeys(byte[]) + */ + @Override + public Set hKeys(byte[] key) { + + try { + return connection.getCluster().hkeys(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hVals(byte[]) + */ + @Override + public List hVals(byte[] key) { + + try { + return new ArrayList(connection.getCluster().hvals(key)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGetAll(byte[]) + */ + @Override + public Map hGetAll(byte[] key) { + + try { + return connection.getCluster().hgetAll(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor> hScan(final byte[] key, ScanOptions options) { + + return new ScanCursor>(options) { + + @Override + protected ScanIteration> doScan(long cursorId, ScanOptions options) { + + ScanParams params = JedisConverters.toScanParams(options); + + redis.clients.jedis.ScanResult> result = connection.getCluster().hscan(key, + JedisConverters.toBytes(cursorId), params); + return new ScanIteration<>(Long.valueOf(result.getStringCursor()), result.getResult()); + } + }.open(); + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java new file mode 100644 index 000000000..c03a4e8e5 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java @@ -0,0 +1,93 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.util.ByteUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterHyperLogLogCommands implements RedisHyperLogLogCommands { + + private final JedisClusterConnection connection; + + public JedisClusterHyperLogLogCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfAdd(byte[], byte[][]) + */ + @Override + public Long pfAdd(byte[] key, byte[]... values) { + + try { + return connection.getCluster().pfadd(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfCount(byte[][]) + */ + @Override + public Long pfCount(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + + try { + return connection.getCluster().pfcount(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfcount in cluster mode."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfMerge(byte[], byte[][]) + */ + @Override + public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destinationKey, sourceKeys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + try { + connection.getCluster().pfmerge(destinationKey, sourceKeys); + return; + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfmerge in cluster mode."); + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java new file mode 100644 index 000000000..fe100fee7 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java @@ -0,0 +1,482 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.Jedis; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.RedisClusterNode; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.RedisNode; +import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterCommandCallback; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterKeyCommands implements RedisKeyCommands { + + private final JedisClusterConnection connection; + + public JedisClusterKeyCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) + */ + @Override + public Long del(byte[]... keys) { + + Assert.noNullElements(keys, "Keys must not be null or contain null key!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + try { + return connection.getCluster().del(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + return Long.valueOf( + connection.getClusterCommandExecutor().executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback() { + + @Override + public Long doInCluster(Jedis client, byte[] key) { + return client.del(key); + } + }, Arrays.asList(keys)).resultsAsList().size()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) + */ + @Override + public DataType type(byte[] key) { + + try { + return JedisConverters.toDataType(connection.getCluster().type(key)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) + */ + @Override + public Set keys(final byte[] pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); + + Collection> keysPerNode = connection.getClusterCommandExecutor() + .executeCommandOnAllNodes(new JedisClusterCommandCallback>() { + + @Override + public Set doInCluster(Jedis client) { + return client.keys(pattern); + } + }).resultsAsList(); + + Set keys = new HashSet(); + for (Set keySet : keysPerNode) { + keys.addAll(keySet); + } + return keys; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) + */ + public Set keys(RedisClusterNode node, final byte[] pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); + + return connection.getClusterCommandExecutor() + .executeCommandOnSingleNode(new JedisClusterCommandCallback>() { + + @Override + public Set doInCluster(Jedis client) { + return client.keys(pattern); + } + }, node).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor scan(ScanOptions options) { + throw new InvalidDataAccessApiUsageException("Scan is not supported accros multiple nodes within a cluster"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() + */ + @Override + public byte[] randomKey() { + + List nodes = new ArrayList( + connection.getTopologyProvider().getTopology().getActiveMasterNodes()); + Set inspectedNodes = new HashSet(nodes.size()); + + do { + + RedisClusterNode node = nodes.get(new Random().nextInt(nodes.size())); + + while (inspectedNodes.contains(node)) { + node = nodes.get(new Random().nextInt(nodes.size())); + } + inspectedNodes.add(node); + byte[] key = randomKey(node); + + if (key != null && key.length > 0) { + return key; + } + } while (nodes.size() != inspectedNodes.size()); + + return null; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisClusterConnection#randomKey(org.springframework.data.redis.connection.RedisClusterNode) + */ + public byte[] randomKey(RedisClusterNode node) { + + return connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public byte[] doInCluster(Jedis client) { + return client.randomBinaryKey(); + } + }, node).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) + */ + @Override + public void rename(final byte[] sourceKey, final byte[] targetKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { + + try { + connection.getCluster().rename(sourceKey, targetKey); + return; + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + byte[] value = dump(sourceKey); + + if (value != null && value.length > 0) { + + restore(targetKey, 0, value); + del(sourceKey); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) + */ + @Override + public Boolean renameNX(final byte[] sourceKey, final byte[] targetKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { + + try { + return JedisConverters.toBoolean(connection.getCluster().renamenx(sourceKey, targetKey)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + byte[] value = dump(sourceKey); + + if (value != null && value.length > 0 && !exists(targetKey)) { + + restore(targetKey, 0, value); + del(sourceKey); + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expire(byte[], long) + */ + @Override + public Boolean expire(byte[] key, long seconds) { + + if (seconds > Integer.MAX_VALUE) { + throw new UnsupportedOperationException("Jedis does not support seconds exceeding Integer.MAX_VALUE."); + } + try { + return JedisConverters.toBoolean(connection.getCluster().expire(key, Long.valueOf(seconds).intValue())); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) + */ + @Override + public Boolean pExpire(final byte[] key, final long millis) { + + try { + return JedisConverters.toBoolean(connection.getCluster().pexpire(key, millis)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) + */ + @Override + public Boolean expireAt(byte[] key, long unixTime) { + + try { + return JedisConverters.toBoolean(connection.getCluster().expireAt(key, unixTime)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) + */ + @Override + public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + + try { + return JedisConverters.toBoolean(connection.getCluster().pexpireAt(key, unixTimeInMillis)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) + */ + @Override + public Boolean persist(byte[] key) { + + try { + return JedisConverters.toBoolean(connection.getCluster().persist(key)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) + */ + @Override + public Boolean move(byte[] key, int dbIndex) { + throw new UnsupportedOperationException("Cluster mode does not allow moving keys."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) + */ + @Override + public Long ttl(byte[] key) { + + try { + return connection.getCluster().ttl(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + public Long ttl(byte[] key, TimeUnit timeUnit) { + + try { + return Converters.secondsToTimeUnit(connection.getCluster().ttl(key), timeUnit); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) + */ + @Override + public Long pTtl(final byte[] key) { + + return connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public Long doInCluster(Jedis client) { + return client.pttl(key); + } + }, connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + public Long pTtl(final byte[] key, final TimeUnit timeUnit) { + + return connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public Long doInCluster(Jedis client) { + return Converters.millisecondsToTimeUnit(client.pttl(key), timeUnit); + } + }, connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) + */ + @Override + public byte[] dump(final byte[] key) { + + return connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public byte[] doInCluster(Jedis client) { + return client.dump(key); + } + }, connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) + */ + @Override + public void restore(final byte[] key, final long ttlInMillis, final byte[] serializedValue) { + + if (ttlInMillis > Integer.MAX_VALUE) { + throw new UnsupportedOperationException("Jedis does not support ttlInMillis exceeding Integer.MAX_VALUE."); + } + + connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public String doInCluster(Jedis client) { + return client.restore(key, Long.valueOf(ttlInMillis).intValue(), serializedValue); + } + }, connection.clusterGetNodeForKey(key)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) + */ + @Override + public List sort(byte[] key, SortParameters params) { + + try { + return connection.getCluster().sort(key, JedisConverters.toSortingParams(params)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) + */ + @Override + public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + + List sorted = sort(key, params); + if (!CollectionUtils.isEmpty(sorted)) { + + byte[][] arr = new byte[sorted.size()][]; + switch (type(key)) { + + case SET: + connection.setCommands().sAdd(storeKey, sorted.toArray(arr)); + return 1L; + case LIST: + connection.listCommands().lPush(storeKey, sorted.toArray(arr)); + return 1L; + default: + throw new IllegalArgumentException("sort and store is only supported for SET and LIST"); + } + } + return 0L; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#exists(byte[]) + */ + @Override + public Boolean exists(final byte[] key) { + + try { + return connection.getCluster().exists(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java new file mode 100644 index 000000000..bec9869ac --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java @@ -0,0 +1,313 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.Jedis; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisListCommands; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback; +import org.springframework.util.CollectionUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterListCommands implements RedisListCommands { + + private final JedisClusterConnection connection; + + public JedisClusterListCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPush(byte[], byte[][]) + */ + @Override + public Long rPush(byte[] key, byte[]... values) { + + try { + return connection.getCluster().rpush(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) + */ + @Override + public Long lPush(byte[] key, byte[]... values) { + + try { + return connection.getCluster().lpush(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) + */ + @Override + public Long rPushX(byte[] key, byte[] value) { + + try { + return connection.getCluster().rpushx(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) + */ + @Override + public Long lPushX(byte[] key, byte[] value) { + + try { + return connection.getCluster().lpushx(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) + */ + @Override + public Long lLen(byte[] key) { + + try { + return connection.getCluster().llen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) + */ + @Override + public List lRange(byte[] key, long begin, long end) { + + try { + return connection.getCluster().lrange(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) + */ + @Override + public void lTrim(final byte[] key, final long begin, final long end) { + + try { + connection.getCluster().ltrim(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) + */ + @Override + public byte[] lIndex(byte[] key, long index) { + + try { + return connection.getCluster().lindex(key, index); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) + */ + @Override + public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + + try { + return connection.getCluster().linsert(key, JedisConverters.toListPosition(where), pivot, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) + */ + @Override + public void lSet(byte[] key, long index, byte[] value) { + + try { + connection.getCluster().lset(key, index, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) + */ + @Override + public Long lRem(byte[] key, long count, byte[] value) { + + try { + return connection.getCluster().lrem(key, count, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) + */ + @Override + public byte[] lPop(byte[] key) { + + try { + return connection.getCluster().lpop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) + */ + @Override + public byte[] rPop(byte[] key) { + + try { + return connection.getCluster().rpop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) + */ + @Override + public List bLPop(final int timeout, final byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + try { + return connection.getCluster().blpop(timeout, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + return connection.getClusterCommandExecutor() + .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { + + @Override + public List doInCluster(Jedis client, byte[] key) { + return client.blpop(timeout, key); + } + }, Arrays.asList(keys)).getFirstNonNullNotEmptyOrDefault(Collections. emptyList()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPop(int, byte[][]) + */ + @Override + public List bRPop(final int timeout, byte[]... keys) { + + return connection.getClusterCommandExecutor() + .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback>() { + + @Override + public List doInCluster(Jedis client, byte[] key) { + return client.brpop(timeout, key); + } + }, Arrays.asList(keys)).getFirstNonNullNotEmptyOrDefault(Collections. emptyList()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPopLPush(byte[], byte[]) + */ + @Override + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { + try { + return connection.getCluster().rpoplpush(srcKey, dstKey); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + byte[] val = rPop(srcKey); + lPush(dstKey, val); + return val; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPopLPush(int, byte[], byte[]) + */ + @Override + public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { + try { + return connection.getCluster().brpoplpush(srcKey, dstKey, timeout); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + List val = bRPop(timeout, srcKey); + if (!CollectionUtils.isEmpty(val)) { + lPush(dstKey, val.get(1)); + return val.get(1); + } + + return null; + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java new file mode 100644 index 000000000..06b1f2b51 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java @@ -0,0 +1,393 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback; +import org.springframework.data.redis.connection.util.ByteArraySet; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.util.ByteUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterSetCommands implements RedisSetCommands { + + private final JedisClusterConnection connection; + + public JedisClusterSetCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sAdd(byte[], byte[][]) + */ + @Override + public Long sAdd(byte[] key, byte[]... values) { + + try { + return connection.getCluster().sadd(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRem(byte[], byte[][]) + */ + @Override + public Long sRem(byte[] key, byte[]... values) { + + try { + return connection.getCluster().srem(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sPop(byte[]) + */ + @Override + public byte[] sPop(byte[] key) { + try { + return connection.getCluster().spop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMove(byte[], byte[], byte[]) + */ + @Override + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { + try { + return JedisConverters.toBoolean(connection.getCluster().smove(srcKey, destKey, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + if (connection.keyCommands().exists(srcKey)) { + if (sRem(srcKey, value) > 0 && !sIsMember(destKey, value)) { + return JedisConverters.toBoolean(sAdd(destKey, value)); + } + } + return Boolean.FALSE; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sCard(byte[]) + */ + @Override + public Long sCard(byte[] key) { + + try { + return connection.getCluster().scard(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sIsMember(byte[], byte[]) + */ + @Override + public Boolean sIsMember(byte[] key, byte[] value) { + + try { + return connection.getCluster().sismember(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInter(byte[][]) + */ + @Override + public Set sInter(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + try { + return connection.getCluster().sinter(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + Collection> resultList = connection.getClusterCommandExecutor() + .executeMuliKeyCommand((JedisMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(keys)) + .resultsAsList(); + + ByteArraySet result = null; + + for (Set value : resultList) { + + ByteArraySet tmp = new ByteArraySet(value); + if (result == null) { + result = tmp; + } else { + result.retainAll(tmp); + if (result.isEmpty()) { + break; + } + } + } + + if (result.isEmpty()) { + return Collections.emptySet(); + } + + return result.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInterStore(byte[], byte[][]) + */ + @Override + public Long sInterStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + try { + return connection.getCluster().sinterstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + Set result = sInter(keys); + if (result.isEmpty()) { + return 0L; + } + return sAdd(destKey, result.toArray(new byte[result.size()][])); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnion(byte[][]) + */ + @Override + public Set sUnion(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + try { + return connection.getCluster().sunion(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + Collection> resultList = connection.getClusterCommandExecutor() + .executeMuliKeyCommand((JedisMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(keys)) + .resultsAsList(); + + ByteArraySet result = new ByteArraySet(); + for (Set entry : resultList) { + result.addAll(entry); + } + + if (result.isEmpty()) { + return Collections.emptySet(); + } + + return result.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnionStore(byte[], byte[][]) + */ + @Override + public Long sUnionStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + try { + return connection.getCluster().sunionstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + Set result = sUnion(keys); + if (result.isEmpty()) { + return 0L; + } + return sAdd(destKey, result.toArray(new byte[result.size()][])); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiff(byte[][]) + */ + @Override + public Set sDiff(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + try { + return connection.getCluster().sdiff(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + byte[] source = keys[0]; + byte[][] others = Arrays.copyOfRange(keys, 1, keys.length - 1); + + ByteArraySet values = new ByteArraySet(sMembers(source)); + Collection> resultList = connection.getClusterCommandExecutor() + .executeMuliKeyCommand((JedisMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(others)) + .resultsAsList(); + + if (values.isEmpty()) { + return Collections.emptySet(); + } + + for (Set singleNodeValue : resultList) { + values.removeAll(singleNodeValue); + } + + return values.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiffStore(byte[], byte[][]) + */ + @Override + public Long sDiffStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + try { + return connection.getCluster().sdiffstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + Set diff = sDiff(keys); + if (diff.isEmpty()) { + return 0L; + } + + return sAdd(destKey, diff.toArray(new byte[diff.size()][])); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMembers(byte[]) + */ + @Override + public Set sMembers(byte[] key) { + + try { + return connection.getCluster().smembers(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[]) + */ + @Override + public byte[] sRandMember(byte[] key) { + + try { + return connection.getCluster().srandmember(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[], long) + */ + @Override + public List sRandMember(byte[] key, long count) { + + if (count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count cannot exceed Integer.MAX_VALUE!"); + } + + try { + return connection.getCluster().srandmember(key, Long.valueOf(count).intValue()); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor sScan(final byte[] key, ScanOptions options) { + + return new ScanCursor(options) { + + @Override + protected ScanIteration doScan(long cursorId, ScanOptions options) { + + ScanParams params = JedisConverters.toScanParams(options); + redis.clients.jedis.ScanResult result = connection.getCluster().sscan(key, + JedisConverters.toBytes(cursorId), params); + return new ScanIteration<>(Long.valueOf(result.getStringCursor()), result.getResult()); + } + }.open(); + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java new file mode 100644 index 000000000..fc0179b5e --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java @@ -0,0 +1,463 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.Jedis; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterCommandCallback; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback; +import org.springframework.data.redis.core.types.Expiration; +import org.springframework.data.redis.util.ByteUtils; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterStringCommands implements RedisStringCommands { + + private final JedisClusterConnection connection; + + public JedisClusterStringCommands(JedisClusterConnection jedisClusterConnection) { + this.connection = jedisClusterConnection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[]) + */ + @Override + public byte[] get(byte[] key) { + + try { + return connection.getCluster().get(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[]) + */ + @Override + public byte[] getSet(byte[] key, byte[] value) { + + try { + return connection.getCluster().getSet(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mGet(byte[][]) + */ + @Override + public List mGet(byte[]... keys) { + + Assert.noNullElements(keys, "Keys must not contain null elements!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return connection.getCluster().mget(keys); + } + + return connection.getClusterCommandExecutor() + .executeMuliKeyCommand(new JedisMultiKeyClusterCommandCallback() { + + @Override + public byte[] doInCluster(Jedis client, byte[] key) { + return client.get(key); + } + }, Arrays.asList(keys)).resultsAsListSortBy(keys); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[]) + */ + @Override + public void set(byte[] key, byte[] value) { + + try { + connection.getCluster().set(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOptions) + */ + @Override + public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + + if (expiration == null || expiration.isPersistent()) { + + if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + set(key, value); + } else { + + // BinaryCluster does not support set with nxxx and binary key/value pairs. + if (ObjectUtils.nullSafeEquals(SetOption.SET_IF_PRESENT, option)) { + throw new UnsupportedOperationException("Jedis does not support SET XX without PX or EX on BinaryCluster."); + } + + setNX(key, value); + } + } else { + + if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + + if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) { + pSetEx(key, expiration.getExpirationTime(), value); + } else { + setEx(key, expiration.getExpirationTime(), value); + } + } else { + + byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); + byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration); + + try { + connection.getCluster().set(key, value, nxxx, expx, expiration.getExpirationTime()); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setNX(byte[], byte[]) + */ + @Override + public Boolean setNX(byte[] key, byte[] value) { + + try { + return JedisConverters.toBoolean(connection.getCluster().setnx(key, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setEx(byte[], long, byte[]) + */ + @Override + public void setEx(byte[] key, long seconds, byte[] value) { + + if (seconds > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Seconds have cannot exceed Integer.MAX_VALUE!"); + } + + try { + connection.getCluster().setex(key, Long.valueOf(seconds).intValue(), value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) + */ + @Override + public void pSetEx(final byte[] key, final long milliseconds, final byte[] value) { + + if (milliseconds > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Milliseconds have cannot exceed Integer.MAX_VALUE!"); + } + + connection.getClusterCommandExecutor().executeCommandOnSingleNode(new JedisClusterCommandCallback() { + + @Override + public String doInCluster(Jedis client) { + return client.psetex(key, milliseconds, value); + } + }, connection.getTopologyProvider().getTopology().getKeyServingMasterNode(key)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSet(java.util.Map) + */ + @Override + public void mSet(Map tuples) { + + Assert.notNull(tuples, "Tuples must not be null!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { + try { + connection.getCluster().mset(JedisConverters.toByteArrays(tuples)); + return; + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + for (Map.Entry entry : tuples.entrySet()) { + set(entry.getKey(), entry.getValue()); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSetNX(java.util.Map) + */ + @Override + public Boolean mSetNX(Map tuples) { + + Assert.notNull(tuples, "Tuple must not be null!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { + try { + return JedisConverters.toBoolean(connection.getCluster().msetnx(JedisConverters.toByteArrays(tuples))); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + boolean result = true; + for (Map.Entry entry : tuples.entrySet()) { + if (!setNX(entry.getKey(), entry.getValue()) && result) { + result = false; + } + } + return result; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incr(byte[]) + */ + @Override + public Long incr(byte[] key) { + + try { + return connection.getCluster().incr(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], long) + */ + @Override + public Long incrBy(byte[] key, long value) { + + try { + return connection.getCluster().incrBy(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], double) + */ + @Override + public Double incrBy(byte[] key, double value) { + + try { + return connection.getCluster().incrByFloat(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decr(byte[]) + */ + @Override + public Long decr(byte[] key) { + + try { + return connection.getCluster().decr(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decrBy(byte[], long) + */ + @Override + public Long decrBy(byte[] key, long value) { + + try { + return connection.getCluster().decrBy(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#append(byte[], byte[]) + */ + @Override + public Long append(byte[] key, byte[] value) { + + try { + return connection.getCluster().append(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getRange(byte[], long, long) + */ + @Override + public byte[] getRange(byte[] key, long begin, long end) { + + try { + return connection.getCluster().getrange(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setRange(byte[], byte[], long) + */ + @Override + public void setRange(byte[] key, byte[] value, long offset) { + + try { + connection.getCluster().setrange(key, offset, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getBit(byte[], long) + */ + @Override + public Boolean getBit(byte[] key, long offset) { + + try { + return connection.getCluster().getbit(key, offset); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setBit(byte[], long, boolean) + */ + @Override + public Boolean setBit(byte[] key, long offset, boolean value) { + + try { + return connection.getCluster().setbit(key, offset, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[]) + */ + @Override + public Long bitCount(byte[] key) { + + try { + return connection.getCluster().bitcount(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[], long, long) + */ + @Override + public Long bitCount(byte[] key, long begin, long end) { + + try { + return connection.getCluster().bitcount(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitOp(org.springframework.data.redis.connection.RedisStringCommands.BitOperation, byte[], byte[][]) + */ + @Override + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destination, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + try { + return connection.getCluster().bitop(JedisConverters.toBitOp(op), destination, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new InvalidDataAccessApiUsageException("BITOP is only supported for same slot keys in cluster mode."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#strLen(byte[]) + */ + @Override + public Long strLen(byte[] key) { + + try { + return connection.getCluster().strlen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java new file mode 100644 index 000000000..841937bc2 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterZSetCommands.java @@ -0,0 +1,681 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.ZParams; + +import java.util.Set; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisZSetCommands; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.util.ByteUtils; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisClusterZSetCommands implements RedisZSetCommands { + + private final JedisClusterConnection connection; + + public JedisClusterZSetCommands(JedisClusterConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[]) + */ + @Override + public Boolean zAdd(byte[] key, double score, byte[] value) { + + try { + return JedisConverters.toBoolean(connection.getCluster().zadd(key, score, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set) + */ + @Override + public Long zAdd(byte[] key, Set tuples) { + + // TODO: need to move the tuple conversion form jedisconnection. + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) + */ + @Override + public Long zRem(byte[] key, byte[]... values) { + + try { + return connection.getCluster().zrem(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zIncrBy(byte[], double, byte[]) + */ + @Override + public Double zIncrBy(byte[] key, double increment, byte[] value) { + try { + return connection.getCluster().zincrby(key, increment, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) + */ + @Override + public Long zRank(byte[] key, byte[] value) { + + try { + return connection.getCluster().zrank(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) + */ + @Override + public Long zRevRank(byte[] key, byte[] value) { + + try { + return connection.getCluster().zrevrank(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRange(byte[], long, long) + */ + @Override + public Set zRange(byte[] key, long begin, long end) { + + try { + return connection.getCluster().zrange(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (limit != null) { + return JedisConverters.toTupleSet( + connection.getCluster().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); + } + return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (limit != null) { + return connection.getCluster().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); + } + return connection.getCluster().zrevrangeByScore(key, max, min); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (limit != null) { + return JedisConverters.toTupleSet( + connection.getCluster().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); + } + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zCount(byte[] key, Range range) { + + Assert.notNull(range, "Range cannot be null for ZCOUNT."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + return connection.getCluster().zcount(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + return connection.getCluster().zremrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (limit != null) { + return connection.getCluster().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getCluster().zrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.toBytes("-")); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.toBytes("+")); + + try { + if (limit != null) { + return connection.getCluster().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getCluster().zrangeByLex(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeWithScores(byte[], long, long) + */ + @Override + public Set zRangeWithScores(byte[] key, long begin, long end) { + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrangeWithScores(key, begin, end)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double) + */ + @Override + public Set zRangeByScore(byte[] key, double min, double max) { + + try { + return connection.getCluster().zrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, double min, double max) { + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double, long, long) + */ + @Override + public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); + } + + try { + return connection.getCluster().zrangeByScore(key, min, max, Long.valueOf(offset).intValue(), + Long.valueOf(count).intValue()); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double, long, long) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); + } + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max, + Long.valueOf(offset).intValue(), Long.valueOf(count).intValue())); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + */ + @Override + public Set zRevRange(byte[] key, long begin, long end) { + + try { + return connection.getCluster().zrevrange(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) + */ + @Override + public Set zRevRangeWithScores(byte[] key, long begin, long end) { + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeWithScores(key, begin, end)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double) + */ + @Override + public Set zRevRangeByScore(byte[] key, double min, double max) { + + try { + return connection.getCluster().zrevrangeByScore(key, max, min); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double, long, long) + */ + @Override + public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); + } + + try { + return connection.getCluster().zrevrangeByScore(key, max, min, Long.valueOf(offset).intValue(), + Long.valueOf(count).intValue()); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double, long, long) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); + } + + try { + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min, + Long.valueOf(offset).intValue(), Long.valueOf(count).intValue())); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], double, double) + */ + @Override + public Long zCount(byte[] key, double min, double max) { + + try { + return connection.getCluster().zcount(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) + */ + @Override + public Long zCard(byte[] key) { + + try { + return connection.getCluster().zcard(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) + */ + @Override + public Double zScore(byte[] key, byte[] value) { + + try { + return connection.getCluster().zscore(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) + */ + @Override + public Long zRemRange(byte[] key, long begin, long end) { + + try { + return connection.getCluster().zremrangeByRank(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], double, double) + */ + @Override + public Long zRemRangeByScore(byte[] key, double min, double max) { + + try { + return connection.getCluster().zremrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, byte[]... sets) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + + try { + return connection.getCluster().zunionstore(destKey, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new InvalidDataAccessApiUsageException("ZUNIONSTORE can only be executed when all keys map to the same slot"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); + + try { + return connection.getCluster().zunionstore(destKey, zparams, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new InvalidDataAccessApiUsageException("ZUNIONSTORE can only be executed when all keys map to the same slot"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, byte[]... sets) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + + try { + return connection.getCluster().zinterstore(destKey, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new InvalidDataAccessApiUsageException("ZINTERSTORE can only be executed when all keys map to the same slot"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); + + try { + return connection.getCluster().zinterstore(destKey, zparams, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + throw new IllegalArgumentException("ZINTERSTORE can only be executed when all keys map to the same slot"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor zScan(final byte[] key, final ScanOptions options) { + return new ScanCursor(options) { + + @Override + protected ScanIteration doScan(long cursorId, ScanOptions options) { + + ScanParams params = JedisConverters.toScanParams(options); + + redis.clients.jedis.ScanResult result = connection.getCluster().zscan(key, + JedisConverters.toBytes(cursorId), params); + return new ScanIteration(Long.valueOf(result.getStringCursor()), + JedisConverters.tuplesToTuples().convert(result.getResult())); + } + }.open(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max) { + + try { + return connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String, long, long) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); + } + + try { + return connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max), + Long.valueOf(offset).intValue(), Long.valueOf(count).intValue()); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private DataAccessException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 8fa50eae5..cee87697b 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -15,53 +15,52 @@ */ package org.springframework.data.redis.connection.jedis; +import redis.clients.jedis.BinaryJedis; +import redis.clients.jedis.BinaryJedisPubSub; +import redis.clients.jedis.Builder; +import redis.clients.jedis.Client; +import redis.clients.jedis.Connection; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Pipeline; +import redis.clients.jedis.Protocol.Command; +import redis.clients.jedis.Queable; +import redis.clients.jedis.Response; +import redis.clients.jedis.Transaction; +import redis.clients.jedis.exceptions.JedisDataException; +import redis.clients.util.Pool; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Properties; import java.util.Queue; -import java.util.Set; -import java.util.concurrent.TimeUnit; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; -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.ExceptionTranslationStrategy; import org.springframework.data.redis.FallbackExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; import org.springframework.data.redis.connection.AbstractRedisConnection; -import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.FutureResult; import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.RedisHashCommands; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisPipelineException; +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.RedisSubscribedConnectionException; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; -import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.convert.TransactionResultConverter; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.KeyBoundCursor; -import org.springframework.data.redis.core.ScanCursor; -import org.springframework.data.redis.core.ScanIteration; -import org.springframework.data.redis.core.ScanOptions; -import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -70,27 +69,6 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.BinaryJedisPubSub; -import redis.clients.jedis.Builder; -import redis.clients.jedis.Client; -import redis.clients.jedis.Connection; -import redis.clients.jedis.GeoCoordinate; -import redis.clients.jedis.GeoUnit; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Protocol; -import redis.clients.jedis.Protocol.Command; -import redis.clients.jedis.Queable; -import redis.clients.jedis.Response; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; -import redis.clients.jedis.SortingParams; -import redis.clients.jedis.Transaction; -import redis.clients.jedis.ZParams; -import redis.clients.jedis.exceptions.JedisDataException; -import redis.clients.util.Pool; - /** * {@code RedisConnection} implementation on top of Jedis library. * @@ -155,7 +133,7 @@ public class JedisConnection extends AbstractRedisConnection { private List>> pipelinedResults = new ArrayList>>(); private Queue>> txResults = new LinkedList>>(); - private class JedisResult extends FutureResult> { + class JedisResult extends FutureResult> { public JedisResult(Response resultHolder, Converter converter) { super(resultHolder, converter); } @@ -246,7 +224,84 @@ public class JedisConnection extends AbstractRedisConnection { return exception; } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#keyCommands() + */ + @Override + public RedisKeyCommands keyCommands() { + return new JedisKeyCommands(this); + } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#stringCommands() + */ + @Override + public RedisStringCommands stringCommands() { + return new JedisStringCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#listCommands() + */ + @Override + public RedisListCommands listCommands() { + return new JedisListCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#setCommands() + */ + @Override + public RedisSetCommands setCommands() { + return new JedisSetCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#zSetCommands() + */ + @Override + public RedisZSetCommands zSetCommands() { + return new JedisZSetCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#hashCommands() + */ + @Override + public RedisHashCommands hashCommands() { + return new JedisHashCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#geoCommands() + */ + @Override + public RedisGeoCommands geoCommands() { + return new JedisGeoCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#hyperLogLogCommands() + */ + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return new JedisHyperLogLogCommands(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisCommands#execute(java.lang.String, byte[][]) + */ + @Override public Object execute(String command, byte[]... args) { Assert.hasText(command, "a valid command needs to be specified"); try { @@ -283,6 +338,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.AbstractRedisConnection#close() + */ + @Override public void close() throws DataAccessException { super.close(); // return the connection to the pool @@ -338,10 +398,20 @@ public class JedisConnection extends AbstractRedisConnection { throw convertJedisAccessException(exc); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#getNativeConnection() + */ + @Override public Jedis getNativeConnection() { return jedis; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#isClosed() + */ + @Override public boolean isClosed() { try { return !jedis.isConnected(); @@ -350,20 +420,40 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#isQueueing() + */ + @Override public boolean isQueueing() { return client.isInMulti(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#isPipelined() + */ + @Override public boolean isPipelined() { return (pipeline != null); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#openPipeline() + */ + @Override public void openPipeline() { if (pipeline == null) { pipeline = jedis.pipelined(); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnection#closePipeline() + */ + @Override public List closePipeline() { if (pipeline != null) { try { @@ -405,11 +495,7 @@ public class JedisConnection extends AbstractRedisConnection { return results; } - private void doPipelined(Response response) { - pipeline(new JedisStatusResult(response)); - } - - private void pipeline(FutureResult> result) { + void pipeline(FutureResult> result) { if (isQueueing()) { transaction(result); } else { @@ -417,72 +503,15 @@ public class JedisConnection extends AbstractRedisConnection { } } - private void doQueued(Response response) { - transaction(new JedisStatusResult(response)); - } - - private void transaction(FutureResult> result) { + void transaction(FutureResult> result) { txResults.add(result); } - public List sort(byte[] key, SortParameters params) { - - SortingParams sortParams = JedisConverters.toSortingParams(params); - - try { - if (isPipelined()) { - if (sortParams != null) { - pipeline(new JedisResult(pipeline.sort(key, sortParams))); - } else { - pipeline(new JedisResult(pipeline.sort(key))); - } - - return null; - } - if (isQueueing()) { - if (sortParams != null) { - transaction(new JedisResult(transaction.sort(key, sortParams))); - } else { - transaction(new JedisResult(transaction.sort(key))); - } - - return null; - } - return (sortParams != null ? jedis.sort(key, sortParams) : jedis.sort(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sort(byte[] key, SortParameters params, byte[] storeKey) { - - SortingParams sortParams = JedisConverters.toSortingParams(params); - - try { - if (isPipelined()) { - if (sortParams != null) { - pipeline(new JedisResult(pipeline.sort(key, sortParams, storeKey))); - } else { - pipeline(new JedisResult(pipeline.sort(key, storeKey))); - } - - return null; - } - if (isQueueing()) { - if (sortParams != null) { - transaction(new JedisResult(transaction.sort(key, sortParams, storeKey))); - } else { - transaction(new JedisResult(transaction.sort(key, storeKey))); - } - - return null; - } - return (sortParams != null ? jedis.sort(key, sortParams, storeKey) : jedis.sort(key, storeKey)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#dbSize() + */ + @Override public Long dbSize() { try { if (isPipelined()) { @@ -499,6 +528,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#flushDb() + */ + @Override public void flushDb() { try { if (isPipelined()) { @@ -515,6 +549,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#flushAll() + */ + @Override public void flushAll() { try { if (isPipelined()) { @@ -531,6 +570,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#bgSave() + */ + @Override public void bgSave() { try { if (isPipelined()) { @@ -547,6 +591,10 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#bgReWriteAof() + */ @Override public void bgReWriteAof() { try { @@ -572,6 +620,11 @@ public class JedisConnection extends AbstractRedisConnection { bgReWriteAof(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#save() + */ + @Override public void save() { try { if (isPipelined()) { @@ -588,6 +641,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String) + */ + @Override public List getConfig(String param) { try { if (isPipelined()) { @@ -604,6 +662,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#info() + */ + @Override public Properties info() { try { if (isPipelined()) { @@ -620,6 +683,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#info(java.lang.String) + */ + @Override public Properties info(String section) { if (isPipelined()) { throw new UnsupportedOperationException(); @@ -634,6 +702,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#lastSave() + */ + @Override public Long lastSave() { try { if (isPipelined()) { @@ -650,6 +723,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#setConfig(java.lang.String, java.lang.String) + */ + @Override public void setConfig(String param, String value) { try { if (isPipelined()) { @@ -666,6 +744,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#resetConfigStats() + */ + @Override public void resetConfigStats() { try { if (isPipelined()) { @@ -682,6 +765,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisServerCommands#shutdown() + */ + @Override public void shutdown() { try { if (isPipelined()) { @@ -713,6 +801,11 @@ public class JedisConnection extends AbstractRedisConnection { eval(String.format(SHUTDOWN_SCRIPT, option.name()).getBytes(), ReturnType.STATUS, 0); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnectionCommands#echo(byte[]) + */ + @Override public byte[] echo(byte[] message) { try { if (isPipelined()) { @@ -729,6 +822,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnectionCommands#ping() + */ + @Override public String ping() { try { if (isPipelined()) { @@ -745,22 +843,11 @@ public class JedisConnection extends AbstractRedisConnection { } } - public Long del(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.del(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.del(keys))); - return null; - } - return jedis.del(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisTxCommands#discard() + */ + @Override public void discard() { try { if (isPipelined()) { @@ -776,6 +863,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisTxCommands#exec() + */ + @Override public List exec() { try { if (isPipelined()) { @@ -800,80 +892,36 @@ public class JedisConnection extends AbstractRedisConnection { } } - public Boolean exists(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.exists(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.exists(key))); - return null; - } - return jedis.exists(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + public Pipeline getPipeline() { + return pipeline; } - public Boolean expire(byte[] key, long seconds) { - - Assert.notNull(key, "Key must not be null!"); - - if (seconds > Integer.MAX_VALUE) { - return pExpire(key, TimeUnit.SECONDS.toMillis(seconds)); - } - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.expire(key, (int) seconds), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.expire(key, (int) seconds), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.expire(key, (int) seconds)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + public Transaction getTransaction() { + return transaction; } - public Boolean expireAt(byte[] key, long unixTime) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.expireAt(key, unixTime), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.expireAt(key, unixTime), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.expireAt(key, unixTime)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + public Jedis getJedis() { + return jedis; } - public Set keys(byte[] pattern) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.keys(pattern))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.keys(pattern))); - return null; - } - return (jedis.keys(pattern)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + + JedisResult newJedisResult(Response response) { + return new JedisResult(response); } + JedisResult newJedisResult(Response response, Converter converter) { + return new JedisResult(response, converter); + } + + JedisStatusResult newStatusResult(Response response) { + return new JedisStatusResult(response); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisTxCommands#multi() + */ + @Override public void multi() { if (isQueueing()) { return; @@ -889,86 +937,11 @@ public class JedisConnection extends AbstractRedisConnection { } } - public Boolean persist(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.persist(key), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.persist(key), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.persist(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean move(byte[] key, int dbIndex) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.move(key, dbIndex), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.move(key, dbIndex), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.move(key, dbIndex)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] randomKey() { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.randomKeyBinary())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.randomKeyBinary())); - return null; - } - return jedis.randomBinaryKey(); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void rename(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.rename(oldName, newName))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.rename(oldName, newName))); - return; - } - jedis.rename(oldName, newName); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean renameNX(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.renamenx(oldName, newName), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.renamenx(oldName, newName), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.renamenx(oldName, newName)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int) + */ + @Override public void select(int dbIndex) { try { if (isPipelined()) { @@ -985,196 +958,11 @@ public class JedisConnection extends AbstractRedisConnection { } } - /* + /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) + * @see org.springframework.data.redis.connection.RedisTxCommands#unwatch() */ @Override - public Long ttl(byte[] key) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.ttl(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.ttl(key))); - return null; - } - - return jedis.ttl(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long ttl(byte[] key, TimeUnit timeUnit) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.secondsToTimeUnit(jedis.ttl(key), timeUnit); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean pExpire(byte[] key, long millis) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pexpire(key, millis), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pexpire(key, millis), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.pexpire(key, millis)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pexpireAt(key, unixTimeInMillis), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pexpireAt(key, unixTimeInMillis), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.pexpireAt(key, unixTimeInMillis)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) - */ - @Override - public Long pTtl(byte[] key) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pttl(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pttl(key))); - return null; - } - - return jedis.pttl(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long pTtl(byte[] key, TimeUnit timeUnit) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.millisecondsToTimeUnit(jedis.pttl(key), timeUnit); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] dump(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.dump(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.dump(key))); - return null; - } - return jedis.dump(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { - - if (ttlInMillis > Integer.MAX_VALUE) { - throw new IllegalArgumentException("TtlInMillis must be less than Integer.MAX_VALUE for restore in Jedis."); - } - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.restore(key, (int) ttlInMillis, serializedValue))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.restore(key, (int) ttlInMillis, serializedValue))); - return; - } - jedis.restore(key, (int) ttlInMillis, serializedValue); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public DataType type(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.type(key), JedisConverters.stringToDataType())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.type(key), JedisConverters.stringToDataType())); - return null; - } - return JedisConverters.toDataType(jedis.type(key)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - public void unwatch() { try { jedis.unwatch(); @@ -1183,6 +971,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisTxCommands#watch(byte[][]) + */ + @Override public void watch(byte[]... keys) { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1200,1921 +993,15 @@ public class JedisConnection extends AbstractRedisConnection { } } - // - // String commands - // - - public byte[] get(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.get(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.get(key))); - return null; - } - - return jedis.get(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void set(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.set(key, value))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.set(key, value))); - return; - } - jedis.set(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption) - */ - @Override - public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { - - if (expiration == null || expiration.isPersistent()) { - - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { - set(key, value); - } else { - - try { - - byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); - - if (isPipelined()) { - - pipeline(new JedisStatusResult(pipeline.set(key, value, nxxx))); - return; - } - if (isQueueing()) { - - transaction(new JedisStatusResult(transaction.set(key, value, nxxx))); - return; - } - - jedis.set(key, value, nxxx); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - } else { - - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { - - if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) { - pSetEx(key, expiration.getExpirationTime(), value); - } else { - setEx(key, expiration.getExpirationTime(), value); - } - } else { - - byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); - byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration); - - try { - if (isPipelined()) { - - if (expiration.getExpirationTime() > Integer.MAX_VALUE) { - - throw new IllegalArgumentException( - "Expiration.expirationTime must be less than Integer.MAX_VALUE for pipeline in Jedis."); - } - - pipeline(new JedisStatusResult(pipeline.set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); - return; - } - if (isQueueing()) { - - if (expiration.getExpirationTime() > Integer.MAX_VALUE) { - throw new IllegalArgumentException( - "Expiration.expirationTime must be less than Integer.MAX_VALUE for transactions in Jedis."); - } - - transaction( - new JedisStatusResult(transaction.set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); - return; - } - - jedis.set(key, value, nxxx, expx, expiration.getExpirationTime()); - - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - } - } - - public byte[] getSet(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.getSet(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.getSet(key, value))); - return null; - } - return jedis.getSet(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long append(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.append(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.append(key, value))); - return null; - } - return jedis.append(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List mGet(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.mget(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.mget(keys))); - return null; - } - return jedis.mget(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void mSet(Map tuples) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.mset(JedisConverters.toByteArrays(tuples)))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.mset(JedisConverters.toByteArrays(tuples)))); - return; - } - jedis.mset(JedisConverters.toByteArrays(tuples)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean mSetNX(Map tuples) { - try { - if (isPipelined()) { - pipeline( - new JedisResult(pipeline.msetnx(JedisConverters.toByteArrays(tuples)), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction( - new JedisResult(transaction.msetnx(JedisConverters.toByteArrays(tuples)), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.msetnx(JedisConverters.toByteArrays(tuples))); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void setEx(byte[] key, long time, byte[] value) { - - if (time > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Time must be less than Integer.MAX_VALUE for setEx in Jedis."); - } - - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.setex(key, (int) time, value))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.setex(key, (int) time, value))); - return; - } - jedis.setex(key, (int) time, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) - */ - @Override - public void pSetEx(byte[] key, long milliseconds, byte[] value) { - - try { - if (isPipelined()) { - doPipelined(pipeline.psetex(key, milliseconds, value)); - return; - } - if (isQueueing()) { - doQueued(transaction.psetex(key, milliseconds, value)); - return; - } - jedis.psetex(key, milliseconds, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean setNX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.setnx(key, value), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.setnx(key, value), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.setnx(key, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] getRange(byte[] key, long start, long end) { - - if (start > Integer.MAX_VALUE || end > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Start and end must be less than Integer.MAX_VALUE for getRange in Jedis."); - } - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); - return null; - } - return jedis.substr(key, (int) start, (int) end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long decr(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.decr(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.decr(key))); - return null; - } - return jedis.decr(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long decrBy(byte[] key, long value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.decrBy(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.decrBy(key, value))); - return null; - } - return jedis.decrBy(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long incr(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.incr(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.incr(key))); - return null; - } - return jedis.incr(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long incrBy(byte[] key, long value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.incrBy(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.incrBy(key, value))); - return null; - } - return jedis.incrBy(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Double incrBy(byte[] key, double value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.incrByFloat(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.incrByFloat(key, value))); - return null; - } - return jedis.incrByFloat(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean getBit(byte[] key, long offset) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.getbit(key, offset))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.getbit(key, offset))); - return null; - } - // compatibility check for Jedis 2.0.0 - Object getBit = jedis.getbit(key, offset); - // Jedis 2.0 - if (getBit instanceof Long) { - return (((Long) getBit) == 0 ? Boolean.FALSE : Boolean.TRUE); - } - // Jedis 2.1 - return ((Boolean) getBit); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean setBit(byte[] key, long offset, boolean value) { - try { - if (isPipelined()) { - - pipeline(new JedisResult(pipeline.setbit(key, offset, JedisConverters.toBit(value)))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.setbit(key, offset, JedisConverters.toBit(value)))); - return null; - } - return jedis.setbit(key, offset, JedisConverters.toBit(value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void setRange(byte[] key, byte[] value, long start) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.setrange(key, start, value))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.setrange(key, start, value))); - return; - } - jedis.setrange(key, start, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long strLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.strlen(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.strlen(key))); - return null; - } - return jedis.strlen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long bitCount(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.bitcount(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.bitcount(key))); - return null; - } - return jedis.bitcount(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long bitCount(byte[] key, long begin, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.bitcount(key, begin, end))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.bitcount(key, begin, end))); - return null; - } - return jedis.bitcount(key, begin, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - 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(new JedisResult(pipeline.bitop(JedisConverters.toBitOp(op), destination, keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.bitop(JedisConverters.toBitOp(op), destination, keys))); - return null; - } - return jedis.bitop(JedisConverters.toBitOp(op), destination, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - // - // List commands - // - - public Long lPush(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lpush(key, values))); - return null; - } - return jedis.lpush(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long rPush(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.rpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.rpush(key, values))); - return null; - } - return jedis.rpush(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List bLPop(int timeout, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.blpop(bXPopArgs(timeout, keys)))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.blpop(bXPopArgs(timeout, keys)))); - return null; - } - return jedis.blpop(timeout, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List bRPop(int timeout, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.brpop(bXPopArgs(timeout, keys)))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.brpop(bXPopArgs(timeout, keys)))); - return null; - } - return jedis.brpop(timeout, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] lIndex(byte[] key, long index) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lindex(key, index))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lindex(key, index))); - return null; - } - return jedis.lindex(key, index); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.linsert(key, JedisConverters.toListPosition(where), pivot, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.linsert(key, JedisConverters.toListPosition(where), pivot, value))); - return null; - } - return jedis.linsert(key, JedisConverters.toListPosition(where), pivot, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long lLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.llen(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.llen(key))); - return null; - } - return jedis.llen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] lPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lpop(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lpop(key))); - return null; - } - return jedis.lpop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List lRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lrange(key, start, end))); - return null; - } - return jedis.lrange(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long lRem(byte[] key, long count, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lrem(key, count, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lrem(key, count, value))); - return null; - } - return jedis.lrem(key, count, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void lSet(byte[] key, long index, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.lset(key, index, value))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.lset(key, index, value))); - return; - } - jedis.lset(key, index, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void lTrim(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.ltrim(key, start, end))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.ltrim(key, start, end))); - return; - } - jedis.ltrim(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] rPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.rpop(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.rpop(key))); - return null; - } - return jedis.rpop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.rpoplpush(srcKey, dstKey))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.rpoplpush(srcKey, dstKey))); - return null; - } - return jedis.rpoplpush(srcKey, dstKey); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.brpoplpush(srcKey, dstKey, timeout))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.brpoplpush(srcKey, dstKey, timeout))); - return null; - } - return jedis.brpoplpush(srcKey, dstKey, timeout); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long lPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.lpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.lpushx(key, value))); - return null; - } - return jedis.lpushx(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long rPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.rpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.rpushx(key, value))); - return null; - } - return jedis.rpushx(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - // - // Set commands - // - - public Long sAdd(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sadd(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sadd(key, values))); - return null; - } - return jedis.sadd(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sCard(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.scard(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.scard(key))); - return null; - } - return jedis.scard(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set sDiff(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sdiff(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sdiff(keys))); - return null; - } - return jedis.sdiff(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sDiffStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sdiffstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sdiffstore(destKey, keys))); - return null; - } - return jedis.sdiffstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set sInter(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sinter(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sinter(keys))); - return null; - } - return jedis.sinter(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sInterStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sinterstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sinterstore(destKey, keys))); - return null; - } - return jedis.sinterstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean sIsMember(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sismember(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sismember(key, value))); - return null; - } - return jedis.sismember(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set sMembers(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.smembers(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.smembers(key))); - return null; - } - return jedis.smembers(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.smove(srcKey, destKey, value), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.smove(srcKey, destKey, value), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.smove(srcKey, destKey, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] sPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.spop(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.spop(key))); - return null; - } - return jedis.spop(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] sRandMember(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.srandmember(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.srandmember(key))); - return null; - } - return jedis.srandmember(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List sRandMember(byte[] key, long count) { - - if (count > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Count must be less than Integer.MAX_VALUE for sRandMember in Jedis."); - } - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.srandmember(key, (int) count))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.srandmember(key, (int) count))); - return null; - } - return jedis.srandmember(key, (int) count); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sRem(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.srem(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.srem(key, values))); - return null; - } - return jedis.srem(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set sUnion(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sunion(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sunion(keys))); - return null; - } - return jedis.sunion(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long sUnionStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.sunionstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.sunionstore(destKey, keys))); - return null; - } - return jedis.sunionstore(destKey, keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - // - // ZSet commands - // - - public Boolean zAdd(byte[] key, double score, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zadd(key, score, value), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zadd(key, score, value), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.zadd(key, score, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zAdd(byte[] key, Set tuples) { - if (isPipelined() || isQueueing()) { - throw new UnsupportedOperationException("zAdd of multiple fields not supported " + "in pipeline or transaction"); - } - Map args = zAddArgs(tuples); - try { - return jedis.zadd(key, args); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zCard(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zcard(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zcard(key))); - return null; - } - return jedis.zcard(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zCount(byte[] key, double min, double max) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zcount(key, min, max))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zcount(key, min, max))); - return null; - } - return jedis.zcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zCount(byte[] key, Range range) { - - if (isPipelined() || isQueueing()) { - throw new UnsupportedOperationException( - "ZCOUNT not implemented in jedis for binary protocol on transaction and pipeline"); - } - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - return jedis.zcount(key, min, max); - } - - public Double zIncrBy(byte[] key, double increment, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zincrby(key, increment, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zincrby(key, increment, value))); - return null; - } - return jedis.zincrby(key, increment, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - try { - ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); - - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zinterstore(destKey, zparams, sets))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zinterstore(destKey, zparams, sets))); - return null; - } - return jedis.zinterstore(destKey, zparams, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zInterStore(byte[] destKey, byte[]... sets) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zinterstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zinterstore(destKey, sets))); - return null; - } - return jedis.zinterstore(destKey, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set zRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrange(key, start, end))); - return null; - } - return jedis.zrange(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set zRangeWithScores(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); - return null; - } - if (isQueueing()) { - transaction( - new JedisResult(transaction.zrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); - return null; - } - return JedisConverters.toTupleSet(jedis.zrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) - */ - public Set zRangeByLex(byte[] key) { - return zRangeByLex(key, Range.unbounded()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - public Set zRangeByLex(byte[] key, Range range) { - return zRangeByLex(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - public Set zRangeByLex(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); - - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new JedisResult(pipeline.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - pipeline(new JedisResult(pipeline.zrangeByLex(key, min, max))); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction(new JedisResult(transaction.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - transaction(new JedisResult(transaction.zrangeByLex(key, min, max))); - } - return null; - } - - if (limit != null) { - return jedis.zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); - } - return jedis.zrangeByLex(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double) - */ - public Set zRangeByScore(byte[] key, double min, double max) { - return zRangeByScore(key, new Range().gte(min).lte(max)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByScore(byte[] key, Range range) { - return zRangeByScore(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - pipeline(new JedisResult(pipeline.zrangeByScore(key, min, max))); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction(new JedisResult(transaction.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - transaction(new JedisResult(transaction.zrangeByScore(key, min, max))); - } - return null; - } - - if (limit != null) { - return jedis.zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); - } - return jedis.zrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double) - */ - public Set zRangeByScoreWithScores(byte[] key, double min, double max) { - return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range) { - return zRangeByScoreWithScores(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new JedisResult(pipeline.zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); - } else { - pipeline( - new JedisResult(pipeline.zrangeByScoreWithScores(key, min, max), JedisConverters.tupleSetToTupleSet())); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction( - new JedisResult(transaction.zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); - } else { - transaction(new JedisResult(transaction.zrangeByScoreWithScores(key, min, max), - JedisConverters.tupleSetToTupleSet())); - } - return null; - } - - if (limit != null) { - return JedisConverters - .toTupleSet(jedis.zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); - } - return JedisConverters.toTupleSet(jedis.zrangeByScoreWithScores(key, min, max)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set zRevRangeWithScores(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); - return null; - } - if (isQueueing()) { - transaction( - new JedisResult(transaction.zrevrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); - return null; - } - return JedisConverters.toTupleSet(jedis.zrevrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], double, double, long, long) - */ - @Override - public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - - return zRangeByScore(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], double, double, long, long) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double, long, long) - */ - @Override - public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - - return zRevRangeByScore(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], double, double) - */ - @Override - public Set zRevRangeByScore(byte[] key, double min, double max) { - return zRevRangeByScore(key, new Range().gte(min).lte(max)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRevRangeByScore(byte[] key, Range range) { - return zRevRangeByScore(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); - } else { - pipeline(new JedisResult(pipeline.zrevrangeByScore(key, max, min))); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction( - new JedisResult(transaction.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); - } else { - transaction(new JedisResult(transaction.zrevrangeByScore(key, max, min))); - } - return null; - } - - if (limit != null) { - return jedis.zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); - } - return jedis.zrevrangeByScore(key, max, min); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double, long, long) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range) { - return zRevRangeByScoreWithScores(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline( - new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); - } else { - pipeline(new JedisResult(pipeline.zrevrangeByScoreWithScores(key, max, min), - JedisConverters.tupleSetToTupleSet())); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction(new JedisResult( - transaction.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); - } else { - transaction(new JedisResult(transaction.zrevrangeByScoreWithScores(key, max, min), - JedisConverters.tupleSetToTupleSet())); - } - return null; - } - - if (limit != null) { - return JedisConverters - .toTupleSet(jedis.zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); - } - return JedisConverters.toTupleSet(jedis.zrevrangeByScoreWithScores(key, max, min)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], double, double) - */ - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { - return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), null); - } - - public Long zRank(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrank(key, value))); - return null; - } - return jedis.zrank(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zRem(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrem(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrem(key, values))); - return null; - } - return jedis.zrem(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zRemRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zremrangeByRank(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zremrangeByRank(key, start, end))); - return null; - } - return jedis.zremrangeByRank(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], double, double) - */ - @Override - public Long zRemRangeByScore(byte[] key, double min, double max) { - return zRemRangeByScore(key, new Range().gte(min).lte(max)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zRemRangeByScore(byte[] key, Range range) { - - Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zremrangeByScore(key, min, max))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zremrangeByScore(key, min, max))); - return null; - } - return jedis.zremrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set zRevRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrange(key, start, end))); - return null; - } - return jedis.zrevrange(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zRevRank(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrevrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrevrank(key, value))); - return null; - } - return jedis.zrevrank(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Double zScore(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zscore(key, value))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zscore(key, value))); - return null; - } - return jedis.zscore(key, value); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - try { - ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); - - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zunionstore(destKey, zparams, sets))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zunionstore(destKey, zparams, sets))); - return null; - } - return jedis.zunionstore(destKey, zparams, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long zUnionStore(byte[] destKey, byte[]... sets) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zunionstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zunionstore(destKey, sets))); - return null; - } - return jedis.zunionstore(destKey, sets); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - // - // Hash commands - // - - public Boolean hSet(byte[] key, byte[] field, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hset(key, field, value), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hset(key, field, value), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.hset(key, field, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hsetnx(key, field, value), JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hsetnx(key, field, value), JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(jedis.hsetnx(key, field, value)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long hDel(byte[] key, byte[]... fields) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hdel(key, fields))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hdel(key, fields))); - return null; - } - return jedis.hdel(key, fields); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Boolean hExists(byte[] key, byte[] field) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hexists(key, field))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hexists(key, field))); - return null; - } - return jedis.hexists(key, field); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public byte[] hGet(byte[] key, byte[] field) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hget(key, field))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hget(key, field))); - return null; - } - return jedis.hget(key, field); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Map hGetAll(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hgetAll(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hgetAll(key))); - return null; - } - return jedis.hgetAll(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long hIncrBy(byte[] key, byte[] field, long delta) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hincrBy(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hincrBy(key, field, delta))); - return null; - } - return jedis.hincrBy(key, field, delta); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Double hIncrBy(byte[] key, byte[] field, double delta) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hincrByFloat(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hincrByFloat(key, field, delta))); - return null; - } - return jedis.hincrByFloat(key, field, delta); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Set hKeys(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hkeys(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hkeys(key))); - return null; - } - return jedis.hkeys(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public Long hLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hlen(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hlen(key))); - return null; - } - return jedis.hlen(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List hMGet(byte[] key, byte[]... fields) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hmget(key, fields))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hmget(key, fields))); - return null; - } - return jedis.hmget(key, fields); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public void hMSet(byte[] key, Map tuple) { - try { - if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.hmset(key, tuple))); - return; - } - if (isQueueing()) { - transaction(new JedisStatusResult(transaction.hmset(key, tuple))); - return; - } - jedis.hmset(key, tuple); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - public List hVals(byte[] key) { - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.hvals(key))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.hvals(key))); - return null; - } - return jedis.hvals(key); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - // // Pub/Sub functionality // + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisPubSubCommands#publish(byte[], byte[]) + */ + @Override public Long publish(byte[] channel, byte[] message) { try { if (isPipelined()) { @@ -3131,14 +1018,29 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisPubSubCommands#getSubscription() + */ + @Override public Subscription getSubscription() { return subscription; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisPubSubCommands#isSubscribed() + */ + @Override public boolean isSubscribed() { return (subscription != null && subscription.isAlive()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisPubSubCommands#pSubscribe(org.springframework.data.redis.connection.MessageListener, byte[][]) + */ + @Override public void pSubscribe(MessageListener listener, byte[]... patterns) { if (isSubscribed()) { throw new RedisSubscribedConnectionException( @@ -3162,6 +1064,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisPubSubCommands#subscribe(org.springframework.data.redis.connection.MessageListener, byte[][]) + */ + @Override public void subscribe(MessageListener listener, byte[]... channels) { if (isSubscribed()) { throw new RedisSubscribedConnectionException( @@ -3186,383 +1093,15 @@ public class JedisConnection extends AbstractRedisConnection { } } - // - // Geo commands - // - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) - */ - @Override - public Long geoAdd(byte[] key, Point point, byte[] member) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(point, "Point must not be null!"); - Assert.notNull(member, "Member must not be null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geoadd(key, point.getX(), point.getY(), member))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geoadd(key, point.getX(), point.getY(), member))); - return null; - } - - return jedis.geoadd(key, point.getX(), point.getY(), member); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation) - */ - public Long geoAdd(byte[] key, GeoLocation location) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(location, "Location must not be null!"); - - return geoAdd(key, location.getPoint(), location.getName()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) - */ - @Override - public Long geoAdd(byte[] key, Map memberCoordinateMap) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); - - Map redisGeoCoordinateMap = new HashMap(); - - for (byte[] mapKey : memberCoordinateMap.keySet()) { - redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey))); - } - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geoadd(key, redisGeoCoordinateMap))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geoadd(key, redisGeoCoordinateMap))); - return null; - } - - return jedis.geoadd(key, redisGeoCoordinateMap); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) - */ - @Override - public Long geoAdd(byte[] key, Iterable> locations) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(locations, "Locations must not be null!"); - - Map redisGeoCoordinateMap = new HashMap(); - - for (GeoLocation location : locations) { - redisGeoCoordinateMap.put(location.getName(), JedisConverters.toGeoCoordinate(location.getPoint())); - } - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geoadd(key, redisGeoCoordinateMap))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geoadd(key, redisGeoCoordinateMap))); - return null; - } - - return jedis.geoadd(key, redisGeoCoordinateMap); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member1, "Member1 must not be null!"); - Assert.notNull(member2, "Member2 must not be null!"); - - Converter distanceConverter = JedisConverters.distanceConverterForMetric(DistanceUnit.METERS); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geodist(key, member1, member2), distanceConverter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geodist(key, member1, member2), distanceConverter)); - return null; - } - - return distanceConverter.convert(jedis.geodist(key, member1, member2)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member1, "Member1 must not be null!"); - Assert.notNull(member2, "Member2 must not be null!"); - Assert.notNull(metric, "Metric must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(metric); - Converter distanceConverter = JedisConverters.distanceConverterForMetric(metric); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geodist(key, member1, member2, geoUnit), distanceConverter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geodist(key, member1, member2, geoUnit), distanceConverter)); - return null; - } - - return distanceConverter.convert(jedis.geodist(key, member1, member2, geoUnit)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) - */ - @Override - public List geoHash(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geohash(key, members), JedisConverters.bytesListToStringListConverter())); - return null; - } - if (isQueueing()) { - transaction( - new JedisResult(transaction.geohash(key, members), JedisConverters.bytesListToStringListConverter())); - return null; - } - - return JedisConverters.bytesListToStringListConverter().convert(jedis.geohash(key, members)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) - */ - @Override - public List geoPos(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - ListConverter converter = JedisConverters.geoCoordinateToPointConverter(); - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.geopos(key, members), converter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.geopos(key, members), converter)); - return null; - } - return converter.convert(jedis.geopos(key, members)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - - Converter, GeoResults>> converter = JedisConverters - .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), converter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), converter)); - return null; - } - - return converter.convert(jedis.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()))); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - Converter, GeoResults>> converter = JedisConverters - .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), - converter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), - converter)); - return null; - } - - return converter.convert(jedis.georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { - return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - Converter, GeoResults>> converter = JedisConverters - .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); - return null; - } - - return converter.convert(jedis.georadiusByMember(key, member, radius.getValue(), geoUnit)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, - GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); - Converter, GeoResults>> converter = JedisConverters - .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); - redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), - converter)); - return null; - } - if (isQueueing()) { - transaction(new JedisResult( - transaction.georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), converter)); - return null; - } - return converter.convert(jedis.georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) - */ - @Override - public Long geoRemove(byte[] key, byte[]... members) { - return zRem(key, members); - } - // // Scripting commands // + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#scriptFlush() + */ + @Override public void scriptFlush() { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -3577,6 +1116,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#scriptKill() + */ + @Override public void scriptKill() { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -3591,6 +1135,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#scriptLoad(byte[]) + */ + @Override public String scriptLoad(byte[] script) { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -3605,6 +1154,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#scriptExists(java.lang.String[]) + */ + @Override public List scriptExists(String... scriptSha1) { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -3619,6 +1173,11 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#eval(byte[], org.springframework.data.redis.connection.ReturnType, int, byte[][]) + */ + @Override @SuppressWarnings("unchecked") public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { if (isQueueing()) { @@ -3635,10 +1194,20 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#evalSha(java.lang.String, org.springframework.data.redis.connection.ReturnType, int, byte[][]) + */ + @Override public T evalSha(String scriptSha1, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { return evalSha(JedisConverters.toBytes(scriptSha1), returnType, numKeys, keysAndArgs); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisScriptingCommands#evalSha(byte[], org.springframework.data.redis.connection.ReturnType, int, byte[][]) + */ + @Override @SuppressWarnings("unchecked") public T evalSha(byte[] scriptSha1, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { @@ -3771,173 +1340,6 @@ public class JedisConnection extends AbstractRedisConnection { } } - /** - * @since 1.4 - * @return - */ - public Cursor scan() { - return scan(ScanOptions.NONE); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) - */ - public Cursor scan(ScanOptions options) { - return scan(0, options != null ? options : ScanOptions.NONE); - } - - /** - * @since 1.4 - * @param cursorId - * @param options - * @return - */ - public Cursor scan(long cursorId, ScanOptions options) { - - return new ScanCursor(cursorId, options) { - - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); - } - - ScanParams params = JedisConverters.toScanParams(options); - redis.clients.jedis.ScanResult result = jedis.scan(Long.toString(cursorId), params); - return new ScanIteration(Long.valueOf(result.getStringCursor()), - JedisConverters.stringListToByteList().convert(result.getResult())); - } - - protected void doClose() { - JedisConnection.this.close(); - }; - - }.open(); - - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor zScan(byte[] key, ScanOptions options) { - return zScan(key, 0L, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor zScan(byte[] key, Long cursorId, ScanOptions options) { - - return new KeyBoundCursor(key, cursorId, options) { - - @Override - protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); - } - - ScanParams params = JedisConverters.toScanParams(options); - - ScanResult result = jedis.zscan(key, JedisConverters.toBytes(cursorId), params); - return new ScanIteration(Long.valueOf(result.getStringCursor()), - JedisConverters.tuplesToTuples().convert(result.getResult())); - } - - protected void doClose() { - JedisConnection.this.close(); - }; - - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor sScan(byte[] key, ScanOptions options) { - return sScan(key, 0, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { - - return new KeyBoundCursor(key, cursorId, options) { - - @Override - protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); - } - - ScanParams params = JedisConverters.toScanParams(options); - - redis.clients.jedis.ScanResult result = jedis.sscan(key, JedisConverters.toBytes(cursorId), params); - return new ScanIteration(Long.valueOf(result.getStringCursor()), result.getResult()); - } - - protected void doClose() { - JedisConnection.this.close(); - }; - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor> hScan(byte[] key, ScanOptions options) { - return hScan(key, 0, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { - - return new KeyBoundCursor>(key, cursorId, options) { - - @Override - protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); - } - - ScanParams params = JedisConverters.toScanParams(options); - - ScanResult> result = jedis.hscan(key, JedisConverters.toBytes(cursorId), params); - return new ScanIteration>(Long.valueOf(result.getStringCursor()), result.getResult()); - } - - protected void doClose() { - JedisConnection.this.close(); - }; - - }.open(); - } - /** * Specifies if pipelined results should be converted to the expected data type. If false, results of * {@link #closePipeline()} and {@link #exec()} will be of the type returned by the Jedis driver @@ -3948,38 +1350,10 @@ public class JedisConnection extends AbstractRedisConnection { this.convertPipelineAndTxResults = convertPipelineAndTxResults; } - private byte[][] bXPopArgs(int timeout, byte[]... keys) { - final List args = new ArrayList(); - for (final byte[] arg : keys) { - args.add(arg); - } - args.add(Protocol.toByteArray(timeout)); - return args.toArray(new byte[args.size()][]); - } - - private Map zAddArgs(Set tuples) { - - Map args = new LinkedHashMap(tuples.size(), 1); - Set scores = new HashSet(tuples.size(), 1); - - boolean isAtLeastJedis24 = JedisVersionUtil.atLeastJedis24(); - - for (Tuple tuple : tuples) { - - if (!isAtLeastJedis24) { - if (scores.contains(tuple.getScore())) { - throw new UnsupportedOperationException( - "Bulk add of multiple elements with the same score is not supported. Add the elements individually."); - } - scores.add(tuple.getScore()); - } - - args.put(tuple.getValue(), tuple.getScore()); - } - - return args; - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.AbstractRedisConnection#isActive(org.springframework.data.redis.connection.RedisNode) + */ @Override protected boolean isActive(RedisNode node) { @@ -4002,6 +1376,10 @@ public class JedisConnection extends AbstractRedisConnection { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.AbstractRedisConnection#getSentinelConnection(org.springframework.data.redis.connection.RedisNode) + */ @Override protected JedisSentinelConnection getSentinelConnection(RedisNode sentinel) { return new JedisSentinelConnection(getJedis(sentinel)); @@ -4018,123 +1396,6 @@ public class JedisConnection extends AbstractRedisConnection { return jedis; } - @Override - public Set zRangeByScore(byte[] key, String min, String max) { - - try { - String keyStr = new String(key, "UTF-8"); - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScore(keyStr, min, max))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScore(keyStr, min, max))); - return null; - } - return JedisConverters.stringSetToByteSet().convert(jedis.zrangeByScore(keyStr, min, max)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - @Override - public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { - - if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { - - throw new IllegalArgumentException( - "Offset and count must be less than Integer.MAX_VALUE for zRangeByScore in Jedis."); - } - - try { - String keyStr = new String(key, "UTF-8"); - if (isPipelined()) { - pipeline(new JedisResult(pipeline.zrangeByScore(keyStr, min, max, (int) offset, (int) count))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.zrangeByScore(keyStr, min, max, (int) offset, (int) count))); - return null; - } - return JedisConverters.stringSetToByteSet() - .convert(jedis.zrangeByScore(keyStr, min, max, (int) offset, (int) count)); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfAdd(byte[], byte[][]) - */ - @Override - 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(new JedisResult(pipeline.pfadd(key, values))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pfadd(key, values))); - return null; - } - return jedis.pfadd(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfCount(byte[][]) - */ - @Override - public Long pfCount(byte[]... keys) { - - Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); - Assert.noNullElements(keys, "Keys for PFOUNT must not contain 'null'."); - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pfcount(keys))); - return null; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pfcount(keys))); - return null; - } - return jedis.pfcount(keys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfMerge(byte[], byte[][]) - */ - @Override - public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { - - try { - if (isPipelined()) { - pipeline(new JedisResult(pipeline.pfmerge(destinationKey, sourceKeys))); - return; - } - if (isQueueing()) { - transaction(new JedisResult(transaction.pfmerge(destinationKey, sourceKeys))); - return; - } - jedis.pfmerge(destinationKey, sourceKeys); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java new file mode 100644 index 000000000..3fc834120 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java @@ -0,0 +1,433 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.GeoCoordinate; +import redis.clients.jedis.GeoUnit; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.convert.converter.Converter; +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.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisGeoCommands implements RedisGeoCommands { + + private final JedisConnection connection; + + public JedisGeoCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) + */ + @Override + public Long geoAdd(byte[] key, Point point, byte[] member) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(point, "Point must not be null!"); + Assert.notNull(member, "Member must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, point.getX(), point.getY(), member))); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().geoadd(key, point.getX(), point.getY(), member))); + return null; + } + + return connection.getJedis().geoadd(key, point.getX(), point.getY(), member); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) + */ + @Override + public Long geoAdd(byte[] key, Map memberCoordinateMap) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); + + Map redisGeoCoordinateMap = new HashMap(); + + for (byte[] mapKey : memberCoordinateMap.keySet()) { + redisGeoCoordinateMap.put(mapKey, JedisConverters.toGeoCoordinate(memberCoordinateMap.get(mapKey))); + } + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, redisGeoCoordinateMap))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().geoadd(key, redisGeoCoordinateMap))); + return null; + } + + return connection.getJedis().geoadd(key, redisGeoCoordinateMap); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) + */ + @Override + public Long geoAdd(byte[] key, Iterable> locations) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(locations, "Locations must not be null!"); + + Map redisGeoCoordinateMap = new HashMap(); + + for (GeoLocation location : locations) { + redisGeoCoordinateMap.put(location.getName(), JedisConverters.toGeoCoordinate(location.getPoint())); + } + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, redisGeoCoordinateMap))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().geoadd(key, redisGeoCoordinateMap))); + return null; + } + + return connection.getJedis().geoadd(key, redisGeoCoordinateMap); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member1, "Member1 must not be null!"); + Assert.notNull(member2, "Member2 must not be null!"); + + Converter distanceConverter = JedisConverters.distanceConverterForMetric(DistanceUnit.METERS); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geodist(key, member1, member2), distanceConverter)); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().geodist(key, member1, member2), distanceConverter)); + return null; + } + + return distanceConverter.convert(connection.getJedis().geodist(key, member1, member2)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member1, "Member1 must not be null!"); + Assert.notNull(member2, "Member2 must not be null!"); + Assert.notNull(metric, "Metric must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(metric); + Converter distanceConverter = JedisConverters.distanceConverterForMetric(metric); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geodist(key, member1, member2, geoUnit), + distanceConverter)); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().geodist(key, member1, member2, geoUnit), + distanceConverter)); + return null; + } + + return distanceConverter.convert(connection.getJedis().geodist(key, member1, member2, geoUnit)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) + */ + @Override + public List geoHash(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(members, "Members must not be null!"); + Assert.noNullElements(members, "Members must not contain null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geohash(key, members), + JedisConverters.bytesListToStringListConverter())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().geohash(key, members), + JedisConverters.bytesListToStringListConverter())); + return null; + } + + return JedisConverters.bytesListToStringListConverter().convert(connection.getJedis().geohash(key, members)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) + */ + @Override + public List geoPos(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(members, "Members must not be null!"); + Assert.noNullElements(members, "Members must not contain null!"); + + ListConverter converter = JedisConverters.geoCoordinateToPointConverter(); + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().geopos(key, members), converter)); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().geopos(key, members), converter)); + return null; + } + return converter.convert(connection.getJedis().geopos(key, members)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + + Converter, GeoResults>> converter = JedisConverters + .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); + try { + if (isPipelined()) { + pipeline( + connection.newJedisResult( + connection.getPipeline().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), + converter)); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult( + connection.getTransaction().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), + converter)); + return null; + } + + return converter + .convert(connection.getJedis().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()))); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); + Converter, GeoResults>> converter = JedisConverters + .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().georadius(key, within.getCenter().getX(), + within.getCenter().getY(), within.getRadius().getValue(), + JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), converter)); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().georadius(key, within.getCenter().getX(), + within.getCenter().getY(), within.getRadius().getValue(), + JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), converter)); + return null; + } + + return converter.convert(connection.getJedis().georadius(key, within.getCenter().getX(), + within.getCenter().getY(), within.getRadius().getValue(), + JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); + Converter, GeoResults>> converter = JedisConverters + .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult( + connection.getPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult( + connection.getTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); + return null; + } + + return converter.convert(connection.getJedis().georadiusByMember(key, member, radius.getValue(), geoUnit)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, + GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + GeoUnit geoUnit = JedisConverters.toGeoUnit(radius.getMetric()); + Converter, GeoResults>> converter = JedisConverters + .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); + redis.clients.jedis.params.geo.GeoRadiusParam geoRadiusParam = JedisConverters.toGeoRadiusParam(args); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult( + connection.getPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), + converter)); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult( + connection.getTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), + converter)); + return null; + } + return converter + .convert(connection.getJedis().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) + */ + @Override + public Long geoRemove(byte[] key, byte[]... members) { + return connection.zSetCommands().zRem(key, members); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java new file mode 100644 index 000000000..5981b95ac --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java @@ -0,0 +1,396 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.ScanResult; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.springframework.data.redis.connection.RedisHashCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisHashCommands implements RedisHashCommands { + + private final JedisConnection connection; + + public JedisHashCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSet(byte[], byte[], byte[]) + */ + @Override + public Boolean hSet(byte[] key, byte[] field, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hset(key, field, value), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hset(key, field, value), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().hset(key, field, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSetNX(byte[], byte[], byte[]) + */ + @Override + public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hsetnx(key, field, value), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hsetnx(key, field, value), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().hsetnx(key, field, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hDel(byte[], byte[][]) + */ + @Override + public Long hDel(byte[] key, byte[]... fields) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hdel(key, fields))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hdel(key, fields))); + return null; + } + return connection.getJedis().hdel(key, fields); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hExists(byte[], byte[]) + */ + @Override + public Boolean hExists(byte[] key, byte[] field) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hexists(key, field))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hexists(key, field))); + return null; + } + return connection.getJedis().hexists(key, field); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGet(byte[], byte[]) + */ + @Override + public byte[] hGet(byte[] key, byte[] field) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hget(key, field))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hget(key, field))); + return null; + } + return connection.getJedis().hget(key, field); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGetAll(byte[]) + */ + @Override + public Map hGetAll(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hgetAll(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hgetAll(key))); + return null; + } + return connection.getJedis().hgetAll(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], long) + */ + @Override + public Long hIncrBy(byte[] key, byte[] field, long delta) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hincrBy(key, field, delta))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hincrBy(key, field, delta))); + return null; + } + return connection.getJedis().hincrBy(key, field, delta); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], double) + */ + @Override + public Double hIncrBy(byte[] key, byte[] field, double delta) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hincrByFloat(key, field, delta))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hincrByFloat(key, field, delta))); + return null; + } + return connection.getJedis().hincrByFloat(key, field, delta); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hKeys(byte[]) + */ + @Override + public Set hKeys(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hkeys(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hkeys(key))); + return null; + } + return connection.getJedis().hkeys(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hLen(byte[]) + */ + @Override + public Long hLen(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hlen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hlen(key))); + return null; + } + return connection.getJedis().hlen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMGet(byte[], byte[][]) + */ + @Override + public List hMGet(byte[] key, byte[]... fields) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hmget(key, fields))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hmget(key, fields))); + return null; + } + return connection.getJedis().hmget(key, fields); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) + */ + @Override + public void hMSet(byte[] key, Map tuple) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().hmset(key, tuple))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().hmset(key, tuple))); + return; + } + connection.getJedis().hmset(key, tuple); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hVals(byte[]) + */ + @Override + public List hVals(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().hvals(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().hvals(key))); + return null; + } + return connection.getJedis().hvals(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor> hScan(byte[] key, ScanOptions options) { + return hScan(key, 0, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { + + return new KeyBoundCursor>(key, cursorId, options) { + + @Override + protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); + } + + ScanParams params = JedisConverters.toScanParams(options); + + ScanResult> result = connection.getJedis().hscan(key, JedisConverters.toBytes(cursorId), + params); + return new ScanIteration<>(Long.valueOf(result.getStringCursor()), result.getResult()); + } + + protected void doClose() { + JedisHashCommands.this.connection.close(); + }; + + }.open(); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java new file mode 100644 index 000000000..3909b4038 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java @@ -0,0 +1,126 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisHyperLogLogCommands implements RedisHyperLogLogCommands { + + private final JedisConnection connection; + + public JedisHyperLogLogCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfAdd(byte[], byte[][]) + */ + @Override + 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.newJedisResult(connection.getPipeline().pfadd(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pfadd(key, values))); + return null; + } + return connection.getJedis().pfadd(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfCount(byte[][]) + */ + @Override + public Long pfCount(byte[]... keys) { + + Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); + Assert.noNullElements(keys, "Keys for PFOUNT must not contain 'null'."); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().pfcount(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pfcount(keys))); + return null; + } + return connection.getJedis().pfcount(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfMerge(byte[], byte[][]) + */ + @Override + public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().pfmerge(destinationKey, sourceKeys))); + return; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pfmerge(destinationKey, sourceKeys))); + return; + } + connection.getJedis().pfmerge(destinationKey, sourceKeys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java new file mode 100644 index 000000000..c6bee6e01 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java @@ -0,0 +1,634 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.SortingParams; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisKeyCommands implements RedisKeyCommands { + + private final JedisConnection connection; + + public JedisKeyCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#exists(byte[]) + */ + @Override + public Boolean exists(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().exists(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().exists(key))); + return null; + } + return connection.getJedis().exists(key); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) + */ + @Override + public Long del(byte[]... keys) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().del(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().del(keys))); + return null; + } + return connection.getJedis().del(keys); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) + */ + @Override + public DataType type(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().type(key), JedisConverters.stringToDataType())); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().type(key), JedisConverters.stringToDataType())); + return null; + } + return JedisConverters.toDataType(connection.getJedis().type(key)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) + */ + @Override + public Set keys(byte[] pattern) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().keys(pattern))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().keys(pattern))); + return null; + } + return connection.getJedis().keys(pattern); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) + */ + public Cursor scan(ScanOptions options) { + return scan(0, options != null ? options : ScanOptions.NONE); + } + + /** + * @since 1.4 + * @param cursorId + * @param options + * @return + */ + public Cursor scan(long cursorId, ScanOptions options) { + + return new ScanCursor(cursorId, options) { + + @Override + protected ScanIteration doScan(long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); + } + + ScanParams params = JedisConverters.toScanParams(options); + redis.clients.jedis.ScanResult result = connection.getJedis().scan(Long.toString(cursorId), params); + return new ScanIteration(Long.valueOf(result.getStringCursor()), + JedisConverters.stringListToByteList().convert(result.getResult())); + } + + protected void doClose() { + JedisKeyCommands.this.connection.close(); + }; + + }.open(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() + */ + @Override + public byte[] randomKey() { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().randomKeyBinary())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().randomKeyBinary())); + return null; + } + return connection.getJedis().randomBinaryKey(); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) + */ + @Override + public void rename(byte[] oldName, byte[] newName) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().rename(oldName, newName))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().rename(oldName, newName))); + return; + } + connection.getJedis().rename(oldName, newName); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) + */ + @Override + public Boolean renameNX(byte[] oldName, byte[] newName) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().renamenx(oldName, newName), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().renamenx(oldName, newName), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().renamenx(oldName, newName)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expire(byte[], long) + */ + @Override + public Boolean expire(byte[] key, long seconds) { + + Assert.notNull(key, "Key must not be null!"); + + if (seconds > Integer.MAX_VALUE) { + return pExpire(key, TimeUnit.SECONDS.toMillis(seconds)); + } + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().expire(key, (int) seconds), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().expire(key, (int) seconds), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().expire(key, (int) seconds)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) + */ + @Override + public Boolean expireAt(byte[] key, long unixTime) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().expireAt(key, unixTime), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().expireAt(key, unixTime), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().expireAt(key, unixTime)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) + */ + @Override + public Boolean pExpire(byte[] key, long millis) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline( + connection.newJedisResult(connection.getPipeline().pexpire(key, millis), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pexpire(key, millis), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().pexpire(key, millis)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) + */ + @Override + public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().pexpireAt(key, unixTimeInMillis), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pexpireAt(key, unixTimeInMillis), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().pexpireAt(key, unixTimeInMillis)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) + */ + @Override + public Boolean persist(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().persist(key), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().persist(key), JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().persist(key)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) + */ + @Override + public Boolean move(byte[] key, int dbIndex) { + + try { + if (isPipelined()) { + pipeline( + connection.newJedisResult(connection.getPipeline().move(key, dbIndex), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().move(key, dbIndex), JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().move(key, dbIndex)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) + */ + @Override + public Long ttl(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().ttl(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().ttl(key))); + return null; + } + + return connection.getJedis().ttl(key); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + public Long ttl(byte[] key, TimeUnit timeUnit) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + return null; + } + + return Converters.secondsToTimeUnit(connection.getJedis().ttl(key), timeUnit); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) + */ + @Override + public Long pTtl(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().pttl(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pttl(key))); + return null; + } + + return connection.getJedis().pttl(key); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + public Long pTtl(byte[] key, TimeUnit timeUnit) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline( + connection.newJedisResult(connection.getPipeline().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().pttl(key), + Converters.millisecondsToTimeUnit(timeUnit))); + return null; + } + + return Converters.millisecondsToTimeUnit(connection.getJedis().pttl(key), timeUnit); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) + */ + @Override + public List sort(byte[] key, SortParameters params) { + + SortingParams sortParams = JedisConverters.toSortingParams(params); + + try { + if (isPipelined()) { + if (sortParams != null) { + pipeline(connection.newJedisResult(connection.getPipeline().sort(key, sortParams))); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().sort(key))); + } + + return null; + } + if (isQueueing()) { + if (sortParams != null) { + transaction(connection.newJedisResult(connection.getTransaction().sort(key, sortParams))); + } else { + transaction(connection.newJedisResult(connection.getTransaction().sort(key))); + } + + return null; + } + return (sortParams != null ? connection.getJedis().sort(key, sortParams) : connection.getJedis().sort(key)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) + */ + @Override + public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + + SortingParams sortParams = JedisConverters.toSortingParams(params); + + try { + if (isPipelined()) { + if (sortParams != null) { + pipeline(connection.newJedisResult(connection.getPipeline().sort(key, sortParams, storeKey))); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().sort(key, storeKey))); + } + + return null; + } + if (isQueueing()) { + if (sortParams != null) { + transaction(connection.newJedisResult(connection.getTransaction().sort(key, sortParams, storeKey))); + } else { + transaction(connection.newJedisResult(connection.getTransaction().sort(key, storeKey))); + } + + return null; + } + return (sortParams != null ? connection.getJedis().sort(key, sortParams, storeKey) + : connection.getJedis().sort(key, storeKey)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) + */ + @Override + public byte[] dump(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().dump(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().dump(key))); + return null; + } + return connection.getJedis().dump(key); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) + */ + @Override + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + + if (ttlInMillis > Integer.MAX_VALUE) { + throw new IllegalArgumentException("TtlInMillis must be less than Integer.MAX_VALUE for restore in Jedis."); + } + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().restore(key, (int) ttlInMillis, serializedValue))); + return; + } + if (isQueueing()) { + transaction( + connection.newStatusResult(connection.getTransaction().restore(key, (int) ttlInMillis, serializedValue))); + return; + } + connection.getJedis().restore(key, (int) ttlInMillis, serializedValue); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java new file mode 100644 index 000000000..b9165cf29 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java @@ -0,0 +1,443 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.Protocol; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.redis.connection.RedisListCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisListCommands implements RedisListCommands { + + private final JedisConnection connection; + + public JedisListCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPush(byte[], byte[][]) + */ + @Override + public Long rPush(byte[] key, byte[]... values) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().rpush(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().rpush(key, values))); + return null; + } + return connection.getJedis().rpush(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) + */ + @Override + public Long lPush(byte[] key, byte[]... values) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lpush(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lpush(key, values))); + return null; + } + return connection.getJedis().lpush(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) + */ + @Override + public Long rPushX(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().rpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().rpushx(key, value))); + return null; + } + return connection.getJedis().rpushx(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) + */ + @Override + public Long lPushX(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lpushx(key, value))); + return null; + } + return connection.getJedis().lpushx(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) + */ + @Override + public Long lLen(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().llen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().llen(key))); + return null; + } + return connection.getJedis().llen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) + */ + @Override + public List lRange(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lrange(key, start, end))); + return null; + } + return connection.getJedis().lrange(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) + */ + @Override + public void lTrim(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().ltrim(key, start, end))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().ltrim(key, start, end))); + return; + } + connection.getJedis().ltrim(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) + */ + @Override + public byte[] lIndex(byte[] key, long index) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lindex(key, index))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lindex(key, index))); + return null; + } + return connection.getJedis().lindex(key, index); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) + */ + @Override + public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult( + connection.getPipeline().linsert(key, JedisConverters.toListPosition(where), pivot, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult( + connection.getTransaction().linsert(key, JedisConverters.toListPosition(where), pivot, value))); + return null; + } + return connection.getJedis().linsert(key, JedisConverters.toListPosition(where), pivot, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) + */ + @Override + public void lSet(byte[] key, long index, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().lset(key, index, value))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().lset(key, index, value))); + return; + } + connection.getJedis().lset(key, index, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) + */ + @Override + public Long lRem(byte[] key, long count, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lrem(key, count, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lrem(key, count, value))); + return null; + } + return connection.getJedis().lrem(key, count, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) + */ + @Override + public byte[] lPop(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().lpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().lpop(key))); + return null; + } + return connection.getJedis().lpop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) + */ + @Override + public byte[] rPop(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().rpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().rpop(key))); + return null; + } + return connection.getJedis().rpop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) + */ + @Override + public List bLPop(int timeout, byte[]... keys) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().blpop(bXPopArgs(timeout, keys)))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().blpop(bXPopArgs(timeout, keys)))); + return null; + } + return connection.getJedis().blpop(timeout, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPop(int, byte[][]) + */ + @Override + public List bRPop(int timeout, byte[]... keys) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().brpop(bXPopArgs(timeout, keys)))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().brpop(bXPopArgs(timeout, keys)))); + return null; + } + return connection.getJedis().brpop(timeout, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPopLPush(byte[], byte[]) + */ + @Override + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().rpoplpush(srcKey, dstKey))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().rpoplpush(srcKey, dstKey))); + return null; + } + return connection.getJedis().rpoplpush(srcKey, dstKey); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPopLPush(int, byte[], byte[]) + */ + @Override + public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().brpoplpush(srcKey, dstKey, timeout))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().brpoplpush(srcKey, dstKey, timeout))); + return null; + } + return connection.getJedis().brpoplpush(srcKey, dstKey, timeout); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private byte[][] bXPopArgs(int timeout, byte[]... keys) { + + final List args = new ArrayList<>(); + for (final byte[] arg : keys) { + args.add(arg); + } + args.add(Protocol.toByteArray(timeout)); + return args.toArray(new byte[args.size()][]); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java new file mode 100644 index 000000000..07408341f --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java @@ -0,0 +1,419 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import java.util.List; +import java.util.Set; + +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import redis.clients.jedis.ScanParams; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisSetCommands implements RedisSetCommands { + + private final JedisConnection connection; + + public JedisSetCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sAdd(byte[], byte[][]) + */ + @Override + public Long sAdd(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sadd(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sadd(key, values))); + return null; + } + return connection.getJedis().sadd(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sCard(byte[]) + */ + @Override + public Long sCard(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().scard(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().scard(key))); + return null; + } + return connection.getJedis().scard(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiff(byte[][]) + */ + @Override + public Set sDiff(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sdiff(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sdiff(keys))); + return null; + } + return connection.getJedis().sdiff(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiffStore(byte[], byte[][]) + */ + @Override + public Long sDiffStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sdiffstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sdiffstore(destKey, keys))); + return null; + } + return connection.getJedis().sdiffstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInter(byte[][]) + */ + @Override + public Set sInter(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sinter(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sinter(keys))); + return null; + } + return connection.getJedis().sinter(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInterStore(byte[], byte[][]) + */ + @Override + public Long sInterStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sinterstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sinterstore(destKey, keys))); + return null; + } + return connection.getJedis().sinterstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sIsMember(byte[], byte[]) + */ + @Override + public Boolean sIsMember(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sismember(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sismember(key, value))); + return null; + } + return connection.getJedis().sismember(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMembers(byte[]) + */ + @Override + public Set sMembers(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().smembers(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().smembers(key))); + return null; + } + return connection.getJedis().smembers(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMove(byte[], byte[], byte[]) + */ + @Override + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().smove(srcKey, destKey, value), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().smove(srcKey, destKey, value), JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().smove(srcKey, destKey, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sPop(byte[]) + */ + @Override + public byte[] sPop(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().spop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().spop(key))); + return null; + } + return connection.getJedis().spop(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[]) + */ + @Override + public byte[] sRandMember(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().srandmember(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().srandmember(key))); + return null; + } + return connection.getJedis().srandmember(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[], long) + */ + @Override + public List sRandMember(byte[] key, long count) { + + if (count > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Count must be less than Integer.MAX_VALUE for sRandMember in Jedis."); + } + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().srandmember(key, (int) count))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().srandmember(key, (int) count))); + return null; + } + return connection.getJedis().srandmember(key, (int) count); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRem(byte[], byte[][]) + */ + @Override + public Long sRem(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().srem(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().srem(key, values))); + return null; + } + return connection.getJedis().srem(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnion(byte[][]) + */ + @Override + public Set sUnion(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sunion(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sunion(keys))); + return null; + } + return connection.getJedis().sunion(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnionStore(byte[], byte[][]) + */ + @Override + public Long sUnionStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().sunionstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().sunionstore(destKey, keys))); + return null; + } + return connection.getJedis().sunionstore(destKey, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor sScan(byte[] key, ScanOptions options) { + return sScan(key, 0, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { + + return new KeyBoundCursor(key, cursorId, options) { + + @Override + protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); + } + + ScanParams params = JedisConverters.toScanParams(options); + + redis.clients.jedis.ScanResult result = connection.getJedis().sscan(key, JedisConverters.toBytes(cursorId), params); + return new ScanIteration<>(Long.valueOf(result.getStringCursor()), result.getResult()); + } + + protected void doClose() { + JedisSetCommands.this.connection.close(); + }; + }.open(); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java new file mode 100644 index 000000000..6e95f4903 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java @@ -0,0 +1,580 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.data.redis.core.types.Expiration; +import org.springframework.util.ObjectUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisStringCommands implements RedisStringCommands { + + private final JedisConnection connection; + + public JedisStringCommands(JedisConnection connection) { + this.connection = connection; + } + + @Override + public byte[] get(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().get(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().get(key))); + return null; + } + + return connection.getJedis().get(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public byte[] getSet(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().getSet(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().getSet(key, value))); + return null; + } + return connection.getJedis().getSet(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public List mGet(byte[]... keys) { + + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().mget(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().mget(keys))); + return null; + } + return connection.getJedis().mget(keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public void set(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().set(key, value))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().set(key, value))); + return; + } + connection.getJedis().set(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + + if (expiration == null || expiration.isPersistent()) { + + if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + set(key, value); + } else { + + try { + + byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); + + if (isPipelined()) { + + pipeline(connection.newStatusResult(connection.getPipeline().set(key, value, nxxx))); + return; + } + if (isQueueing()) { + + transaction(connection.newStatusResult(connection.getTransaction().set(key, value, nxxx))); + return; + } + + connection.getJedis().set(key, value, nxxx); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + } else { + + if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + + if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) { + pSetEx(key, expiration.getExpirationTime(), value); + } else { + setEx(key, expiration.getExpirationTime(), value); + } + } else { + + byte[] nxxx = JedisConverters.toSetCommandNxXxArgument(option); + byte[] expx = JedisConverters.toSetCommandExPxArgument(expiration); + + try { + if (isPipelined()) { + + if (expiration.getExpirationTime() > Integer.MAX_VALUE) { + + throw new IllegalArgumentException( + "Expiration.expirationTime must be less than Integer.MAX_VALUE for pipeline in Jedis."); + } + + pipeline(connection.newStatusResult(connection.getPipeline().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); + return; + } + if (isQueueing()) { + + if (expiration.getExpirationTime() > Integer.MAX_VALUE) { + throw new IllegalArgumentException( + "Expiration.expirationTime must be less than Integer.MAX_VALUE for transactions in Jedis."); + } + + transaction( + connection.newStatusResult(connection.getTransaction().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); + return; + } + + connection.getJedis().set(key, value, nxxx, expx, expiration.getExpirationTime()); + + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + } + } + + + + @Override + public Boolean setNX(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().setnx(key, value), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().setnx(key, value), JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().setnx(key, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public void setEx(byte[] key, long seconds, byte[] value) { + if (seconds > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Time must be less than Integer.MAX_VALUE for setEx in Jedis."); + } + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().setex(key, (int) seconds, value))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().setex(key, (int) seconds, value))); + return; + } + connection.getJedis().setex(key, (int) seconds, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public void pSetEx(byte[] key, long milliseconds, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().psetex(key, milliseconds, value))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().psetex(key, milliseconds, value))); + return; + } + connection.getJedis().psetex(key, milliseconds, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public void mSet(Map tuples) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().mset(JedisConverters.toByteArrays(tuples)))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().mset(JedisConverters.toByteArrays(tuples)))); + return; + } + connection.getJedis().mset(JedisConverters.toByteArrays(tuples)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Boolean mSetNX(Map tuples) { + + try { + if (isPipelined()) { + pipeline( + connection.newJedisResult(connection.getPipeline().msetnx(JedisConverters.toByteArrays(tuples)), JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction( + connection.newJedisResult(connection.getTransaction().msetnx(JedisConverters.toByteArrays(tuples)), JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().msetnx(JedisConverters.toByteArrays(tuples))); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Long incr(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().incr(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().incr(key))); + return null; + } + return connection.getJedis().incr(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public Long incrBy(byte[] key, long value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().incrBy(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().incrBy(key, value))); + return null; + } + return connection.getJedis().incrBy(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public Double incrBy(byte[] key, double value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().incrByFloat(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().incrByFloat(key, value))); + return null; + } + return connection.getJedis().incrByFloat(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Long decr(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().decr(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().decr(key))); + return null; + } + return connection.getJedis().decr(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public Long decrBy(byte[] key, long value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().decrBy(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().decrBy(key, value))); + return null; + } + return connection.getJedis().decrBy(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Long append(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().append(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().append(key, value))); + return null; + } + return connection.getJedis().append(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public byte[] getRange(byte[] key, long start, long end) { + + if (start > Integer.MAX_VALUE || end > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Start and end must be less than Integer.MAX_VALUE for getRange in Jedis."); + } + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); + return null; + } + return connection.getJedis().substr(key, (int) start, (int) end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public void setRange(byte[] key, byte[] value, long start) { + + try { + if (isPipelined()) { + pipeline(connection.newStatusResult(connection.getPipeline().setrange(key, start, value))); + return; + } + if (isQueueing()) { + transaction(connection.newStatusResult(connection.getTransaction().setrange(key, start, value))); + return; + } + connection.getJedis().setrange(key, start, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Boolean getBit(byte[] key, long offset) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().getbit(key, offset))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().getbit(key, offset))); + return null; + } + // compatibility check for Jedis 2.0.0 + Object getBit = connection.getJedis().getbit(key, offset); + // Jedis 2.0 + if (getBit instanceof Long) { + return (((Long) getBit) == 0 ? Boolean.FALSE : Boolean.TRUE); + } + // Jedis 2.1 + return ((Boolean) getBit); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Boolean setBit(byte[] key, long offset, boolean value) { + + try { + if (isPipelined()) { + + pipeline(connection.newJedisResult(connection.getPipeline().setbit(key, offset, JedisConverters.toBit(value)))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().setbit(key, offset, JedisConverters.toBit(value)))); + return null; + } + return connection.getJedis().setbit(key, offset, JedisConverters.toBit(value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + @Override + public Long bitCount(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().bitcount(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().bitcount(key))); + return null; + } + return connection.getJedis().bitcount(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Long bitCount(byte[] key, long begin, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().bitcount(key, begin, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().bitcount(key, begin, end))); + return null; + } + return connection.getJedis().bitcount(key, begin, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + 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.newJedisResult(connection.getPipeline().bitop(JedisConverters.toBitOp(op), destination, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().bitop(JedisConverters.toBitOp(op), destination, keys))); + return null; + } + return connection.getJedis().bitop(JedisConverters.toBitOp(op), destination, keys); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + @Override + public Long strLen(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().strlen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().strlen(key))); + return null; + } + return connection.getJedis().strlen(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java new file mode 100644 index 000000000..6174a2cf2 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java @@ -0,0 +1,853 @@ +/* + * Copyright 2017 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 + * + * http://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.jedis; + +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.ScanResult; +import redis.clients.jedis.ZParams; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.data.redis.connection.RedisZSetCommands; +import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class JedisZSetCommands implements RedisZSetCommands { + + private final JedisConnection connection; + + public JedisZSetCommands(JedisConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[]) + */ + @Override + public Boolean zAdd(byte[] key, double score, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zadd(key, score, value), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zadd(key, score, value), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().zadd(key, score, value)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set) + */ + @Override + public Long zAdd(byte[] key, Set tuples) { + + if (isPipelined() || isQueueing()) { + throw new UnsupportedOperationException("zAdd of multiple fields not supported " + "in pipeline or transaction"); + } + + Map args = zAddArgs(tuples); + try { + return connection.getJedis().zadd(key, args); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) + */ + @Override + public Long zCard(byte[] key) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zcard(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zcard(key))); + return null; + } + return connection.getJedis().zcard(key); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], double, double) + */ + @Override + public Long zCount(byte[] key, double min, double max) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zcount(key, min, max))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zcount(key, min, max))); + return null; + } + return connection.getJedis().zcount(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zCount(byte[] key, Range range) { + + if (isPipelined() || isQueueing()) { + throw new UnsupportedOperationException( + "ZCOUNT not implemented in jedis for binary protocol on transaction and pipeline"); + } + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + return connection.getJedis().zcount(key, min, max); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zIncrBy(byte[], double, byte[]) + */ + @Override + public Double zIncrBy(byte[] key, double increment, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zincrby(key, increment, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zincrby(key, increment, value))); + return null; + } + return connection.getJedis().zincrby(key, increment, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + try { + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); + + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zinterstore(destKey, zparams, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zinterstore(destKey, zparams, sets))); + return null; + } + return connection.getJedis().zinterstore(destKey, zparams, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, byte[]... sets) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zinterstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zinterstore(destKey, sets))); + return null; + } + return connection.getJedis().zinterstore(destKey, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRange(byte[], long, long) + */ + @Override + public Set zRange(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrange(key, start, end))); + return null; + } + return connection.getJedis().zrange(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeWithScores(byte[], long, long) + */ + @Override + public Set zRangeWithScores(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrangeWithScores(key, start, end), + JedisConverters.tupleSetToTupleSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrangeWithScores(key, start, end), + JedisConverters.tupleSetToTupleSet())); + return null; + } + return JedisConverters.toTupleSet(connection.getJedis().zrangeWithScores(key, start, end)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getPipeline().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().zrangeByLex(key, min, max))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getTransaction().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(connection.newJedisResult(connection.getTransaction().zrangeByLex(key, min, max))); + } + return null; + } + + if (limit != null) { + return connection.getJedis().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getJedis().zrangeByLex(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getPipeline().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScore(key, min, max))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getTransaction().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(connection.newJedisResult(connection.getTransaction().zrangeByScore(key, min, max))); + } + return null; + } + + if (limit != null) { + return connection.getJedis().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getJedis().zrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getPipeline().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), + JedisConverters.tupleSetToTupleSet())); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScoreWithScores(key, min, max), + JedisConverters.tupleSetToTupleSet())); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getTransaction().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), + JedisConverters.tupleSetToTupleSet())); + } else { + transaction(connection.newJedisResult(connection.getTransaction().zrangeByScoreWithScores(key, min, max), + JedisConverters.tupleSetToTupleSet())); + } + return null; + } + + if (limit != null) { + return JedisConverters.toTupleSet( + connection.getJedis().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); + } + return JedisConverters.toTupleSet(connection.getJedis().zrangeByScoreWithScores(key, min, max)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) + */ + @Override + public Set zRevRangeWithScores(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeWithScores(key, start, end), + JedisConverters.tupleSetToTupleSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrevrangeWithScores(key, start, end), + JedisConverters.tupleSetToTupleSet())); + return null; + } + return JedisConverters.toTupleSet(connection.getJedis().zrevrangeWithScores(key, start, end)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getPipeline().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeByScore(key, max, min))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getTransaction().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + } else { + transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScore(key, max, min))); + } + return null; + } + + if (limit != null) { + return connection.getJedis().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); + } + return connection.getJedis().zrevrangeByScore(key, max, min); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getPipeline().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount()), + JedisConverters.tupleSetToTupleSet())); + } else { + pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeByScoreWithScores(key, max, min), + JedisConverters.tupleSetToTupleSet())); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScoreWithScores(key, max, min, + limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); + } else { + transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScoreWithScores(key, max, min), + JedisConverters.tupleSetToTupleSet())); + } + return null; + } + + if (limit != null) { + return JedisConverters.toTupleSet( + connection.getJedis().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); + } + return JedisConverters.toTupleSet(connection.getJedis().zrevrangeByScoreWithScores(key, max, min)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) + */ + @Override + public Long zRank(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrank(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrank(key, value))); + return null; + } + return connection.getJedis().zrank(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) + */ + @Override + public Long zRem(byte[] key, byte[]... values) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrem(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrem(key, values))); + return null; + } + return connection.getJedis().zrem(key, values); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) + */ + @Override + public Long zRemRange(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zremrangeByRank(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zremrangeByRank(key, start, end))); + return null; + } + return connection.getJedis().zremrangeByRank(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zremrangeByScore(key, min, max))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zremrangeByScore(key, min, max))); + return null; + } + return connection.getJedis().zremrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + */ + @Override + public Set zRevRange(byte[] key, long start, long end) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrevrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrevrange(key, start, end))); + return null; + } + return connection.getJedis().zrevrange(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) + */ + @Override + public Long zRevRank(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrevrank(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrevrank(key, value))); + return null; + } + return connection.getJedis().zrevrank(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) + */ + @Override + public Double zScore(byte[] key, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zscore(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zscore(key, value))); + return null; + } + return connection.getJedis().zscore(key, value); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + try { + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); + + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zunionstore(destKey, zparams, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zunionstore(destKey, zparams, sets))); + return null; + } + return connection.getJedis().zunionstore(destKey, zparams, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, byte[]... sets) { + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zunionstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zunionstore(destKey, sets))); + return null; + } + return connection.getJedis().zunionstore(destKey, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor zScan(byte[] key, ScanOptions options) { + return zScan(key, 0L, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor zScan(byte[] key, Long cursorId, ScanOptions options) { + + return new KeyBoundCursor(key, cursorId, options) { + + @Override + protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); + } + + ScanParams params = JedisConverters.toScanParams(options); + + ScanResult result = connection.getJedis().zscan(key, + JedisConverters.toBytes(cursorId), params); + return new ScanIteration<>(Long.valueOf(result.getStringCursor()), + JedisConverters.tuplesToTuples().convert(result.getResult())); + } + + protected void doClose() { + JedisZSetCommands.this.connection.close(); + }; + + }.open(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max) { + + try { + String keyStr = new String(key, "UTF-8"); + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScore(keyStr, min, max))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getTransaction().zrangeByScore(keyStr, min, max))); + return null; + } + return JedisConverters.stringSetToByteSet().convert(connection.getJedis().zrangeByScore(keyStr, min, max)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String, long, long) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { + + throw new IllegalArgumentException( + "Offset and count must be less than Integer.MAX_VALUE for zRangeByScore in Jedis."); + } + + try { + String keyStr = new String(key, "UTF-8"); + if (isPipelined()) { + pipeline(connection + .newJedisResult(connection.getPipeline().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); + return null; + } + if (isQueueing()) { + transaction(connection + .newJedisResult(connection.getTransaction().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); + return null; + } + return JedisConverters.stringSetToByteSet() + .convert(connection.getJedis().zrangeByScore(keyStr, min, max, (int) offset, (int) count)); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + private Map zAddArgs(Set tuples) { + + Map args = new LinkedHashMap<>(tuples.size(), 1); + Set scores = new HashSet(tuples.size(), 1); + + boolean isAtLeastJedis24 = JedisVersionUtil.atLeastJedis24(); + + for (Tuple tuple : tuples) { + + if (!isAtLeastJedis24) { + if (scores.contains(tuple.getScore())) { + throw new UnsupportedOperationException( + "Bulk add of multiple elements with the same score is not supported. Add the elements individually."); + } + scores.add(tuple.getScore()); + } + + args.put(tuple.getValue(), tuple.getScore()); + } + + return args; + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private void pipeline(JedisResult result) { + connection.pipeline(result); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void transaction(JedisResult result) { + connection.transaction(result); + } + + private RuntimeException convertJedisAccessException(Exception ex) { + return connection.convertJedisAccessException(ex); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index 5a30414bc..5a62a28f9 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection.lettuce; -import io.lettuce.core.KeyValue; import io.lettuce.core.RedisException; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.cluster.RedisClusterClient; @@ -27,17 +26,13 @@ import io.lettuce.core.codec.ByteArrayCodec; import io.lettuce.core.codec.RedisCodec; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.Random; import java.util.Set; import org.springframework.beans.DirectFieldAccessor; @@ -51,18 +46,20 @@ import org.springframework.data.redis.connection.ClusterCommandExecutor.MultiKey import org.springframework.data.redis.connection.ClusterCommandExecutor.NodeResult; import org.springframework.data.redis.connection.ClusterInfo; import org.springframework.data.redis.connection.ClusterNodeResourceProvider; -import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.ClusterTopology; import org.springframework.data.redis.connection.ClusterTopologyProvider; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; -import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.RedisHashCommands; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.RedisListCommands; +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.util.ByteArraySet; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.RedisClientInfo; -import org.springframework.data.redis.util.ByteUtils; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -119,39 +116,48 @@ public class LettuceClusterConnection extends LettuceConnection clusterCommandExecutor = executor; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#scan(long, org.springframework.data.redis.core.ScanOptions) - */ @Override - public Cursor scan(long cursorId, ScanOptions options) { - throw new InvalidDataAccessApiUsageException("Scan is not supported accros multiple nodes within a cluster."); + public RedisGeoCommands geoCommands() { + return new LettuceClusterGeoCommands(this); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#keys(byte[]) - */ @Override - public Set keys(final byte[] pattern) { + public RedisHashCommands hashCommands() { + return new LettuceClusterHashCommands(this); + } - Assert.notNull(pattern, "Pattern must not be null!"); + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return new LettuceClusterHyperLogLogCommands(this); + } - Collection> keysPerNode = clusterCommandExecutor - .executeCommandOnAllNodes(new LettuceClusterCommandCallback>() { + @Override + public RedisKeyCommands keyCommands() { + return doGetClusterKeyCommands(); + } - @Override - public List doInCluster(RedisClusterCommands connection) { - return connection.keys(pattern); - } - }).resultsAsList(); + private LettuceClusterKeyCommands doGetClusterKeyCommands() { + return new LettuceClusterKeyCommands(this); + } - Set keys = new HashSet(); + @Override + public RedisListCommands listCommands() { + return new LettuceClusterListCommands(this); + } - for (List keySet : keysPerNode) { - keys.addAll(keySet); - } - return keys; + @Override + public RedisStringCommands stringCommands() { + return new LettuceClusterStringCommands(this); + } + + @Override + public RedisSetCommands setCommands() { + return new LettuceClusterSetCommands(this); + } + + @Override + public RedisZSetCommands zSetCommands() { + return new LettuceClusterZSetCommands(this); } /* @@ -280,28 +286,6 @@ public class LettuceClusterConnection extends LettuceConnection }, node).getValue()); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#move(byte[], int) - */ - @Override - public Boolean move(byte[] key, int dbIndex) { - throw new UnsupportedOperationException("MOVE not supported in CLUSTER mode!"); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#del(byte[][]) - */ - @Override - public Long del(byte[]... keys) { - - Assert.noNullElements(keys, "Keys must not be null or contain null key!"); - - // Routing for mget is handled by lettuce. - return super.del(keys); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisClusterCommands#getClusterSlaves(org.springframework.data.redis.connection.RedisClusterNode) @@ -722,102 +706,11 @@ public class LettuceClusterConnection extends LettuceConnection */ @Override public Set keys(RedisClusterNode node, final byte[] pattern) { - - return LettuceConverters.toBytesSet( - clusterCommandExecutor.executeCommandOnSingleNode(new LettuceClusterCommandCallback>() { - - @Override - public List doInCluster(RedisClusterCommands client) { - return client.keys(pattern); - } - }, node).getValue()); + return doGetClusterKeyCommands().keys(node, pattern); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisClusterConnection#randomKey(org.springframework.data.redis.connection.RedisClusterNode) - */ - @Override public byte[] randomKey(RedisClusterNode node) { - - return clusterCommandExecutor.executeCommandOnSingleNode(new LettuceClusterCommandCallback() { - - @Override - public byte[] doInCluster(RedisClusterCommands client) { - return client.randomkey(); - } - }, node).getValue(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#randomKey() - */ - @Override - public byte[] randomKey() { - - List nodes = clusterGetNodes(); - Set inspectedNodes = new HashSet(nodes.size()); - - do { - - RedisClusterNode node = nodes.get(new Random().nextInt(nodes.size())); - - while (inspectedNodes.contains(node)) { - node = nodes.get(new Random().nextInt(nodes.size())); - } - inspectedNodes.add(node); - byte[] key = randomKey(node); - - if (key != null && key.length > 0) { - return key; - } - } while (nodes.size() != inspectedNodes.size()); - - return null; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#rename(byte[], byte[]) - */ - @Override - public void rename(byte[] oldName, byte[] newName) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { - super.rename(oldName, newName); - return; - } - - byte[] value = dump(oldName); - - if (value != null && value.length > 0) { - - restore(newName, 0, value); - del(oldName); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#renameNX(byte[], byte[]) - */ - @Override - public Boolean renameNX(byte[] oldName, byte[] newName) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { - return super.renameNX(oldName, newName); - } - - byte[] value = dump(oldName); - - if (value != null && value.length > 0 && !exists(newName)) { - - restore(newName, 0, value); - del(oldName); - return Boolean.TRUE; - } - return Boolean.FALSE; + return doGetClusterKeyCommands().randomKey(node); } /* @@ -837,176 +730,6 @@ public class LettuceClusterConnection extends LettuceConnection }, node); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) - */ - @Override - public Long sort(byte[] key, SortParameters params, byte[] storeKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(key, storeKey)) { - return super.sort(key, params, storeKey); - } - - List sorted = sort(key, params); - if (!CollectionUtils.isEmpty(sorted)) { - - byte[][] arr = new byte[sorted.size()][]; - switch (type(key)) { - - case SET: - sAdd(storeKey, sorted.toArray(arr)); - return 1L; - case LIST: - lPush(storeKey, sorted.toArray(arr)); - return 1L; - default: - throw new IllegalArgumentException("sort and store is only supported for SET and LIST"); - } - } - return 0L; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#mGet(byte[][]) - */ - @Override - public List mGet(byte[]... keys) { - - Assert.notNull(keys, "Keys must not be null!"); - - // Routing for mget is handled by lettuce. - return super.mGet(keys); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#mSet(java.util.Map) - */ - @Override - public void mSet(Map tuples) { - - Assert.notNull(tuples, "Tuples must not be null!"); - - // Routing for mset is handled by lettuce. - super.mSet(tuples); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#mSetNX(java.util.Map) - */ - @Override - public Boolean mSetNX(Map tuples) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { - return super.mSetNX(tuples); - } - - boolean result = true; - for (Map.Entry entry : tuples.entrySet()) { - if (!setNX(entry.getKey(), entry.getValue()) && result) { - result = false; - } - } - return result; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bLPop(int, byte[][]) - */ - @Override - public List bLPop(final int timeout, byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return super.bLPop(timeout, keys); - } - - List> resultList = this.clusterCommandExecutor - .executeMuliKeyCommand(new LettuceMultiKeyClusterCommandCallback>() { - - @Override - public KeyValue doInCluster(RedisClusterCommands client, byte[] key) { - return client.blpop(timeout, key); - } - }, Arrays.asList(keys)).resultsAsList(); - - for (KeyValue kv : resultList) { - if (kv != null) { - return LettuceConverters.toBytesList(kv); - } - } - - return Collections.emptyList(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bRPop(int, byte[][]) - */ - @Override - public List bRPop(final int timeout, byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return super.bRPop(timeout, keys); - } - - List> resultList = this.clusterCommandExecutor - .executeMuliKeyCommand(new LettuceMultiKeyClusterCommandCallback>() { - - @Override - public KeyValue doInCluster(RedisClusterCommands client, byte[] key) { - return client.brpop(timeout, key); - } - }, Arrays.asList(keys)).resultsAsList(); - - for (KeyValue kv : resultList) { - if (kv != null) { - return LettuceConverters.toBytesList(kv); - } - } - - return Collections.emptyList(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#rPopLPush(byte[], byte[]) - */ - @Override - public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { - return super.rPopLPush(srcKey, dstKey); - } - - byte[] val = rPop(srcKey); - lPush(dstKey, val); - return val; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bRPopLPush(int, byte[], byte[]) - */ - @Override - public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { - return super.bRPopLPush(timeout, srcKey, dstKey); - } - - List val = bRPop(timeout, srcKey); - if (!CollectionUtils.isEmpty(val)) { - lPush(dstKey, val.get(1)); - return val.get(1); - } - - return null; - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int) @@ -1019,194 +742,6 @@ public class LettuceClusterConnection extends LettuceConnection } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sMove(byte[], byte[], byte[]) - */ - @Override - public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { - return super.sMove(srcKey, destKey, value); - } - - if (exists(srcKey)) { - if (sRem(srcKey, value) > 0 && !sIsMember(destKey, value)) { - return LettuceConverters.toBoolean(sAdd(destKey, value)); - } - } - return Boolean.FALSE; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sInter(byte[][]) - */ - @Override - public Set sInter(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return super.sInter(keys); - } - - Collection> nodeResult = this.clusterCommandExecutor - .executeMuliKeyCommand(new LettuceMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(RedisClusterCommands client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(keys)).resultsAsList(); - - ByteArraySet result = null; - for (Set entry : nodeResult) { - - ByteArraySet tmp = new ByteArraySet(entry); - if (result == null) { - result = tmp; - } else { - result.retainAll(tmp); - if (result.isEmpty()) { - break; - } - } - } - - if (result.isEmpty()) { - return Collections.emptySet(); - } - - return result.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sInterStore(byte[], byte[][]) - */ - @Override - public Long sInterStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - return super.sInterStore(destKey, keys); - } - - Set result = sInter(keys); - if (result.isEmpty()) { - return 0L; - } - return sAdd(destKey, result.toArray(new byte[result.size()][])); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sUnion(byte[][]) - */ - @Override - public Set sUnion(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return super.sUnion(keys); - } - - Collection> nodeResult = this.clusterCommandExecutor - .executeMuliKeyCommand(new LettuceMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(RedisClusterCommands client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(keys)).resultsAsList(); - - ByteArraySet result = new ByteArraySet(); - for (Set entry : nodeResult) { - result.addAll(entry); - } - - if (result.isEmpty()) { - return Collections.emptySet(); - } - - return result.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sUnionStore(byte[], byte[][]) - */ - @Override - public Long sUnionStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - return super.sUnionStore(destKey, keys); - } - - Set result = sUnion(keys); - if (result.isEmpty()) { - return 0L; - } - return sAdd(destKey, result.toArray(new byte[result.size()][])); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sDiff(byte[][]) - */ - @Override - public Set sDiff(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - return super.sDiff(keys); - } - - byte[] source = keys[0]; - byte[][] others = Arrays.copyOfRange(keys, 1, keys.length - 1); - - ByteArraySet values = new ByteArraySet(sMembers(source)); - Collection> nodeResult = clusterCommandExecutor - .executeMuliKeyCommand(new LettuceMultiKeyClusterCommandCallback>() { - - @Override - public Set doInCluster(RedisClusterCommands client, byte[] key) { - return client.smembers(key); - } - }, Arrays.asList(others)).resultsAsList(); - - if (values.isEmpty()) { - return Collections.emptySet(); - } - - for (Set toSubstract : nodeResult) { - values.removeAll(toSubstract); - } - - return values.asRawSet(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sDiffStore(byte[], byte[][]) - */ - @Override - public Long sDiffStore(byte[] destKey, byte[]... keys) { - - byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { - return super.sDiffStore(destKey, keys); - } - - Set diff = sDiff(keys); - if (diff.isEmpty()) { - return 0L; - } - - return sAdd(destKey, diff.toArray(new byte[diff.size()][])); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#getAsyncDedicatedConnection() @@ -1227,46 +762,6 @@ public class LettuceClusterConnection extends LettuceConnection return LettuceConverters.partitionsToClusterNodes(clusterClient.getPartitions()); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#pfCount(byte[][]) - */ - @Override - public Long pfCount(byte[]... keys) { - - if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { - - try { - return super.pfCount(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - - } - throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfcount in cluster mode."); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#pfMerge(byte[], byte[][]) - */ - @Override - 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); - } - - } - throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfmerge in cluster mode."); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#watch(byte[][]) @@ -1513,6 +1008,10 @@ public class LettuceClusterConnection extends LettuceConnection return result; } + public ClusterCommandExecutor getClusterCommandExecutor() { + return clusterCommandExecutor; + } + /** * Lettuce specific implementation of {@link ClusterCommandCallback}. * diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterGeoCommands.java new file mode 100644 index 000000000..a19de75d2 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterGeoCommands.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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 + * + * http://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; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterGeoCommands extends LettuceGeoCommands { + + public LettuceClusterGeoCommands(LettuceClusterConnection connection) { + super(connection); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHashCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHashCommands.java new file mode 100644 index 000000000..72b5d74be --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHashCommands.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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 + * + * http://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; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterHashCommands extends LettuceHashCommands { + + public LettuceClusterHashCommands(LettuceClusterConnection connection) { + super(connection); + } +} 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 new file mode 100644 index 000000000..6c14ddb40 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterHyperLogLogCommands.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 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 + * + * http://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 org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.util.ByteUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterHyperLogLogCommands extends LettuceHyperLogLogCommands { + + public LettuceClusterHyperLogLogCommands(LettuceClusterConnection connection) { + super(connection); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#pfCount(byte[][]) + */ + @Override + public Long pfCount(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + + try { + return super.pfCount(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + + } + throw new InvalidDataAccessApiUsageException("All keys must map to same slot for pfcount in cluster mode."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#pfMerge(byte[], byte[][]) + */ + @Override + 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); + } + + } + 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/LettuceClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java new file mode 100644 index 000000000..ef18f90a3 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java @@ -0,0 +1,235 @@ +/* + * Copyright 2017 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 + * + * http://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.cluster.api.sync.RedisClusterCommands; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.RedisClusterNode; +import org.springframework.data.redis.connection.SortParameters; +import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceClusterCommandCallback; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterKeyCommands extends LettuceKeyCommands { + + private final LettuceClusterConnection connection; + + public LettuceClusterKeyCommands(LettuceClusterConnection connection) { + + super(connection); + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#scan(long, org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor scan(long cursorId, ScanOptions options) { + throw new InvalidDataAccessApiUsageException("Scan is not supported accros multiple nodes within a cluster."); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#randomKey() + */ + @Override + public byte[] randomKey() { + + List nodes = connection.clusterGetNodes(); + Set inspectedNodes = new HashSet<>(nodes.size()); + + do { + + RedisClusterNode node = nodes.get(new Random().nextInt(nodes.size())); + + while (inspectedNodes.contains(node)) { + node = nodes.get(new Random().nextInt(nodes.size())); + } + inspectedNodes.add(node); + byte[] key = randomKey(node); + + if (key != null && key.length > 0) { + return key; + } + } while (nodes.size() != inspectedNodes.size()); + + return null; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#keys(byte[]) + */ + @Override + public Set keys(final byte[] pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); + + Collection> keysPerNode = connection.getClusterCommandExecutor() + .executeCommandOnAllNodes((LettuceClusterCommandCallback>) connection -> connection.keys(pattern)) + .resultsAsList(); + + Set keys = new HashSet<>(); + + for (List keySet : keysPerNode) { + keys.addAll(keySet); + } + return keys; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#rename(byte[], byte[]) + */ + @Override + public void rename(byte[] oldName, byte[] newName) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { + super.rename(oldName, newName); + return; + } + + byte[] value = dump(oldName); + + if (value != null && value.length > 0) { + + restore(newName, 0, value); + del(oldName); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#renameNX(byte[], byte[]) + */ + @Override + public Boolean renameNX(byte[] oldName, byte[] newName) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { + return super.renameNX(oldName, newName); + } + + byte[] value = dump(oldName); + + if (value != null && value.length > 0 && !exists(newName)) { + + restore(newName, 0, value); + del(oldName); + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#move(byte[], int) + */ + @Override + public Boolean move(byte[] key, int dbIndex) { + throw new UnsupportedOperationException("MOVE not supported in CLUSTER mode!"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#del(byte[][]) + */ + @Override + public Long del(byte[]... keys) { + + Assert.noNullElements(keys, "Keys must not be null or contain null key!"); + + // Routing for mget is handled by lettuce. + return super.del(keys); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisClusterConnection#randomKey(org.springframework.data.redis.connection.RedisClusterNode) + */ + public byte[] randomKey(RedisClusterNode node) { + + return connection.getClusterCommandExecutor() + .executeCommandOnSingleNode(new LettuceClusterCommandCallback() { + + @Override + public byte[] doInCluster(RedisClusterCommands client) { + return client.randomkey(); + } + }, node).getValue(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) + */ + public Set keys(RedisClusterNode node, final byte[] pattern) { + + return LettuceConverters.toBytesSet(connection.getClusterCommandExecutor() + .executeCommandOnSingleNode(new LettuceClusterCommandCallback>() { + + @Override + public List doInCluster(RedisClusterCommands client) { + return client.keys(pattern); + } + }, node).getValue()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) + */ + @Override + public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(key, storeKey)) { + return super.sort(key, params, storeKey); + } + + List sorted = sort(key, params); + if (!CollectionUtils.isEmpty(sorted)) { + + byte[][] arr = new byte[sorted.size()][]; + switch (type(key)) { + + case SET: + connection.setCommands().sAdd(storeKey, sorted.toArray(arr)); + return 1L; + case LIST: + connection.listCommands().lPush(storeKey, sorted.toArray(arr)); + return 1L; + default: + throw new IllegalArgumentException("sort and store is only supported for SET and LIST"); + } + } + return 0L; + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java new file mode 100644 index 000000000..0bdcd2e09 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java @@ -0,0 +1,125 @@ +/* + * Copyright 2017 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 + * + * http://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.KeyValue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceMultiKeyClusterCommandCallback; +import org.springframework.util.CollectionUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterListCommands extends LettuceListCommands { + + private final LettuceClusterConnection connection; + + public LettuceClusterListCommands(LettuceClusterConnection connection) { + + super(connection); + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bLPop(int, byte[][]) + */ + @Override + public List bLPop(final int timeout, byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return super.bLPop(timeout, keys); + } + + List> resultList = connection.getClusterCommandExecutor().executeMuliKeyCommand( + (LettuceMultiKeyClusterCommandCallback>) (client, key) -> client.blpop(timeout, key), + Arrays.asList(keys)).resultsAsList(); + + for (KeyValue kv : resultList) { + if (kv != null) { + return LettuceConverters.toBytesList(kv); + } + } + + return Collections.emptyList(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bRPop(int, byte[][]) + */ + @Override + public List bRPop(final int timeout, byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return super.bRPop(timeout, keys); + } + + List> resultList = connection.getClusterCommandExecutor().executeMuliKeyCommand( + (LettuceMultiKeyClusterCommandCallback>) (client, key) -> client.brpop(timeout, key), + Arrays.asList(keys)).resultsAsList(); + + for (KeyValue kv : resultList) { + if (kv != null) { + return LettuceConverters.toBytesList(kv); + } + } + + return Collections.emptyList(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#rPopLPush(byte[], byte[]) + */ + @Override + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { + return super.rPopLPush(srcKey, dstKey); + } + + byte[] val = rPop(srcKey); + lPush(dstKey, val); + return val; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bRPopLPush(int, byte[], byte[]) + */ + @Override + public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { + return super.bRPopLPush(timeout, srcKey, dstKey); + } + + List val = bRPop(timeout, srcKey); + if (!CollectionUtils.isEmpty(val)) { + lPush(dstKey, val.get(1)); + return val.get(1); + } + + return null; + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java new file mode 100644 index 000000000..272c997be --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java @@ -0,0 +1,220 @@ +/* + * Copyright 2017 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 + * + * http://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 java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceMultiKeyClusterCommandCallback; +import org.springframework.data.redis.connection.util.ByteArraySet; +import org.springframework.data.redis.util.ByteUtils; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterSetCommands extends LettuceSetCommands { + + private final LettuceClusterConnection connection; + + public LettuceClusterSetCommands(LettuceClusterConnection connection) { + + super(connection); + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sMove(byte[], byte[], byte[]) + */ + @Override + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { + return super.sMove(srcKey, destKey, value); + } + + if (connection.keyCommands().exists(srcKey)) { + if (sRem(srcKey, value) > 0 && !sIsMember(destKey, value)) { + return LettuceConverters.toBoolean(sAdd(destKey, value)); + } + } + return Boolean.FALSE; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sInter(byte[][]) + */ + @Override + public Set sInter(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return super.sInter(keys); + } + + Collection> nodeResult = connection.getClusterCommandExecutor() + .executeMuliKeyCommand( + (LettuceMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(keys)) + .resultsAsList(); + + ByteArraySet result = null; + for (Set entry : nodeResult) { + + ByteArraySet tmp = new ByteArraySet(entry); + if (result == null) { + result = tmp; + } else { + result.retainAll(tmp); + if (result.isEmpty()) { + break; + } + } + } + + if (result.isEmpty()) { + return Collections.emptySet(); + } + + return result.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sInterStore(byte[], byte[][]) + */ + @Override + public Long sInterStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + return super.sInterStore(destKey, keys); + } + + Set result = sInter(keys); + if (result.isEmpty()) { + return 0L; + } + return sAdd(destKey, result.toArray(new byte[result.size()][])); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sUnion(byte[][]) + */ + @Override + public Set sUnion(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return super.sUnion(keys); + } + + Collection> nodeResult = connection.getClusterCommandExecutor() + .executeMuliKeyCommand( + (LettuceMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(keys)) + .resultsAsList(); + + ByteArraySet result = new ByteArraySet(); + for (Set entry : nodeResult) { + result.addAll(entry); + } + + if (result.isEmpty()) { + return Collections.emptySet(); + } + + return result.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sUnionStore(byte[], byte[][]) + */ + @Override + public Long sUnionStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + return super.sUnionStore(destKey, keys); + } + + Set result = sUnion(keys); + if (result.isEmpty()) { + return 0L; + } + return sAdd(destKey, result.toArray(new byte[result.size()][])); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sDiff(byte[][]) + */ + @Override + public Set sDiff(byte[]... keys) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { + return super.sDiff(keys); + } + + byte[] source = keys[0]; + byte[][] others = Arrays.copyOfRange(keys, 1, keys.length - 1); + + ByteArraySet values = new ByteArraySet(sMembers(source)); + Collection> nodeResult = connection.getClusterCommandExecutor() + .executeMuliKeyCommand( + (LettuceMultiKeyClusterCommandCallback>) (client, key) -> client.smembers(key), + Arrays.asList(others)) + .resultsAsList(); + + if (values.isEmpty()) { + return Collections.emptySet(); + } + + for (Set toSubstract : nodeResult) { + values.removeAll(toSubstract); + } + + return values.asRawSet(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#sDiffStore(byte[], byte[][]) + */ + @Override + public Long sDiffStore(byte[] destKey, byte[]... keys) { + + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { + return super.sDiffStore(destKey, keys); + } + + Set diff = sDiff(keys); + if (diff.isEmpty()) { + return 0L; + } + + return sAdd(destKey, diff.toArray(new byte[diff.size()][])); + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java new file mode 100644 index 000000000..f89b75094 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 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 + * + * http://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 java.util.Map; + +import org.springframework.data.redis.connection.ClusterSlotHashUtil; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterStringCommands extends LettuceStringCommands { + + private final LettuceClusterConnection connection; + + public LettuceClusterStringCommands(LettuceClusterConnection connection) { + + super(connection); + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#mSetNX(java.util.Map) + */ + @Override + public Boolean mSetNX(Map tuples) { + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { + return super.mSetNX(tuples); + } + + boolean result = true; + for (Map.Entry entry : tuples.entrySet()) { + if (!setNX(entry.getKey(), entry.getValue()) && result) { + result = false; + } + } + return result; + } +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterZSetCommands.java new file mode 100644 index 000000000..fc56c9878 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterZSetCommands.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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 + * + * http://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; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceClusterZSetCommands extends LettuceZSetCommands { + + public LettuceClusterZSetCommands(LettuceClusterConnection connection) { + super(connection); + } +} 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 33738b654..715b982e4 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 @@ -18,29 +18,17 @@ package org.springframework.data.redis.connection.lettuce; import static io.lettuce.core.protocol.CommandType.*; import io.lettuce.core.AbstractRedisClient; -import io.lettuce.core.GeoArgs; -import io.lettuce.core.GeoCoordinates; -import io.lettuce.core.GeoWithin; -import io.lettuce.core.KeyScanCursor; import io.lettuce.core.LettuceFutures; -import io.lettuce.core.MapScanCursor; import io.lettuce.core.RedisClient; import io.lettuce.core.RedisException; import io.lettuce.core.RedisFuture; import io.lettuce.core.RedisURI; import io.lettuce.core.ScanArgs; -import io.lettuce.core.ScoredValue; -import io.lettuce.core.ScoredValueScanCursor; -import io.lettuce.core.SortArgs; import io.lettuce.core.TransactionResult; -import io.lettuce.core.ValueScanCursor; -import io.lettuce.core.ZStoreArgs; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.api.async.RedisAsyncCommands; -import io.lettuce.core.api.async.RedisHLLAsyncCommands; import io.lettuce.core.api.sync.RedisCommands; -import io.lettuce.core.api.sync.RedisHLLCommands; import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; @@ -69,55 +57,45 @@ import io.lettuce.core.sentinel.api.StatefulRedisSentinelConnection; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Properties; import java.util.Queue; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.QueryTimeoutException; -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.ExceptionTranslationStrategy; import org.springframework.data.redis.FallbackExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; import org.springframework.data.redis.connection.AbstractRedisConnection; -import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.FutureResult; import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.RedisHashCommands; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.RedisKeyCommands; +import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisPipelineException; import org.springframework.data.redis.connection.RedisSentinelConnection; +import org.springframework.data.redis.connection.RedisSetCommands; +import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.RedisSubscribedConnectionException; +import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.connection.ReturnType; -import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.Subscription; -import org.springframework.data.redis.connection.convert.Converters; -import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.convert.TransactionResultConverter; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.RedisCommand; -import org.springframework.data.redis.core.ScanCursor; -import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; -import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -165,7 +143,7 @@ public class LettuceConnection extends AbstractRedisConnection { private boolean convertPipelineAndTxResults = true; @SuppressWarnings("rawtypes") - private class LettuceResult extends FutureResult> { + class LettuceResult extends FutureResult> { public LettuceResult(Future resultHolder, Converter converter) { super((io.lettuce.core.protocol.RedisCommand) resultHolder, converter); } @@ -188,6 +166,14 @@ public class LettuceConnection extends AbstractRedisConnection { } } + LettuceResult newLettuceResult(Future resultHolder) { + return new LettuceResult(resultHolder); + } + + LettuceResult newLettuceResult(Future resultHolder, Converter converter) { + return new LettuceResult(resultHolder, converter); + } + private class LettuceStatusResult extends LettuceResult { @SuppressWarnings("rawtypes") public LettuceStatusResult(Future resultHolder) { @@ -196,7 +182,11 @@ public class LettuceConnection extends AbstractRedisConnection { } } - private class LettuceTxResult extends FutureResult { + LettuceStatusResult newLettuceStatusResult(Future resultHolder) { + return new LettuceStatusResult(resultHolder); + } + + class LettuceTxResult extends FutureResult { public LettuceTxResult(Object resultHolder, Converter converter) { super(resultHolder, converter); } @@ -215,6 +205,14 @@ public class LettuceConnection extends AbstractRedisConnection { } } + LettuceTxResult newLettuceTxResult(Object resultHolder) { + return new LettuceTxResult(resultHolder); + } + + LettuceTxResult newLettuceTxResult(Object resultHolder, Converter converter) { + return new LettuceTxResult(resultHolder, converter); + } + private class LettuceTxStatusResult extends LettuceTxResult { public LettuceTxStatusResult(Object resultHolder) { super(resultHolder); @@ -222,6 +220,10 @@ public class LettuceConnection extends AbstractRedisConnection { } } + LettuceTxStatusResult newLettuceTxStatusResult(Object resultHolder) { + return new LettuceTxStatusResult(resultHolder); + } + private class LettuceTransactionResultConverter extends TransactionResultConverter { public LettuceTransactionResultConverter(Queue> txResults, Converter exceptionConverter) { @@ -337,6 +339,46 @@ public class LettuceConnection extends AbstractRedisConnection { return exception; } + @Override + public RedisGeoCommands geoCommands() { + return new LettuceGeoCommands(this); + } + + @Override + public RedisHashCommands hashCommands() { + return new LettuceHashCommands(this); + } + + @Override + public RedisHyperLogLogCommands hyperLogLogCommands() { + return new LettuceHyperLogLogCommands(this); + } + + @Override + public RedisKeyCommands keyCommands() { + return new LettuceKeyCommands(this); + } + + @Override + public RedisListCommands listCommands() { + return new LettuceListCommands(this); + } + + @Override + public RedisSetCommands setCommands() { + return new LettuceSetCommands(this); + } + + @Override + public RedisStringCommands stringCommands() { + return new LettuceStringCommands(this); + } + + @Override + public RedisZSetCommands zSetCommands() { + return new LettuceZSetCommands(this); + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private Object await(RedisFuture cmd) { @@ -354,8 +396,7 @@ public class LettuceConnection extends AbstractRedisConnection { /** * 'Native' or 'raw' execution of the given command along-side the given arguments. - * - * @see RedisCommands#execute(String, byte[]...) + * * @param command Command to execute * @param commandOutputTypeHint Type of Output to use, may be (may be {@literal null}). * @param args Possible command arguments (may be {@literal null}) @@ -519,44 +560,6 @@ public class LettuceConnection extends AbstractRedisConnection { return Collections.emptyList(); } - public List sort(byte[] key, SortParameters params) { - - SortArgs args = LettuceConverters.toSortArgs(params); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sort(key, args))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sort(key, args))); - return null; - } - return getConnection().sort(key, args); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sort(byte[] key, SortParameters params, byte[] sortKey) { - - SortArgs args = LettuceConverters.toSortArgs(params); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sortStore(key, args, sortKey))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sortStore(key, args, sortKey))); - return null; - } - return getConnection().sortStore(key, args, sortKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - public Long dbSize() { try { if (isPipelined()) { @@ -825,22 +828,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - public Long del(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().del(keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().del(keys))); - return null; - } - return getConnection().del(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - public void discard() { isMulti = false; try { @@ -883,186 +870,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - public Boolean exists(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().exists(new byte[][] { key }), - LettuceConverters.longToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction(new LettuceResult(getAsyncConnection().exists(new byte[][] { key }), - LettuceConverters.longToBooleanConverter())); - return null; - } - return LettuceConverters.longToBooleanConverter().convert(getConnection().exists(new byte[][] { key })); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean expire(byte[] key, long seconds) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().expire(key, seconds))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().expire(key, seconds))); - return null; - } - return getConnection().expire(key, seconds); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean expireAt(byte[] key, long unixTime) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().expireat(key, unixTime))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().expireat(key, unixTime))); - return null; - } - return getConnection().expireat(key, unixTime); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean pExpire(byte[] key, long millis) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().pexpire(key, millis))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().pexpire(key, millis))); - return null; - } - return getConnection().pexpire(key, millis); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().pexpireat(key, unixTimeInMillis))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().pexpireat(key, unixTimeInMillis))); - return null; - } - return getConnection().pexpireat(key, unixTimeInMillis); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) - */ - @Override - public Long pTtl(byte[] key) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().pttl(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().pttl(key))); - return null; - } - - return getConnection().pttl(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long pTtl(byte[] key, TimeUnit timeUnit) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.millisecondsToTimeUnit(getConnection().pttl(key), timeUnit); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] dump(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().dump(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().dump(key))); - return null; - } - return getConnection().dump(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().restore(key, ttlInMillis, serializedValue))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().restore(key, ttlInMillis, serializedValue))); - return; - } - getConnection().restore(key, ttlInMillis, serializedValue); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set keys(byte[] pattern) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().keys(pattern)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - public void multi() { if (isQueueing()) { return; @@ -1079,86 +886,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - public Boolean persist(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().persist(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().persist(key))); - return null; - } - return getConnection().persist(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean move(byte[] key, int dbIndex) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().move(key, dbIndex))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().move(key, dbIndex))); - return null; - } - return getConnection().move(key, dbIndex); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] randomKey() { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().randomkey())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().randomkey())); - return null; - } - return getConnection().randomkey(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void rename(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().rename(oldName, newName))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().rename(oldName, newName))); - return; - } - getConnection().rename(oldName, newName); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean renameNX(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().renamenx(oldName, newName))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().renamenx(oldName, newName))); - return null; - } - return (getConnection().renamenx(oldName, newName)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - public void select(int dbIndex) { if (asyncSharedConn != null) { @@ -1181,72 +908,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) - */ - @Override - public Long ttl(byte[] key) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().ttl(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().ttl(key))); - return null; - } - - return getConnection().ttl(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) - */ - @Override - public Long ttl(byte[] key, TimeUnit timeUnit) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; - } - - return Converters.secondsToTimeUnit(getConnection().ttl(key), timeUnit); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public DataType type(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - return LettuceConverters.toDataType(getConnection().type(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - public void unwatch() { try { if (isPipelined()) { @@ -1282,1714 +943,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - // - // String commands - // - - public byte[] get(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().get(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().get(key))); - return null; - } - return getConnection().get(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void set(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().set(key, value))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().set(key, value))); - return; - } - getConnection().set(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption) - */ - @Override - public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { - - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult( - getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult( - getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)))); - return; - } - getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] getSet(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().getset(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().getset(key, value))); - return null; - } - return getConnection().getset(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long append(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().append(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().append(key, value))); - return null; - } - return getConnection().append(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List mGet(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - - return LettuceConverters. keyValueListUnwrapper().convert(getConnection().mget(keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void mSet(Map tuples) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().mset(tuples))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().mset(tuples))); - return; - } - getConnection().mset(tuples); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean mSetNX(Map tuples) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().msetnx(tuples))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().msetnx(tuples))); - return null; - } - return getConnection().msetnx(tuples); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void setEx(byte[] key, long time, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().setex(key, time, value))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().setex(key, time, value))); - return; - } - getConnection().setex(key, time, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /** - * @since 1.3 - * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) - */ - @Override - public void pSetEx(byte[] key, long milliseconds, byte[] value) { - - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().psetex(key, milliseconds, value))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().psetex(key, milliseconds, value))); - return; - } - getConnection().psetex(key, milliseconds, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean setNX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().setnx(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().setnx(key, value))); - return null; - } - return getConnection().setnx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] getRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().getrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().getrange(key, start, end))); - return null; - } - return getConnection().getrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long decr(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().decr(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().decr(key))); - return null; - } - return getConnection().decr(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long decrBy(byte[] key, long value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().decrby(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().decrby(key, value))); - return null; - } - return getConnection().decrby(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long incr(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().incr(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().incr(key))); - return null; - } - return getConnection().incr(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long incrBy(byte[] key, long value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().incrby(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().incrby(key, value))); - return null; - } - return getConnection().incrby(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Double incrBy(byte[] key, double value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().incrbyfloat(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().incrbyfloat(key, value))); - return null; - } - return getConnection().incrbyfloat(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean getBit(byte[] key, long offset) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().getbit(key, offset), LettuceConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().getbit(key, offset), LettuceConverters.longToBoolean())); - return null; - } - return LettuceConverters.toBoolean(getConnection().getbit(key, offset)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean setBit(byte[] key, long offset, boolean value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().setbit(key, offset, LettuceConverters.toInt(value)), - LettuceConverters.longToBooleanConverter())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().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); - } - } - - public void setRange(byte[] key, byte[] value, long start) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().setrange(key, start, value))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().setrange(key, start, value))); - return; - } - getConnection().setrange(key, start, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long strLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().strlen(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().strlen(key))); - return null; - } - return getConnection().strlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long bitCount(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().bitcount(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().bitcount(key))); - return null; - } - return getConnection().bitcount(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long bitCount(byte[] key, long begin, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().bitcount(key, begin, end))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().bitcount(key, begin, end))); - return null; - } - return getConnection().bitcount(key, begin, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(asyncBitOp(op, destination, keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(syncBitOp(op, destination, keys))); - return null; - } - return syncBitOp(op, destination, keys); - } catch (UnsupportedOperationException ex) { - throw ex; - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - // - // List commands - // - - public Long lPush(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lpush(key, values))); - return null; - } - return getConnection().lpush(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long rPush(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().rpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().rpush(key, values))); - return null; - } - return getConnection().rpush(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List bLPop(int timeout, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncDedicatedConnection().blpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getDedicatedConnection().blpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - return LettuceConverters.toBytesList(getDedicatedConnection().blpop(timeout, keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List bRPop(int timeout, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncDedicatedConnection().brpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getDedicatedConnection().brpop(timeout, keys), - LettuceConverters.keyValueToBytesList())); - return null; - } - return LettuceConverters.toBytesList(getDedicatedConnection().brpop(timeout, keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] lIndex(byte[] key, long index) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lindex(key, index))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lindex(key, index))); - return null; - } - return getConnection().lindex(key, index); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { - try { - if (isPipelined()) { - pipeline( - new LettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - if (isQueueing()) { - transaction( - new LettuceTxResult(getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - return getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long lLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().llen(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().llen(key))); - return null; - } - return getConnection().llen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] lPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lpop(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lpop(key))); - return null; - } - return getConnection().lpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List lRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lrange(key, start, end))); - return null; - } - return getConnection().lrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long lRem(byte[] key, long count, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lrem(key, count, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lrem(key, count, value))); - return null; - } - return getConnection().lrem(key, count, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void lSet(byte[] key, long index, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().lset(key, index, value))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().lset(key, index, value))); - return; - } - getConnection().lset(key, index, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void lTrim(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().ltrim(key, start, end))); - return; - } - getConnection().ltrim(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] rPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().rpop(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().rpop(key))); - return null; - } - return getConnection().rpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().rpoplpush(srcKey, dstKey))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().rpoplpush(srcKey, dstKey))); - return null; - } - return getConnection().rpoplpush(srcKey, dstKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); - return null; - } - return getDedicatedConnection().brpoplpush(timeout, srcKey, dstKey); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long lPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().lpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().lpushx(key, value))); - return null; - } - return getConnection().lpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long rPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().rpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().rpushx(key, value))); - return null; - } - return getConnection().rpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - // - // Set commands - // - - public Long sAdd(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sadd(key, values))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sadd(key, values))); - return null; - } - return getConnection().sadd(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sCard(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().scard(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().scard(key))); - return null; - } - return getConnection().scard(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set sDiff(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sdiff(keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sdiff(keys))); - return null; - } - return getConnection().sdiff(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sDiffStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sdiffstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sdiffstore(destKey, keys))); - return null; - } - return getConnection().sdiffstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set sInter(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sinter(keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sinter(keys))); - return null; - } - return getConnection().sinter(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sInterStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sinterstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sinterstore(destKey, keys))); - return null; - } - return getConnection().sinterstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean sIsMember(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sismember(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sismember(key, value))); - return null; - } - return getConnection().sismember(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set sMembers(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().smembers(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().smembers(key))); - return null; - } - return getConnection().smembers(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().smove(srcKey, destKey, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().smove(srcKey, destKey, value))); - return null; - } - return getConnection().smove(srcKey, destKey, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] sPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().spop(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().spop(key))); - return null; - } - return getConnection().spop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] sRandMember(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().srandmember(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().srandmember(key))); - return null; - } - return getConnection().srandmember(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List sRandMember(byte[] key, long count) { - try { - if (isPipelined()) { - pipeline(new LettuceResult((RedisFuture) getAsyncConnection().srandmember(key, count), - LettuceConverters.bytesCollectionToBytesList())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().srandmember(key, count), - LettuceConverters.bytesCollectionToBytesList())); - return null; - } - return LettuceConverters.toBytesList(getConnection().srandmember(key, count)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sRem(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().srem(key, values))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().srem(key, values))); - return null; - } - return getConnection().srem(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set sUnion(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sunion(keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sunion(keys))); - return null; - } - return getConnection().sunion(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long sUnionStore(byte[] destKey, byte[]... keys) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().sunionstore(destKey, keys))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().sunionstore(destKey, keys))); - return null; - } - return getConnection().sunionstore(destKey, keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - // - // ZSet commands - // - - public Boolean zAdd(byte[] key, double score, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zadd(key, score, value), LettuceConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zadd(key, score, value), LettuceConverters.longToBoolean())); - return null; - } - return LettuceConverters.toBoolean(getConnection().zadd(key, score, value)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zAdd(byte[] key, Set tuples) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); - return null; - } - return getConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zCard(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zcard(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zcard(key))); - return null; - } - return getConnection().zcard(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Long zCount(byte[] key, double min, double max) { - return zCount(key, new Range().gte(min).lte(max)); - } - - @Override - public Long zCount(byte[] key, Range range) { - - Assert.notNull(range, "Range for ZCOUNT must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zcount(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zcount(key, LettuceConverters.toRange(range)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Double zIncrBy(byte[] key, double increment, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zincrby(key, increment, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zincrby(key, increment, value))); - return null; - } - return getConnection().zincrby(key, increment, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zinterstore(destKey, storeArgs, sets))); - return null; - } - return getConnection().zinterstore(destKey, storeArgs, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zInterStore(byte[] destKey, byte[]... sets) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zinterstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zinterstore(destKey, sets))); - return null; - } - return getConnection().zinterstore(destKey, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set zRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline( - new LettuceResult(getAsyncConnection().zrange(key, start, end), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - new LettuceTxResult(getConnection().zrange(key, start, end), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrange(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set zRangeWithScores(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRangeByScore(byte[] key, double min, double max) { - return zRangeByScore(key, new Range().gte(min).lte(max)); - } - - @Override - public Set zRangeByScore(byte[] key, Range range) { - return zRangeByScore(key, range, null); - } - - @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit != null) { - transaction(new LettuceTxResult( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction(new LettuceTxResult(getConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (limit != null) { - return LettuceConverters.toBytesSet( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRangeByScoreWithScores(byte[] key, double min, double max) { - return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); - } - - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range) { - return zRangeByScoreWithScores(key, range, null); - } - - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.scoredValuesToTupleSet())); - } else { - pipeline( - new LettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (isQueueing()) { - if (limit != null) { - transaction(new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.scoredValuesToTupleSet())); - } else { - transaction( - new LettuceTxResult(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (limit != null) { - return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } - return LettuceConverters - .toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set zRevRangeWithScores(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrangeWithScores(key, start, end), - LettuceConverters.scoredValuesToTupleSet())); - return null; - } - return LettuceConverters.toTupleSet(getConnection().zrevrangeWithScores(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { - - return zRangeByScore(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - @Override - public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - @Override - public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { - - return zRevRangeByScore(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - @Override - public Set zRevRangeByScore(byte[] key, Range range) { - return zRevRangeByScore(key, range, null); - } - - @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(new LettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit != null) { - transaction(new LettuceTxResult( - getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction(new LettuceTxResult(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (limit != null) { - return LettuceConverters.toBytesSet( - getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } - return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRevRangeByScore(byte[] key, double min, double max) { - return zRevRangeByScore(key, new Range().gte(min).lte(max)); - } - - @Override - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { - - return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), - new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); - } - - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range) { - return zRevRangeByScoreWithScores(key, range, null); - } - - @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline( - new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.scoredValuesToTupleSet())); - } else { - pipeline( - new LettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (isQueueing()) { - if (limit != null) { - transaction( - new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.scoredValuesToTupleSet())); - } else { - transaction( - new LettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), - LettuceConverters.scoredValuesToTupleSet())); - } - return null; - } - if (limit != null) { - return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } - return LettuceConverters - .toTupleSet(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { - return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max)); - } - - public Long zRank(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrank(key, value))); - return null; - } - return getConnection().zrank(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zRem(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrem(key, values))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrem(key, values))); - return null; - } - return getConnection().zrem(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zRemRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zremrangebyrank(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zremrangebyrank(key, start, end))); - return null; - } - return getConnection().zremrangebyrank(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Long zRemRangeByScore(byte[] key, double min, double max) { - return zRemRangeByScore(key, new Range().gte(min).lte(max)); - } - - @Override - public Long zRemRangeByScore(byte[] key, Range range) { - - Assert.notNull(range, "Range for ZREMRANGEBYSCORE must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zremrangebyscore(key, LettuceConverters.toRange(range)))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zremrangebyscore(key, LettuceConverters.toRange(range)))); - return null; - } - return getConnection().zremrangebyscore(key, LettuceConverters.toRange(range)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set zRevRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - new LettuceTxResult(getConnection().zrevrange(key, start, end), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrevrange(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zRevRank(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrevrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zrevrank(key, value))); - return null; - } - return getConnection().zrevrank(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Double zScore(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zscore(key, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zscore(key, value))); - return null; - } - return getConnection().zscore(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { - ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zunionstore(destKey, storeArgs, sets))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zunionstore(destKey, storeArgs, sets))); - return null; - } - return getConnection().zunionstore(destKey, storeArgs, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long zUnionStore(byte[] destKey, byte[]... sets) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zunionstore(destKey, sets))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().zunionstore(destKey, sets))); - return null; - } - return getConnection().zunionstore(destKey, sets); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - // - // Hash commands - // - - public Boolean hSet(byte[] key, byte[] field, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hset(key, field, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hset(key, field, value))); - return null; - } - return getConnection().hset(key, field, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hsetnx(key, field, value))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hsetnx(key, field, value))); - return null; - } - return getConnection().hsetnx(key, field, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long hDel(byte[] key, byte[]... fields) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hdel(key, fields))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hdel(key, fields))); - return null; - } - return getConnection().hdel(key, fields); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Boolean hExists(byte[] key, byte[] field) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hexists(key, field))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hexists(key, field))); - return null; - } - return getConnection().hexists(key, field); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public byte[] hGet(byte[] key, byte[] field) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hget(key, field))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hget(key, field))); - return null; - } - return getConnection().hget(key, field); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Map hGetAll(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hgetall(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hgetall(key))); - return null; - } - return getConnection().hgetall(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long hIncrBy(byte[] key, byte[] field, long delta) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hincrby(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hincrby(key, field, delta))); - return null; - } - return getConnection().hincrby(key, field, delta); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Double hIncrBy(byte[] key, byte[] field, double delta) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hincrbyfloat(key, field, delta))); - return null; - } - return getConnection().hincrbyfloat(key, field, delta); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Set hKeys(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().hkeys(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long hLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hlen(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hlen(key))); - return null; - } - return getConnection().hlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List hMGet(byte[] key, byte[]... fields) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hmget(key, fields), LettuceConverters.keyValueListUnwrapper())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hmget(key, fields), LettuceConverters.keyValueListUnwrapper())); - return null; - } - return LettuceConverters. keyValueListUnwrapper().convert(getConnection().hmget(key, fields)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void hMSet(byte[] key, Map tuple) { - try { - if (isPipelined()) { - pipeline(new LettuceStatusResult(getAsyncConnection().hmset(key, tuple))); - return; - } - if (isQueueing()) { - transaction(new LettuceTxStatusResult(getConnection().hmset(key, tuple))); - return; - } - getConnection().hmset(key, tuple); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List hVals(byte[] key) { - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().hvals(key))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().hvals(key))); - return null; - } - return getConnection().hvals(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - // // Scripting commands // @@ -3173,376 +1126,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - // - // Geo functionality - // - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) - */ - @Override - public Long geoAdd(byte[] key, Point point, byte[] member) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(point, "Point must not be null!"); - Assert.notNull(member, "Member must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geoadd(key, point.getX(), point.getY(), member))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().geoadd(key, point.getX(), point.getY(), member))); - return null; - } - return getConnection().geoadd(key, point.getX(), point.getY(), member); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation) - */ - @Override - public Long geoAdd(byte[] key, GeoLocation location) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(location, "Location must not be null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geoadd(key, location.getPoint().getX(), - location.getPoint().getY(), location.getName()))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult( - getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()))); - return null; - } - return getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) - */ - @Override - public Long geoAdd(byte[] key, Map memberCoordinateMap) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); - - List values = new ArrayList(); - for (Entry entry : memberCoordinateMap.entrySet()) { - - values.add(entry.getValue().getX()); - values.add(entry.getValue().getY()); - values.add(entry.getKey()); - } - - return geoAdd(key, values); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) - */ - @Override - public Long geoAdd(byte[] key, Iterable> locations) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(locations, "Locations must not be null!"); - - List values = new ArrayList(); - for (GeoLocation location : locations) { - - values.add(location.getPoint().getX()); - values.add(location.getPoint().getY()); - values.add(location.getName()); - } - - return geoAdd(key, values); - } - - private Long geoAdd(byte[] key, Collection values) { - - try { - - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geoadd(key, values.toArray()))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().geoadd(key, values.toArray()))); - return null; - } - return getConnection().geoadd(key, values.toArray()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { - return geoDist(key, member1, member2, DistanceUnit.METERS); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) - */ - @Override - public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member1, "Member1 must not be null!"); - Assert.notNull(member2, "Member2 must not be null!"); - Assert.notNull(metric, "Metric must not be null!"); - - GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(metric); - Converter distanceConverter = LettuceConverters.distanceConverterForMetric(metric); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geodist(key, member1, member2, geoUnit), distanceConverter)); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().geodist(key, member1, member2, geoUnit), distanceConverter)); - return null; - } - return distanceConverter.convert(getConnection().geodist(key, member1, member2, geoUnit)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) - */ - @Override - public List geoHash(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geohash(key, members))); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) - */ - @Override - public List geoPos(byte[] key, byte[]... members) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(members, "Members must not be null!"); - Assert.noNullElements(members, "Members must not contain null!"); - - ListConverter converter = LettuceConverters.geoCoordinatesToPointConverter(); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().geopos(key, members), converter)); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().geopos(key, members), converter)); - return null; - } - return converter.convert(getConnection().geopos(key, members)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - - Converter, GeoResults>> geoResultsConverter = LettuceConverters - .bytesSetToGeoResultsConverter(); - - try { - if (isPipelined()) { - pipeline(new LettuceResult( - getAsyncConnection().georadius(key, within.getCenter().getX(), within.getCenter().getY(), - within.getRadius().getValue(), LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric())), - geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult( - getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(within, "Within must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - GeoArgs geoArgs = LettuceConverters.toGeoArgs(args); - Converter>, GeoResults>> geoResultsConverter = LettuceConverters - .geoRadiusResponseToGeoResultsConverter(within.getRadius().getMetric()); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().georadius(key, within.getCenter().getX(), - within.getCenter().getY(), within.getRadius().getValue(), - LettuceConverters.toGeoArgsUnit(within.getRadius().getMetric()), geoArgs), geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { - return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double, org.springframework.data.geo.Metric) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - - GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(radius.getMetric()); - Converter, GeoResults>> converter = LettuceConverters - .bytesSetToGeoResultsConverter(); - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit), - converter)); - return null; - } - if (isQueueing()) { - transaction( - new LettuceTxResult(getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.core.GeoRadiusCommandArgs) - */ - @Override - public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, - GeoRadiusCommandArgs args) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(member, "Member must not be null!"); - Assert.notNull(radius, "Radius must not be null!"); - Assert.notNull(args, "Args must not be null!"); - - GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(radius.getMetric()); - GeoArgs geoArgs = LettuceConverters.toGeoArgs(args); - Converter>, GeoResults>> geoResultsConverter = LettuceConverters - .geoRadiusResponseToGeoResultsConverter(radius.getMetric()); - - try { - if (isPipelined()) { - pipeline( - new LettuceResult(getAsyncConnection().georadiusbymember(key, member, radius.getValue(), geoUnit, geoArgs), - geoResultsConverter)); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult( - getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) - */ - @Override - public Long geoRemove(byte[] key, byte[]... values) { - return zRem(key, values); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#time() @@ -3682,194 +1265,8 @@ public class LettuceConnection extends AbstractRedisConnection { } } - /** - * @since 1.4 - * @return - */ - public Cursor scan() { - return scan(0, ScanOptions.NONE); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) - */ - public Cursor scan(ScanOptions options) { - return scan(0, options != null ? options : ScanOptions.NONE); - } - - /** - * @since 1.4 - * @param cursorId - * @param options - * @return - */ - public Cursor scan(long cursorId, ScanOptions options) { - - return new ScanCursor(cursorId, options) { - - @SuppressWarnings("unchecked") - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); - } - - io.lettuce.core.ScanCursor scanCursor = getScanCursor(cursorId); - ScanArgs scanArgs = getScanArgs(options); - - KeyScanCursor keyScanCursor = getConnection().scan(scanCursor, scanArgs); - String nextCursorId = keyScanCursor.getCursor(); - - List keys = keyScanCursor.getKeys(); - - return new ScanIteration(Long.valueOf(nextCursorId), (keys)); - } - - protected void doClose() { - LettuceConnection.this.close(); - } - - }.open(); - - } - - /* (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor> hScan(byte[] key, ScanOptions options) { - return hScan(key, 0, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { - - return new KeyBoundCursor>(key, cursorId, options) { - - @Override - protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); - } - - io.lettuce.core.ScanCursor scanCursor = getScanCursor(cursorId); - ScanArgs scanArgs = getScanArgs(options); - - MapScanCursor mapScanCursor = getConnection().hscan(key, scanCursor, scanArgs); - String nextCursorId = mapScanCursor.getCursor(); - - Map values = mapScanCursor.getMap(); - return new ScanIteration>(Long.valueOf(nextCursorId), values.entrySet()); - } - - protected void doClose() { - LettuceConnection.this.close(); - } - - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor sScan(byte[] key, ScanOptions options) { - return sScan(key, 0, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { - - return new KeyBoundCursor(key, cursorId, options) { - - @Override - protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); - } - - io.lettuce.core.ScanCursor scanCursor = getScanCursor(cursorId); - ScanArgs scanArgs = getScanArgs(options); - - ValueScanCursor valueScanCursor = getConnection().sscan(key, scanCursor, scanArgs); - String nextCursorId = valueScanCursor.getCursor(); - - List values = failsafeReadScanValues(valueScanCursor.getValues(), null); - return new ScanIteration(Long.valueOf(nextCursorId), values); - } - - protected void doClose() { - LettuceConnection.this.close(); - } - - }.open(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor zScan(byte[] key, ScanOptions options) { - return zScan(key, 0L, options); - } - - /** - * @since 1.4 - * @param key - * @param cursorId - * @param options - * @return - */ - public Cursor zScan(byte[] key, long cursorId, ScanOptions options) { - - return new KeyBoundCursor(key, cursorId, options) { - - @Override - protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); - } - - io.lettuce.core.ScanCursor scanCursor = getScanCursor(cursorId); - ScanArgs scanArgs = getScanArgs(options); - - ScoredValueScanCursor scoredValueScanCursor = getConnection().zscan(key, scanCursor, scanArgs); - String nextCursorId = scoredValueScanCursor.getCursor(); - - List> result = scoredValueScanCursor.getValues(); - - List values = failsafeReadScanValues(result, LettuceConverters.scoredValuesToTupleList()); - return new ScanIteration(Long.valueOf(nextCursorId), values); - } - - protected void doClose() { - LettuceConnection.this.close(); - } - - }.open(); - } - @SuppressWarnings("unchecked") - private T failsafeReadScanValues(List source, @SuppressWarnings("rawtypes") Converter converter) { + T failsafeReadScanValues(List source, @SuppressWarnings("rawtypes") Converter converter) { try { return (T) (converter != null ? converter.convert(source) : source); @@ -3903,7 +1300,7 @@ public class LettuceConnection extends AbstractRedisConnection { // return ((RedisClient) client).connectPubSub(CODEC); } - private void pipeline(LettuceResult result) { + void pipeline(LettuceResult result) { if (isQueueing()) { transaction(result); } else { @@ -3911,11 +1308,11 @@ public class LettuceConnection extends AbstractRedisConnection { } } - private void transaction(FutureResult result) { + void transaction(FutureResult result) { txResults.add(result); } - private RedisClusterAsyncCommands getAsyncConnection() { + RedisClusterAsyncCommands getAsyncConnection() { if (isQueueing()) { return getAsyncDedicatedConnection(); } @@ -3978,7 +1375,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } - private RedisClusterCommands getDedicatedConnection() { + RedisClusterCommands getDedicatedConnection() { if (asyncDedicatedConn == null) { @@ -4004,42 +1401,6 @@ public class LettuceConnection extends AbstractRedisConnection { String.format("%s is not a supported connection type.", asyncDedicatedConn.getClass().getName())); } - 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"); - } - } - private byte[][] extractScriptKeys(int numKeys, byte[]... keysAndArgs) { if (numKeys > 0) { return Arrays.copyOfRange(keysAndArgs, 0, numKeys); @@ -4054,11 +1415,11 @@ public class LettuceConnection extends AbstractRedisConnection { return new byte[0][0]; } - private io.lettuce.core.ScanCursor getScanCursor(long cursorId) { + io.lettuce.core.ScanCursor getScanCursor(long cursorId) { return io.lettuce.core.ScanCursor.of(Long.toString(cursorId)); } - private ScanArgs getScanArgs(ScanOptions options) { + ScanArgs getScanArgs(ScanOptions options) { if (options == null) { return null; } @@ -4076,29 +1437,6 @@ public class LettuceConnection extends AbstractRedisConnection { return scanArgs; } - private ZStoreArgs zStoreArgs(Aggregate aggregate, int[] weights) { - ZStoreArgs args = new ZStoreArgs(); - if (aggregate != null) { - switch (aggregate) { - case MIN: - args.min(); - break; - case MAX: - args.max(); - break; - default: - args.sum(); - break; - } - } - double[] lg = new double[weights.length]; - for (int i = 0; i < lg.length; i++) { - lg[i] = weights[i]; - } - args.weights(lg); - return args; - } - private void validateCommandIfRunningInTransactionMode(CommandType cmd, byte[]... args) { if (this.isQueueing()) { @@ -4354,198 +1692,6 @@ public class LettuceConnection extends AbstractRedisConnection { } } - @Override - public Set zRangeByScore(byte[] key, String min, String max) { - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - new LettuceTxResult(getConnection().zrangebyscore(key, min, max), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - @Override - public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { - - try { - if (isPipelined()) { - pipeline(new LettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(new LettuceTxResult(getConnection().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); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfAdd(byte[], byte[][]) - */ - @Override - 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()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - pipeline(new LettuceResult(asyncConnection.pfadd(key, values))); - return null; - } - - if (isQueueing()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - transaction(new LettuceResult(asyncConnection.pfadd(key, values))); - return null; - } - - RedisHLLCommands connection = getConnection(); - return connection.pfadd(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfCount(byte[][]) - */ - @Override - 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()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - pipeline(new LettuceResult(asyncConnection.pfcount(keys))); - return null; - } - - if (isQueueing()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - transaction(new LettuceResult(asyncConnection.pfcount(keys))); - return null; - } - - RedisHLLCommands connection = getConnection(); - return connection.pfcount(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.HyperLogLogCommands#pfMerge(byte[], byte[][]) - */ - @Override - public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { - - Assert.notEmpty(sourceKeys, "PFMERGE requires at least one non 'null' source key."); - Assert.noNullElements(sourceKeys, "source key for PFMERGE must not contain 'null'."); - - try { - if (isPipelined()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - pipeline(new LettuceResult(asyncConnection.pfmerge(destinationKey, sourceKeys))); - return; - } - - if (isQueueing()) { - RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); - transaction(new LettuceResult(asyncConnection.pfmerge(destinationKey, sourceKeys))); - return; - } - - RedisHLLCommands connection = getConnection(); - connection.pfmerge(destinationKey, sourceKeys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[]) - */ - @Override - public Set zRangeByLex(byte[] key) { - return zRangeByLex(key, Range.unbounded()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Set zRangeByLex(byte[] key, Range range) { - return zRangeByLex(key, range, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByLex(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(new LettuceResult( - getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(new LettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit != null) { - transaction(new LettuceTxResult( - getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction(new LettuceTxResult(getConnection().zrangebylex(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - - if (limit != null) { - return LettuceConverters.bytesListToBytesSet().convert( - getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } - - return LettuceConverters.bytesListToBytesSet() - .convert(getConnection().zrangebylex(key, LettuceConverters.toRange(range))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) 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 new file mode 100644 index 000000000..8d0b4db02 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java @@ -0,0 +1,452 @@ +/* + * Copyright 2017 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 + * + * http://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.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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.dao.DataAccessException; +import org.springframework.data.geo.Circle; +import org.springframework.data.geo.Distance; +import org.springframework.data.geo.GeoResults; +import org.springframework.data.geo.Metric; +import org.springframework.data.geo.Point; +import org.springframework.data.redis.connection.RedisGeoCommands; +import org.springframework.data.redis.connection.convert.ListConverter; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceGeoCommands implements RedisGeoCommands { + + private final LettuceConnection connection; + + public LettuceGeoCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.geo.Point, byte[]) + */ + @Override + public Long geoAdd(byte[] key, Point point, byte[] member) { + + Assert.notNull(key, "Key must not be null!"); + 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.newLettuceTxResult(getConnection().geoadd(key, point.getX(), point.getY(), member))); + return null; + } + return getConnection().geoadd(key, point.getX(), point.getY(), member); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation) + */ + @Override + public Long geoAdd(byte[] key, GeoLocation location) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(location, "Location must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().geoadd(key, location.getPoint().getX(), + location.getPoint().getY(), location.getName()))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult( + getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()))); + return null; + } + return getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) + */ + @Override + public Long geoAdd(byte[] key, Map memberCoordinateMap) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(memberCoordinateMap, "MemberCoordinateMap must not be null!"); + + List values = new ArrayList(); + for (Entry entry : memberCoordinateMap.entrySet()) { + + values.add(entry.getValue().getX()); + values.add(entry.getValue().getY()); + values.add(entry.getKey()); + } + + return geoAdd(key, values); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.lang.Iterable) + */ + @Override + public Long geoAdd(byte[] key, Iterable> locations) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(locations, "Locations must not be null!"); + + List values = new ArrayList(); + for (GeoLocation location : locations) { + + values.add(location.getPoint().getX()); + values.add(location.getPoint().getY()); + values.add(location.getName()); + } + + return geoAdd(key, values); + } + + private Long geoAdd(byte[] key, Collection values) { + + try { + + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().geoadd(key, values.toArray()))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().geoadd(key, values.toArray()))); + return null; + } + return getConnection().geoadd(key, values.toArray()); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[]) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2) { + return geoDist(key, member1, member2, DistanceUnit.METERS); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoDist(byte[], byte[], byte[], org.springframework.data.geo.Metric) + */ + @Override + public Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member1, "Member1 must not be null!"); + Assert.notNull(member2, "Member2 must not be null!"); + Assert.notNull(metric, "Metric must not be null!"); + + 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.newLettuceTxResult(getConnection().geodist(key, member1, member2, geoUnit), distanceConverter)); + return null; + } + return distanceConverter.convert(getConnection().geodist(key, member1, member2, geoUnit)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoHash(byte[], byte[][]) + */ + @Override + public List geoHash(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + 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.newLettuceTxResult(getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoPos(byte[], byte[][]) + */ + @Override + public List geoPos(byte[] key, byte[]... members) { + + Assert.notNull(key, "Key must not be null!"); + 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.newLettuceTxResult(getConnection().geopos(key, members), converter)); + return null; + } + return converter.convert(getConnection().geopos(key, members)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + + 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.newLettuceTxResult( + getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadius(byte[], org.springframework.data.geo.Circle, org.springframework.data.redis.core.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(within, "Within must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + GeoArgs geoArgs = LettuceConverters.toGeoArgs(args); + 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.newLettuceTxResult(getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { + return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], double, org.springframework.data.geo.Metric) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + + GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(radius.getMetric()); + 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 + .newLettuceTxResult(getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRadiusByMember(byte[], byte[], org.springframework.data.geo.Distance, org.springframework.data.redis.core.GeoRadiusCommandArgs) + */ + @Override + public GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, + GeoRadiusCommandArgs args) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(member, "Member must not be null!"); + Assert.notNull(radius, "Radius must not be null!"); + Assert.notNull(args, "Args must not be null!"); + + GeoArgs.Unit geoUnit = LettuceConverters.toGeoArgsUnit(radius.getMetric()); + GeoArgs geoArgs = LettuceConverters.toGeoArgs(args); + 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.newLettuceTxResult( + getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisGeoCommands#geoRemove(byte[], byte[][]) + */ + @Override + 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(LettuceTxResult result) { + connection.transaction(result); + } + + 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 new file mode 100644 index 000000000..7bb93bf2a --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java @@ -0,0 +1,395 @@ +/* + * Copyright 2017 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 + * + * http://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.MapScanCursor; +import io.lettuce.core.ScanArgs; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; + +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.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceHashCommands implements RedisHashCommands { + + private final LettuceConnection connection; + + public LettuceHashCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSet(byte[], byte[], byte[]) + */ + @Override + public Boolean hSet(byte[] key, byte[] field, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hset(key, field, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hset(key, field, value))); + return null; + } + return getConnection().hset(key, field, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hSetNX(byte[], byte[], byte[]) + */ + @Override + public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hsetnx(key, field, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hsetnx(key, field, value))); + return null; + } + return getConnection().hsetnx(key, field, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hDel(byte[], byte[][]) + */ + @Override + public Long hDel(byte[] key, byte[]... fields) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hdel(key, fields))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hdel(key, fields))); + return null; + } + return getConnection().hdel(key, fields); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hExists(byte[], byte[]) + */ + @Override + public Boolean hExists(byte[] key, byte[] field) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hexists(key, field))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hexists(key, field))); + return null; + } + return getConnection().hexists(key, field); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGet(byte[], byte[]) + */ + @Override + public byte[] hGet(byte[] key, byte[] field) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hget(key, field))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hget(key, field))); + return null; + } + return getConnection().hget(key, field); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hGetAll(byte[]) + */ + @Override + public Map hGetAll(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hgetall(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hgetall(key))); + return null; + } + return getConnection().hgetall(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], long) + */ + @Override + public Long hIncrBy(byte[] key, byte[] field, long delta) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hincrby(key, field, delta))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hincrby(key, field, delta))); + return null; + } + return getConnection().hincrby(key, field, delta); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hIncrBy(byte[], byte[], double) + */ + @Override + public Double hIncrBy(byte[] key, byte[] field, double delta) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hincrbyfloat(key, field, delta))); + return null; + } + return getConnection().hincrbyfloat(key, field, delta); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hKeys(byte[]) + */ + @Override + public Set hKeys(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().hkeys(key)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hLen(byte[]) + */ + @Override + public Long hLen(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hlen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hlen(key))); + return null; + } + return getConnection().hlen(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMGet(byte[], byte[][]) + */ + @Override + public List hMGet(byte[] key, byte[]... fields) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hmget(key, fields), + LettuceConverters.keyValueListUnwrapper())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hmget(key, fields), + LettuceConverters.keyValueListUnwrapper())); + return null; + } + return LettuceConverters. keyValueListUnwrapper().convert(getConnection().hmget(key, fields)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) + */ + @Override + public void hMSet(byte[] key, Map tuple) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, tuple))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().hmset(key, tuple))); + return; + } + getConnection().hmset(key, tuple); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hVals(byte[]) + */ + @Override + public List hVals(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().hvals(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().hvals(key))); + return null; + } + return getConnection().hvals(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor> hScan(byte[] key, ScanOptions options) { + return hScan(key, 0, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { + + return new KeyBoundCursor>(key, cursorId, options) { + + @Override + protected ScanIteration> doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'HSCAN' cannot be called in pipeline / transaction mode."); + } + + io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); + ScanArgs scanArgs = connection.getScanArgs(options); + + MapScanCursor mapScanCursor = getConnection().hscan(key, scanCursor, scanArgs); + String nextCursorId = mapScanCursor.getCursor(); + + Map values = mapScanCursor.getMap(); + return new ScanIteration<>(Long.valueOf(nextCursorId), values.entrySet()); + } + + protected void doClose() { + LettuceHashCommands.this.connection.close(); + } + + }.open(); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void pipeline(LettuceResult result) { + connection.pipeline(result); + } + + private void transaction(LettuceTxResult result) { + connection.transaction(result); + } + + 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/LettuceHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java new file mode 100644 index 000000000..05a3df8a7 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java @@ -0,0 +1,157 @@ +/* + * Copyright 2017 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 + * + * http://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.api.async.RedisHLLAsyncCommands; +import io.lettuce.core.api.sync.RedisHLLCommands; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisHyperLogLogCommands; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { + + private final LettuceConnection connection; + + public LettuceHyperLogLogCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfAdd(byte[], byte[][]) + */ + @Override + 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()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + pipeline(connection.newLettuceResult(asyncConnection.pfadd(key, values))); + return null; + } + + if (isQueueing()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + transaction(connection.newLettuceTxResult(asyncConnection.pfadd(key, values))); + return null; + } + + RedisHLLCommands connection = getConnection(); + return connection.pfadd(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfCount(byte[][]) + */ + @Override + 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()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + pipeline(connection.newLettuceResult(asyncConnection.pfcount(keys))); + return null; + } + + if (isQueueing()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + transaction(connection.newLettuceTxResult(asyncConnection.pfcount(keys))); + return null; + } + + RedisHLLCommands connection = getConnection(); + return connection.pfcount(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisHyperLogLogCommands#pfMerge(byte[], byte[][]) + */ + @Override + public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + + Assert.notEmpty(sourceKeys, "PFMERGE requires at least one non 'null' source key."); + Assert.noNullElements(sourceKeys, "source key for PFMERGE must not contain 'null'."); + + try { + if (isPipelined()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + pipeline(connection.newLettuceResult(asyncConnection.pfmerge(destinationKey, sourceKeys))); + return; + } + + if (isQueueing()) { + RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); + transaction(connection.newLettuceTxResult(asyncConnection.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(LettuceTxResult result) { + connection.transaction(result); + } + + RedisClusterAsyncCommands getAsyncConnection() { + return connection.getAsyncConnection(); + } + + public RedisClusterCommands getConnection() { + return connection.getConnection(); + } + + protected DataAccessException convertLettuceAccessException(Exception ex) { + return connection.convertLettuceAccessException(ex); + } +} 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 new file mode 100644 index 000000000..4dfcb0450 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java @@ -0,0 +1,604 @@ +/* + * Copyright 2017 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 + * + * http://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.KeyScanCursor; +import io.lettuce.core.ScanArgs; +import io.lettuce.core.SortArgs; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; + +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; +import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceKeyCommands implements RedisKeyCommands { + + private final LettuceConnection connection; + + public LettuceKeyCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) + */ + @Override + public byte[] dump(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().dump(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().dump(key))); + return null; + } + return getConnection().dump(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) + */ + @Override + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().restore(key, ttlInMillis, serializedValue))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().restore(key, ttlInMillis, serializedValue))); + return; + } + getConnection().restore(key, ttlInMillis, serializedValue); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) + */ + @Override + public Set keys(byte[] pattern) { + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().keys(pattern)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#exists(byte[]) + */ + @Override + public Boolean exists(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().exists(new byte[][] { key }), + LettuceConverters.longToBooleanConverter())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getAsyncConnection().exists(new byte[][] { key }), + LettuceConverters.longToBooleanConverter())); + return null; + } + return LettuceConverters.longToBooleanConverter().convert(getConnection().exists(new byte[][] { key })); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expire(byte[], long) + */ + @Override + public Boolean expire(byte[] key, long seconds) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().expire(key, seconds))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().expire(key, seconds))); + return null; + } + return getConnection().expire(key, seconds); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) + */ + @Override + public Boolean expireAt(byte[] key, long unixTime) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().expireat(key, unixTime))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().expireat(key, unixTime))); + return null; + } + return getConnection().expireat(key, unixTime); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) + */ + @Override + public Boolean pExpire(byte[] key, long millis) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().pexpire(key, millis))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().pexpire(key, millis))); + return null; + } + return getConnection().pexpire(key, millis); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) + */ + @Override + public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().pexpireat(key, unixTimeInMillis))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().pexpireat(key, unixTimeInMillis))); + return null; + } + return getConnection().pexpireat(key, unixTimeInMillis); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) + */ + @Override + 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.newLettuceTxResult(getConnection().pttl(key))); + return null; + } + + return getConnection().pttl(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + 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.newLettuceTxResult(getConnection().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); + return null; + } + + return Converters.millisecondsToTimeUnit(getConnection().pttl(key), timeUnit); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) + */ + @Override + public Long del(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().del(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().del(keys))); + return null; + } + return getConnection().del(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) + */ + @Override + 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.newLettuceTxResult(getConnection().sort(key, args))); + return null; + } + return getConnection().sort(key, args); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) + */ + @Override + 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.newLettuceTxResult(getConnection().sortStore(key, args, sortKey))); + return null; + } + return getConnection().sortStore(key, args, sortKey); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) + */ + @Override + public Boolean persist(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().persist(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().persist(key))); + return null; + } + return getConnection().persist(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) + */ + @Override + public Boolean move(byte[] key, int dbIndex) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().move(key, dbIndex))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().move(key, dbIndex))); + return null; + } + return getConnection().move(key, dbIndex); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() + */ + @Override + public byte[] randomKey() { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().randomkey())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().randomkey())); + return null; + } + return getConnection().randomkey(); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) + */ + @Override + public void rename(byte[] oldName, byte[] newName) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().rename(oldName, newName))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().rename(oldName, newName))); + return; + } + getConnection().rename(oldName, newName); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) + */ + @Override + public Boolean renameNX(byte[] oldName, byte[] newName) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().renamenx(oldName, newName))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().renamenx(oldName, newName))); + return null; + } + return (getConnection().renamenx(oldName, newName)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) + */ + @Override + 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.newLettuceTxResult(getConnection().ttl(key))); + return null; + } + + return getConnection().ttl(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + 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.newLettuceTxResult(getConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + return null; + } + + return Converters.secondsToTimeUnit(getConnection().ttl(key), timeUnit); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) + */ + @Override + public DataType type(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().type(key), LettuceConverters.stringToDataType())); + return null; + } + return LettuceConverters.toDataType(getConnection().type(key)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /** + * @since 1.4 + * @return + */ + public Cursor scan() { + return scan(0, ScanOptions.NONE); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor scan(ScanOptions options) { + return scan(0, options != null ? options : ScanOptions.NONE); + } + + /** + * @since 1.4 + * @param cursorId + * @param options + * @return + */ + public Cursor scan(long cursorId, ScanOptions options) { + + return new ScanCursor(cursorId, options) { + + @SuppressWarnings("unchecked") + @Override + protected ScanIteration doScan(long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); + } + + io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); + ScanArgs scanArgs = connection.getScanArgs(options); + + KeyScanCursor keyScanCursor = getConnection().scan(scanCursor, scanArgs); + String nextCursorId = keyScanCursor.getCursor(); + + List keys = keyScanCursor.getKeys(); + + return new ScanIteration<>(Long.valueOf(nextCursorId), (keys)); + } + + protected void doClose() { + LettuceKeyCommands.this.connection.close(); + } + + }.open(); + + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void pipeline(LettuceResult result) { + connection.pipeline(result); + } + + private void transaction(LettuceTxResult result) { + connection.transaction(result); + } + + RedisClusterAsyncCommands getAsyncConnection() { + return connection.getAsyncConnection(); + } + + public RedisClusterCommands getConnection() { + return connection.getConnection(); + } + + private DataAccessException convertLettuceAccessException(Exception ex) { + return connection.convertLettuceAccessException(ex); + } + +} diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java new file mode 100644 index 000000000..be2e28eca --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java @@ -0,0 +1,433 @@ +/* + * Copyright 2017 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 + * + * http://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.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; + +import java.util.List; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisListCommands; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceListCommands implements RedisListCommands { + + private final LettuceConnection connection; + + public LettuceListCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) + */ + @Override + public Long lPush(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpush(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpush(key, values))); + return null; + } + return getConnection().lpush(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPush(byte[], byte[][]) + */ + @Override + public Long rPush(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpush(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpush(key, values))); + return null; + } + return getConnection().rpush(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) + */ + @Override + public List bLPop(int timeout, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().blpop(timeout, keys), + LettuceConverters.keyValueToBytesList())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(connection.getDedicatedConnection().blpop(timeout, keys), + LettuceConverters.keyValueToBytesList())); + return null; + } + return LettuceConverters.toBytesList(connection.getDedicatedConnection().blpop(timeout, keys)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPop(int, byte[][]) + */ + @Override + public List bRPop(int timeout, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpop(timeout, keys), + LettuceConverters.keyValueToBytesList())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(connection.getDedicatedConnection().brpop(timeout, keys), + LettuceConverters.keyValueToBytesList())); + return null; + } + return LettuceConverters.toBytesList(connection.getDedicatedConnection().brpop(timeout, keys)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) + */ + @Override + public byte[] lIndex(byte[] key, long index) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lindex(key, index))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lindex(key, index))); + return null; + } + return getConnection().lindex(key, index); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) + */ + @Override + public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection + .newLettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); + return null; + } + if (isQueueing()) { + transaction(connection + .newLettuceTxResult(getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); + return null; + } + return getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) + */ + @Override + public Long lLen(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().llen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().llen(key))); + return null; + } + return getConnection().llen(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) + */ + @Override + public byte[] lPop(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpop(key))); + return null; + } + return getConnection().lpop(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) + */ + @Override + public List lRange(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lrange(key, start, end))); + return null; + } + return getConnection().lrange(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) + */ + @Override + public Long lRem(byte[] key, long count, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lrem(key, count, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lrem(key, count, value))); + return null; + } + return getConnection().lrem(key, count, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) + */ + @Override + public void lSet(byte[] key, long index, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().lset(key, index, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().lset(key, index, value))); + return; + } + getConnection().lset(key, index, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) + */ + @Override + public void lTrim(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().ltrim(key, start, end))); + return; + } + getConnection().ltrim(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) + */ + @Override + public byte[] rPop(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpop(key))); + return null; + } + return getConnection().rpop(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPopLPush(byte[], byte[]) + */ + @Override + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpoplpush(srcKey, dstKey))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpoplpush(srcKey, dstKey))); + return null; + } + return getConnection().rpoplpush(srcKey, dstKey); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#bRPopLPush(int, byte[], byte[]) + */ + @Override + public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(connection.getDedicatedConnection().brpoplpush(timeout, srcKey, dstKey))); + return null; + } + return connection.getDedicatedConnection().brpoplpush(timeout, srcKey, dstKey); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) + */ + @Override + public Long lPushX(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpushx(key, value))); + return null; + } + return getConnection().lpushx(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) + */ + @Override + public Long rPushX(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpushx(key, value))); + return null; + } + return getConnection().rpushx(key, value); + } 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(LettuceTxResult result) { + connection.transaction(result); + } + + 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/LettuceSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java new file mode 100644 index 000000000..97ae364ed --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java @@ -0,0 +1,437 @@ +/* + * Copyright 2017 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 + * + * http://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.ScanArgs; +import io.lettuce.core.ValueScanCursor; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +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.RedisSetCommands; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceSetCommands implements RedisSetCommands { + + private final LettuceConnection connection; + + public LettuceSetCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sAdd(byte[], byte[][]) + */ + @Override + public Long sAdd(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sadd(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sadd(key, values))); + return null; + } + return getConnection().sadd(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sCard(byte[]) + */ + @Override + public Long sCard(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().scard(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().scard(key))); + return null; + } + return getConnection().scard(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiff(byte[][]) + */ + @Override + public Set sDiff(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sdiff(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sdiff(keys))); + return null; + } + return getConnection().sdiff(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sDiffStore(byte[], byte[][]) + */ + @Override + public Long sDiffStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sdiffstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sdiffstore(destKey, keys))); + return null; + } + return getConnection().sdiffstore(destKey, keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInter(byte[][]) + */ + @Override + public Set sInter(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sinter(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sinter(keys))); + return null; + } + return getConnection().sinter(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sInterStore(byte[], byte[][]) + */ + @Override + public Long sInterStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sinterstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sinterstore(destKey, keys))); + return null; + } + return getConnection().sinterstore(destKey, keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sIsMember(byte[], byte[]) + */ + @Override + public Boolean sIsMember(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sismember(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sismember(key, value))); + return null; + } + return getConnection().sismember(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMembers(byte[]) + */ + @Override + public Set sMembers(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().smembers(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().smembers(key))); + return null; + } + return getConnection().smembers(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sMove(byte[], byte[], byte[]) + */ + @Override + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().smove(srcKey, destKey, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().smove(srcKey, destKey, value))); + return null; + } + return getConnection().smove(srcKey, destKey, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sPop(byte[]) + */ + @Override + public byte[] sPop(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().spop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().spop(key))); + return null; + } + return getConnection().spop(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[]) + */ + @Override + public byte[] sRandMember(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().srandmember(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().srandmember(key))); + return null; + } + return getConnection().srandmember(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRandMember(byte[], long) + */ + @Override + public List sRandMember(byte[] key, long count) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult((RedisFuture) getAsyncConnection().srandmember(key, count), + LettuceConverters.bytesCollectionToBytesList())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().srandmember(key, count), + LettuceConverters.bytesCollectionToBytesList())); + return null; + } + return LettuceConverters.toBytesList(getConnection().srandmember(key, count)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sRem(byte[], byte[][]) + */ + @Override + public Long sRem(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().srem(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().srem(key, values))); + return null; + } + return getConnection().srem(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnion(byte[][]) + */ + @Override + public Set sUnion(byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sunion(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sunion(keys))); + return null; + } + return getConnection().sunion(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sUnionStore(byte[], byte[][]) + */ + @Override + public Long sUnionStore(byte[] destKey, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().sunionstore(destKey, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().sunionstore(destKey, keys))); + return null; + } + return getConnection().sunionstore(destKey, keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor sScan(byte[] key, ScanOptions options) { + return sScan(key, 0, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { + + return new KeyBoundCursor(key, cursorId, options) { + + @Override + protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode."); + } + + io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); + ScanArgs scanArgs = connection.getScanArgs(options); + + ValueScanCursor valueScanCursor = getConnection().sscan(key, scanCursor, scanArgs); + String nextCursorId = valueScanCursor.getCursor(); + + List values = connection.failsafeReadScanValues(valueScanCursor.getValues(), null); + return new ScanIteration<>(Long.valueOf(nextCursorId), values); + } + + protected void doClose() { + LettuceSetCommands.this.connection.close(); + } + + }.open(); + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void pipeline(LettuceResult result) { + connection.pipeline(result); + } + + private void transaction(LettuceTxResult result) { + connection.transaction(result); + } + + 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/LettuceStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java new file mode 100644 index 000000000..2f6ec2044 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java @@ -0,0 +1,514 @@ +/* + * Copyright 2017 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 + * + * http://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.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; + +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.data.redis.core.types.Expiration; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceStringCommands implements RedisStringCommands { + + private final LettuceConnection connection; + + public LettuceStringCommands(LettuceConnection connection) { + this.connection = connection; + } + + public byte[] get(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().get(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().get(key))); + return null; + } + return getConnection().get(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public void set(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().set(key, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().set(key, value))); + return; + } + getConnection().set(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption) + */ + @Override + public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult( + getAsyncConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult( + getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)))); + return; + } + getConnection().set(key, value, LettuceConverters.toSetArgs(expiration, option)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public byte[] getSet(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().getset(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().getset(key, value))); + return null; + } + return getConnection().getset(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long append(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().append(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().append(key, value))); + return null; + } + return getConnection().append(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public List mGet(byte[]... keys) { + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); + return null; + } + + return LettuceConverters. keyValueListUnwrapper().convert(getConnection().mget(keys)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public void mSet(Map tuples) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().mset(tuples))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().mset(tuples))); + return; + } + getConnection().mset(tuples); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Boolean mSetNX(Map tuples) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().msetnx(tuples))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().msetnx(tuples))); + return null; + } + return getConnection().msetnx(tuples); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public void setEx(byte[] key, long time, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().setex(key, time, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().setex(key, time, value))); + return; + } + getConnection().setex(key, time, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /** + * @since 1.3 + * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) + */ + @Override + public void pSetEx(byte[] key, long milliseconds, byte[] value) { + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().psetex(key, milliseconds, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().psetex(key, milliseconds, value))); + return; + } + getConnection().psetex(key, milliseconds, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Boolean setNX(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().setnx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().setnx(key, value))); + return null; + } + return getConnection().setnx(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public byte[] getRange(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().getrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().getrange(key, start, end))); + return null; + } + return getConnection().getrange(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long decr(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().decr(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().decr(key))); + return null; + } + return getConnection().decr(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long decrBy(byte[] key, long value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().decrby(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().decrby(key, value))); + return null; + } + return getConnection().decrby(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long incr(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().incr(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().incr(key))); + return null; + } + return getConnection().incr(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long incrBy(byte[] key, long value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().incrby(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().incrby(key, value))); + return null; + } + return getConnection().incrby(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Double incrBy(byte[] key, double value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().incrbyfloat(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().incrbyfloat(key, value))); + return null; + } + return getConnection().incrbyfloat(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Boolean getBit(byte[] key, long offset) { + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().getbit(key, offset), LettuceConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().getbit(key, offset), LettuceConverters.longToBoolean())); + return null; + } + return LettuceConverters.toBoolean(getConnection().getbit(key, offset)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Boolean setBit(byte[] key, long offset, boolean value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().setbit(key, offset, LettuceConverters.toInt(value)), + LettuceConverters.longToBooleanConverter())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().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); + } + } + + public void setRange(byte[] key, byte[] value, long start) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().setrange(key, start, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().setrange(key, start, value))); + return; + } + getConnection().setrange(key, start, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long strLen(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().strlen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().strlen(key))); + return null; + } + return getConnection().strlen(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long bitCount(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().bitcount(key))); + return null; + } + return getConnection().bitcount(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long bitCount(byte[] key, long begin, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key, begin, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().bitcount(key, begin, end))); + return null; + } + return getConnection().bitcount(key, begin, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(asyncBitOp(op, destination, keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(syncBitOp(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"); + } + } + + private boolean isPipelined() { + return connection.isPipelined(); + } + + private boolean isQueueing() { + return connection.isQueueing(); + } + + private void pipeline(LettuceResult result) { + connection.pipeline(result); + } + + private void transaction(LettuceTxResult result) { + connection.transaction(result); + } + + 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/LettuceZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java new file mode 100644 index 000000000..1795e416f --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceZSetCommands.java @@ -0,0 +1,841 @@ +/* + * Copyright 2017 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 + * + * http://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.ScanArgs; +import io.lettuce.core.ScoredValue; +import io.lettuce.core.ScoredValueScanCursor; +import io.lettuce.core.ZStoreArgs; +import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; +import io.lettuce.core.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.connection.lettuce.LettuceConnection.LettuceResult; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.KeyBoundCursor; +import org.springframework.data.redis.core.ScanIteration; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; + +/** + * @author Christoph Strobl + * @since 2.0 + */ +class LettuceZSetCommands implements RedisZSetCommands { + + private final LettuceConnection connection; + + public LettuceZSetCommands(LettuceConnection connection) { + this.connection = connection; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], double, byte[]) + */ + @Override + public Boolean zAdd(byte[] key, double score, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zadd(key, score, value), + LettuceConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().zadd(key, score, value), LettuceConverters.longToBoolean())); + return null; + } + return LettuceConverters.toBoolean(getConnection().zadd(key, score, value)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zAdd(byte[], java.util.Set) + */ + @Override + public Long zAdd(byte[] key, Set tuples) { + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()))); + return null; + } + return getConnection().zadd(key, LettuceConverters.toObjects(tuples).toArray()); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) + */ + @Override + public Long zCard(byte[] key) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zcard(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zcard(key))); + return null; + } + return getConnection().zcard(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zCount(byte[] key, Range range) { + + Assert.notNull(range, "Range for ZCOUNT must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zcount(key, LettuceConverters.toRange(range)))); + return null; + } + return getConnection().zcount(key, LettuceConverters.toRange(range)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zIncrBy(byte[], double, byte[]) + */ + @Override + public Double zIncrBy(byte[] key, double increment, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zincrby(key, increment, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zincrby(key, increment, value))); + return null; + } + return getConnection().zincrby(key, increment, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, storeArgs, sets))); + return null; + } + return getConnection().zinterstore(destKey, storeArgs, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, byte[]... sets) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, sets))); + return null; + } + return getConnection().zinterstore(destKey, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRange(byte[], long, long) + */ + @Override + public Set zRange(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().zrange(key, start, end)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeWithScores(byte[], long, long) + */ + @Override + public Set zRangeWithScores(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangeWithScores(key, start, end), + LettuceConverters.scoredValuesToTupleSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrangeWithScores(key, start, end), + LettuceConverters.scoredValuesToTupleSet())); + return null; + } + return LettuceConverters.toTupleSet(getConnection().zrangeWithScores(key, start, end)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), + LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); + } else { + pipeline( + connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (isQueueing()) { + if (limit != null) { + transaction(connection.newLettuceTxResult( + getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); + } else { + transaction( + connection.newLettuceTxResult(getConnection().zrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (limit != null) { + return LettuceConverters.toBytesSet( + getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } + return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(connection.newLettuceResult( + getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), + LettuceConverters.scoredValuesToTupleSet())); + } + return null; + } + if (isQueueing()) { + if (limit != null) { + transaction(connection.newLettuceTxResult(getConnection().zrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(connection.newLettuceTxResult( + getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), + LettuceConverters.scoredValuesToTupleSet())); + } + return null; + } + if (limit != null) { + return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } + return LettuceConverters + .toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range))); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) + */ + @Override + public Set zRevRangeWithScores(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangeWithScores(key, start, end), + LettuceConverters.scoredValuesToTupleSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrevrangeWithScores(key, start, end), + LettuceConverters.scoredValuesToTupleSet())); + return null; + } + return LettuceConverters.toTupleSet(getConnection().zrevrangeWithScores(key, start, end)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline( + connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), + LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); + } else { + pipeline( + connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (isQueueing()) { + if (limit != null) { + transaction(connection.newLettuceTxResult( + getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); + } else { + transaction( + connection.newLettuceTxResult(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (limit != null) { + return LettuceConverters.toBytesSet( + getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } + return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range))); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(connection.newLettuceResult( + getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), + LettuceConverters.scoredValuesToTupleSet())); + } + return null; + } + if (isQueueing()) { + if (limit != null) { + transaction(connection.newLettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(connection.newLettuceTxResult( + getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), + LettuceConverters.scoredValuesToTupleSet())); + } + return null; + } + if (limit != null) { + return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } + return LettuceConverters + .toTupleSet(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range))); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) + */ + @Override + public Long zRank(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrank(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrank(key, value))); + return null; + } + return getConnection().zrank(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) + */ + @Override + public Long zRem(byte[] key, byte[]... values) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrem(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrem(key, values))); + return null; + } + return getConnection().zrem(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) + */ + @Override + public Long zRemRange(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zremrangebyrank(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zremrangebyrank(key, start, end))); + return null; + } + return getConnection().zremrangebyrank(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + 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.newLettuceTxResult(getConnection().zremrangebyscore(key, LettuceConverters.toRange(range)))); + return null; + } + return getConnection().zremrangebyscore(key, LettuceConverters.toRange(range)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + */ + @Override + public Set zRevRange(byte[] key, long start, long end) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrevrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().zrevrange(key, start, end)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) + */ + @Override + public Long zRevRank(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrank(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrevrank(key, value))); + return null; + } + return getConnection().zrevrank(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) + */ + @Override + public Double zScore(byte[] key, byte[] value) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zscore(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zscore(key, value))); + return null; + } + return getConnection().zscore(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, storeArgs, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zunionstore(destKey, storeArgs, sets))); + return null; + } + return getConnection().zunionstore(destKey, storeArgs, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], byte[][]) + */ + @Override + public Long zUnionStore(byte[] destKey, byte[]... sets) { + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zunionstore(destKey, sets))); + return null; + } + return getConnection().zunionstore(destKey, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor zScan(byte[] key, ScanOptions options) { + return zScan(key, 0L, options); + } + + /** + * @since 1.4 + * @param key + * @param cursorId + * @param options + * @return + */ + public Cursor zScan(byte[] key, long cursorId, ScanOptions options) { + + return new KeyBoundCursor(key, cursorId, options) { + + @Override + protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode."); + } + + io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); + ScanArgs scanArgs = connection.getScanArgs(options); + + ScoredValueScanCursor scoredValueScanCursor = getConnection().zscan(key, scanCursor, scanArgs); + String nextCursorId = scoredValueScanCursor.getCursor(); + + List> result = scoredValueScanCursor.getValues(); + + List values = connection.failsafeReadScanValues(result, LettuceConverters.scoredValuesToTupleList()); + return new ScanIteration(Long.valueOf(nextCursorId), values); + } + + protected void doClose() { + LettuceZSetCommands.this.connection.close(); + } + + }.open(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max) { + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max), + LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrangebyscore(key, min, max), + LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, min, max)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], java.lang.String, java.lang.String, long, long) + */ + @Override + public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), + LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().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); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, Limit limit) { + + Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newLettuceResult( + getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); + } else { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (isQueueing()) { + if (limit != null) { + transaction(connection.newLettuceTxResult( + getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); + } else { + transaction(connection.newLettuceTxResult(getConnection().zrangebylex(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + + if (limit != null) { + return LettuceConverters.bytesListToBytesSet().convert( + getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } + + return LettuceConverters.bytesListToBytesSet() + .convert(getConnection().zrangebylex(key, LettuceConverters.toRange(range))); + } 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(LettuceTxResult result) { + connection.transaction(result); + } + + RedisClusterAsyncCommands getAsyncConnection() { + return connection.getAsyncConnection(); + } + + public RedisClusterCommands getConnection() { + return connection.getConnection(); + } + + private DataAccessException convertLettuceAccessException(Exception ex) { + return connection.convertLettuceAccessException(ex); + } + + private ZStoreArgs zStoreArgs(Aggregate aggregate, int[] weights) { + ZStoreArgs args = new ZStoreArgs(); + if (aggregate != null) { + switch (aggregate) { + case MIN: + args.min(); + break; + case MAX: + args.max(); + break; + default: + args.sum(); + break; + } + } + double[] lg = new double[weights.length]; + for (int i = 0; i < lg.length; i++) { + lg[i] = weights[i]; + } + args.weights(lg); + return args; + } + +} diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java index 5e050fbb6..1a58509ff 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionUnitTestSuite.java @@ -171,7 +171,7 @@ public class JedisConnectionUnitTestSuite { doReturn(new ScanResult("0", Collections. emptyList())).when(jedisSpy).scan(anyString(), any(ScanParams.class)); - connection.scan(); + connection.scan(ScanOptions.NONE); verify(jedisSpy, never()).quit(); } @@ -182,7 +182,7 @@ public class JedisConnectionUnitTestSuite { doReturn(new ScanResult("0", Collections. emptyList())).when(jedisSpy).scan(anyString(), any(ScanParams.class)); - Cursor cursor = connection.scan(); + Cursor cursor = connection.scan(ScanOptions.NONE); cursor.close(); verify(jedisSpy, times(1)).quit();