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

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

There is a newer version: 2.3.3
Show newest version
// 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.*;

/**
 * An asynchronous thread-safe connection to a redis server. Multiple threads may
 * share one {@link RedisAsyncConnection} 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 RedisAsyncConnection extends SimpleChannelUpstreamHandler {
    protected BlockingQueue> queue;
    protected RedisCodec codec;
    protected Channel channel;
    protected long timeout;
    protected TimeUnit unit;
    protected MultiOutput multi;
    private String password;
    private int db;
    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 response.
     * @param unit    Unit of time for the timeout.
     */
    public RedisAsyncConnection(BlockingQueue> queue, RedisCodec codec, long 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(long timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    public Future append(K key, V value) {
        return dispatch(APPEND, new IntegerOutput(codec), key, value);
    }

    public String auth(String password) {
        CommandArgs args = new CommandArgs(codec).add(password);
        Command cmd = dispatch(AUTH, new StatusOutput(codec), args);
        String status = await(cmd, timeout, unit);
        if ("OK".equals(status)) this.password = password;
        return status;
    }

    public Future bgrewriteaof() {
        return dispatch(BGREWRITEAOF, new StatusOutput(codec));
    }

    public Future bgsave() {
        return dispatch(BGSAVE, new StatusOutput(codec));
    }

    public Future> blpop(long timeout, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys).add(timeout);
        return dispatch(BLPOP, new KeyValueOutput(codec), args);
    }

    public Future> brpop(long timeout, K... keys) {
        CommandArgs args = new CommandArgs(codec).addKeys(keys).add(timeout);
        return dispatch(BRPOP, new KeyValueOutput(codec), args);
    }

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

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

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

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

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

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

    public Future dbsize() {
        return dispatch(DBSIZE, new IntegerOutput(codec));
    }

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

    public Future decr(K key) {
        return dispatch(DECR, new IntegerOutput(codec), key);
    }

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

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

    public Future discard() {
        multi = null;
        return dispatch(DISCARD, new StatusOutput(codec));
    }

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

    public Future exists(K key) {
        return dispatch(EXISTS, new BooleanOutput(codec), key);
    }

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

    public Future expireat(K key, Date timestamp) {
        return expireat(key, timestamp.getTime() / 1000);
    }

    public Future expireat(K key, long timestamp) {
        CommandArgs args = new CommandArgs(codec).addKey(key).add(timestamp);
        return dispatch(EXPIREAT, new BooleanOutput(codec), args);
    }

    public Future> exec() {
        MultiOutput multi = this.multi;
        this.multi = null;
        return dispatch(EXEC, multi);
    }

    public Future flushall() throws Exception {
        return dispatch(FLUSHALL, new StatusOutput(codec));
    }

    public Future flushdb() throws Exception {
        return dispatch(FLUSHDB, new StatusOutput(codec));
    }

    public Future get(K key) {
        return dispatch(GET, new ValueOutput(codec), key);
    }

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

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

    public Future getset(K key, V value) {
        return dispatch(GETSET, new ValueOutput(codec), key, value);
    }

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

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

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

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

    public Future> hgetall(K key) {
        return dispatch(HGETALL, new MapOutput(codec), key);
    }

    public Future> hkeys(K key) {
        return dispatch(HKEYS, new KeyListOutput(codec), key);
    }

    public Future hlen(K key) {
        return dispatch(HLEN, new IntegerOutput(codec), key);
    }

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

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

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

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

    public Future> hvals(K key) {
        return dispatch(HVALS, new ValueListOutput(codec), key);
    }

    public Future incr(K key) {
        return dispatch(INCR, new IntegerOutput(codec), key);
    }

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

    public Future info() {
        return dispatch(INFO, new StatusOutput(codec));
    }

    public Future> keys(K pattern) {
       return dispatch(KEYS, new KeyListOutput(codec), pattern);
    }

    public Future lastsave() {
        return dispatch(LASTSAVE, new DateOutput(codec));
    }

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

    public Future 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);
        return dispatch(LINSERT, new IntegerOutput(codec), args);
    }

    public Future llen(K key) {
        return dispatch(LLEN, new IntegerOutput(codec), key);
    }

    public Future lpop(K key) {
        return dispatch(LPOP, new ValueOutput(codec), key);
    }

    public Future lpush(K key, V... values) {
        return dispatch(LPUSH, new IntegerOutput(codec), key, values);
    }

    public Future lpushx(K key, V value) {
        return dispatch(LPUSHX, new IntegerOutput(codec), key, value);
    }

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

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

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

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

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

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

    public Future multi() {
        Command cmd = dispatch(MULTI, new StatusOutput(codec));
        multi = (multi == null ? new MultiOutput(codec) : multi);
        return cmd;
    }

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

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

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

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

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

    public Future persist(K key) {
        return dispatch(PERSIST, new BooleanOutput(codec), key);
    }

    public Future ping() {
        return dispatch(PING, new StatusOutput(codec));
    }

    public Future publish(K channel, V message) {
        CommandArgs args = new CommandArgs(codec).addKey(channel).addValue(message);
        return dispatch(PUBLISH, new IntegerOutput(codec), args);
    }

    public Future quit() {
        return dispatch(QUIT, new StatusOutput(codec));
    }

    public Future randomkey() {
        return dispatch(RANDOMKEY, new ValueOutput(codec));
    }

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

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

    public Future rpop(K key) {
        return dispatch(RPOP, new ValueOutput(codec), key);
    }

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

    public Future rpush(K key, V... values) {
        return dispatch(RPUSH, new IntegerOutput(codec), key, values);
    }

    public Future rpushx(K key, V value) {
        return dispatch(RPUSHX, new IntegerOutput(codec), key, value);
    }

    public Future sadd(K key, V... members) {
        return dispatch(SADD, new IntegerOutput(codec), key, members);
    }

    public Future save() {
        return dispatch(SAVE, new StatusOutput(codec));
    }

    public Future scard(K key) {
        return dispatch(SCARD, new IntegerOutput(codec), key);
    }

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

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

    public String select(int db) {
        CommandArgs args = new CommandArgs(codec).add(db);
        Command cmd = dispatch(SELECT, new StatusOutput(codec), args);
        String status = await(cmd, timeout, unit);
        if ("OK".equals(status)) this.db = db;
        return status;
    }

    public Future set(K key, V value) {
        return dispatch(SET, new StatusOutput(codec), key, value);
    }

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

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

    public Future setnx(K key, V value) {
        return dispatch(SETNX, new BooleanOutput(codec), key, value);
    }

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

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

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

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

    public Future sismember(K key, V member) {
        return dispatch(SISMEMBER, new BooleanOutput(codec), key, member);
    }

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

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

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

    public Future> slowlogGet() {
        CommandArgs args = new CommandArgs(codec).add(GET);
        return dispatch(SLOWLOG, new NestedMultiOutput(codec), args);
    }

    public Future> slowlogGet(int count) {
        CommandArgs args = new CommandArgs(codec).add(GET).add(count);
        return dispatch(SLOWLOG, new NestedMultiOutput(codec), args);
    }

    public Future slowlogLen() {
        CommandArgs args = new CommandArgs(codec).add(LEN);
        return dispatch(SLOWLOG, new IntegerOutput(codec), args);
    }

    public Future slowlogReset() {
        CommandArgs args = new CommandArgs(codec).add(RESET);
        return dispatch(SLOWLOG, new StatusOutput(codec), args);
    }

    public Future> smembers(K key) {
        return dispatch(SMEMBERS, new ValueSetOutput(codec), key);
    }

    public Future> sort(K key) {
        return dispatch(SORT, new ValueListOutput(codec), key);
    }

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

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

    public Future spop(K key) {
        return dispatch(SPOP, new ValueOutput(codec), key);
    }

    public Future srandmember(K key) {
        return dispatch(SRANDMEMBER, new ValueOutput(codec), key);
    }

    public Future srem(K key, V... members) {
        return dispatch(SREM, new IntegerOutput(codec), key, members);
    }

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

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

    public Future sync() {
        return dispatch(SYNC, new StatusOutput(codec));
    }

    public Future strlen(K key) {
        return dispatch(STRLEN, new IntegerOutput(codec), key);
    }

    public Future ttl(K key) {
        return dispatch(TTL, new IntegerOutput(codec), key);
    }

    public Future type(K key) {
        return dispatch(TYPE, new StatusOutput(codec), key);
    }

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

    public Future unwatch() {
        return dispatch(UNWATCH, new StatusOutput(codec));
    }

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

    @SuppressWarnings("unchecked")
    public Future 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]);
        }
        return dispatch(ZADD, new IntegerOutput(codec), args);
    }

    public Future zcard(K key) {
        return dispatch(ZCARD, new IntegerOutput(codec), key);
    }

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

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

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

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

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

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

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

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

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

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

    public Future> 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);
        return dispatch(ZRANGEBYSCORE, new ValueListOutput(codec), args);
    }

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

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

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

    public Future>> 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);
        return dispatch(ZRANGEBYSCORE, new ScoredValueListOutput(codec), args);
    }

    public Future zrank(K key, V member) {
        return dispatch(ZRANK, new IntegerOutput(codec), key, member);
    }

    public Future zrem(K key, V... members) {
        return dispatch(ZREM, new IntegerOutput(codec), key, members);
    }

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

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

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

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

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

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

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

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

    public Future> 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);
        return dispatch(ZREVRANGEBYSCORE, new ValueListOutput(codec), args);
    }

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

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

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

    public Future>> 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);
        return dispatch(ZREVRANGEBYSCORE, new ScoredValueListOutput(codec), args);
    }

    public Future zrevrank(K key, V member) {
        return dispatch(ZREVRANK, new IntegerOutput(codec), key, member);
    }

    public Future zscore(K key, V member) {
        return dispatch(ZSCORE, new DoubleOutput(codec), key, member);
    }

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

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

    /**
     * Wait until commands are complete or the connection timeout is reached.
     *
     * @param futures   Futures to wait for.
     *
     * @return True if all futures complete in time.
     */
    public boolean awaitAll(Future... futures) {
        return awaitAll(timeout, unit, futures);
    }

    /**
     * Wait until futures are complete or the supplied timeout is reached.
     *
     * @param timeout   Maximum time to wait for futures to complete.
     * @param unit      Unit of time for the timeout.
     * @param futures   Futures to wait for.
     *
     * @return True if all futures complete in time.
     */
    public boolean awaitAll(long timeout, TimeUnit unit, Future... futures) {
        boolean complete;

        try {
            long nanos = unit.toNanos(timeout);
            long time  = System.nanoTime();

            for (Future f : futures) {
                if (nanos < 0) return false;
                f.get(nanos, TimeUnit.NANOSECONDS);
                long now = System.nanoTime();
                nanos -= now - time;
                time   = now;
            }

            complete = true;
        } catch (TimeoutException e) {
            complete = false;
        } catch (Exception e) {
            throw new RedisCommandInterruptedException(e);
        }

        return complete;
    }

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

        List> tmp = new ArrayList>(queue.size() + 2);

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

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

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

        for (Command cmd : tmp) {
            if (!cmd.isCancelled()) {
                queue.add(cmd);
                channel.write(cmd);
            }
        }

        tmp.clear();
    }

    @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, (CommandArgs) null);
    }

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

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

    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, multi != null);

        try {
            if (multi != null) {
                multi.add(cmd);
            }

            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 await(Command cmd, long timeout, TimeUnit unit) {
        if (!cmd.await(timeout, unit)) {
            cmd.cancel(true);
            throw new RedisException("Command timed out");
        }
        CommandOutput output = cmd.getOutput();
        if (output.hasError()) throw new RedisException(output.getError());
        return output.get();
    }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy