All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lambdaworks.redis.RedisConnection Maven / Gradle / Ivy

// Copyright (C) 2011 - Will Glozer.  All rights reserved.

package com.lambdaworks.redis;

import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.output.*;
import com.lambdaworks.redis.protocol.*;
import org.jboss.netty.channel.*;

import java.util.*;
import java.util.concurrent.*;

import static com.lambdaworks.redis.protocol.CommandKeyword.*;
import static com.lambdaworks.redis.protocol.CommandType.*;

/**
 * A synchronous thread-safe connection to a redis server. Multiple threads may
 * share one {@link RedisConnection} provided they avoid blocking and transactional
 * operations such as {@link #blpop} and {@link #multi()}/{@link #exec}.
 *
 * A {@link ConnectionWatchdog} monitors each connection and reconnects
 * automatically until {@link #close} is called. All pending commands will be
 * (re)sent after successful reconnection.
 *
 * @author Will Glozer
 */
public class RedisConnection extends SimpleChannelUpstreamHandler {
    protected BlockingQueue> queue;
    protected RedisCodec codec;
    protected Channel channel;
    private int timeout;
    private TimeUnit unit;
    private String password;
    private int db;
    private MultiOutput multi;
    private boolean closed;

    /**
     * Initialize a new connection.
     *
     * @param queue   Command queue.
     * @param codec   Codec used to encode/decode keys and values.
     * @param timeout Maximum time to wait for a responses.
     * @param unit    Unit of time for the timeout.
     */
    public RedisConnection(BlockingQueue> queue, RedisCodec codec, int timeout, TimeUnit unit) {
        this.queue = queue;
        this.codec = codec;
        this.timeout = timeout;
        this.unit = unit;
    }

