Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.redisson.spring.data.connection.RedissonConnection Maven / Gradle / Ivy
/**
* Copyright (c) 2013-2024 Nikita Koksharov
*
* 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.redisson.spring.data.connection;
import org.redisson.Redisson;
import org.redisson.api.BatchOptions;
import org.redisson.api.BatchOptions.ExecutionMode;
import org.redisson.api.BatchResult;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.client.codec.*;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.client.protocol.convertor.*;
import org.redisson.client.protocol.decoder.*;
import org.redisson.command.BatchPromise;
import org.redisson.command.CommandAsyncService;
import org.redisson.command.CommandBatchService;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.misc.CompletableFutureWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.geo.*;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.core.*;
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.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.redisson.client.protocol.RedisCommands.LRANGE;
/**
* Redisson connection
*
* @author Nikita Koksharov
*
*/
public class RedissonConnection extends AbstractRedisConnection {
private boolean closed;
protected final Redisson redisson;
CommandAsyncService executorService;
private RedissonSubscription subscription;
public RedissonConnection(RedissonClient redisson) {
super();
this.redisson = (Redisson) redisson;
executorService = (CommandAsyncService) this.redisson.getCommandExecutor();
}
@Override
public void close() throws DataAccessException {
super.close();
if (isQueueing()) {
CommandBatchService es = (CommandBatchService) executorService;
if (!es.isExecuted()) {
discard();
}
}
closed = true;
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public Object getNativeConnection() {
return redisson;
}
@Override
public boolean isQueueing() {
if (executorService instanceof CommandBatchService) {
CommandBatchService es = (CommandBatchService) executorService;
return es.getOptions().getExecutionMode() == ExecutionMode.REDIS_WRITE_ATOMIC;
}
return false;
}
@Override
public boolean isPipelined() {
if (executorService instanceof CommandBatchService) {
CommandBatchService es = (CommandBatchService) executorService;
return es.getOptions().getExecutionMode() == ExecutionMode.IN_MEMORY || es.getOptions().getExecutionMode() == ExecutionMode.IN_MEMORY_ATOMIC;
}
return false;
}
public boolean isPipelinedAtomic() {
if (executorService instanceof CommandBatchService) {
CommandBatchService es = (CommandBatchService) executorService;
return es.getOptions().getExecutionMode() == ExecutionMode.IN_MEMORY_ATOMIC;
}
return false;
}
@Override
public void openPipeline() {
BatchOptions options = BatchOptions.defaults()
.executionMode(ExecutionMode.IN_MEMORY);
this.executorService = executorService.createCommandBatchService(options);
}
@Override
public List closePipeline() throws RedisPipelineException {
if (isPipelined()) {
CommandBatchService es = (CommandBatchService) executorService;
try {
BatchResult> result = es.execute();
filterResults(result);
if (isPipelinedAtomic()) {
return Arrays.asList((List) result.getResponses());
}
return (List) result.getResponses();
} catch (Exception ex) {
throw new RedisPipelineException(ex);
} finally {
resetConnection();
}
}
return Collections.emptyList();
}
@Override
public Object execute(String command, byte[]... args) {
for (Method method : this.getClass().getDeclaredMethods()) {
if (method.getName().equalsIgnoreCase(command)
&& Modifier.isPublic(method.getModifiers())
&& (method.getParameterTypes().length == args.length)) {
try {
Object t = execute(method, args);
if (t instanceof String) {
return ((String) t).getBytes();
}
return t;
} catch (IllegalArgumentException e) {
if (isPipelined()) {
throw new RedisPipelineException(e);
}
throw new InvalidDataAccessApiUsageException(e.getMessage(), e);
}
}
}
throw new UnsupportedOperationException();
}
private Object execute(Method method, byte[]... args) {
if (method.getParameterTypes().length > 0 && method.getParameterTypes()[0] == byte[][].class) {
return ReflectionUtils.invokeMethod(method, this, args);
}
if (args == null) {
return ReflectionUtils.invokeMethod(method, this);
}
return ReflectionUtils.invokeMethod(method, this, Arrays.asList(args).toArray());
}
V syncFuture(RFuture future) {
try {
return executorService.get(future);
} catch (Exception ex) {
throw transform(ex);
}
}
protected RuntimeException transform(Exception ex) {
DataAccessException exception = RedissonConnectionFactory.EXCEPTION_TRANSLATION.translate(ex);
if (exception != null) {
return exception;
}
return new RedisSystemException(ex.getMessage(), ex);
}
@Override
public Boolean exists(byte[] key) {
return read(key, StringCodec.INSTANCE, RedisCommands.EXISTS, key);
}
@Override
public Long del(byte[]... keys) {
return write(keys[0], LongCodec.INSTANCE, RedisCommands.DEL, Arrays.asList(keys).toArray());
}
@Override
public Long unlink(byte[]... keys) {
return write(keys[0], LongCodec.INSTANCE, RedisCommands.UNLINK, Arrays.asList(keys).toArray());
}
private static final RedisStrictCommand TYPE = new RedisStrictCommand("TYPE", new DataTypeConvertor());
@Override
public DataType type(byte[] key) {
return read(key, StringCodec.INSTANCE, TYPE, key);
}
private static final RedisStrictCommand> KEYS = new RedisStrictCommand>("KEYS", new ObjectSetReplayDecoder());
@Override
public Set keys(byte[] pattern) {
if (isQueueing()) {
return read(null, ByteArrayCodec.INSTANCE, KEYS, pattern);
}
List>> futures = executorService.readAllAsync(ByteArrayCodec.INSTANCE, KEYS, pattern);
CompletableFuture ff = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
CompletableFuture> future = ff.thenApply(r -> {
return futures.stream().flatMap(f -> f.getNow(new HashSet<>()).stream()).collect(Collectors.toSet());
}).toCompletableFuture();
return sync(new CompletableFutureWrapper<>(future));
}
@Override
public Cursor scan(ScanOptions options) {
return new ScanCursor(0, options) {
private RedisClient client;
private Iterator entries = redisson.getConnectionManager().getEntrySet().iterator();
private MasterSlaveEntry entry = entries.next();
@Override
protected ScanIteration doScan(long cursorId, ScanOptions options) {
if (isQueueing() || isPipelined()) {
throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode.");
}
if (entry == null) {
return null;
}
List args = new ArrayList();
if (cursorId == 101010101010101010L) {
cursorId = 0;
}
args.add(Long.toUnsignedString(cursorId));
if (options.getPattern() != null) {
args.add("MATCH");
args.add(options.getPattern());
}
if (options.getCount() != null) {
args.add("COUNT");
args.add(options.getCount());
}
RFuture> f = executorService.readAsync(client, entry, ByteArrayCodec.INSTANCE, RedisCommands.SCAN, args.toArray());
ListScanResult res = syncFuture(f);
String pos = res.getPos();
client = res.getRedisClient();
if ("0".equals(pos)) {
if (entries.hasNext()) {
pos = "101010101010101010";
entry = entries.next();
client = null;
} else {
entry = null;
}
}
return new ScanIteration(Long.parseUnsignedLong(pos), res.getValues());
}
}.open();
}
@Override
public byte[] randomKey() {
if (isQueueing()) {
return read(null, ByteArrayCodec.INSTANCE, RedisCommands.RANDOM_KEY);
}
RFuture f = executorService.readRandomAsync(ByteArrayCodec.INSTANCE, RedisCommands.RANDOM_KEY);
return sync(f);
}
@Override
public void rename(byte[] oldName, byte[] newName) {
write(oldName, StringCodec.INSTANCE, RedisCommands.RENAME, oldName, newName);
}
@Override
public Boolean renameNX(byte[] oldName, byte[] newName) {
return write(oldName, StringCodec.INSTANCE, RedisCommands.RENAMENX, oldName, newName);
}
private static final RedisStrictCommand EXPIRE = new RedisStrictCommand("EXPIRE", new BooleanReplayConvertor());
@Override
public Boolean expire(byte[] key, long seconds) {
return write(key, StringCodec.INSTANCE, EXPIRE, key, seconds);
}
@Override
public Boolean pExpire(byte[] key, long millis) {
return write(key, StringCodec.INSTANCE, RedisCommands.PEXPIRE, key, millis);
}
private static final RedisStrictCommand EXPIREAT = new RedisStrictCommand("EXPIREAT", new BooleanReplayConvertor());
@Override
public Boolean expireAt(byte[] key, long unixTime) {
return write(key, StringCodec.INSTANCE, EXPIREAT, key, unixTime);
}
@Override
public Boolean pExpireAt(byte[] key, long unixTimeInMillis) {
return write(key, StringCodec.INSTANCE, RedisCommands.PEXPIREAT, key, unixTimeInMillis);
}
@Override
public Boolean persist(byte[] key) {
return write(key, StringCodec.INSTANCE, RedisCommands.PERSIST, key);
}
@Override
public Boolean move(byte[] key, int dbIndex) {
return write(key, StringCodec.INSTANCE, RedisCommands.MOVE, key, dbIndex);
}
private static final RedisStrictCommand TTL = new RedisStrictCommand("TTL");
@Override
public Long ttl(byte[] key) {
return read(key, StringCodec.INSTANCE, TTL, key);
}
protected T sync(RFuture f) {
if (isPipelined()) {
return null;
}
if (isQueueing()) {
((BatchPromise)f.toCompletableFuture()).getSentPromise().join();
return null;
}
return syncFuture(f);
}
@Override
public Long ttl(byte[] key, TimeUnit timeUnit) {
return read(key, StringCodec.INSTANCE, new RedisStrictCommand("TTL", new SecondsConvertor(timeUnit, TimeUnit.SECONDS)), key);
}
@Override
public Long pTtl(byte[] key) {
return read(key, StringCodec.INSTANCE, RedisCommands.PTTL, key);
}
@Override
public Long pTtl(byte[] key, TimeUnit timeUnit) {
return read(key, StringCodec.INSTANCE, new RedisStrictCommand("PTTL", new SecondsConvertor(timeUnit, TimeUnit.MILLISECONDS)), key);
}
@Override
public List sort(byte[] key, SortParameters sortParams) {
List params = new ArrayList();
params.add(key);
if (sortParams != null) {
if (sortParams.getByPattern() != null) {
params.add("BY");
params.add(sortParams.getByPattern());
}
if (sortParams.getLimit() != null) {
params.add("LIMIT");
if (sortParams.getLimit().getStart() != -1) {
params.add(sortParams.getLimit().getStart());
}
if (sortParams.getLimit().getCount() != -1) {
params.add(sortParams.getLimit().getCount());
}
}
if (sortParams.getGetPattern() != null) {
for (byte[] pattern : sortParams.getGetPattern()) {
params.add("GET");
params.add(pattern);
}
}
if (sortParams.getOrder() != null) {
params.add(sortParams.getOrder());
}
Boolean isAlpha = sortParams.isAlphabetic();
if (isAlpha != null && isAlpha) {
params.add("ALPHA");
}
}
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.SORT_LIST, params.toArray());
}
private static final RedisCommand SORT_TO = new RedisCommand("SORT");
@Override
public Long sort(byte[] key, SortParameters sortParams, byte[] storeKey) {
List params = new ArrayList();
params.add(key);
if (sortParams != null) {
if (sortParams.getByPattern() != null) {
params.add("BY");
params.add(sortParams.getByPattern());
}
if (sortParams.getLimit() != null) {
params.add("LIMIT");
if (sortParams.getLimit().getStart() != -1) {
params.add(sortParams.getLimit().getStart());
}
if (sortParams.getLimit().getCount() != -1) {
params.add(sortParams.getLimit().getCount());
}
}
if (sortParams.getGetPattern() != null) {
for (byte[] pattern : sortParams.getGetPattern()) {
params.add("GET");
params.add(pattern);
}
}
if (sortParams.getOrder() != null) {
params.add(sortParams.getOrder());
}
Boolean isAlpha = sortParams.isAlphabetic();
if (isAlpha != null && isAlpha) {
params.add("ALPHA");
}
}
params.add("STORE");
params.add(storeKey);
return read(key, ByteArrayCodec.INSTANCE, SORT_TO, params.toArray());
}
@Override
public byte[] dump(byte[] key) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.DUMP, key);
}
@Override
public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) {
write(key, StringCodec.INSTANCE, RedisCommands.RESTORE, key, ttlInMillis, serializedValue);
}
@Override
public byte[] get(byte[] key) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.GET, key);
}
@Override
public byte[] getSet(byte[] key, byte[] value) {
return write(key, ByteArrayCodec.INSTANCE, RedisCommands.GETSET, key, value);
}
private static final RedisCommand> MGET = new RedisCommand>("MGET", new ObjectListReplayDecoder());
@Override
public List mGet(byte[]... keys) {
return read(keys[0], ByteArrayCodec.INSTANCE, MGET, Arrays.asList(keys).toArray());
}
private static final RedisCommand SET = new RedisCommand<>("SET", new BooleanNullSafeReplayConvertor());
@Override
public Boolean set(byte[] key, byte[] value) {
return write(key, StringCodec.INSTANCE, SET, key, value);
}
@Override
public Boolean set(byte[] key, byte[] value, Expiration expiration, SetOption option) {
if (expiration == null) {
return set(key, value);
} else if (expiration.isPersistent()) {
if (option == null || option == SetOption.UPSERT) {
return set(key, value);
}
if (option == SetOption.SET_IF_ABSENT) {
return write(key, StringCodec.INSTANCE, SET, key, value, "NX");
}
if (option == SetOption.SET_IF_PRESENT) {
return write(key, StringCodec.INSTANCE, SET, key, value, "XX");
}
} else {
if (option == null || option == SetOption.UPSERT) {
return write(key, StringCodec.INSTANCE, SET, key, value, "PX", expiration.getExpirationTimeInMilliseconds());
}
if (option == SetOption.SET_IF_ABSENT) {
return write(key, StringCodec.INSTANCE, SET, key, value, "PX", expiration.getExpirationTimeInMilliseconds(), "NX");
}
if (option == SetOption.SET_IF_PRESENT) {
return write(key, StringCodec.INSTANCE, SET, key, value, "PX", expiration.getExpirationTimeInMilliseconds(), "XX");
}
}
throw new IllegalArgumentException();
}
@Override
public Boolean setNX(byte[] key, byte[] value) {
return write(key, StringCodec.INSTANCE, RedisCommands.SETNX, key, value);
}
private static final RedisCommand SETEX = new RedisCommand("SETEX", new BooleanReplayConvertor());
@Override
public Boolean setEx(byte[] key, long seconds, byte[] value) {
return write(key, StringCodec.INSTANCE, SETEX, key, seconds, value);
}
private static final RedisCommand PSETEX = new RedisCommand("PSETEX", new BooleanReplayConvertor());
@Override
public Boolean pSetEx(byte[] key, long milliseconds, byte[] value) {
return write(key, StringCodec.INSTANCE, PSETEX, key, milliseconds, value);
}
private static final RedisCommand MSET = new RedisCommand("MSET", new BooleanReplayConvertor());
@Override
public Boolean mSet(Map tuple) {
List params = convert(tuple);
return write(tuple.keySet().iterator().next(), StringCodec.INSTANCE, MSET, params.toArray());
}
protected List convert(Map tuple) {
List params = new ArrayList(tuple.size()*2);
for (Entry entry : tuple.entrySet()) {
params.add(entry.getKey());
params.add(entry.getValue());
}
return params;
}
@Override
public Boolean mSetNX(Map tuple) {
List params = convert(tuple);
return write(tuple.keySet().iterator().next(), StringCodec.INSTANCE, RedisCommands.MSETNX, params.toArray());
}
@Override
public Long incr(byte[] key) {
return write(key, StringCodec.INSTANCE, RedisCommands.INCR, key);
}
@Override
public Long incrBy(byte[] key, long value) {
return write(key, StringCodec.INSTANCE, RedisCommands.INCRBY, key, value);
}
@Override
public Double incrBy(byte[] key, double value) {
return write(key, StringCodec.INSTANCE, RedisCommands.INCRBYFLOAT, key, BigDecimal.valueOf(value).toPlainString());
}
@Override
public Long decr(byte[] key) {
return write(key, StringCodec.INSTANCE, RedisCommands.DECR, key);
}
private static final RedisStrictCommand DECRBY = new RedisStrictCommand("DECRBY");
@Override
public Long decrBy(byte[] key, long value) {
return write(key, StringCodec.INSTANCE, DECRBY, key, value);
}
private static final RedisStrictCommand APPEND = new RedisStrictCommand("APPEND");
@Override
public Long append(byte[] key, byte[] value) {
return write(key, StringCodec.INSTANCE, APPEND, key, value);
}
private static final RedisCommand GETRANGE = new RedisCommand("GETRANGE");
@Override
public byte[] getRange(byte[] key, long begin, long end) {
return read(key, ByteArrayCodec.INSTANCE, GETRANGE, key, begin, end);
}
private static final RedisCommand SETRANGE = new RedisCommand("SETRANGE", new VoidReplayConvertor());
@Override
public void setRange(byte[] key, byte[] value, long offset) {
write(key, ByteArrayCodec.INSTANCE, SETRANGE, key, offset, value);
}
@Override
public Boolean getBit(byte[] key, long offset) {
return read(key, StringCodec.INSTANCE, RedisCommands.GETBIT, key, offset);
}
@Override
public Boolean setBit(byte[] key, long offset, boolean value) {
return write(key, StringCodec.INSTANCE, RedisCommands.SETBIT, key, offset, value ? 1 : 0);
}
@Override
public Long bitCount(byte[] key) {
return read(key, StringCodec.INSTANCE, RedisCommands.BITCOUNT, key);
}
@Override
public Long bitCount(byte[] key, long begin, long end) {
return read(key, StringCodec.INSTANCE, RedisCommands.BITCOUNT, key, begin, end);
}
private static final RedisStrictCommand BITOP = new RedisStrictCommand("BITOP");
@Override
public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) {
if (op == BitOperation.NOT && keys.length > 1) {
throw new UnsupportedOperationException("NOT operation doesn't support more than single source key");
}
List params = new ArrayList(keys.length + 2);
params.add(op);
params.add(destination);
params.addAll(Arrays.asList(keys));
return write(keys[0], StringCodec.INSTANCE, BITOP, params.toArray());
}
@Override
public Long strLen(byte[] key) {
return read(key, StringCodec.INSTANCE, RedisCommands.STRLEN, key);
}
private static final RedisStrictCommand RPUSH = new RedisStrictCommand("RPUSH");
@Override
public Long rPush(byte[] key, byte[]... values) {
List args = new ArrayList(values.length + 1);
args.add(key);
args.addAll(Arrays.asList(values));
return write(key, StringCodec.INSTANCE, RPUSH, args.toArray());
}
private static final RedisStrictCommand LPUSH = new RedisStrictCommand("LPUSH");
@Override
public Long lPush(byte[] key, byte[]... values) {
List args = new ArrayList(values.length + 1);
args.add(key);
args.addAll(Arrays.asList(values));
return write(key, StringCodec.INSTANCE, LPUSH, args.toArray());
}
private static final RedisStrictCommand RPUSHX = new RedisStrictCommand("RPUSHX");
@Override
public Long rPushX(byte[] key, byte[] value) {
return write(key, StringCodec.INSTANCE, RPUSHX, key, value);
}
private static final RedisStrictCommand LPUSHX = new RedisStrictCommand("LPUSHX");
@Override
public Long lPushX(byte[] key, byte[] value) {
return write(key, StringCodec.INSTANCE, LPUSHX, key, value);
}
private static final RedisStrictCommand LLEN = new RedisStrictCommand("LLEN");
@Override
public Long lLen(byte[] key) {
return read(key, StringCodec.INSTANCE, LLEN, key);
}
@Override
public List lRange(byte[] key, long start, long end) {
return read(key, ByteArrayCodec.INSTANCE, LRANGE, key, start, end);
}
@Override
public void lTrim(byte[] key, long start, long end) {
write(key, StringCodec.INSTANCE, RedisCommands.LTRIM, key, start, end);
}
@Override
public byte[] lIndex(byte[] key, long index) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.LINDEX, key, index);
}
private static final RedisStrictCommand LINSERT = new RedisStrictCommand("LINSERT");
@Override
public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) {
return write(key, StringCodec.INSTANCE, LINSERT, key, where, pivot, value);
}
private final List commandsToRemove = Arrays.asList("SET",
"RESTORE", "LTRIM", "SETEX", "SETRANGE", "FLUSHDB", "LSET", "MSET", "HMSET", "RENAME");
private final List indexToRemove = new ArrayList();
private int index = -1;
T write(byte[] key, Codec codec, RedisCommand> command, Object... params) {
RFuture f = executorService.writeAsync(key, codec, command, params);
indexCommand(command);
return sync(f);
}
protected void indexCommand(RedisCommand> command) {
if (isQueueing() || isPipelined()) {
index++;
if (commandsToRemove.contains(command.getName())) {
indexToRemove.add(index);
}
}
}
T read(byte[] key, Codec codec, RedisCommand> command, Object... params) {
RFuture f = executorService.readAsync(key, codec, command, params);
indexCommand(command);
return sync(f);
}
@Override
public void lSet(byte[] key, long index, byte[] value) {
write(key, StringCodec.INSTANCE, RedisCommands.LSET, key, index, value);
}
private static final RedisStrictCommand LREM = new RedisStrictCommand("LREM");
@Override
public Long lRem(byte[] key, long count, byte[] value) {
return write(key, StringCodec.INSTANCE, LREM, key, count, value);
}
@Override
public byte[] lPop(byte[] key) {
return write(key, ByteArrayCodec.INSTANCE, RedisCommands.LPOP, key);
}
@Override
public byte[] rPop(byte[] key) {
return write(key, ByteArrayCodec.INSTANCE, RedisCommands.RPOP, key);
}
@Override
public List bLPop(int timeout, byte[]... keys) {
List params = new ArrayList(keys.length + 1);
params.addAll(Arrays.asList(keys));
params.add(timeout);
return write(keys[0], ByteArrayCodec.INSTANCE, RedisCommands.BLPOP, params.toArray());
}
@Override
public List bRPop(int timeout, byte[]... keys) {
List params = new ArrayList(keys.length + 1);
params.addAll(Arrays.asList(keys));
params.add(timeout);
return write(keys[0], ByteArrayCodec.INSTANCE, RedisCommands.BRPOP, params.toArray());
}
@Override
public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) {
return write(srcKey, ByteArrayCodec.INSTANCE, RedisCommands.RPOPLPUSH, srcKey, dstKey);
}
@Override
public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) {
return write(srcKey, ByteArrayCodec.INSTANCE, RedisCommands.BRPOPLPUSH, srcKey, dstKey, timeout);
}
private static final RedisCommand> LPOS = new RedisCommand<>("LPOS", new ObjectListReplayDecoder<>());
@Override
public List lPos(byte[] key, byte[] element, Integer rank, Integer count) {
List args = new ArrayList<>();
args.add(key);
args.add(element);
if (rank != null) {
args.add("RANK");
args.add(rank);
}
if (count != null) {
args.add("COUNT");
args.add(count);
}
Object read = read(key, ByteArrayCodec.INSTANCE, LPOS, args.toArray());
if (read == null) {
return Collections.emptyList();
} else if (read instanceof Long) {
return Collections.singletonList((Long) read);
} else {
return (List) read;
}
}
private static final RedisCommand SADD = new RedisCommand("SADD");
@Override
public Long sAdd(byte[] key, byte[]... values) {
List args = new ArrayList(values.length + 1);
args.add(key);
args.addAll(Arrays.asList(values));
return write(key, StringCodec.INSTANCE, SADD, args.toArray());
}
private static final RedisStrictCommand SREM = new RedisStrictCommand("SREM");
@Override
public Long sRem(byte[] key, byte[]... values) {
List args = new ArrayList(values.length + 1);
args.add(key);
args.addAll(Arrays.asList(values));
return write(key, StringCodec.INSTANCE, SREM, args.toArray());
}
@Override
public byte[] sPop(byte[] key) {
return write(key, ByteArrayCodec.INSTANCE, RedisCommands.SPOP_SINGLE, key);
}
private static final RedisCommand> SPOP = new RedisCommand>("SPOP", new ObjectListReplayDecoder());
@Override
public List sPop(byte[] key, long count) {
return write(key, ByteArrayCodec.INSTANCE, SPOP, key, count);
}
@Override
public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) {
return write(srcKey, StringCodec.INSTANCE, RedisCommands.SMOVE, srcKey, destKey, value);
}
private static final RedisStrictCommand SCARD = new RedisStrictCommand("SCARD");
@Override
public Long sCard(byte[] key) {
return read(key, StringCodec.INSTANCE, SCARD, key);
}
@Override
public Boolean sIsMember(byte[] key, byte[] value) {
return read(key, StringCodec.INSTANCE, RedisCommands.SISMEMBER, key, value);
}
@Override
public Set sInter(byte[]... keys) {
return write(keys[0], ByteArrayCodec.INSTANCE, RedisCommands.SINTER, Arrays.asList(keys).toArray());
}
@Override
public Long sInterStore(byte[] destKey, byte[]... keys) {
List args = new ArrayList(keys.length + 1);
args.add(destKey);
args.addAll(Arrays.asList(keys));
return write(keys[0], StringCodec.INSTANCE, RedisCommands.SINTERSTORE, args.toArray());
}
@Override
public Set sUnion(byte[]... keys) {
return write(keys[0], ByteArrayCodec.INSTANCE, RedisCommands.SUNION, Arrays.asList(keys).toArray());
}
@Override
public Long sUnionStore(byte[] destKey, byte[]... keys) {
List args = new ArrayList(keys.length + 1);
args.add(destKey);
args.addAll(Arrays.asList(keys));
return write(keys[0], StringCodec.INSTANCE, RedisCommands.SUNIONSTORE, args.toArray());
}
@Override
public Set sDiff(byte[]... keys) {
return write(keys[0], ByteArrayCodec.INSTANCE, RedisCommands.SDIFF, Arrays.asList(keys).toArray());
}
@Override
public Long sDiffStore(byte[] destKey, byte[]... keys) {
List args = new ArrayList(keys.length + 1);
args.add(destKey);
args.addAll(Arrays.asList(keys));
return write(keys[0], StringCodec.INSTANCE, RedisCommands.SDIFFSTORE, args.toArray());
}
@Override
public Set sMembers(byte[] key) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.SMEMBERS, key);
}
@Override
public byte[] sRandMember(byte[] key) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.SRANDMEMBER_SINGLE, key);
}
private static final RedisCommand> SRANDMEMBER = new RedisCommand<>("SRANDMEMBER", new ObjectListReplayDecoder<>());
@Override
public List sRandMember(byte[] key, long count) {
return read(key, ByteArrayCodec.INSTANCE, SRANDMEMBER, key, count);
}
@Override
public Cursor sScan(byte[] key, ScanOptions options) {
return new KeyBoundCursor(key, 0, options) {
private RedisClient client;
@Override
protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) {
if (isQueueing() || isPipelined()) {
throw new UnsupportedOperationException("'SSCAN' cannot be called in pipeline / transaction mode.");
}
List args = new ArrayList();
args.add(key);
args.add(Long.toUnsignedString(cursorId));
if (options.getPattern() != null) {
args.add("MATCH");
args.add(options.getPattern());
}
if (options.getCount() != null) {
args.add("COUNT");
args.add(options.getCount());
}
RFuture> f = executorService.readAsync(client, key, ByteArrayCodec.INSTANCE, RedisCommands.SSCAN, args.toArray());
ListScanResult res = syncFuture(f);
client = res.getRedisClient();
return new ScanIteration(Long.parseUnsignedLong(res.getPos()), res.getValues());
}
}.open();
}
@Override
public Boolean zAdd(byte[] key, double score, byte[] value) {
return write(key, StringCodec.INSTANCE, RedisCommands.ZADD_BOOL, key, BigDecimal.valueOf(score).toPlainString(), value);
}
@Override
public Long zAdd(byte[] key, Set tuples) {
List params = new ArrayList(tuples.size()*2+1);
params.add(key);
for (Tuple entry : tuples) {
params.add(BigDecimal.valueOf(entry.getScore()).toPlainString());
params.add(entry.getValue());
}
return write(key, StringCodec.INSTANCE, RedisCommands.ZADD, params.toArray());
}
@Override
public Long zRem(byte[] key, byte[]... values) {
List params = new ArrayList(values.length+1);
params.add(key);
params.addAll(Arrays.asList(values));
return write(key, StringCodec.INSTANCE, RedisCommands.ZREM_LONG, params.toArray());
}
@Override
public Double zIncrBy(byte[] key, double increment, byte[] value) {
return write(key, DoubleCodec.INSTANCE, RedisCommands.ZINCRBY,
key, new BigDecimal(increment).toPlainString(), value);
}
@Override
public Long zRank(byte[] key, byte[] value) {
return read(key, StringCodec.INSTANCE, RedisCommands.ZRANK, key, value);
}
@Override
public Long zRevRank(byte[] key, byte[] value) {
return read(key, StringCodec.INSTANCE, RedisCommands.ZREVRANK, key, value);
}
private static final RedisCommand> ZRANGE = new RedisCommand>("ZRANGE", new ObjectSetReplayDecoder());
@Override
public Set zRange(byte[] key, long start, long end) {
return read(key, ByteArrayCodec.INSTANCE, ZRANGE, key, start, end);
}
private static final RedisCommand> ZRANGE_ENTRY = new RedisCommand>("ZRANGE", new ScoredSortedSetReplayDecoder());
private static final RedisCommand> ZRANGE_ENTRY_V2 = new RedisCommand>("ZRANGE",
new ListMultiDecoder2(new ObjectSetReplayDecoder(), new ScoredSortedSetReplayDecoderV2()));
@Override
public Set zRangeWithScores(byte[] key, long start, long end) {
if (executorService.getServiceManager().isResp3()) {
return read(key, ByteArrayCodec.INSTANCE, ZRANGE_ENTRY_V2, key, start, end, "WITHSCORES");
}
return read(key, ByteArrayCodec.INSTANCE, ZRANGE_ENTRY, key, start, end, "WITHSCORES");
}
private String value(Range.Boundary boundary, String defaultValue) {
if (boundary == null) {
return defaultValue;
}
Object score = boundary.getValue();
if (score == null) {
return defaultValue;
}
StringBuilder element = new StringBuilder();
if (!boundary.isIncluding()) {
element.append("(");
} else {
if (!(score instanceof Double)) {
element.append("[");
}
}
if (score instanceof Double) {
if (Double.isInfinite((Double) score)) {
element.append((Double)score > 0 ? "+inf" : "-inf");
} else {
element.append(BigDecimal.valueOf((Double)score).toPlainString());
}
} else {
element.append(score);
}
return element.toString();
}
@Override
public Set zRangeByScore(byte[] key, double min, double max) {
return zRangeByScore(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, double min, double max) {
return zRangeByScoreWithScores(key, new Range().gte(min).lte(max));
}
@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()));
}
private static final RedisCommand> ZRANGEBYSCORE = new RedisCommand>("ZRANGEBYSCORE", new ScoredSortedSetReplayDecoder());
private static final RedisCommand> ZRANGEBYSCORE_V2 = new RedisCommand>("ZRANGEBYSCORE",
new ListMultiDecoder2(new ObjectSetReplayDecoder(), new ScoredSortedSetReplayDecoderV2()));
@Override
public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
List args = new ArrayList();
args.add(key);
args.add(min);
args.add(max);
args.add("WITHSCORES");
if (limit != null) {
args.add("LIMIT");
args.add(limit.getOffset());
args.add(limit.getCount());
}
if (executorService.getServiceManager().isResp3()) {
return read(key, ByteArrayCodec.INSTANCE, ZRANGEBYSCORE_V2, args.toArray());
}
return read(key, ByteArrayCodec.INSTANCE, ZRANGEBYSCORE, args.toArray());
}
private static final RedisCommand> ZREVRANGE = new RedisCommand>("ZREVRANGE", new ObjectSetReplayDecoder());
@Override
public Set zRevRange(byte[] key, long start, long end) {
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGE, key, start, end);
}
private static final RedisCommand> ZREVRANGE_ENTRY = new RedisCommand>("ZREVRANGE", new ScoredSortedSetReplayDecoder());
private static final RedisCommand> ZREVRANGE_ENTRY_V2 = new RedisCommand("ZREVRANGE",
new ListMultiDecoder2(new ObjectSetReplayDecoder(), new ScoredSortedSetReplayDecoderV2()));
@Override
public Set zRevRangeWithScores(byte[] key, long start, long end) {
if (executorService.getServiceManager().isResp3()) {
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGE_ENTRY_V2, key, start, end, "WITHSCORES");
}
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGE_ENTRY, key, start, end, "WITHSCORES");
}
@Override
public Set zRevRangeByScore(byte[] key, double min, double max) {
return zRevRangeByScore(key, new Range().gte(min).lte(max));
}
private static final RedisCommand> ZREVRANGEBYSCORE = new RedisCommand>("ZREVRANGEBYSCORE", new ObjectSetReplayDecoder());
private static final RedisCommand> ZREVRANGEBYSCOREWITHSCORES = new RedisCommand>("ZREVRANGEBYSCORE", new ScoredSortedSetReplayDecoder());
private static final RedisCommand> ZREVRANGEBYSCOREWITHSCORES_V2 = new RedisCommand>("ZREVRANGEBYSCORE",
new ListMultiDecoder2(new ObjectSetReplayDecoder(), new ScoredSortedSetReplayDecoderV2()));
@Override
public Set zRevRangeByScore(byte[] key, Range range) {
return zRevRangeByScore(key, range, null);
}
@Override
public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) {
return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max));
}
@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, Limit limit) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
List args = new ArrayList();
args.add(key);
args.add(max);
args.add(min);
if (limit != null) {
args.add("LIMIT");
args.add(limit.getOffset());
args.add(limit.getCount());
}
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGEBYSCORE, args.toArray());
}
@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) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
List args = new ArrayList();
args.add(key);
args.add(max);
args.add(min);
args.add("WITHSCORES");
if (limit != null) {
args.add("LIMIT");
args.add(limit.getOffset());
args.add(limit.getCount());
}
if (executorService.getServiceManager().isResp3()) {
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGEBYSCOREWITHSCORES_V2, args.toArray());
}
return read(key, ByteArrayCodec.INSTANCE, ZREVRANGEBYSCOREWITHSCORES, args.toArray());
}
@Override
public Long zCount(byte[] key, double min, double max) {
return zCount(key, new Range().gte(min).lte(max));
}
private static final RedisStrictCommand ZCOUNT = new RedisStrictCommand("ZCOUNT");
@Override
public Long zCount(byte[] key, Range range) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
return read(key, StringCodec.INSTANCE, ZCOUNT, key, min, max);
}
@Override
public Long zCard(byte[] key) {
return read(key, StringCodec.INSTANCE, RedisCommands.ZCARD, key);
}
@Override
public Double zScore(byte[] key, byte[] value) {
return read(key, StringCodec.INSTANCE, RedisCommands.ZSCORE, key, value);
}
private static final RedisStrictCommand ZREMRANGEBYRANK = new RedisStrictCommand("ZREMRANGEBYRANK");
private static final RedisStrictCommand ZREMRANGEBYSCORE = new RedisStrictCommand("ZREMRANGEBYSCORE");
@Override
public Long zRemRange(byte[] key, long start, long end) {
return write(key, StringCodec.INSTANCE, ZREMRANGEBYRANK, key, start, end);
}
@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) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
return write(key, StringCodec.INSTANCE, ZREMRANGEBYSCORE, key, min, max);
}
@Override
public Long zUnionStore(byte[] destKey, byte[]... sets) {
return zUnionStore(destKey, null, (Weights)null, sets);
}
private static final RedisStrictCommand ZUNIONSTORE = new RedisStrictCommand("ZUNIONSTORE");
@Override
public Long zUnionStore(byte[] destKey, Aggregate aggregate, Weights weights, byte[]... sets) {
List args = new ArrayList(sets.length*2 + 5);
args.add(destKey);
args.add(sets.length);
args.addAll(Arrays.asList(sets));
if (weights != null) {
args.add("WEIGHTS");
for (double weight : weights.toArray()) {
args.add(BigDecimal.valueOf(weight).toPlainString());
}
}
if (aggregate != null) {
args.add("AGGREGATE");
args.add(aggregate.name());
}
return write(destKey, LongCodec.INSTANCE, ZUNIONSTORE, args.toArray());
}
private static final RedisStrictCommand ZINTERSTORE = new RedisStrictCommand("ZINTERSTORE");
@Override
public Long zInterStore(byte[] destKey, byte[]... sets) {
return zInterStore(destKey, null, (Weights)null, sets);
}
@Override
public Long zInterStore(byte[] destKey, Aggregate aggregate, Weights weights, byte[]... sets) {
List args = new ArrayList(sets.length*2 + 5);
args.add(destKey);
args.add(sets.length);
args.addAll(Arrays.asList(sets));
if (weights != null) {
args.add("WEIGHTS");
for (double weight : weights.toArray()) {
args.add(BigDecimal.valueOf(weight).toPlainString());
}
}
if (aggregate != null) {
args.add("AGGREGATE");
args.add(aggregate.name());
}
return write(destKey, StringCodec.INSTANCE, ZINTERSTORE, args.toArray());
}
private static final RedisCommand> ZSCAN = new RedisCommand<>("ZSCAN", new ListMultiDecoder2(new ListScanResultReplayDecoder(), new ScoredSortedListReplayDecoder()));
@Override
public Cursor zScan(byte[] key, ScanOptions options) {
return new KeyBoundCursor(key, 0, options) {
private RedisClient client;
@Override
protected ScanIteration doScan(byte[] key, long cursorId, ScanOptions options) {
if (isQueueing() || isPipelined()) {
throw new UnsupportedOperationException("'ZSCAN' cannot be called in pipeline / transaction mode.");
}
List args = new ArrayList();
args.add(key);
args.add(Long.toUnsignedString(cursorId));
if (options.getPattern() != null) {
args.add("MATCH");
args.add(options.getPattern());
}
if (options.getCount() != null) {
args.add("COUNT");
args.add(options.getCount());
}
RFuture> f = executorService.readAsync(client, key, ByteArrayCodec.INSTANCE, ZSCAN, args.toArray());
ListScanResult res = syncFuture(f);
client = res.getRedisClient();
return new ScanIteration(Long.parseUnsignedLong(res.getPos()), res.getValues());
}
}.open();
}
@Override
public Set zRangeByScore(byte[] key, String min, String max) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.ZRANGEBYSCORE, key, min, max);
}
@Override
public Set zRangeByScore(byte[] key, Range range) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.ZRANGEBYSCORE, key, min, max);
}
@Override
public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.ZRANGEBYSCORE, key, min, max, "LIMIT", offset, count);
}
@Override
public Set zRangeByScore(byte[] key, Range range, Limit limit) {
String min = value(range.getMin(), "-inf");
String max = value(range.getMax(), "+inf");
List args = new ArrayList();
args.add(key);
args.add(min);
args.add(max);
if (limit != null) {
args.add("LIMIT");
args.add(limit.getOffset());
args.add(limit.getCount());
}
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.ZRANGEBYSCORE, args.toArray());
}
@Override
public Set zRangeByLex(byte[] key) {
return zRangeByLex(key, Range.unbounded());
}
private static final RedisCommand> ZRANGEBYLEX = new RedisCommand>("ZRANGEBYLEX", new ObjectSetReplayDecoder());
@Override
public Set zRangeByLex(byte[] key, Range range) {
List params = new ArrayList();
params.add(key);
if (range.getMin() != null) {
String min = value(range.getMin(), "-");
params.add(min);
} else {
params.add("-");
}
if (range.getMax() != null) {
String max = value(range.getMax(), "+");
params.add(max);
} else {
params.add("+");
}
return read(key, ByteArrayCodec.INSTANCE, ZRANGEBYLEX, params.toArray());
}
@Override
public Set zRangeByLex(byte[] key, Range range, Limit limit) {
String min = value(range.getMin(), "-");
String max = value(range.getMax(), "+");
List args = new ArrayList();
args.add(key);
args.add(min);
args.add(max);
if (limit != null) {
args.add("LIMIT");
args.add(limit.getOffset());
args.add(limit.getCount());
}
return read(key, ByteArrayCodec.INSTANCE, ZRANGEBYLEX, args.toArray());
}
@Override
public Boolean hSet(byte[] key, byte[] field, byte[] value) {
return write(key, StringCodec.INSTANCE, RedisCommands.HSET, key, field, value);
}
@Override
public Boolean hSetNX(byte[] key, byte[] field, byte[] value) {
return write(key, StringCodec.INSTANCE, RedisCommands.HSETNX, key, field, value);
}
@Override
public byte[] hGet(byte[] key, byte[] field) {
return read(key, ByteArrayCodec.INSTANCE, RedisCommands.HGET, key, field);
}
private static final RedisCommand> HMGET = new RedisCommand>("HMGET", new ObjectListReplayDecoder());
@Override
public List hMGet(byte[] key, byte[]... fields) {
List args = new ArrayList(fields.length + 1);
args.add(key);
args.addAll(Arrays.asList(fields));
return read(key, ByteArrayCodec.INSTANCE, HMGET, args.toArray());
}
@Override
public void hMSet(byte[] key, Map hashes) {
List params = new ArrayList(hashes.size()*2 + 1);
params.add(key);
for (Map.Entry entry : hashes.entrySet()) {
params.add(entry.getKey());
params.add(entry.getValue());
}
write(key, StringCodec.INSTANCE, RedisCommands.HMSET, params.toArray());
}
private static final RedisCommand HINCRBY = new RedisCommand("HINCRBY");
@Override
public Long hIncrBy(byte[] key, byte[] field, long delta) {
return write(key, StringCodec.INSTANCE, HINCRBY, key, field, delta);
}
private static final RedisCommand HINCRBYFLOAT = new RedisCommand("HINCRBYFLOAT", new DoubleReplayConvertor());
@Override
public Double hIncrBy(byte[] key, byte[] field, double delta) {
return write(key, StringCodec.INSTANCE, HINCRBYFLOAT, key, field, BigDecimal.valueOf(delta).toPlainString());
}
@Override
public Boolean hExists(byte[] key, byte[] field) {
return read(key, StringCodec.INSTANCE, RedisCommands.HEXISTS, key, field);
}
@Override
public Long hDel(byte[] key, byte[]... fields) {
List args = new ArrayList