Java tutorial
/** * Copyright (c) 2015 CodisLabs. * * 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 io.codis.nedis; import io.codis.nedis.handler.RedisDuplexHandler; import io.codis.nedis.handler.RedisRequest; import io.codis.nedis.handler.TxnRedisRequest; import io.codis.nedis.protocol.BitOp; import io.codis.nedis.protocol.HashEntry; import io.codis.nedis.protocol.RedisCommand; import io.codis.nedis.protocol.RedisKeyword; import io.codis.nedis.protocol.ScanParams; import io.codis.nedis.protocol.ScanResult; import io.codis.nedis.protocol.SetParams; import io.codis.nedis.protocol.SortParams; import io.codis.nedis.protocol.SortedSetEntry; import io.codis.nedis.protocol.ZSetOpParams; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoop; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import static io.codis.nedis.handler.RedisRequestEncoder.encode; import static io.codis.nedis.handler.RedisRequestEncoder.encodeReverse; import static io.codis.nedis.protocol.RedisCommand.*; import static io.codis.nedis.protocol.RedisKeyword.BY; import static io.codis.nedis.protocol.RedisKeyword.COUNT; import static io.codis.nedis.protocol.RedisKeyword.EX; import static io.codis.nedis.protocol.RedisKeyword.FLUSH; import static io.codis.nedis.protocol.RedisKeyword.GETNAME; import static io.codis.nedis.protocol.RedisKeyword.KILL; import static io.codis.nedis.protocol.RedisKeyword.LIMIT; import static io.codis.nedis.protocol.RedisKeyword.LIST; import static io.codis.nedis.protocol.RedisKeyword.LOAD; import static io.codis.nedis.protocol.RedisKeyword.MATCH; import static io.codis.nedis.protocol.RedisKeyword.NX; import static io.codis.nedis.protocol.RedisKeyword.PX; import static io.codis.nedis.protocol.RedisKeyword.REPLACE; import static io.codis.nedis.protocol.RedisKeyword.RESETSTAT; import static io.codis.nedis.protocol.RedisKeyword.REWRITE; import static io.codis.nedis.protocol.RedisKeyword.SETNAME; import static io.codis.nedis.protocol.RedisKeyword.STORE; import static io.codis.nedis.protocol.RedisKeyword.WITHSCORES; import static io.codis.nedis.protocol.RedisKeyword.XX; import static io.codis.nedis.util.NedisUtils.toBytes; import static io.codis.nedis.util.NedisUtils.toParamsReverse; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import javax.naming.OperationNotSupportedException; /** * @author Apache9 */ public class NedisClientImpl implements NedisClient { private final Channel channel; private final NedisClientPool pool; private final PromiseConverter<ScanResult<byte[]>> arrayScanResultConverter; private final PromiseConverter<Boolean> booleanConverter; private final PromiseConverter<List<Boolean>> booleanListConverter; private final PromiseConverter<byte[]> bytesConverter; private final PromiseConverter<Double> doubleConverter; private final PromiseConverter<ScanResult<HashEntry>> hashScanResultConverter; private final PromiseConverter<List<byte[]>> listConverter; private final PromiseConverter<Long> longConverter; private final PromiseConverter<Map<byte[], byte[]>> mapConverter; private final PromiseConverter<Object> objectConverter; private final PromiseConverter<List<Object>> objectListConverter; private final PromiseConverter<Set<byte[]>> setConverter; private final PromiseConverter<List<SortedSetEntry>> sortedSetEntryListConverter; private final PromiseConverter<ScanResult<SortedSetEntry>> sortedSetScanResultConverter; private final PromiseConverter<String> stringConverter; private final PromiseConverter<Void> voidConverter; public NedisClientImpl(Channel channel, NedisClientPool pool) { this.channel = channel; this.pool = pool; EventLoop eventLoop = channel.eventLoop(); this.listConverter = PromiseConverter.toList(eventLoop); this.booleanConverter = PromiseConverter.toBoolean(eventLoop); this.bytesConverter = PromiseConverter.toBytes(eventLoop); this.doubleConverter = PromiseConverter.toDouble(eventLoop); this.longConverter = PromiseConverter.toLong(eventLoop); this.objectConverter = PromiseConverter.toObject(eventLoop); this.stringConverter = PromiseConverter.toString(eventLoop); this.voidConverter = PromiseConverter.toVoid(eventLoop); this.arrayScanResultConverter = PromiseConverter.toArrayScanResult(eventLoop); this.mapConverter = PromiseConverter.toMap(eventLoop); this.hashScanResultConverter = PromiseConverter.toHashScanResult(eventLoop); this.setConverter = PromiseConverter.toSet(eventLoop); this.sortedSetEntryListConverter = PromiseConverter.toSortedSetEntryList(eventLoop); this.sortedSetScanResultConverter = PromiseConverter.toSortedSetScanResult(eventLoop); this.booleanListConverter = PromiseConverter.toBooleanList(eventLoop); this.objectListConverter = PromiseConverter.toObjectList(eventLoop); } @Override public Future<Long> append(byte[] key, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), APPEND.raw, key, value)); } @Override public Future<Void> auth(byte[] password) { if (pool != null) { return eventLoop().newFailedFuture( new OperationNotSupportedException("'auth' is not allowed on a pooled connection")); } return auth0(password); } Future<Void> auth0(byte[] password) { return execCmd(voidConverter, encode(channel.alloc(), AUTH.raw, password)); } @Override public Future<Void> bgrewriteaof() { return execCmd(voidConverter, encode(channel.alloc(), BGREWRITEAOF.raw)); } @Override public Future<Void> bgsave() { return execCmd(voidConverter, encode(channel.alloc(), BGSAVE.raw)); } @Override public Future<Long> bitcount(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), BITCOUNT.raw, key)); } @Override public Future<Long> bitcount(byte[] key, long startInclusive, long endInclusive) { return execCmd(longConverter, encode(channel.alloc(), BITCOUNT.raw, toBytes(startInclusive), toBytes(endInclusive))); } @Override public Future<Long> bitop(BitOp op, byte[] dst, byte[]... keys) { return execCmd(longConverter, encode(channel.alloc(), BITOP.raw, toParamsReverse(keys, op.raw, dst))); } @Override public Future<Long> bitpos(byte[] key, boolean bit) { return execCmd(longConverter, encode(channel.alloc(), BITPOS.raw, key, toBytes(bit))); } @Override public Future<Long> bitpos(byte[] key, boolean bit, long startInclusive) { return execCmd(longConverter, encode(channel.alloc(), BITPOS.raw, key, toBytes(bit), toBytes(startInclusive))); } @Override public Future<Long> bitpos(byte[] key, boolean bit, long startInclusive, long endInclusive) { return execCmd(longConverter, encode(channel.alloc(), BITPOS.raw, key, toBytes(bit), toBytes(startInclusive), toBytes(endInclusive))); } @Override public Future<List<byte[]>> blpop(long timeoutSeconds, byte[]... keys) { return execCmd(listConverter, encode(channel.alloc(), BLPOP.raw, keys, toBytes(timeoutSeconds))); } @Override public Future<List<byte[]>> brpop(long timeoutSeconds, byte[]... keys) { return execCmd(listConverter, encode(channel.alloc(), BRPOP.raw, keys, toBytes(timeoutSeconds))); } @Override public Future<byte[]> brpoplpush(byte[] src, byte[] dst, long timeoutSeconds) { return execCmd(bytesConverter, encode(channel.alloc(), BRPOPLPUSH.raw, src, dst, toBytes(timeoutSeconds))); } @Override public Future<byte[]> clientGetname() { return execCmd(bytesConverter, encode(channel.alloc(), CLIENT.raw, GETNAME.raw)); } @Override public Future<Void> clientKill(byte[] addr) { return execCmd(voidConverter, encode(channel.alloc(), CLIENT.raw, KILL.raw)); } @Override public Future<byte[]> clientList() { return execCmd(bytesConverter, encode(channel.alloc(), CLIENT.raw, LIST.raw)); } @Override public Future<Void> clientSetname(byte[] name) { if (pool != null) { return eventLoop().newFailedFuture( new OperationNotSupportedException("'client setname' is not allowed on a pooled connection")); } return clientSetname0(name); } Future<Void> clientSetname0(byte[] name) { return execCmd(voidConverter, encode(channel.alloc(), CLIENT.raw, SETNAME.raw, name)); } @Override public ChannelFuture close() { return channel.close(); } @Override public ChannelFuture closeFuture() { return channel.closeFuture(); } @Override public Future<List<byte[]>> configGet(byte[] pattern) { return execCmd(listConverter, encode(channel.alloc(), CONFIG.raw, RedisKeyword.GET.raw)); } @Override public Future<Void> configResetstat() { return execCmd(voidConverter, encode(channel.alloc(), CONFIG.raw, RESETSTAT.raw)); } @Override public Future<Void> configRewrite() { return execCmd(voidConverter, encode(channel.alloc(), CONFIG.raw, REWRITE.raw)); } @Override public Future<Void> configSet(byte[] name, byte[] value) { return execCmd(voidConverter, encode(channel.alloc(), CONFIG.raw, RedisKeyword.SET.raw)); } @Override public Future<Long> dbsize() { return execCmd(longConverter, encode(channel.alloc(), DBSIZE.raw)); } @Override public Future<Long> decr(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), DECR.raw, key)); } @Override public Future<Long> decrby(byte[] key, long delta) { return execCmd(longConverter, encode(channel.alloc(), DECRBY.raw, key, toBytes(delta))); } @Override public Future<Long> del(byte[]... keys) { return execCmd(longConverter, encode(channel.alloc(), DEL.raw, keys)); } @Override public Future<Void> discard() { return execTxnCmd(voidConverter, DISCARD); } @Override public Future<byte[]> dump(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), DUMP.raw, key)); } @Override public Future<byte[]> echo(byte[] msg) { return execCmd(bytesConverter, encode(channel.alloc(), ECHO.raw, msg)); } private ByteBuf encodeSortParams(RedisCommand cmd, byte[] key, SortParams sort, byte[] dst) { List<byte[]> params = new ArrayList<>(); params.add(key); if (sort.by() != null) { params.add(BY.raw); params.add(sort.by()); } if (!sort.limit().isEmpty()) { params.add(LIMIT.raw); params.addAll(sort.limit()); } if (!sort.get().isEmpty()) { params.addAll(sort.get()); } if (sort.order() != null) { params.add(sort.order()); } if (sort.getAlpha() != null) { params.add(sort.getAlpha()); } if (dst != null) { params.add(STORE.raw); params.add(dst); } return encode(channel.alloc(), cmd.raw, params); } private ByteBuf encodeZSetOpParams(RedisCommand cmd, byte[] dst, ZSetOpParams params) { byte[][] p = new byte[2 + params.keys().size() + params.weights().size() + (params.aggregate() != null ? 1 : 0)][]; p[0] = dst; p[1] = toBytes(params.keys().size()); int i = 2; for (byte[] key : params.keys()) { p[i++] = key; } for (byte[] weight : params.weights()) { p[i++] = weight; } if (params.aggregate() != null) { p[i] = params.aggregate().raw; } return encode(channel.alloc(), cmd.raw, p); } @Override public Future<Object> eval(byte[] script, int numKeys, byte[]... keysvalues) { return execCmd(objectConverter, encodeReverse(channel.alloc(), EVAL.raw, keysvalues, script, toBytes(numKeys))); } @Override public Future<Object> evalsha(byte[] sha1, int numKeys, byte[]... keysvalues) { return execCmd(objectConverter, encodeReverse(channel.alloc(), EVALSHA.raw, keysvalues, sha1, toBytes(numKeys))); } @Override public EventLoop eventLoop() { return channel.eventLoop(); } @Override public Future<List<Object>> exec() { return execTxnCmd(objectListConverter, EXEC); } @Override public Future<Object> execCmd(byte[] cmd, byte[]... params) { return execCmd(objectConverter, encode(channel.alloc(), cmd, params)); } private <T> Future<T> execCmd(PromiseConverter<T> converter, ByteBuf buf) { Promise<T> promise = converter.newPromise(); execCmd0(buf).addListener(converter.newListener(promise)); return promise; } private Future<Object> execCmd0(ByteBuf buf) { Promise<Object> promise = eventLoop().newPromise(); RedisRequest req = new RedisRequest(promise, buf); channel.writeAndFlush(req); return promise; } private <T> Future<ScanResult<T>> execScanCmd(PromiseConverter<ScanResult<T>> converter, RedisCommand cmd, byte[] key, ScanParams params) { List<byte[]> p = new ArrayList<>(); if (key != null) { p.add(key); } p.add(params.cursor()); if (params.match() != null) { p.add(MATCH.raw); p.add(params.match()); } if (params.count() > 0) { p.add(COUNT.raw); p.add(toBytes(params.count())); } return execCmd(converter, encode(channel.alloc(), cmd.raw, p)); } private <T> Future<T> execTxnCmd(PromiseConverter<T> converter, RedisCommand cmd) { Promise<Object> rawPromise = eventLoop().newPromise(); channel.writeAndFlush(new TxnRedisRequest(rawPromise, cmd)); Promise<T> promise = converter.newPromise(); rawPromise.addListener(converter.newListener(promise)); return promise; } @Override public Future<Boolean> exists(byte[] key) { return execCmd(booleanConverter, encode(channel.alloc(), EXISTS.raw, key)); } @Override public Future<Long> exists(byte[]... keys) { return execCmd(longConverter, encode(channel.alloc(), EXISTS.raw, keys)); } @Override public Future<Boolean> expire(byte[] key, long seconds) { return execCmd(booleanConverter, encode(channel.alloc(), EXPIRE.raw, key, toBytes(seconds))); } @Override public Future<Boolean> expireat(byte[] key, long unixTimeSeconds) { return execCmd(booleanConverter, encode(channel.alloc(), EXPIREAT.raw, key, toBytes(unixTimeSeconds))); } @Override public Future<Void> flushall() { return execCmd(voidConverter, encode(channel.alloc(), FLUSHALL.raw)); } @Override public Future<Void> flushdb() { return execCmd(voidConverter, encode(channel.alloc(), FLUSHDB.raw)); } @Override public Future<byte[]> get(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), GET.raw, key)); } @Override public Future<Boolean> getbit(byte[] key, long offset) { return execCmd(booleanConverter, encode(channel.alloc(), GETBIT.raw, key, toBytes(offset))); } @Override public Future<byte[]> getrange(byte[] key, long startInclusive, long endInclusive) { return execCmd(bytesConverter, encode(channel.alloc(), GETRANGE.raw, key, toBytes(startInclusive), toBytes(endInclusive))); } @Override public Future<byte[]> getset(byte[] key, byte[] value) { return execCmd(bytesConverter, encode(channel.alloc(), GETSET.raw, key, value)); } @Override public Future<Long> hdel(byte[] key, byte[]... fields) { return execCmd(longConverter, encodeReverse(channel.alloc(), HDEL.raw, fields, key)); } @Override public Future<Boolean> hexists(byte[] key, byte[] field) { return execCmd(booleanConverter, encode(channel.alloc(), HEXISTS.raw, key, field)); } @Override public Future<byte[]> hget(byte[] key, byte[] field) { return execCmd(bytesConverter, encode(channel.alloc(), HGET.raw, key, field)); } @Override public Future<Map<byte[], byte[]>> hgetall(byte[] key) { return execCmd(mapConverter, encode(channel.alloc(), HGETALL.raw, key)); } @Override public Future<Long> hincrby(byte[] key, byte[] field, long delta) { return execCmd(longConverter, encode(channel.alloc(), HINCRBY.raw, key, field, toBytes(delta))); } @Override public Future<Double> hincrbyfloat(byte[] key, byte[] field, double delta) { return execCmd(doubleConverter, encode(channel.alloc(), HINCRBYFLOAT.raw, key, field, toBytes(delta))); } @Override public Future<List<byte[]>> hkeys(byte[] key) { return execCmd(listConverter, encode(channel.alloc(), HKEYS.raw, key)); } @Override public Future<Long> hlen(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), HLEN.raw, key)); } @Override public Future<List<byte[]>> hmget(byte[] key, byte[]... fields) { return execCmd(listConverter, encodeReverse(channel.alloc(), HMGET.raw, fields, key)); } @Override public Future<Void> hmset(byte[] key, Map<byte[], byte[]> field2Value) { byte[][] params = new byte[2 * field2Value.size() + 1][]; params[0] = key; int i = 1; for (Map.Entry<byte[], byte[]> e : field2Value.entrySet()) { params[i++] = e.getKey(); params[i++] = e.getValue(); } return execCmd(voidConverter, encode(channel.alloc(), HMSET.raw, params)); } @Override public Future<ScanResult<HashEntry>> hscan(byte[] key, ScanParams params) { return execScanCmd(hashScanResultConverter, HSCAN, key, params); } @Override public Future<Boolean> hset(byte[] key, byte[] field, byte[] value) { return execCmd(booleanConverter, encode(channel.alloc(), HSET.raw, key, field, value)); } @Override public Future<Boolean> hsetnx(byte[] key, byte[] field, byte[] value) { return execCmd(booleanConverter, encode(channel.alloc(), HSETNX.raw, key, field, value)); } @Override public Future<List<byte[]>> hvals(byte[] key) { return execCmd(listConverter, encode(channel.alloc(), HVALS.raw, key)); } @Override public Future<Long> incr(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), INCR.raw, key)); } @Override public Future<Long> incrby(byte[] key, long delta) { return execCmd(longConverter, encode(channel.alloc(), INCRBY.raw, key, toBytes(delta))); } @Override public Future<Double> incrbyfloat(byte[] key, double delta) { return execCmd(doubleConverter, encode(channel.alloc(), INCRBYFLOAT.raw, key, toBytes(delta))); } @Override public Future<byte[]> info() { return execCmd(bytesConverter, encode(channel.alloc(), INFO.raw)); } @Override public Future<byte[]> info(byte[] section) { return execCmd(bytesConverter, encode(channel.alloc(), INFO.raw, section)); } @Override public boolean isOpen() { return channel.isOpen(); } @Override public Future<List<byte[]>> keys(byte[] pattern) { return execCmd(listConverter, encode(channel.alloc(), KEYS.raw, pattern)); } @Override public Future<Long> lastsave() { return execCmd(longConverter, encode(channel.alloc(), LASTSAVE.raw)); } @Override public Future<byte[]> lindex(byte[] key, long index) { return execCmd(bytesConverter, encode(channel.alloc(), LINDEX.raw, key, toBytes(index))); } @Override public Future<Long> linsert(byte[] key, LIST_POSITION where, byte[] pivot, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), LINSERT.raw, key, where.raw, pivot, value)); } @Override public Future<Long> llen(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), LLEN.raw, key)); } @Override public Future<byte[]> lpop(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), LPOP.raw, key)); } @Override public Future<Long> lpush(byte[] key, byte[]... values) { return execCmd(longConverter, encodeReverse(channel.alloc(), LPUSH.raw, values, key)); } @Override public Future<Long> lpushx(byte[] key, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), LPUSHX.raw, key, value)); } @Override public Future<List<byte[]>> lrange(byte[] key, long startInclusive, long stopInclusive) { return execCmd(listConverter, encode(channel.alloc(), LRANGE.raw, key, toBytes(startInclusive), toBytes(stopInclusive))); } @Override public Future<Long> lrem(byte[] key, long count, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), LREM.raw, key, toBytes(count), value)); } @Override public Future<byte[]> lset(byte[] key, long index, byte[] value) { return execCmd(bytesConverter, encode(channel.alloc(), LSET.raw, key, toBytes(index), value)); } @Override public Future<Void> ltrim(byte[] key, long startInclusive, long stopInclusive) { return execCmd(voidConverter, encode(channel.alloc(), LTRIM.raw, key, toBytes(startInclusive), toBytes(stopInclusive))); } @Override public Future<List<byte[]>> mget(byte[]... keys) { return execCmd(listConverter, encode(channel.alloc(), MGET.raw, keys)); } @Override public Future<Void> migrate(byte[] host, int port, byte[] key, int dstDb, long timeoutMs) { return execCmd(voidConverter, encode(channel.alloc(), MIGRATE.raw, host, toBytes(port), key, toBytes(dstDb), toBytes(timeoutMs))); } @Override public Future<Boolean> move(byte[] key, int db) { return execCmd(booleanConverter, encode(channel.alloc(), MOVE.raw, key, toBytes(db))); } @Override public Future<Void> mset(byte[]... keysvalues) { return execCmd(voidConverter, encode(channel.alloc(), MSET.raw, keysvalues)); } @Override public Future<Boolean> msetnx(byte[]... keysvalues) { return execCmd(booleanConverter, encode(channel.alloc(), MSETNX.raw, keysvalues)); } @Override public Future<Void> multi() { return execTxnCmd(voidConverter, MULTI); } @Override public Future<Boolean> persist(byte[] key) { return execCmd(booleanConverter, encode(channel.alloc(), PERSIST.raw, key)); } @Override public Future<Boolean> pexpire(byte[] key, long millis) { return execCmd(booleanConverter, encode(channel.alloc(), PEXPIRE.raw, toBytes(millis))); } @Override public Future<Boolean> pexpireat(byte[] key, long unixTimeMs) { return execCmd(booleanConverter, encode(channel.alloc(), PEXPIREAT.raw, toBytes(unixTimeMs))); } @Override public Future<Boolean> pfadd(byte[] key, byte[]... elements) { return execCmd(booleanConverter, encodeReverse(channel.alloc(), PFADD.raw, elements, key)); } @Override public Future<Long> pfcount(byte[]... keys) { return execCmd(longConverter, encode(channel.alloc(), PFCOUNT.raw, keys)); } @Override public Future<Void> pfmerge(byte[] dst, byte[]... keys) { return execCmd(voidConverter, encodeReverse(channel.alloc(), PFMERGE.raw, keys, dst)); } @Override public Future<String> ping() { return execCmd(stringConverter, encode(channel.alloc(), PING.raw)); } @Override public Future<Long> pttl(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), PTTL.raw, key)); } @Override public Future<Void> quit() { if (pool != null) { return eventLoop().newFailedFuture( new OperationNotSupportedException("'quit' is not allowed on a pooled connection")); } return quit0(); } Future<Void> quit0() { return execCmd(voidConverter, encode(channel.alloc(), QUIT.raw)); } @Override public Future<byte[]> randomkey() { return execCmd(bytesConverter, encode(channel.alloc(), RANDOMKEY.raw)); } @Override public void release() { if (pool != null && pool.exclusive()) { pool.release(this); } } @Override public Future<Void> rename(byte[] key, byte[] newKey) { return execCmd(voidConverter, encode(channel.alloc(), RENAME.raw, key, newKey)); } @Override public Future<Boolean> renamenx(byte[] key, byte[] newKey) { return execCmd(booleanConverter, encode(channel.alloc(), RENAMENX.raw, key, newKey)); } @Override public Future<Void> restore(byte[] key, int ttlMs, byte[] serializedValue, boolean replace) { if (replace) { return execCmd(voidConverter, encode(channel.alloc(), RESTORE.raw, key, toBytes(ttlMs), serializedValue, REPLACE.raw)); } else { return execCmd(voidConverter, encode(channel.alloc(), RESTORE.raw, key, toBytes(ttlMs), serializedValue)); } } @Override public Future<List<byte[]>> role() { return execCmd(listConverter, encode(channel.alloc(), ROLE.raw)); } @Override public Future<byte[]> rpop(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), RPOP.raw, key)); } @Override public Future<byte[]> rpoplpush(byte[] src, byte[] dst) { return execCmd(bytesConverter, encode(channel.alloc(), RPOPLPUSH.raw, src, dst)); } @Override public Future<Long> rpush(byte[] key, byte[]... values) { return execCmd(longConverter, encodeReverse(channel.alloc(), RPUSH.raw, values, key)); } @Override public Future<Long> rpushx(byte[] key, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), RPUSHX.raw, key, value)); } @Override public Future<Long> sadd(byte[] key, byte[]... members) { return execCmd(longConverter, encodeReverse(channel.alloc(), SADD.raw, members, key)); } @Override public Future<Void> save(boolean save) { return execCmd(voidConverter, encode(channel.alloc(), SAVE.raw)); } @Override public Future<ScanResult<byte[]>> scan(ScanParams params) { return execScanCmd(arrayScanResultConverter, SCAN, null, params); } @Override public Future<Long> scard(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), SCARD.raw, key)); } @Override public Future<List<Boolean>> scriptExists(byte[]... scripts) { return execCmd(booleanListConverter, encodeReverse(channel.alloc(), SCRIPT.raw, scripts, RedisKeyword.EXISTS.raw)); } @Override public Future<Void> scriptFlush() { return execCmd(voidConverter, encode(channel.alloc(), SCRIPT.raw, FLUSH.raw)); } @Override public Future<Void> scriptKill() { return execCmd(voidConverter, encode(channel.alloc(), SCRIPT.raw, KILL.raw)); } @Override public Future<byte[]> scriptLoad(byte[] script) { return execCmd(bytesConverter, encode(channel.alloc(), SCRIPT.raw, LOAD.raw, script)); } @Override public Future<Set<byte[]>> sdiff(byte[]... keys) { return execCmd(setConverter, encode(channel.alloc(), SDIFF.raw, keys)); } @Override public Future<Long> sdiffstore(byte[] dst, byte[]... keys) { return execCmd(longConverter, encodeReverse(channel.alloc(), SDIFFSTORE.raw, keys, dst)); } @Override public Future<Void> select(int index) { if (pool != null) { return eventLoop().newFailedFuture( new OperationNotSupportedException("'select' is not allowed on a pooled connection")); } return select0(index); } Future<Void> select0(int index) { return execCmd(voidConverter, encode(channel.alloc(), SELECT.raw, toBytes(index))); } @Override public Future<Boolean> set(byte[] key, byte[] value) { return execCmd(booleanConverter, encode(channel.alloc(), SET.raw, key, value)); } @Override public Future<Boolean> set(byte[] key, byte[] value, SetParams params) { List<byte[]> p = new ArrayList<>(); p.add(key); p.add(value); if (params.ex() > 0) { p.add(EX.raw); p.add(toBytes(params.ex())); } else if (params.px() > 0) { p.add(PX.raw); p.add(toBytes(params.px())); } if (params.nx()) { p.add(NX.raw); } else if (params.xx()) { p.add(XX.raw); } return execCmd(booleanConverter, encode(channel.alloc(), SET.raw, p)); } @Override public Future<Boolean> setbit(byte[] key, long offset, boolean bit) { return execCmd(booleanConverter, encode(channel.alloc(), SETBIT.raw, key, toBytes(offset), toBytes(bit))); } @Override public Future<Long> setrange(byte[] key, long offset, byte[] value) { return execCmd(longConverter, encode(channel.alloc(), SETRANGE.raw, key, toBytes(offset), value)); } @Override public Future<Long> setTimeout(final long timeoutMs) { return eventLoop().submit(new Callable<Long>() { @Override public Long call() { RedisDuplexHandler handler = channel.pipeline().get(RedisDuplexHandler.class); if (handler == null) { return null; } long previousTimeoutMs = TimeUnit.NANOSECONDS.toMillis(handler.getTimeoutNs()); handler.setTimeoutNs(TimeUnit.MILLISECONDS.toNanos(timeoutMs)); return previousTimeoutMs; } }); } @Override public Future<Set<byte[]>> sinter(byte[]... keys) { return execCmd(setConverter, encode(channel.alloc(), SINTER.raw, keys)); } @Override public Future<Long> sinterstore(byte[] dst, byte[]... keys) { return execCmd(longConverter, encodeReverse(channel.alloc(), SINTERSTORE.raw, keys, dst)); } @Override public Future<Boolean> sismember(byte[] key, byte[] member) { return execCmd(booleanConverter, encode(channel.alloc(), SISMEMBER.raw, key, member)); } @Override public Future<Void> slaveof(String host, int port) { return execCmd(voidConverter, encode(channel.alloc(), SLAVEOF.raw, toBytes(host), toBytes(port))); } @Override public Future<Set<byte[]>> smembers(byte[] key) { return execCmd(setConverter, encode(channel.alloc(), SMEMBERS.raw, key)); } @Override public Future<Boolean> smove(byte[] src, byte[] dst, byte[] member) { return execCmd(booleanConverter, encode(channel.alloc(), SMOVE.raw, src, dst, member)); } @Override public Future<List<byte[]>> sort(byte[] key) { return execCmd(listConverter, encode(channel.alloc(), SORT.raw, key)); } @Override public Future<Long> sort(byte[] key, byte[] dst) { return execCmd(longConverter, encode(channel.alloc(), SORT.raw, key, STORE.raw, dst)); } @Override public Future<List<byte[]>> sort(byte[] key, SortParams params) { return execCmd(listConverter, encodeSortParams(SORT, key, params, null)); } @Override public Future<Long> sort(byte[] key, SortParams params, byte[] dst) { return execCmd(longConverter, encodeSortParams(SORT, key, params, dst)); } @Override public Future<byte[]> spop(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), SPOP.raw, key)); } @Override public Future<byte[]> srandmember(byte[] key) { return execCmd(bytesConverter, encode(channel.alloc(), SRANDMEMBER.raw, key)); } @Override public Future<Set<byte[]>> srandmember(byte[] key, long count) { return execCmd(setConverter, encode(channel.alloc(), SRANDMEMBER.raw, key, toBytes(count))); } @Override public Future<Long> srem(byte[] key, byte[]... members) { return execCmd(longConverter, encodeReverse(channel.alloc(), SREM.raw, members, key)); } @Override public Future<ScanResult<byte[]>> sscan(byte[] key, ScanParams params) { return execScanCmd(arrayScanResultConverter, SSCAN, key, params); } @Override public Future<Long> strlen(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), STRLEN.raw, key)); } @Override public Future<Set<byte[]>> sunion(byte[]... keys) { return execCmd(setConverter, encode(channel.alloc(), SUNION.raw, keys)); } @Override public Future<Long> sunionstore(byte[] dst, byte[]... keys) { return execCmd(longConverter, encodeReverse(channel.alloc(), SUNIONSTORE.raw, keys, dst)); } @Override public Future<Void> sync() { return execCmd(voidConverter, encode(channel.alloc(), SYNC.raw)); } @Override public Future<List<byte[]>> time() { return execCmd(listConverter, encode(channel.alloc(), TIME.raw)); } @Override public Future<Long> ttl(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), TTL.raw, key)); } @Override public Future<String> type(byte[] key) { return execCmd(stringConverter, encode(channel.alloc(), TYPE.raw, key)); } @Override public Future<Void> unwatch() { return execCmd(voidConverter, encode(channel.alloc(), UNWATCH.raw)); } @Override public Future<Void> watch(byte[]... keys) { return execCmd(voidConverter, encode(channel.alloc(), WATCH.raw, keys)); } @Override public Future<Long> zadd(byte[] key, double score, byte[] member) { return execCmd(longConverter, encode(channel.alloc(), ZADD.raw, key, toBytes(score), member)); } @Override public Future<Long> zadd(byte[] key, Map<byte[], Double> member2Score) { byte[][] params = new byte[member2Score.size() * 2 + 1][]; params[0] = key; int i = 1; for (Map.Entry<byte[], Double> e : member2Score.entrySet()) { params[i++] = toBytes(e.getValue().doubleValue()); params[i++] = e.getKey(); } return execCmd(longConverter, encode(channel.alloc(), ZADD.raw, params)); } @Override public Future<Long> zcard(byte[] key) { return execCmd(longConverter, encode(channel.alloc(), ZCARD.raw, key)); } @Override public Future<Long> zcount(byte[] key, byte[] min, byte[] max) { return execCmd(longConverter, encode(channel.alloc(), ZCOUNT.raw, key, min, max)); } @Override public Future<Double> zincrby(byte[] key, double delta, byte[] member) { return execCmd(doubleConverter, encode(channel.alloc(), ZINCRBY.raw, key, toBytes(delta), member)); } @Override public Future<Long> zinterstore(byte[] dst, byte[]... keys) { return execCmd(longConverter, encodeReverse(channel.alloc(), ZINTERSTORE.raw, keys, dst)); } @Override public Future<Long> zinterstore(byte[] dst, ZSetOpParams params) { return execCmd(longConverter, encodeZSetOpParams(ZINTERSTORE, dst, params)); } @Override public Future<Long> zlexcount(byte[] key, byte[] min, byte[] max) { return execCmd(longConverter, encode(channel.alloc(), ZLEXCOUNT.raw, key, min, max)); } @Override public Future<List<byte[]>> zrange(byte[] key, long startInclusive, long stopInclusive) { return execCmd(listConverter, encode(channel.alloc(), ZRANGE.raw, key, toBytes(startInclusive), toBytes(stopInclusive))); } @Override public Future<List<byte[]>> zrangebylex(byte[] key, byte[] min, byte[] max) { return execCmd(listConverter, encode(channel.alloc(), ZRANGEBYLEX.raw, key, min, max)); } @Override public Future<List<byte[]>> zrangebylex(byte[] key, byte[] min, byte[] max, long offset, long count) { return execCmd(listConverter, encode(channel.alloc(), ZRANGEBYLEX.raw, key, min, max, LIMIT.raw, toBytes(offset), toBytes(count))); } @Override public Future<List<byte[]>> zrangebyscore(byte[] key, byte[] min, byte[] max) { return execCmd(listConverter, encode(channel.alloc(), ZRANGEBYSCORE.raw, key, min, max)); } @Override public Future<List<byte[]>> zrangebyscore(byte[] key, byte[] min, byte[] max, long offset, long count) { return execCmd(listConverter, encode(channel.alloc(), ZRANGEBYSCORE.raw, key, min, max, LIMIT.raw, toBytes(offset), toBytes(count))); } @Override public Future<List<SortedSetEntry>> zrangebyscoreWithScores(byte[] key, byte[] min, byte[] max) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZRANGEBYSCORE.raw, key, min, max, WITHSCORES.raw)); } @Override public Future<List<SortedSetEntry>> zrangebyscoreWithScores(byte[] key, byte[] min, byte[] max, long offset, long count) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZRANGEBYSCORE.raw, key, min, max, WITHSCORES.raw, LIMIT.raw, toBytes(offset), toBytes(count))); } @Override public Future<List<SortedSetEntry>> zrangeWithScores(byte[] key, long startInclusive, long stopInclusive) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZRANGE.raw, key, toBytes(startInclusive), toBytes(stopInclusive), WITHSCORES.raw)); } @Override public Future<Long> zrank(byte[] key, byte[] member) { return execCmd(longConverter, encode(channel.alloc(), ZRANK.raw, key, member)); } @Override public Future<Long> zrem(byte[] key, byte[]... members) { return execCmd(longConverter, encode(channel.alloc(), ZREM.raw, toParamsReverse(members, key))); } @Override public Future<Long> zremrangebylex(byte[] key, byte[] min, byte[] max) { return execCmd(longConverter, encode(channel.alloc(), ZREMRANGEBYLEX.raw, key, min, max)); } @Override public Future<Long> zremrangebyrank(byte[] key, long startInclusive, long stopInclusive) { return execCmd(longConverter, encode(channel.alloc(), ZREMRANGEBYRANK.raw, key, toBytes(startInclusive), toBytes(stopInclusive))); } @Override public Future<Long> zremrangebyscore(byte[] key, byte[] min, byte[] max) { return execCmd(longConverter, encode(channel.alloc(), ZREMRANGEBYSCORE.raw, key, min, max)); } @Override public Future<List<byte[]>> zrevrange(byte[] key, long startInclusive, long stopInclusive) { return execCmd(listConverter, encode(channel.alloc(), ZREVRANGE.raw, key, toBytes(startInclusive), toBytes(stopInclusive))); } @Override public Future<List<byte[]>> zrevrangebylex(byte[] key, byte[] max, byte[] min) { return execCmd(listConverter, encode(channel.alloc(), ZREVRANGEBYLEX.raw, key, max, min)); } @Override public Future<List<byte[]>> zrevrangebylex(byte[] key, byte[] max, byte[] min, long offset, long count) { return execCmd(listConverter, encode(channel.alloc(), ZREVRANGEBYLEX.raw, key, max, min, LIMIT.raw, toBytes(offset), toBytes(count))); } @Override public Future<List<byte[]>> zrevrangebyscore(byte[] key, byte[] max, byte[] min) { return execCmd(listConverter, encode(channel.alloc(), ZREVRANGEBYSCORE.raw, key, max, min)); } @Override public Future<List<byte[]>> zrevrangebyscore(byte[] key, byte[] max, byte[] min, long offset, long count) { return execCmd(listConverter, encode(channel.alloc(), ZREVRANGEBYSCORE.raw, key, max, min, LIMIT.raw, toBytes(offset), toBytes(count))); } @Override public Future<List<SortedSetEntry>> zrevrangebyscoreWithScores(byte[] key, byte[] max, byte[] min) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZREVRANGEBYSCORE.raw, key, max, min, WITHSCORES.raw)); } @Override public Future<List<SortedSetEntry>> zrevrangebyscoreWithScores(byte[] key, byte[] max, byte[] min, long offset, long count) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZREVRANGEBYSCORE.raw, key, max, min, WITHSCORES.raw, LIMIT.raw, toBytes(offset), toBytes(count), WITHSCORES.raw)); } @Override public Future<List<SortedSetEntry>> zrevrangeWithScores(byte[] key, long startInclusive, long stopInclusive) { return execCmd(sortedSetEntryListConverter, encode(channel.alloc(), ZREVRANGE.raw, key, toBytes(startInclusive), toBytes(stopInclusive), WITHSCORES.raw)); } @Override public Future<Long> zrevrank(byte[] key, byte[] member) { return execCmd(longConverter, encode(channel.alloc(), ZREVRANK.raw, key, member)); } @Override public Future<ScanResult<SortedSetEntry>> zscan(byte[] key, ScanParams params) { return execScanCmd(sortedSetScanResultConverter, ZSCAN, key, params); } @Override public Future<Double> zscore(byte[] key, byte[] member) { return execCmd(doubleConverter, encode(channel.alloc(), ZSCORE.raw, key, member)); } @Override public Future<Long> zunionstore(byte[] dst, byte[]... keys) { return execCmd(longConverter, encodeReverse(channel.alloc(), ZUNIONSTORE.raw, keys, dst)); } @Override public Future<Long> zunionstore(byte[] dst, ZSetOpParams params) { return execCmd(longConverter, encodeZSetOpParams(ZUNIONSTORE, dst, params)); } }