    /**
     * Set the command timeout for this connection.
     *
     * @param timeout Command timeout.
     * @param unit    Unit of time for the timeout.
     */
    public void setTimeout(int timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    public Long append(K key, V value) {
        Command cmd = dispatch(APPEND, new IntegerOutput(codec), key, value);
        return getOutput(cmd);
    }

    public String auth(String password) {
        this.password = password;
        CommandArgs args = new CommandArgs(codec).add(password);
        Command cmd = dispatch(AUTH, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String bgrewriteaof() {
        Command cmd = dispatch(BGREWRITEAOF, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public String bgsave() {
        Command cmd = dispatch(BGSAVE, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public List blpop(long timeout, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys).add(timeout);
        Command> cmd = dispatch(BLPOP, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List brpop(long timeout, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys).add(timeout);
        Command> cmd = dispatch(BRPOP, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public V brpoplpush(long timeout, K source, K destination) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(source).addKey(destination).add(timeout);
        Command cmd = dispatch(BRPOPLPUSH, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public String clientKill(String addr) {
        CommandArgs args = new CommandArgs(codec).add(KILL).add(addr);
        Command cmd = dispatch(CLIENT, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String clientList() {
        CommandArgs args = new CommandArgs(codec).add(LIST);
        Command cmd = dispatch(CLIENT, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public List configGet(String parameter) {
        CommandArgs args = new CommandArgs(codec).add(GET).add(parameter);
        Command> cmd = dispatch(CONFIG, new StringListOutput(codec), args);
        return getOutput(cmd);
    }

    public String configResetstat() {
        CommandArgs args = new CommandArgs(codec).add(RESETSTAT);
        Command cmd = dispatch(CONFIG, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String configSet(String parameter, String value) {
        CommandArgs args = new CommandArgs(codec).add(SET).add(parameter).add(value);
        Command cmd = dispatch(CONFIG, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Long dbsize() {
        Command cmd = dispatch(DBSIZE, new IntegerOutput(codec));
        return getOutput(cmd);
    }

    public String debugObject(K key) {
        CommandArgs args = new CommandArgs(codec).add(OBJECT).addKey(key);
        Command cmd = dispatch(DEBUG, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Long decr(K key) {
        Command cmd = dispatch(DECR, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public Long decrby(K key, long amount) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(amount);
        Command cmd = dispatch(DECRBY, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Long del(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command cmd = dispatch(DEL, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String discard() {
        Command cmd = dispatch(DISCARD, new StatusOutput(codec));
        multi = null;
        return getOutput(cmd);
    }

    public V echo(V msg) {
        CommandArgs args = new CommandArgs(codec).addValue(msg);
        Command cmd = dispatch(ECHO, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean exists(K key) {
        Command cmd = dispatch(EXISTS, new BooleanOutput(codec), key);
        return getOutput(cmd);
    }

    public Boolean expire(K key, long seconds) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(seconds);
        Command cmd = dispatch(EXPIRE, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean expireat(K key, Date timestamp) {
        long seconds = timestamp.getTime() / 1000;
        CommandArgs args = new CommandArgs(codec).addKey(key).add(seconds);
        Command cmd = dispatch(EXPIREAT, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public List exec() {
        Command> cmd = dispatch(EXEC, multi);
        multi = null;
        return getOutput(cmd);
    }

    public String flushall() throws Exception {
        Command cmd = dispatch(FLUSHALL, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public String flushdb() throws Exception {
        Command cmd = dispatch(FLUSHDB, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public V get(K key) {
        Command cmd = dispatch(GET, new ValueOutput(codec), key);
        return getOutput(cmd);
    }

    public Long getbit(K key, long offset) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(offset);
        Command cmd = dispatch(GETBIT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public V getrange(K key, long start, long end) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(end);
        Command cmd = dispatch(GETRANGE, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public V getset(K key, V value) {
        Command cmd = dispatch(GETSET, new ValueOutput(codec), key, value);
        return getOutput(cmd);
    }

    public Long hdel(K key, K... fields) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKeys(fields);
        Command cmd = dispatch(HDEL, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean hexists(K key, K field) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(field);
        Command cmd = dispatch(HEXISTS, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public V hget(K key, K field) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(field);
        Command cmd = dispatch(HGET, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public Long hincrby(K key, K field, long amount) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(field).add(amount);
        Command cmd = dispatch(HINCRBY, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Map hgetall(K key) {
        Command> cmd = dispatch(HGETALL, new MapOutput(codec), key);
        return getOutput(cmd);
    }

    public List hkeys(K key) {
        Command> cmd = dispatch(HKEYS, new KeyListOutput(codec), key);
        return getOutput(cmd);
    }

    public Long hlen(K key) {
        Command cmd = dispatch(HLEN, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public List hmget(K key, K... fields) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKeys(fields);
        Command> cmd = dispatch(HMGET, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public String hmset(K key, Map map) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(map);
        Command cmd = dispatch(HMSET, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean hset(K key, K field, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(field).addValue(value);
        Command cmd = dispatch(HSET, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean hsetnx(K key, K field, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(field).addValue(value);
        Command cmd = dispatch(HSETNX, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public List hvals(K key) {
        Command> cmd = dispatch(HVALS, new ValueListOutput(codec), key);
        return getOutput(cmd);
    }

    public Long incr(K key) {
        Command cmd = dispatch(INCR, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public Long incrby(K key, long amount) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(amount);
        Command cmd = dispatch(INCRBY, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String info() {
        Command cmd = dispatch(INFO, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public List keys(K pattern) {
        Command> cmd = dispatch(KEYS, new KeyListOutput(codec), pattern);
        return getOutput(cmd);
    }

    public Date lastsave() {
        Command cmd = dispatch(LASTSAVE, new DateOutput(codec));
        return getOutput(cmd);
    }

    public V lindex(K key, long index) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(index);
        Command cmd = dispatch(LINDEX, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public Long linsert(K key, boolean before, V pivot, V value) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(before ? BEFORE : AFTER).addValue(pivot).addValue(value);
        Command cmd = dispatch(LINSERT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Long llen(K key) {
        Command cmd = dispatch(LLEN, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public V lpop(K key) {
        Command cmd = dispatch(LPOP, new ValueOutput(codec), key);
        return getOutput(cmd);
    }

    public Long lpush(K key, V... values) {
        Command cmd = dispatch(LPUSH, new IntegerOutput(codec), key, values);
        return getOutput(cmd);
    }

    public Long lpushx(K key, V value) {
        Command cmd = dispatch(LPUSHX, new IntegerOutput(codec), key, value);
        return getOutput(cmd);
    }

    public List lrange(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(stop);
        Command> cmd = dispatch(LRANGE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public Long lrem(K key, long count, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(count).addValue(value);
        Command cmd = dispatch(LREM, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String lset(K key, long index, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(index).addValue(value);
        Command cmd = dispatch(LSET, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String ltrim(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(stop);
        Command cmd = dispatch(LTRIM, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public List mget(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command> cmd = dispatch(MGET, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean move(K key, int db) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(db);
        Command cmd = dispatch(MOVE, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public String multi() {
        Command cmd = dispatch(MULTI, new StatusOutput(codec));
        String status = getOutput(cmd);
        if ("OK".equals(status)) {
            multi = new MultiOutput(codec);
        }
        return status;
    }

    public String mset(Map map) {
        CommandArgs args = new CommandArgs(codec).add(map);
        Command cmd = dispatch(MSET, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean msetnx(Map map) {
        CommandArgs args = new CommandArgs(codec).add(map);
        Command cmd = dispatch(MSETNX, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public String objectEncoding(K key) {
        CommandArgs args = new CommandArgs(codec).add(ENCODING).addKey(key);
        Command cmd = dispatch(OBJECT, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Long objectIdletime(K key) {
        CommandArgs args = new CommandArgs(codec).add(IDLETIME).addKey(key);
        Command cmd = dispatch(OBJECT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Long objectRefcount(K key) {
        CommandArgs args = new CommandArgs(codec).add(REFCOUNT).addKey(key);
        Command cmd = dispatch(OBJECT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean persist(K key) {
        Command cmd = dispatch(PERSIST, new BooleanOutput(codec), key);
        return getOutput(cmd);
    }

    public String ping() {
        Command cmd = dispatch(PING, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public Long publish(String channel, V message) {
        CommandArgs args = new CommandArgs(codec).add(channel).addValue(message);
        Command cmd = dispatch(PUBLISH, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String quit() {
        Command cmd = dispatch(QUIT, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public V randomkey() {
        Command cmd = dispatch(RANDOMKEY, new ValueOutput(codec));
        return getOutput(cmd);
    }

    public String rename(K key, K newKey) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(newKey);
        Command cmd = dispatch(RENAME, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean renamenx(K key, K newKey) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addKey(newKey);
        Command cmd = dispatch(RENAMENX, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public V rpop(K key) {
        Command cmd = dispatch(RPOP, new ValueOutput(codec), key);
        return getOutput(cmd);
    }

    public V rpoplpush(K source, K destination) {
        CommandArgs args = new CommandArgs(codec).addKey(source).addKey(destination);
        Command cmd = dispatch(RPOPLPUSH, new ValueOutput(codec), args);
        return getOutput(cmd);
    }

    public Long rpush(K key, V... values) {
        Command cmd = dispatch(RPUSH, new IntegerOutput(codec), key, values);
        return getOutput(cmd);
    }

    public Long rpushx(K key, V value) {
        Command cmd = dispatch(RPUSHX, new IntegerOutput(codec), key, value);
        return getOutput(cmd);
    }

    public Long sadd(K key, V... members) {
        Command cmd = dispatch(SADD, new IntegerOutput(codec), key, members);
        return getOutput(cmd);
    }

    public String save() {
        Command cmd = dispatch(SAVE, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public Long scard(K key) {
        Command cmd = dispatch(SCARD, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public Set sdiff(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command> cmd = dispatch(SDIFF, new ValueSetOutput(codec), args);
        return getOutput(cmd);
    }

    public Long sdiffstore(K destination, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKey(destination).addKeys(keys);
        Command cmd = dispatch(SDIFFSTORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String select(int db) {
        this.db = db;
        CommandArgs args = new CommandArgs(codec).add(db);
        Command cmd = dispatch(SELECT, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String set(K key, V value) {
        Command cmd = dispatch(SET, new StatusOutput(codec), key, value);
        return getOutput(cmd);
    }

    public Long setbit(K key, long offset, int value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(offset).add(value);
        Command cmd = dispatch(SETBIT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String setex(K key, long seconds, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(seconds).addValue(value);
        Command cmd = dispatch(SETEX, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean setnx(K key, V value) {
        Command cmd = dispatch(SETNX, new BooleanOutput(codec), key, value);
        return getOutput(cmd);
    }

    public Long setrange(K key, long offset, V value) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(offset).addValue(value);
        Command cmd = dispatch(SETRANGE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public void shutdown() {
        dispatch(SHUTDOWN, new StatusOutput(codec));
    }

    public Set sinter(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command> cmd = dispatch(SINTER, new ValueSetOutput(codec), args);
        return getOutput(cmd);
    }

    public Long sinterstore(K destination, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKey(destination).addKeys(keys);
        Command cmd = dispatch(SINTERSTORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Boolean sismember(K key, V member) {
        Command cmd = dispatch(SISMEMBER, new BooleanOutput(codec), key, member);
        return getOutput(cmd);
    }

    public Boolean smove(K source, K destination, V member) {
        CommandArgs args = new CommandArgs(codec).addKey(source).addKey(destination).addValue(member);
        Command cmd = dispatch(SMOVE, new BooleanOutput(codec), args);
        return getOutput(cmd);
    }

    public String slaveof(String host, int port) {
        CommandArgs args = new CommandArgs(codec).add(host).add(port);
        Command cmd = dispatch(SLAVEOF, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String slaveofNoOne() {
        CommandArgs args = new CommandArgs(codec).add(NO).add(ONE);
        Command cmd = dispatch(SLAVEOF, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public Set smembers(K key) {
        Command> cmd = dispatch(SMEMBERS, new ValueSetOutput(codec), key);
        return getOutput(cmd);
    }

    public List sort(K key) {
        Command> cmd = dispatch(SORT, new ValueListOutput(codec), key);
        return getOutput(cmd);
    }

    public List sort(K key, SortArgs sortArgs) {
        CommandArgs args = new CommandArgs(codec).addKey(key);
        sortArgs.build(args, null);
        Command> cmd = dispatch(SORT, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public Long sortStore(K key, SortArgs sortArgs, K destination) {
        CommandArgs args = new CommandArgs(codec).addKey(key);
        sortArgs.build(args, destination);
        Command cmd = dispatch(SORT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public V spop(K key) {
        Command cmd = dispatch(SPOP, new ValueOutput(codec), key);
        return getOutput(cmd);
    }

    public V srandmember(K key) {
        Command cmd = dispatch(SRANDMEMBER, new ValueOutput(codec), key);
        return getOutput(cmd);
    }

    public Long srem(K key, V... members) {
        Command cmd = dispatch(SREM, new IntegerOutput(codec), key, members);
        return getOutput(cmd);
    }

    public Set sunion(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command> cmd = dispatch(SUNION, new ValueSetOutput(codec), args);
        return getOutput(cmd);
    }

    public Long sunionstore(K destination, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKey(destination).addKeys(keys);
        Command cmd = dispatch(SUNIONSTORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public String sync() {
        Command cmd = dispatch(SYNC, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public Long strlen(K key) {
        Command cmd = dispatch(STRLEN, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public Long ttl(K key) {
        Command cmd = dispatch(TTL, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public String type(K key) {
        Command cmd = dispatch(TYPE, new StatusOutput(codec), key);
        return getOutput(cmd);
    }

    public String watch(K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys);
        Command cmd = dispatch(WATCH, new StatusOutput(codec), args);
        return getOutput(cmd);
    }

    public String unwatch() {
        Command cmd = dispatch(UNWATCH, new StatusOutput(codec));
        return getOutput(cmd);
    }

    public Long zadd(K key, double score, V member) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(score).addValue(member);
        Command cmd = dispatch(ZADD, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    @SuppressWarnings("unchecked")
    public Long zadd(K key, Object... scoresAndValues) {
        CommandArgs args = new CommandArgs(codec).addKey(key);
        for (int i = 0; i < scoresAndValues.length; i += 2) {
            args.add((Double) scoresAndValues[i]);
            args.addValue((V) scoresAndValues[i + 1]);
        }
        Command cmd = dispatch(ZADD, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Long zcard(K key) {
        Command cmd = dispatch(ZCARD, new IntegerOutput(codec), key);
        return getOutput(cmd);
    }

    public Long zcount(K key, double min, double max) {
        return zcount(key, string(min), string(max));
    }

    public Long zcount(K key, String min, String max) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(min).add(max);
        Command cmd = dispatch(ZCOUNT, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Double zincrby(K key, double amount, K member) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(amount).addKey(member);
        Command cmd = dispatch(ZINCRBY, new DoubleOutput(codec), args);
        return getOutput(cmd);
    }

    public Long zinterstore(K destination, K... keys) {
        return zinterstore(destination, new ZStoreArgs(), keys);
    }

    public Long zinterstore(K destination, ZStoreArgs storeArgs, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKey(destination).add(keys.length).addKeys(keys);
        storeArgs.build(args);
        Command cmd = dispatch(ZINTERSTORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrange(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(stop);
        Command> cmd = dispatch(ZRANGE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrangeWithScores(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(start).add(stop).add(WITHSCORES);
        Command>> cmd = dispatch(ZRANGE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrangebyscore(K key, double min, double max) {
        return zrangebyscore(key, string(min), string(max));
    }

    public List zrangebyscore(K key, String min, String max) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(min).add(max);
        Command> cmd = dispatch(ZRANGEBYSCORE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrangebyscore(K key, double min, double max, long offset, long count) {
        return zrangebyscore(key, string(min), string(max), offset, count);
    }

    public List zrangebyscore(K key, String min, String max, long offset, long count) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(min).add(max).add(LIMIT).add(offset).add(count);
        Command> cmd = dispatch(ZRANGEBYSCORE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrangebyscoreWithScores(K key, double min, double max) {
        return zrangebyscoreWithScores(key, string(min), string(max));
    }

    public List> zrangebyscoreWithScores(K key, String min, String max) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(min).add(max).add(WITHSCORES);
        Command>> cmd = dispatch(ZRANGEBYSCORE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count) {
        return zrangebyscoreWithScores(key, string(min), string(max), offset, count);
    }

    public List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(min).add(max).add(WITHSCORES).add(LIMIT).add(offset).add(count);
        Command>> cmd = dispatch(ZRANGEBYSCORE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public Long zrank(K key, V member) {
        Command cmd = dispatch(ZRANK, new IntegerOutput(codec), key, member);
        return getOutput(cmd);
    }

    public Long zrem(K key, V... members) {
        Command cmd = dispatch(ZREM, new IntegerOutput(codec), key, members);
        return getOutput(cmd);
    }

    public Long zremrangebyrank(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(stop);
        Command cmd = dispatch(ZREMRANGEBYRANK, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public Long zremrangebyscore(K key, double min, double max) {
        return zremrangebyscore(key, string(min), string(max));
    }

    public Long zremrangebyscore(K key, String min, String max) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(min).add(max);
        Command cmd = dispatch(ZREMRANGEBYSCORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrevrange(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(start).add(stop);
        Command> cmd = dispatch(ZREVRANGE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrevrangeWithScores(K key, long start, long stop) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(start).add(stop).add(WITHSCORES);
        Command>> cmd = dispatch(ZREVRANGE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrevrangebyscore(K key, double max, double min) {
        return zrevrangebyscore(key, string(max), string(min));
    }

    public List zrevrangebyscore(K key, String max, String min) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(max).add(min);
        Command> cmd = dispatch(ZREVRANGEBYSCORE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List zrevrangebyscore(K key, double max, double min, long offset, long count) {
        return zrevrangebyscore(key, string(max), string(min), offset, count);
    }

    public List zrevrangebyscore(K key, String max, String min, long offset, long count) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(max).add(min).add(LIMIT).add(offset).add(count);
        Command> cmd = dispatch(ZREVRANGEBYSCORE, new ValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrevrangebyscoreWithScores(K key, double max, double min) {
        return zrevrangebyscoreWithScores(key, string(max), string(min));
    }

    public List> zrevrangebyscoreWithScores(K key, String max, String min) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(max).add(min).add(WITHSCORES);
        Command>> cmd = dispatch(ZREVRANGEBYSCORE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count) {
        return zrevrangebyscoreWithScores(key, string(max), string(min), offset, count);
    }

    public List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(key).add(max).add(min).add(WITHSCORES).add(LIMIT).add(offset).add(count);
        Command>> cmd = dispatch(ZREVRANGEBYSCORE, new ScoredValueListOutput(codec), args);
        return getOutput(cmd);
    }

    public Long zrevrank(K key, V member) {
        Command cmd = dispatch(ZREVRANK, new IntegerOutput(codec), key, member);
        return getOutput(cmd);
    }

    public Double zscore(K key, V member) {
        Command cmd = dispatch(ZSCORE, new DoubleOutput(codec), key, member);
        return getOutput(cmd);
    }

    public Long zunionstore(K destination, K... keys) {
        return zunionstore(destination, new ZStoreArgs(), keys);
    }

    public Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys) {
        CommandArgs args = new CommandArgs(codec);
        args.addKey(destination).add(keys.length).addKeys(keys);
        storeArgs.build(args);
        Command cmd = dispatch(ZUNIONSTORE, new IntegerOutput(codec), args);
        return getOutput(cmd);
    }

    /**
     * Get a new asynchronous wrapper for this connection. The wrapper delegates
     * all commands to this connection but returns null instead of waiting for
     * a response from the server.
     *
     * @return A new asynchronous connection wrapper.
     */
    public RedisAsyncConnection getAsyncConnection() {
        return new RedisAsyncConnection(codec, this);
    }

    /**
     * Close the connection.
     */
    public synchronized void close() {
        if (!closed && channel != null) {
            ConnectionWatchdog watchdog = channel.getPipeline().get(ConnectionWatchdog.class);
            watchdog.setReconnect(false);
            closed = true;
            channel.close();
        }
    }

    @Override
    public synchronized void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        channel = ctx.getChannel();

        BlockingQueue> tmp = new LinkedBlockingQueue>();

        if (password != null) {
            CommandArgs args = new CommandArgs(codec).add(password);
            tmp.put(new Command(AUTH, new StatusOutput(codec), args));
        }

        if (db != 0) {
            CommandArgs args = new CommandArgs(codec).add(db);
            tmp.put(new Command(SELECT, new StatusOutput(codec), args));
        }

        tmp.addAll(queue);

        queue.clear();
        queue.addAll(tmp);

        for (Command cmd : queue) {
            channel.write(cmd);
        }
    }

    @Override
    public synchronized void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        if (closed) {
            for (Command cmd : queue) {
                cmd.getOutput().setError("Connection closed");
                cmd.complete();
            }
            queue.clear();
            queue = null;
            channel = null;
        }
    }

    public  Command dispatch(CommandType type, CommandOutput output) {
        return dispatch(type, output, null);
    }

    public  Command dispatch(CommandType type, CommandOutput output, K key, V... values) {
        CommandArgs args = new CommandArgs(codec).addKey(key).addValues(values);
        return dispatch(type, output, args);
    }

    public synchronized  Command dispatch(CommandType type, CommandOutput output, CommandArgs args) {
        Command cmd = new Command(type, output, args);

        try {
            if (multi != null && type != EXEC) {
                multi.add(cmd.getOutput());
            }

            queue.put(cmd);

            if (channel != null) {
                channel.write(cmd);
            }
        } catch (NullPointerException e) {
            throw new RedisException("Connection is closed");
        } catch (InterruptedException e) {
            throw new RedisCommandInterruptedException(e);
        }

        return cmd;
    }

    public  T getOutput(Command cmd) {
        if (!cmd.await(timeout, unit)) {
            throw new RedisException("Command timed out");
        }
        return cmd.get();
    }

    public String string(double n) {
        if (Double.isInfinite(n)) {
            return (n > 0) ? "+inf" : "-inf";
        }
        return Double.toString(n);
    }
}