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();