Migration to a new client. #183

pull/243/head
Nikita 10 years ago
parent 9310e43d66
commit 63543ced1c

@ -26,17 +26,14 @@ import static com.lambdaworks.redis.protocol.CommandKeyword.SETNAME;
import static com.lambdaworks.redis.protocol.CommandKeyword.WITHSCORES;
import static com.lambdaworks.redis.protocol.CommandKeyword.XOR;
import static com.lambdaworks.redis.protocol.CommandType.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -60,8 +57,6 @@ import com.lambdaworks.redis.output.ListScanOutput;
import com.lambdaworks.redis.output.ListScanResult;
import com.lambdaworks.redis.output.MapKeyListOutput;
import com.lambdaworks.redis.output.MapOutput;
import com.lambdaworks.redis.output.MapScanOutput;
import com.lambdaworks.redis.output.MapScanResult;
import com.lambdaworks.redis.output.MapValueListOutput;
import com.lambdaworks.redis.output.MapValueOutput;
import com.lambdaworks.redis.output.MultiOutput;
@ -80,6 +75,14 @@ import com.lambdaworks.redis.protocol.CommandOutput;
import com.lambdaworks.redis.protocol.CommandType;
import com.lambdaworks.redis.protocol.ConnectionWatchdog;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/**
* An asynchronous thread-safe connection to a redis server. Multiple threads may
* share one {@link RedisAsyncConnection} provided they avoid blocking and transactional
@ -1097,11 +1100,6 @@ public class RedisAsyncConnection<K, V> extends ChannelInboundHandlerAdapter {
return dispatch(SSCAN, new ValueSetScanOutput<K, V>(codec), args);
}
public Future<MapScanResult<K, V>> hscan(K key, long startValue) {
CommandArgs<K, V> args = new CommandArgs<K, V>(codec).addKey(key).add(startValue);
return dispatch(HSCAN, new MapScanOutput<K, V>(codec), args);
}
public Future<ListScanResult<V>> zscan(K key, long startValue) {
CommandArgs<K, V> args = new CommandArgs<K, V>(codec).addKey(key).add(startValue);
return dispatch(ZSCAN, new ListScanOutput<K, V>(codec), args);

@ -1,35 +0,0 @@
package com.lambdaworks.redis.output;
import java.nio.ByteBuffer;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.protocol.CommandOutput;
public class MapScanOutput<K, V> extends CommandOutput<K, V, MapScanResult<K, V>> {
int counter;
public MapScanOutput(RedisCodec<K, V> codec) {
super(codec, new MapScanResult<K, V>());
}
@Override
public void set(ByteBuffer bytes) {
if (output.getPos() == null) {
output.setPos(toLong(bytes));
} else {
if (counter % 2 == 0) {
output.addValue(codec.decodeMapValue(bytes));
} else {
output.addKey(codec.decodeMapKey(bytes));
}
}
counter++;
}
private Long toLong(ByteBuffer bytes) {
return bytes == null ? null : new Long(new String(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.limit()));
}
}

@ -15,6 +15,7 @@
*/
package org.redisson;
import org.redisson.client.protocol.Codec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.codec.RedissonCodec;
@ -42,7 +43,7 @@ public class Config {
/**
* Redis key/value codec. JsonJacksonCodec used by default
*/
private RedissonCodec codec;
private Codec codec;
private boolean useLinuxNativeEpoll;
@ -79,11 +80,11 @@ public class Config {
* @see org.redisson.codec.JsonJacksonCodec
* @see org.redisson.codec.SerializationCodec
*/
public Config setCodec(RedissonCodec codec) {
public Config setCodec(Codec codec) {
this.codec = codec;
return this;
}
public RedissonCodec getCodec() {
public Codec getCodec() {
return codec;
}

@ -15,10 +15,9 @@
*/
package org.redisson;
import org.redisson.client.RedisPubSubListener;
import org.redisson.core.MessageListener;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
/**
*
* @author Nikita Koksharov
@ -26,7 +25,7 @@ import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
* @param <K>
* @param <V>
*/
public class RedisPubSubTopicListenerWrapper<V> extends RedisPubSubAdapter<V> {
public class RedisPubSubTopicListenerWrapper<V> implements RedisPubSubListener<V> {
private final MessageListener<V> listener;
private final String name;
@ -41,19 +40,6 @@ public class RedisPubSubTopicListenerWrapper<V> extends RedisPubSubAdapter<V> {
this.name = name;
}
@Override
public void message(String channel, V message) {
// could be subscribed to multiple channels
if (name.equals(channel)) {
listener.onMessage(message);
}
}
@Override
public void message(String pattern, String channel, V message) {
listener.onMessage(message);
}
@Override
public int hashCode() {
final int prime = 31;
@ -79,6 +65,17 @@ public class RedisPubSubTopicListenerWrapper<V> extends RedisPubSubAdapter<V> {
return true;
}
@Override
public void onMessage(String channel, V message) {
// could be subscribed to multiple channels
if (name.equals(channel)) {
listener.onMessage(message);
}
}
@Override
public void onPatternMessage(String pattern, String channel, V message) {
listener.onMessage(message);
}
}

@ -15,17 +15,32 @@
*/
package org.redisson;
import com.lambdaworks.redis.RedisAsyncConnection;
import io.netty.util.concurrent.Future;
import org.redisson.async.ResultOperation;
import org.redisson.connection.*;
import org.redisson.core.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ClusterConnectionManager;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveConnectionManager;
import org.redisson.connection.SentinelConnectionManager;
import org.redisson.connection.SingleConnectionManager;
import org.redisson.core.RAtomicLong;
import org.redisson.core.RBlockingQueue;
import org.redisson.core.RBucket;
import org.redisson.core.RCountDownLatch;
import org.redisson.core.RDeque;
import org.redisson.core.RHyperLogLog;
import org.redisson.core.RList;
import org.redisson.core.RLock;
import org.redisson.core.RMap;
import org.redisson.core.RQueue;
import org.redisson.core.RScript;
import org.redisson.core.RSet;
import org.redisson.core.RSortedSet;
import org.redisson.core.RTopic;
/**
* Main infrastructure class allows to get access
* to all Redisson objects on top of Redis server.
@ -96,15 +111,7 @@ public class Redisson implements RedissonClient {
*/
@Override
public <V> List<RBucket<V>> getBuckets(final String pattern) {
List<Object> keys = connectionManager.get(connectionManager.readAsync(new ResultOperation<List<Object>, V>() {
@Override
public Future<List<Object>> execute(RedisAsyncConnection<Object, V> async) {
return async.keys(pattern);
}
}));
if (keys == null) {
return Collections.emptyList();
}
Collection<Object> keys = connectionManager.get(connectionManager.readAllAsync(RedisCommands.KEYS, pattern));
List<RBucket<V>> buckets = new ArrayList<RBucket<V>>(keys.size());
for (Object key : keys) {
if(key != null) {
@ -291,12 +298,7 @@ public class Redisson implements RedissonClient {
}
public void flushdb() {
connectionManager.writeAllAsync(new ResultOperation<String, Object>() {
@Override
protected Future<String> execute(RedisAsyncConnection<Object, Object> conn) {
return conn.flushdb();
}
}).awaitUninterruptibly();
connectionManager.writeAllAsync(RedisCommands.FLUSHDB).awaitUninterruptibly();
}
}

@ -15,21 +15,13 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.Collections;
import org.redisson.async.ResultOperation;
import org.redisson.async.SyncOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RAtomicLong;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisConnection;
import org.redisson.core.RScript;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/**
* Distributed alternative to the {@link java.util.concurrent.atomic.AtomicLong}
*
@ -43,31 +35,24 @@ public class RedissonAtomicLong extends RedissonExpirable implements RAtomicLong
}
@Override
public long addAndGet(final long delta) {
return connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.incrby(getName(), delta);
}
});
public long addAndGet(long delta) {
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.INCRBY, getName(), delta);
}
@Override
public boolean compareAndSet(final long expect, final long update) {
return new RedissonScript(connectionManager).evalR(
"if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('set', KEYS[1], ARGV[2]); return true else return false end",
RScript.ReturnType.BOOLEAN,
Collections.<Object>singletonList(getName()), Collections.EMPTY_LIST, Arrays.asList(expect, update));
public boolean compareAndSet(long expect, long update) {
return connectionManager.eval(StringCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if redis.call('get', KEYS[1]) == ARGV[1] then "
+ "redis.call('set', KEYS[1], ARGV[2]); "
+ "return true "
+ "else "
+ "return false end",
Collections.<Object>singletonList(getName()), expect, update);
}
@Override
public long decrementAndGet() {
return connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.decr(getName());
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.DECR, getName());
}
@Override
@ -76,29 +61,24 @@ public class RedissonAtomicLong extends RedissonExpirable implements RAtomicLong
}
@Override
public long getAndAdd(final long delta) {
return new RedissonScript(connectionManager).evalR(
"local v = redis.call('get', KEYS[1]) or 0; redis.call('set', KEYS[1], v + ARGV[1]); return tonumber(v)",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), Collections.EMPTY_LIST, Collections.singletonList(delta));
public long getAndAdd(long delta) {
return connectionManager.eval(StringCodec.INSTANCE, RedisCommands.EVAL_INTEGER,
"local v = redis.call('get', KEYS[1]) or 0; "
+ "redis.call('set', KEYS[1], v + ARGV[1]); "
+ "return tonumber(v)",
Collections.<Object>singletonList(getName()), delta);
}
@Override
public long getAndSet(final long newValue) {
return new RedissonScript(connectionManager).evalR(
return connectionManager.eval(StringCodec.INSTANCE, RedisCommands.EVAL_INTEGER,
"local v = redis.call('get', KEYS[1]) or 0; redis.call('set', KEYS[1], ARGV[1]); return tonumber(v)",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), Collections.EMPTY_LIST, Collections.singletonList(newValue));
Collections.<Object>singletonList(getName()), newValue);
}
@Override
public long incrementAndGet() {
return connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.incr(getName());
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.INCR, getName());
}
@Override
@ -111,11 +91,8 @@ public class RedissonAtomicLong extends RedissonExpirable implements RAtomicLong
}
@Override
public void set(final long newValue) {
new RedissonScript(connectionManager).evalR(
"redis.call('set', KEYS[1], ARGV[1])",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), Collections.EMPTY_LIST, Collections.singletonList(newValue));
public void set(long newValue) {
connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.SET, getName(), newValue);
}
public String toString() {

@ -15,7 +15,6 @@
*/
package org.redisson;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -23,13 +22,12 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.redisson.async.SyncInterruptedOperation;
import org.redisson.async.SyncOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.decoder.KeyValueMessage;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RBlockingQueue;
import com.lambdaworks.redis.RedisConnection;
import org.redisson.core.RScript;
import io.netty.util.concurrent.Future;
/**
* Offers blocking queue facilities through an intermediary
@ -58,22 +56,18 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
@Override
public V take() throws InterruptedException {
return connectionManager.write(getName(), new SyncInterruptedOperation<V, V>() {
@Override
public V execute(RedisConnection<Object, V> conn) throws InterruptedException {
return conn.blpop(0, getName()).value;
}
});
Future<KeyValueMessage<String, V>> res = connectionManager.writeAsync(getName(), RedisCommands.BLPOP, getName(), 0);
return res.await().getNow().getValue();
}
@Override
public V poll(final long timeout, final TimeUnit unit) throws InterruptedException {
return connectionManager.write(getName(), new SyncInterruptedOperation<V, V>() {
@Override
public V execute(RedisConnection<Object, V> conn) throws InterruptedException {
return conn.blpop(unit.toSeconds(timeout), getName()).value;
}
});
public V poll(long timeout, TimeUnit unit) throws InterruptedException {
Future<KeyValueMessage<String, V>> res = connectionManager.writeAsync(getName(), RedisCommands.BLPOP, getName(), unit.toSeconds(timeout));
KeyValueMessage<String, V> m = res.await().getNow();
if (m != null) {
return m.getValue();
}
return null;
}
@Override
@ -83,13 +77,9 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
}
@Override
public V pollLastAndOfferFirstTo(final String queueName, final long timeout, final TimeUnit unit) throws InterruptedException {
return connectionManager.write(getName(), new SyncInterruptedOperation<V, V>() {
@Override
public V execute(RedisConnection<Object, V> conn) throws InterruptedException {
return conn.brpoplpush(unit.toSeconds(timeout), getName(), queueName);
}
});
public V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException {
Future<V> res = connectionManager.writeAsync(getName(), RedisCommands.BRPOPLPUSH, getName(), queueName, unit.toSeconds(timeout));
return res.await().getNow();
}
@Override
@ -102,12 +92,11 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
if (c == null) {
throw new NullPointerException();
}
List<V> list = new RedissonScript(connectionManager).eval(
"local vals = redis.call('lrange', KEYS[1], 0, -1); " +
"redis.call('ltrim', KEYS[1], -1, 0); " +
"return vals",
RScript.ReturnType.MAPVALUELIST,
Collections.<Object>singletonList(getName()));
List<V> list = connectionManager.eval(RedisCommands.EVAL_LIST,
"local vals = redis.call('lrange', KEYS[1], 0, -1); " +
"redis.call('ltrim', KEYS[1], -1, 0); " +
"return vals", Collections.<Object>singletonList(getName()));
c.addAll(list);
return list.size();
}
@ -121,13 +110,12 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
throw new NullPointerException();
}
List<V> list = new RedissonScript(connectionManager).evalR(
List<V> list = connectionManager.eval(RedisCommands.EVAL_LIST,
"local elemNum = math.min(ARGV[1], redis.call('llen', KEYS[1])) - 1;" +
"local vals = redis.call('lrange', KEYS[1], 0, elemNum); " +
"redis.call('ltrim', KEYS[1], elemNum + 1, -1); " +
"return vals",
RScript.ReturnType.MAPVALUELIST,
Collections.<Object>singletonList(getName()), Collections.emptyList(), Collections.singletonList(maxElements));
Collections.<Object>singletonList(getName()), maxElements);
c.addAll(list);
return list.size();
}

@ -15,16 +15,13 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.redisson.async.ResultOperation;
import org.redisson.async.VoidOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RBucket;
import com.lambdaworks.redis.RedisAsyncConnection;
import io.netty.util.concurrent.Future;
public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
@ -39,12 +36,7 @@ public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
@Override
public Future<V> getAsync() {
return connectionManager.readAsync(getName(), new ResultOperation<V, V>() {
@Override
public Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.get(getName());
}
});
return connectionManager.readAsync(getName(), RedisCommands.GET, getName());
}
@Override
@ -53,13 +45,8 @@ public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
}
@Override
public Future<Void> setAsync(final V value) {
return connectionManager.writeAsync(getName(), new VoidOperation<V, String>() {
@Override
public Future<String> execute(RedisAsyncConnection<Object, V> async) {
return async.set(getName(), value);
}
});
public Future<Void> setAsync(V value) {
return connectionManager.writeAsyncVoid(getName(), RedisCommands.SET, getName(), value);
}
@Override
@ -68,13 +55,8 @@ public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
}
@Override
public Future<Void> setAsync(final V value, final long timeToLive, final TimeUnit timeUnit) {
return connectionManager.writeAsync(getName(), new VoidOperation<V, String>() {
@Override
public Future<String> execute(RedisAsyncConnection<Object, V> async) {
return async.setex(getName(), timeUnit.toSeconds(timeToLive), value);
}
});
public Future<Void> setAsync(V value, long timeToLive, TimeUnit timeUnit) {
return connectionManager.writeAsyncVoid(getName(), RedisCommands.SETEX, getName(), timeUnit.toSeconds(timeToLive), value);
}
@Override
@ -84,12 +66,7 @@ public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
@Override
public Future<Boolean> existsAsync() {
return connectionManager.readAsync(getName(), new ResultOperation<Boolean, V>() {
@Override
public Future<Boolean> execute(RedisAsyncConnection<Object, V> async) {
return async.exists(getName());
}
});
return connectionManager.readAsync(getName(), RedisCommands.EXISTS, getName());
}
}

@ -15,20 +15,22 @@
*/
package org.redisson;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.protocol.LongCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RCountDownLatch;
import org.redisson.core.RScript;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/**
@ -72,18 +74,10 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
return oldPromise;
}
RedisPubSubAdapter<Integer> listener = new RedisPubSubAdapter<Integer>() {
@Override
public void subscribed(String channel, long count) {
if (getChannelName().equals(channel)
&& !value.getPromise().isSuccess()) {
value.getPromise().setSuccess(true);
}
}
RedisPubSubListener<Integer> listener = new RedisPubSubListener<Integer>() {
@Override
public void message(String channel, Integer message) {
public void onMessage(String channel, Integer message) {
if (!getChannelName().equals(channel)) {
return;
}
@ -95,11 +89,26 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
}
}
@Override
public void onPatternMessage(String pattern, String channel, Integer message) {
// TODO Auto-generated method stub
}
};
Future<PubSubStatusMessage> res = null;
synchronized (ENTRIES) {
connectionManager.subscribe(listener, getChannelName());
res = connectionManager.subscribe(listener, getChannelName());
}
res.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
if (!value.getPromise().isSuccess()) {
value.getPromise().setSuccess(true);
}
}
});
return newPromise;
}
@ -195,13 +204,12 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
return;
}
new RedissonScript(connectionManager).evalR(
connectionManager.eval(RedisCommands.EVAL_BOOLEAN,
"local v = redis.call('decr', KEYS[1]);" +
"if v <= 0 then redis.call('del', KEYS[1]) end;" +
"if v == 0 then redis.call('publish', ARGV[2], ARGV[1]) end;" +
"return 'OK'",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), Collections.singletonList(zeroCountMessage), Collections.singletonList(getChannelName()));
"return true",
Collections.<Object>singletonList(getName()), zeroCountMessage, getChannelName());
}
private String getEntryName() {
@ -218,12 +226,7 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
}
private long getCountInner() {
Long val = new RedissonScript(connectionManager).eval(
"return redis.call('get', KEYS[1])",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()));
Long val = connectionManager.read(getName(), LongCodec.INSTANCE, RedisCommands.GET, getName());
if (val == null) {
return 0;
}
@ -232,18 +235,16 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
@Override
public boolean trySetCount(long count) {
return new RedissonScript(connectionManager).evalR(
return connectionManager.eval(RedisCommands.EVAL_BOOLEAN,
"if redis.call('exists', KEYS[1]) == 0 then redis.call('set', KEYS[1], ARGV[2]); redis.call('publish', ARGV[3], ARGV[1]); return true else return false end",
RScript.ReturnType.BOOLEAN,
Collections.<Object>singletonList(getName()), Collections.singletonList(newCountMessage), Arrays.asList(count, getChannelName()));
Collections.<Object>singletonList(getName()), newCountMessage, count, getChannelName());
}
@Override
public Future<Boolean> deleteAsync() {
return new RedissonScript(connectionManager).evalAsyncR(
return connectionManager.evalAsync(RedisCommands.EVAL_BOOLEAN,
"if redis.call('del', KEYS[1]) == 1 then redis.call('publish', ARGV[2], ARGV[1]); return true else return false end",
RScript.ReturnType.BOOLEAN,
Collections.<Object>singletonList(getName()), Collections.singletonList(newCountMessage), Collections.singletonList(getChannelName()));
Collections.<Object>singletonList(getName()), newCountMessage, getChannelName());
}
}

@ -15,19 +15,14 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.redisson.async.ResultOperation;
import org.redisson.async.VoidOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RDeque;
import com.lambdaworks.redis.RedisAsyncConnection;
/**
* Distributed and concurrent implementation of {@link java.util.Queue}
*
@ -42,23 +37,13 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
}
@Override
public void addFirst(final V e) {
connectionManager.write(getName(), new VoidOperation<V, Long>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.lpush(getName(), e);
}
});
public void addFirst(V e) {
connectionManager.write(getName(), RedisCommands.LPUSH, getName(), e);
}
@Override
public void addLast(final V e) {
connectionManager.write(getName(), new VoidOperation<V, Long>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.rpush(getName(), e);
}
});
public void addLast(V e) {
connectionManager.write(getName(), RedisCommands.RPUSH, getName(), e);
}
@Override
@ -99,12 +84,7 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
@Override
public V getLast() {
List<V> list = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), -1, -1);
}
});
List<V> list = connectionManager.read(getName(), RedisCommands.LRANGE, getName(), -1, -1);
if (list.isEmpty()) {
throw new NoSuchElementException();
}
@ -112,13 +92,8 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
}
@Override
public boolean offerFirst(final V e) {
connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.lpush(getName(), e);
}
});
public boolean offerFirst(V e) {
connectionManager.write(getName(), RedisCommands.LPUSH, getName(), e);
return true;
}
@ -134,14 +109,9 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
@Override
public V peekLast() {
List<V> list = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), -1, -1);
}
});
List<V> list = connectionManager.read(getName(), RedisCommands.LRANGE, getName(), -1, -1);
if (list.isEmpty()) {
throw null;
return null;
}
return list.get(0);
}
@ -153,12 +123,7 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
@Override
public V pollLast() {
return connectionManager.write(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.rpop(getName());
}
});
return connectionManager.write(getName(), RedisCommands.RPOP, getName());
}
@Override
@ -178,12 +143,7 @@ public class RedissonDeque<V> extends RedissonQueue<V> implements RDeque<V> {
@Override
public V removeLast() {
V value = connectionManager.write(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.rpop(getName());
}
});
V value = connectionManager.write(getName(), RedisCommands.RPOP, getName());
if (value == null) {
throw new NoSuchElementException();
}

@ -15,17 +15,14 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RExpirable;
import com.lambdaworks.redis.RedisAsyncConnection;
abstract class RedissonExpirable extends RedissonObject implements RExpirable {
RedissonExpirable(ConnectionManager connectionManager, String name) {
@ -34,52 +31,27 @@ abstract class RedissonExpirable extends RedissonObject implements RExpirable {
@Override
public boolean expire(final long timeToLive, final TimeUnit timeUnit) {
return connectionManager.write(getName(), new ResultOperation<Boolean, Object>() {
@Override
protected Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.expire(getName(), timeUnit.toSeconds(timeToLive));
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.EXPIRE, getName(), timeUnit.toSeconds(timeToLive));
}
@Override
public boolean expireAt(final long timestamp) {
return connectionManager.write(getName(), new ResultOperation<Boolean, Object>() {
@Override
protected Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.expireat(getName(), timestamp);
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.EXPIREAT, getName(), timestamp);
}
@Override
public boolean expireAt(final Date timestamp) {
return connectionManager.write(getName(), new ResultOperation<Boolean, Object>() {
@Override
protected Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.expireat(getName(), timestamp);
}
});
return expireAt(timestamp.getTime() / 1000);
}
@Override
public boolean clearExpire() {
return connectionManager.write(getName(), new ResultOperation<Boolean, Object>() {
@Override
protected Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.persist(getName());
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.PERSIST, getName());
}
@Override
public long remainTimeToLive() {
return connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.ttl(getName());
}
});
return connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.TTL, getName());
}
}

@ -15,15 +15,16 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RHyperLogLog;
import com.lambdaworks.redis.RedisAsyncConnection;
import io.netty.util.concurrent.Future;
public class RedissonHyperLogLog<V> extends RedissonObject implements RHyperLogLog<V> {
@ -32,12 +33,12 @@ public class RedissonHyperLogLog<V> extends RedissonObject implements RHyperLogL
}
@Override
public long add(V obj) {
public boolean add(V obj) {
return connectionManager.get(addAsync(obj));
}
@Override
public long addAll(Collection<V> objects) {
public boolean addAll(Collection<V> objects) {
return connectionManager.get(addAllAsync(objects));
}
@ -52,58 +53,42 @@ public class RedissonHyperLogLog<V> extends RedissonObject implements RHyperLogL
}
@Override
public long mergeWith(String... otherLogNames) {
return connectionManager.get(mergeWithAsync(otherLogNames));
public void mergeWith(String... otherLogNames) {
connectionManager.get(mergeWithAsync(otherLogNames));
}
@Override
public Future<Long> addAsync(final V obj) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, V>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.pfadd(getName(), obj);
}
});
public Future<Boolean> addAsync(V obj) {
return connectionManager.writeAsync(getName(), RedisCommands.PFADD, getName(), obj);
}
@Override
public Future<Long> addAllAsync(final Collection<V> objects) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.pfadd(getName(), objects.toArray());
}
});
public Future<Boolean> addAllAsync(Collection<V> objects) {
List<Object> args = new ArrayList<Object>(objects.size() + 1);
args.add(getName());
args.addAll(objects);
return connectionManager.writeAsync(getName(), RedisCommands.PFADD, getName(), args.toArray());
}
@Override
public Future<Long> countAsync() {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.pfcount(getName());
}
});
return connectionManager.readAsync(getName(), RedisCommands.PFCOUNT, getName());
}
@Override
public Future<Long> countWithAsync(final String... otherLogNames) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.pfcount(getName(), otherLogNames);
}
});
public Future<Long> countWithAsync(String... otherLogNames) {
List<Object> args = new ArrayList<Object>(otherLogNames.length + 1);
args.add(getName());
args.addAll(Arrays.asList(otherLogNames));
return connectionManager.readAsync(getName(), RedisCommands.PFCOUNT, args.toArray());
}
@Override
public Future<Long> mergeWithAsync(final String... otherLogNames) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.pfmerge(getName(), otherLogNames);
}
});
public Future<Void> mergeWithAsync(String... otherLogNames) {
List<Object> args = new ArrayList<Object>(otherLogNames.length + 1);
args.add(getName());
args.addAll(Arrays.asList(otherLogNames));
return connectionManager.writeAsyncVoid(getName(), RedisCommands.PFMERGE, args.toArray());
}
}

@ -15,19 +15,23 @@
*/
package org.redisson;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisConnection;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.redisson.async.AsyncOperation;
import org.redisson.async.OperationListener;
import org.redisson.async.ResultOperation;
import org.redisson.async.SyncOperation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.redisson.client.protocol.BooleanReplayConvertor;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RList;
import org.redisson.core.RScript;
import java.util.*;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/**
* Distributed and concurrent implementation of {@link java.util.List}
@ -46,12 +50,8 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
@Override
public int size() {
return connectionManager.read(getName(), new ResultOperation<Long, V>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.llen(getName());
}
}).intValue();
Long size = connectionManager.read(getName(), RedisCommands.LLEN, getName());
return size.intValue();
}
@Override
@ -76,13 +76,7 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
}
protected List<V> readAllList() {
List<V> list = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), 0, -1);
}
});
return list;
return connectionManager.read(getName(), RedisCommands.LRANGE, getName(), 0, -1);
}
@Override
@ -106,13 +100,8 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
return remove(o, 1);
}
protected boolean remove(final Object o, final int count) {
return connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.lrem(getName(), count, o);
}
}) > 0;
protected boolean remove(Object o, int count) {
return (Long)connectionManager.write(getName(), RedisCommands.LREM, getName(), count, o) > 0;
}
@Override
@ -125,12 +114,7 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
int to = div(size(), batchSize);
for (int i = 0; i < to; i++) {
final int j = i;
List<Object> range = connectionManager.read(getName(), new ResultOperation<List<Object>, Object>() {
@Override
protected Future<List<Object>> execute(RedisAsyncConnection<Object, Object> async) {
return async.lrange(getName(), j*batchSize, j*batchSize + batchSize - 1);
}
});
List<V> range = connectionManager.read(getName(), RedisCommands.LRANGE, getName(), j*batchSize, j*batchSize + batchSize - 1);
for (Iterator<Object> iterator = copy.iterator(); iterator.hasNext();) {
Object obj = iterator.next();
int index = range.indexOf(obj);
@ -153,17 +137,24 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
if (c.isEmpty()) {
return connectionManager.getGroup().next().newSucceededFuture(false);
}
return connectionManager.writeAsync(getName(), new AsyncOperation<Object, Boolean>() {
final Promise<Boolean> promise = newPromise();
final int listSize = size();
List<Object> args = new ArrayList<Object>(c.size() + 1);
args.add(getName());
args.addAll(c);
Future<Long> res = connectionManager.writeAsync(getName(), RedisCommands.RPUSH, args.toArray());
res.addListener(new FutureListener<Long>() {
@Override
public void execute(final Promise<Boolean> promise, RedisAsyncConnection<Object, Object> async) {
async.rpush((Object) getName(), c.toArray()).addListener(new OperationListener<Object, Boolean, Object>(promise, async, this) {
@Override
public void onOperationComplete(Future<Object> future) throws Exception {
promise.setSuccess(true);
}
});
public void operationComplete(Future<Long> future) throws Exception {
if (future.isSuccess()) {
promise.setSuccess(listSize != future.getNow());
} else {
promise.setFailure(future.cause());
}
}
});
return promise;
}
@Override
@ -172,31 +163,41 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
if (coll.isEmpty()) {
return false;
}
if (index < size()) {
int size = size();
if (index < size) {
if (index == 0) { // prepend elements to list
final ArrayList<V> elemens = new ArrayList<V>(coll);
Collections.reverse(elemens);
return connectionManager.write(getName(), new SyncOperation<Object, Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, Object> conn) {
conn.lpush(getName(), elemens.toArray());
return true;
}
});
List<Object> elements = new ArrayList<Object>(coll);
Collections.reverse(elements);
elements.add(0, getName());
Long newSize = connectionManager.write(getName(), RedisCommands.LPUSH, elements.toArray());
return newSize != size;
}
// insert into middle of list
return "OK".equals(new RedissonScript(connectionManager).evalR(
"local ind = table.remove(ARGV); " + // index is last parameter
List<Object> args = new ArrayList<Object>(coll.size() + 1);
args.add(index);
args.addAll(coll);
return connectionManager.eval(new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 5),
"local ind = table.remove(ARGV, 1); " + // index is the first parameter
"local tail = redis.call('lrange', KEYS[1], ind, -1); " +
"redis.call('ltrim', KEYS[1], 0, ind - 1); " +
"for i, v in ipairs(ARGV) do redis.call('rpush', KEYS[1], v) end;" +
"for i, v in ipairs(tail) do redis.call('rpush', KEYS[1], v) end;" +
"return 'OK'",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), new ArrayList<Object>(coll), Collections.singletonList(index)));
"return true",
Collections.<Object>singletonList(getName()), args.toArray());
// return "OK".equals(new RedissonScript(connectionManager).evalR(
// "local ind = table.remove(ARGV); " + // index is last parameter
// "local tail = redis.call('lrange', KEYS[1], ind, -1); " +
// "redis.call('ltrim', KEYS[1], 0, ind - 1); " +
// "for i, v in ipairs(ARGV) do redis.call('rpush', KEYS[1], v) end;" +
// "for i, v in ipairs(tail) do redis.call('rpush', KEYS[1], v) end;" +
// "return 'OK'",
// RScript.ReturnType.STATUS,
// Collections.<Object>singletonList(getName()), new ArrayList<Object>(coll), Collections.singletonList(index)));
} else {
// append to list
return addAll(coll);
@ -204,25 +205,19 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
}
@Override
public boolean removeAll(final Collection<?> c) {
public boolean removeAll(Collection<?> c) {
if (c.isEmpty()) {
return false;
}
return connectionManager.write(getName(), new SyncOperation<Object, Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, Object> conn) {
boolean result = false;
for (Object object : c) {
boolean res = conn.lrem(getName(), 0, object) > 0;
if (!result) {
result = res;
}
}
return result;
boolean result = false;
for (Object object : c) {
boolean res = (Long)connectionManager.write(getName(), RedisCommands.LREM, getName(), 0, object) > 0;
if (!result) {
result = res;
}
});
}
return result;
}
@Override
@ -240,22 +235,12 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
@Override
public void clear() {
connectionManager.write(getName(), new ResultOperation<Long, V>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.del(getName());
}
});
delete();
}
@Override
public Future<V> getAsync(final int index) {
return connectionManager.readAsync(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lindex(getName(), index);
}
});
public Future<V> getAsync(int index) {
return connectionManager.readAsync(getName(), RedisCommands.LINDEX, getName(), index);
}
@Override
@ -290,19 +275,14 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
@Override
public V set(final int index, final V element) {
public V set(int index, V element) {
checkIndex(index);
return new RedissonScript(connectionManager).evalR(
"local v = redis.call('lindex', KEYS[1], ARGV[2]); " +
"redis.call('lset', KEYS[1], ARGV[2], ARGV[1]); " +
return connectionManager.eval(new RedisCommand<Object>("EVAL", 5),
"local v = redis.call('lindex', KEYS[1], ARGV[1]); " +
"redis.call('lset', KEYS[1], ARGV[1], ARGV[2]); " +
"return v",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()),
Collections.singletonList(element),
Collections.singletonList(index)
);
Collections.<Object>singletonList(getName()), index, element);
}
@Override
@ -322,26 +302,20 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
}
@Override
public V remove(final int index) {
public V remove(int index) {
checkIndex(index);
if (index == 0) {
return connectionManager.write(getName(), new SyncOperation<Object, V>() {
@Override
public V execute(RedisConnection<Object, Object> conn) {
return (V) conn.lpop(getName());
}
});
return connectionManager.write(getName(), RedisCommands.LPOP, getName());
}
// else
return new RedissonScript(connectionManager).evalR(
return connectionManager.eval(RedisCommands.EVAL_OBJECT,
"local v = redis.call('lindex', KEYS[1], ARGV[1]); " +
"local tail = redis.call('lrange', KEYS[1], ARGV[1]);" +
"redis.call('ltrim', KEYS[1], 0, ARGV[1] - 1);" +
"for i, v in ipairs(tail) do redis.call('rpush', KEYS[1], v) end;" +
"return v",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()), Collections.emptyList(), Collections.singletonList(index));
Collections.<Object>singletonList(getName()), index);
}
@Override
@ -350,11 +324,10 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
return -1;
}
Long index = new RedissonScript(connectionManager).eval(
Long index = connectionManager.eval(new RedisCommand<Long>("EVAL", 4),
"local s = redis.call('llen', KEYS[1]);" +
"for i = 0, s, 1 do if ARGV[1] == redis.call('lindex', KEYS[1], i) then return i end end;" +
"return -1",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), o);
return index.intValue();
}
@ -365,13 +338,11 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
return -1;
}
Long index = new RedissonScript(connectionManager).eval(
return ((Long)connectionManager.eval(new RedisCommand<Long>("EVAL", 4),
"local s = redis.call('llen', KEYS[1]);" +
"for i = s, 0, -1 do if ARGV[1] == redis.call('lindex', KEYS[1], i) then return i end end;" +
"return -1",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), o);
return index.intValue();
Collections.<Object>singletonList(getName()), o)).intValue();
}
@Override
@ -475,7 +446,7 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
}
@Override
public List<V> subList(final int fromIndex, final int toIndex) {
public List<V> subList(int fromIndex, int toIndex) {
int size = size();
if (fromIndex < 0 || toIndex > size) {
throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " toIndex: " + toIndex + " size: " + size);
@ -484,13 +455,7 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
throw new IllegalArgumentException("fromIndex: " + fromIndex + " toIndex: " + toIndex);
}
return connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), fromIndex, toIndex - 1);
}
});
return connectionManager.read(getName(), RedisCommands.LRANGE, getName(), fromIndex, toIndex - 1);
}
public String toString() {

@ -15,7 +15,6 @@
*/
package org.redisson;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -23,17 +22,16 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import org.redisson.async.SyncOperation;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RLock;
import org.redisson.core.RScript;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/**
@ -122,28 +120,33 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return oldPromise;
}
RedisPubSubAdapter<Object> listener = new RedisPubSubAdapter<Object>() {
RedisPubSubListener<Integer> listener = new RedisPubSubListener<Integer>() {
@Override
public void subscribed(String channel, long count) {
if (getChannelName().equals(channel)
&& !value.getPromise().isSuccess()) {
value.getPromise().setSuccess(true);
public void onMessage(String channel, Integer message) {
if (message.equals(unlockMessage) && getChannelName().equals(channel)) {
value.getLatch().release();
}
}
@Override
public void message(String channel, Object message) {
if (message.equals(unlockMessage) && getChannelName().equals(channel)) {
value.getLatch().release();
}
public void onPatternMessage(String pattern, String channel, Integer message) {
}
};
Future<PubSubStatusMessage> res = null;
synchronized (ENTRIES) {
connectionManager.subscribe(listener, getChannelName());
res = connectionManager.subscribe(listener, getChannelName());
}
res.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
if (!value.getPromise().isSuccess()) {
value.getPromise().setSuccess(true);
}
}
});
return newPromise;
}
@ -263,8 +266,8 @@ public class RedissonLock extends RedissonExpirable implements RLock {
private Long tryLockInner(final long leaseTime, final TimeUnit unit) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return new RedissonScript(connectionManager)
.evalR("local v = redis.call('get', KEYS[1]); " +
return connectionManager.eval(RedisCommands.EVAL_INTEGER,
"local v = redis.call('get', KEYS[1]); " +
"if (v == false) then " +
" redis.call('set', KEYS[1], cjson.encode({['o'] = ARGV[1], ['c'] = 1}), 'px', ARGV[2]); " +
" return nil; " +
@ -276,8 +279,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
" end;" +
" return redis.call('pttl', KEYS[1]); " +
"end",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), Collections.singletonList(id.toString() + "-" + Thread.currentThread().getId()), Collections.singletonList(internalLockLeaseTime));
Collections.<Object>singletonList(getName()), id.toString() + "-" + Thread.currentThread().getId(), internalLockLeaseTime);
}
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
@ -339,37 +341,34 @@ public class RedissonLock extends RedissonExpirable implements RLock {
@Override
public void unlock() {
String opStatus = new RedissonScript(connectionManager)
.evalR("local v = redis.call('get', KEYS[1]); " +
Boolean opStatus = connectionManager.eval(RedisCommands.EVAL_BOOLEAN,
"local v = redis.call('get', KEYS[1]); " +
"if (v == false) then " +
" redis.call('publish', ARGV[4], ARGV[2]); " +
" return 'OK'; " +
" return true; " +
"else " +
" local o = cjson.decode(v); " +
" if (o['o'] == ARGV[1]) then " +
" o['c'] = o['c'] - 1; " +
" if (o['c'] > 0) then " +
" redis.call('set', KEYS[1], cjson.encode(o), 'px', ARGV[3]); " +
" return 'FALSE';"+
" return false;"+
" else " +
" redis.call('del', KEYS[1]);" +
" redis.call('publish', ARGV[4], ARGV[2]); " +
" return 'OK';"+
" return true;"+
" end" +
" end;" +
" return nil; " +
"end",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), Arrays.asList(id.toString() + "-" + Thread.currentThread().getId(), unlockMessage), Arrays.asList(internalLockLeaseTime, getChannelName()));
if ("OK".equals(opStatus)) {
stopRefreshTask();
} else if ("FALSE".equals(opStatus)) {
//do nothing
} else {
Collections.<Object>singletonList(getName()), id.toString() + "-" + Thread.currentThread().getId(), unlockMessage, internalLockLeaseTime, getChannelName());
if (opStatus == null) {
throw new IllegalStateException("Can't unlock lock Current id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
stopRefreshTask();
}
}
@Override
@ -385,52 +384,44 @@ public class RedissonLock extends RedissonExpirable implements RLock {
private Future<Boolean> forceUnlockAsync() {
stopRefreshTask();
return new RedissonScript(connectionManager)
.evalAsyncR("redis.call('del', KEYS[1]); redis.call('publish', ARGV[2], ARGV[1]); return true",
RScript.ReturnType.BOOLEAN,
Collections.<Object>singletonList(getName()), Collections.singletonList(unlockMessage), Collections.singletonList(getChannelName()));
return connectionManager.evalAsync(RedisCommands.EVAL_BOOLEAN,
"redis.call('del', KEYS[1]); redis.call('publish', ARGV[2], ARGV[1]); return true",
Collections.<Object>singletonList(getName()), unlockMessage, getChannelName());
}
@Override
public boolean isLocked() {
return connectionManager.read(getName(), new SyncOperation<Boolean, Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, Boolean> conn) {
return conn.exists(getName());
}
});
return connectionManager.read(getName(), RedisCommands.EXISTS, getName());
}
@Override
public boolean isHeldByCurrentThread() {
String opStatus = new RedissonScript(connectionManager)
.eval("local v = redis.call('get', KEYS[1]); " +
Boolean opStatus = connectionManager.eval(RedisCommands.EVAL_BOOLEAN,
"local v = redis.call('get', KEYS[1]); " +
"if (v == false) then " +
" return nil; " +
" return false; " +
"else " +
" local o = cjson.decode(v); " +
" if (o['o'] == ARGV[1]) then " +
" return 'OK'; " +
" return true; " +
" else" +
" return nil; " +
" return false; " +
" end;" +
"end",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), id.toString() + "-" + Thread.currentThread().getId());
return "OK".equals(opStatus);
return opStatus;
}
@Override
public int getHoldCount() {
Long opStatus = new RedissonScript(connectionManager)
.eval("local v = redis.call('get', KEYS[1]); " +
Long opStatus = connectionManager.eval(RedisCommands.EVAL_INTEGER,
"local v = redis.call('get', KEYS[1]); " +
"if (v == false) then " +
" return 0; " +
"else " +
" local o = cjson.decode(v); " +
" return o['c']; " +
"end",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), id.toString() + "-" + Thread.currentThread().getId());
return opStatus.intValue();
}

@ -15,23 +15,29 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.math.BigDecimal;
import java.util.*;
import org.redisson.async.AsyncOperation;
import org.redisson.async.OperationListener;
import org.redisson.async.ResultOperation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.redisson.client.protocol.BooleanReplayConvertor;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.client.protocol.decoder.LongReplayDecoder;
import org.redisson.client.protocol.decoder.MapScanResult;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.Predicate;
import org.redisson.core.RMap;
import org.redisson.core.RScript;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.output.MapScanResult;
import io.netty.util.concurrent.Future;
@ -47,18 +53,16 @@ import io.netty.util.concurrent.Future;
//TODO implement watching by keys instead of map name
public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
private final RedisCommand<Object> EVAL_PUT = new RedisCommand<Object>("EVAL", 4, ValueType.MAP, ValueType.MAP_VALUE);
protected RedissonMap(ConnectionManager connectionManager, String name) {
super(connectionManager, name);
}
@Override
public int size() {
return connectionManager.read(getName(), new ResultOperation<Long, V>() {
@Override
public Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.hlen(getName());
}
}).intValue();
Long res = connectionManager.read(getName(), RedisCommands.HLEN, getName());
return res.intValue();
}
@Override
@ -67,46 +71,33 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
}
@Override
public boolean containsKey(final Object key) {
return connectionManager.read(getName(), new ResultOperation<Boolean, V>() {
@Override
public Future<Boolean> execute(RedisAsyncConnection<Object, V> async) {
return async.hexists(getName(), key);
}
});
public boolean containsKey(Object key) {
return connectionManager.read(getName(), RedisCommands.HEXISTS, getName(), key);
}
@Override
public boolean containsValue(final Object value) {
List<V> list = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
public Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.hvals(getName());
}
});
public boolean containsValue(Object value) {
Collection<V> list = values();
return list.contains(value);
}
@Override
public Map<K, V> getAll(final Set<K> keys) {
public Map<K, V> getAll(Set<K> keys) {
if (keys.size() == 0) {
return Collections.emptyMap();
}
final Object[] keysArray = keys.toArray();
List<V> list = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.hmget(getName(), keysArray);
}
});
List<Object> args = new ArrayList<Object>(keys.size() + 1);
args.add(getName());
args.addAll(keys);
List<V> list = connectionManager.read(getName(), RedisCommands.HMGET, args.toArray());
Map<K, V> result = new HashMap<K, V>(list.size());
for (int index = 0; index < keysArray.length; index++) {
for (int index = 0; index < args.size()-1; index++) {
V value = list.get(index);
if (value == null) {
continue;
}
result.put((K) keysArray[index], value);
result.put((K) args.get(index+1), value);
}
return result;
}
@ -131,12 +122,8 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
if (map.size() == 0) {
return;
}
connectionManager.write(getName(), new ResultOperation<String, Object>() {
@Override
public Future<String> execute(RedisAsyncConnection<Object, Object> async) {
return async.hmset(getName(), (Map<Object, Object>) map);
}
});
connectionManager.write(getName(), RedisCommands.HMSET, getName(), map);
}
@Override
@ -146,38 +133,19 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
@Override
public Set<K> keySet() {
return (Set<K>) connectionManager.read(getName(), new ResultOperation<Set<Object>, V>() {
@Override
public Future<Set<Object>> execute(RedisAsyncConnection<Object, V> async) {
return async.hkeys(getName());
}
});
List<K> keys = connectionManager.read(getName(), RedisCommands.HKEYS, getName());
return new HashSet<K>(keys);
}
@Override
public Collection<V> values() {
return connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
public Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.hvals(getName());
}
});
return connectionManager.read(getName(), RedisCommands.HVALS, getName());
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
Map<Object, Object> map = connectionManager.read(getName(), new ResultOperation<Map<Object, Object>, Object>() {
@Override
public Future<Map<Object, Object>> execute(RedisAsyncConnection<Object, Object> async) {
return async.hgetall(getName());
}
});
Map<K, V> result = new HashMap<K, V>();
for (java.util.Map.Entry<Object, Object> entry : map.entrySet()) {
result.put((K)entry.getKey(), (V)entry.getValue());
}
return result.entrySet();
Map<K, V> map = connectionManager.read(getName(), RedisCommands.HGETALL, getName());
return map.entrySet();
}
@Override
@ -187,10 +155,9 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
@Override
public Future<V> putIfAbsentAsync(K key, V value) {
return new RedissonScript(connectionManager)
.evalAsync("if redis.call('hexists', KEYS[1], ARGV[1]) == 0 then redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return nil else return redis.call('hget', KEYS[1], ARGV[1]) end",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()), key, value);
return connectionManager.evalAsync(EVAL_PUT,
"if redis.call('hexists', KEYS[1], ARGV[1]) == 0 then redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return nil else return redis.call('hget', KEYS[1], ARGV[1]) end",
Collections.<Object>singletonList(getName()), key, value);
}
@Override
@ -201,23 +168,22 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
@Override
public Future<Long> removeAsync(Object key, Object value) {
return new RedissonScript(connectionManager)
.evalAsync("if redis.call('hget', KEYS[1], ARGV[1]) == ARGV[2] then return redis.call('hdel', KEYS[1], ARGV[1]) else return nil end",
RScript.ReturnType.INTEGER,
Collections.<Object>singletonList(getName()), key, value);
return connectionManager.evalAsync(new RedisCommand<Long>("EVAL", new LongReplayDecoder(), 4, ValueType.MAP),
"if redis.call('hget', KEYS[1], ARGV[1]) == ARGV[2] then return redis.call('hdel', KEYS[1], ARGV[1]) else return nil end",
Collections.<Object>singletonList(getName()), key, value);
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
return "OK".equals(connectionManager.get(replaceAsync(key, oldValue, newValue)));
return connectionManager.get(replaceAsync(key, oldValue, newValue));
}
@Override
public Future<V> replaceAsync(K key, V oldValue, V newValue) {
return new RedissonScript(connectionManager)
.evalAsync("if redis.call('hget', KEYS[1], ARGV[1]) == ARGV[2] then redis.call('hset', KEYS[1], ARGV[1], ARGV[3]); return 'OK'; else return nil; end",
RScript.ReturnType.STATUS,
Collections.<Object>singletonList(getName()), key, oldValue, newValue);
public Future<Boolean> replaceAsync(K key, V oldValue, V newValue) {
return connectionManager.evalAsync(new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 4,
Arrays.asList(ValueType.MAP_KEY, ValueType.MAP_VALUE, ValueType.MAP_VALUE)),
"if redis.call('hget', KEYS[1], ARGV[1]) == ARGV[2] then redis.call('hset', KEYS[1], ARGV[1], ARGV[3]); return true; else return false; end",
Collections.<Object>singletonList(getName()), key, oldValue, newValue);
}
@Override
@ -227,47 +193,34 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
@Override
public Future<V> replaceAsync(K key, V value) {
return new RedissonScript(connectionManager)
.evalAsync("if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return v; else return nil; end",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()), key, value);
return connectionManager.evalAsync(new RedisCommand<Object>("EVAL", 4, ValueType.MAP, ValueType.MAP_VALUE),
"if redis.call('hexists', KEYS[1], ARGV[1]) == 1 then local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return v; else return nil; end",
Collections.<Object>singletonList(getName()), key, value);
}
@Override
public Future<V> getAsync(final K key) {
return connectionManager.readAsync(getName(), new ResultOperation<V, V>() {
@Override
public Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.hget(getName(), key);
}
});
public Future<V> getAsync(K key) {
return connectionManager.readAsync(getName(), RedisCommands.HGET, getName(), key);
}
@Override
public Future<V> putAsync(K key, V value) {
return new RedissonScript(connectionManager)
.evalAsync("local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return v",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()), key, value);
return connectionManager.evalAsync(EVAL_PUT,
"local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hset', KEYS[1], ARGV[1], ARGV[2]); return v",
Collections.<Object>singletonList(getName()), key, value);
}
@Override
public Future<V> removeAsync(K key) {
return new RedissonScript(connectionManager)
.evalAsync("local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hdel', KEYS[1], ARGV[1]); return v",
RScript.ReturnType.VALUE,
Collections.<Object>singletonList(getName()), key);
return connectionManager.evalAsync(new RedisCommand<Object>("EVAL", 4, ValueType.MAP_KEY, ValueType.MAP_VALUE),
"local v = redis.call('hget', KEYS[1], ARGV[1]); redis.call('hdel', KEYS[1], ARGV[1]); return v",
Collections.<Object>singletonList(getName()), key);
}
@Override
public Future<Boolean> fastPutAsync(final K key, final V value) {
return connectionManager.writeAsync(getName(), new ResultOperation<Boolean, V>() {
@Override
public Future<Boolean> execute(RedisAsyncConnection<Object, V> async) {
return async.hset(getName(), key, value);
}
});
public Future<Boolean> fastPutAsync(K key, V value) {
return connectionManager.writeAsync(getName(), RedisCommands.HSET, getName(), key, value);
}
@Override
@ -277,16 +230,14 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
@Override
public Future<Long> fastRemoveAsync(final K ... keys) {
if (keys != null && keys.length > 0) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, V>() {
@Override
public Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.hdel(getName(), keys);
}
});
} else {
if (keys == null || keys.length == 0) {
return connectionManager.getGroup().next().newSucceededFuture(0L);
}
List<Object> args = new ArrayList<Object>(keys.length + 1);
args.add(getName());
args.addAll(Arrays.asList(keys));
return connectionManager.writeAsync(getName(), RedisCommands.HDEL, args.toArray());
}
@Override
@ -294,13 +245,8 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
return connectionManager.get(fastRemoveAsync(keys));
}
private MapScanResult<Object, V> scanIterator(final long startPos) {
return connectionManager.read(getName(), new ResultOperation<MapScanResult<Object, V>, V>() {
@Override
public Future<MapScanResult<Object, V>> execute(RedisAsyncConnection<Object, V> async) {
return async.hscan(getName(), startPos);
}
});
private MapScanResult<Object, V> scanIterator(long startPos) {
return connectionManager.read(getName(), RedisCommands.HSCAN, getName(), startPos);
}
private Iterator<Map.Entry<K, V>> iterator() {
@ -386,15 +332,9 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
}
@Override
public V addAndGet(final K key, final V value) {
String res = connectionManager.write(getName(), new ResultOperation<String, V>() {
@Override
protected Future<String> execute(RedisAsyncConnection<Object, V> async) {
Number val = (Number) value;
return async.hincrbyfloat(getName(), key, new BigDecimal(val.toString()).toPlainString());
}
});
public V addAndGet(K key, V value) {
String res = connectionManager.write(getName(), StringCodec.INSTANCE,
RedisCommands.HINCRBYFLOAT, getName(), key, new BigDecimal(value.toString()).toPlainString());
if (value instanceof Long) {
Object obj = Long.parseLong(res);

@ -15,16 +15,12 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.redisson.async.AsyncOperation;
import org.redisson.async.OperationListener;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RObject;
import com.lambdaworks.redis.RedisAsyncConnection;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/**
* Base Redisson object
@ -49,36 +45,21 @@ abstract class RedissonObject implements RObject {
public String getName() {
return name;
}
public boolean rename(String newName) {
return connectionManager.get(renameAsync(newName));
}
public Future<Boolean> renameAsync(final String newName) {
return connectionManager.writeAsync(getName(), new AsyncOperation<Object, Boolean>() {
@Override
public void execute(final Promise<Boolean> promise, RedisAsyncConnection<Object, Object> async) {
async.rename(getName(), newName).addListener(new OperationListener<Object, Boolean, String>(promise, async, this) {
@Override
public void onOperationComplete(Future<String> future) throws Exception {
promise.setSuccess("OK".equals(future.get()));
}
});
}
});
public Future<Boolean> renameAsync(String newName) {
return connectionManager.writeAsync(getName(), RedisCommands.RENAME, getName(), newName);
}
public boolean renamenx(String newName) {
return connectionManager.get(renamenxAsync(newName));
}
public Future<Boolean> renamenxAsync(final String newName) {
return connectionManager.writeAsync(getName(), new ResultOperation<Boolean, Object>() {
@Override
public Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.renamenx(getName(), newName);
}
});
public Future<Boolean> renamenxAsync(String newName) {
return connectionManager.writeAsync(getName(), RedisCommands.RENAMENX, getName(), newName);
}
@ -87,17 +68,7 @@ abstract class RedissonObject implements RObject {
}
public Future<Boolean> deleteAsync() {
return connectionManager.writeAsync(getName(), new AsyncOperation<Object, Boolean>() {
@Override
public void execute(final Promise<Boolean> promise, RedisAsyncConnection<Object, Object> async) {
async.del(getName()).addListener(new OperationListener<Object, Boolean, Number>(promise, async, this) {
@Override
public void onOperationComplete(Future<Number> future) throws Exception {
promise.setSuccess(future.get().byteValue() == 1);
}
});
}
});
return connectionManager.writeAsync(getName(), RedisCommands.DEL_SINGLE, getName());
}
}

@ -15,16 +15,12 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.NoSuchElementException;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RQueue;
import com.lambdaworks.redis.RedisAsyncConnection;
/**
* Distributed and concurrent implementation of {@link java.util.Queue}
*
@ -44,12 +40,7 @@ public class RedissonQueue<V> extends RedissonList<V> implements RQueue<V> {
}
public V getFirst() {
V value = connectionManager.read(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lindex(getName(), 0);
}
});
V value = connectionManager.read(getName(), RedisCommands.LINDEX, getName(), 0);
if (value == null) {
throw new NoSuchElementException();
}
@ -71,12 +62,7 @@ public class RedissonQueue<V> extends RedissonList<V> implements RQueue<V> {
@Override
public V poll() {
return connectionManager.write(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lpop(getName());
}
});
return connectionManager.write(getName(), RedisCommands.LPOP, getName());
}
@Override
@ -93,13 +79,8 @@ public class RedissonQueue<V> extends RedissonList<V> implements RQueue<V> {
}
@Override
public V pollLastAndOfferFirstTo(final String queueName) {
return connectionManager.write(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.rpoplpush(getName(), queueName);
}
});
public V pollLastAndOfferFirstTo(String queueName) {
return connectionManager.write(getName(), RedisCommands.RPOPLPUSH, getName(), queueName);
}
@Override

@ -15,22 +15,20 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import java.util.Collections;
import java.util.List;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RScript;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.ScriptOutputType;
import io.netty.util.concurrent.Future;
public class RedissonScript implements RScript {
private final ConnectionManager connectionManager;
public RedissonScript(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
@ -41,113 +39,68 @@ public class RedissonScript implements RScript {
}
@Override
public Future<String> scriptLoadAsync(final String luaScript) {
return connectionManager.writeAsync(new ResultOperation<String, Object>() {
@Override
protected Future<String> execute(RedisAsyncConnection<Object, Object> async) {
return async.scriptLoad(luaScript);
}
});
public Future<String> scriptLoadAsync(String luaScript) {
return connectionManager.writeAsync(RedisCommands.SCRIPT_LOAD, luaScript);
}
@Override
public <R> R eval(String luaScript, ReturnType returnType) {
return eval(luaScript, returnType, Collections.emptyList());
}
@Override
public <R> R eval(String luaScript, ReturnType returnType, List<Object> keys, Object... values) {
return (R) connectionManager.get(evalAsync(luaScript, returnType, keys, values));
}
@Override
public <R> Future<R> evalAsync(final String luaScript, final ReturnType returnType, final List<Object> keys, final Object... values) {
return connectionManager.writeAsync(new ResultOperation<R, Object>() {
@Override
protected Future<R> execute(RedisAsyncConnection<Object, Object> async) {
return async.eval(luaScript, ScriptOutputType.valueOf(returnType.toString()), keys, values);
}
});
}
@Override
public <R> R evalR(String luaScript, ReturnType returnType, List<Object> keys, List<?> values, List<?> rawValues) {
return (R) connectionManager.get(evalAsyncR(luaScript, returnType, keys, values, rawValues));
}
@Override
public <R> Future<R> evalAsyncR(final String luaScript, final ReturnType returnType, final List<Object> keys, final List<?> values, final List<?> rawValues) {
return connectionManager.writeAsync(new ResultOperation<R, Object>() {
@Override
protected Future<R> execute(RedisAsyncConnection<Object, Object> async) {
return async.evalR(luaScript, ScriptOutputType.valueOf(returnType.toString()), keys, values, rawValues);
}
});
public <R> Future<R> evalAsync(String luaScript, ReturnType returnType, List<Object> keys, Object... values) {
return connectionManager.evalAsync(returnType.getCommand(), luaScript, keys, values);
}
@Override
public <R> R evalSha(String shaDigest, ReturnType returnType) {
return evalSha(shaDigest, returnType, Collections.emptyList());
}
@Override
public <R> R evalSha(String shaDigest, ReturnType returnType, List<Object> keys, Object... values) {
return (R) connectionManager.get(evalShaAsync(shaDigest, returnType, keys, values));
}
@Override
public <R> Future<R> evalShaAsync(final String shaDigest, final ReturnType returnType, final List<Object> keys, final Object... values) {
return connectionManager.writeAsync(new ResultOperation<R, Object>() {
@Override
protected Future<R> execute(RedisAsyncConnection<Object, Object> async) {
return async.evalsha(shaDigest, ScriptOutputType.valueOf(returnType.toString()), keys, values);
}
});
public <R> Future<R> evalShaAsync(String shaDigest, ReturnType returnType, List<Object> keys, Object... values) {
return connectionManager.evalAsync(new RedisCommand(returnType.getCommand(), "EVALSHA"), shaDigest, keys, values);
}
@Override
public String scriptKill() {
public boolean scriptKill() {
return connectionManager.get(scriptKillAsync());
}
@Override
public Future<String> scriptKillAsync() {
return connectionManager.writeAsync(new ResultOperation<String, Object>() {
@Override
protected Future<String> execute(RedisAsyncConnection<Object, Object> async) {
return async.scriptKill();
}
});
public Future<Boolean> scriptKillAsync() {
return connectionManager.writeAsync(RedisCommands.SCRIPT_KILL);
}
@Override
public List<Boolean> scriptExists(String ... shaDigests) {
return connectionManager.get(scriptExistsAsync(shaDigests));
}
@Override
public Future<List<Boolean>> scriptExistsAsync(final String ... shaDigests) {
return connectionManager.writeAsync(new ResultOperation<List<Boolean>, Object>() {
@Override
protected Future<List<Boolean>> execute(RedisAsyncConnection<Object, Object> async) {
return async.scriptExists(shaDigests);
}
});
public Future<List<Boolean>> scriptExistsAsync(String ... shaDigests) {
return connectionManager.writeAsync(RedisCommands.SCRIPT_EXISTS, shaDigests);
}
@Override
public String scriptFlush() {
public boolean scriptFlush() {
return connectionManager.get(scriptFlushAsync());
}
@Override
public Future<String> scriptFlushAsync() {
return connectionManager.writeAsync(new ResultOperation<String, Object>() {
@Override
protected Future<String> execute(RedisAsyncConnection<Object, Object> async) {
return async.scriptFlush();
}
});
public Future<Boolean> scriptFlushAsync() {
return connectionManager.writeAsync(RedisCommands.SCRIPT_FLUSH);
}
}

@ -15,19 +15,18 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.util.*;
import org.redisson.async.AsyncOperation;
import org.redisson.async.OperationListener;
import org.redisson.async.ResultOperation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RSet;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.output.ListScanResult;
import io.netty.util.concurrent.Future;
/**
* Distributed and concurrent implementation of {@link java.util.Set}
@ -44,12 +43,7 @@ public class RedissonSet<V> extends RedissonExpirable implements RSet<V> {
@Override
public int size() {
return connectionManager.read(getName(), new ResultOperation<Long, V>() {
@Override
public Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.scard(getName());
}
}).intValue();
return ((Long)connectionManager.read(getName(), RedisCommands.SCARD, getName())).intValue();
}
@Override
@ -58,22 +52,12 @@ public class RedissonSet<V> extends RedissonExpirable implements RSet<V> {
}
@Override
public boolean contains(final Object o) {
return connectionManager.read(getName(), new ResultOperation<Boolean, Object>() {
@Override
public Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.sismember(getName(), o);
}
});
public boolean contains(Object o) {
return connectionManager.read(getName(), RedisCommands.SISMEMBER, getName(), o);
}
private ListScanResult<V> scanIterator(final long startPos) {
return connectionManager.read(getName(), new ResultOperation<ListScanResult<V>, V>() {
@Override
public Future<ListScanResult<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.sscan(getName(), startPos);
}
});
private ListScanResult<V> scanIterator(long startPos) {
return connectionManager.read(getName(), RedisCommands.SSCAN, getName(), startPos);
}
@Override
@ -129,59 +113,29 @@ public class RedissonSet<V> extends RedissonExpirable implements RSet<V> {
@Override
public Object[] toArray() {
Set<V> res = connectionManager.read(getName(), new ResultOperation<Set<V>, V>() {
@Override
public Future<Set<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.smembers(getName());
}
});
List<Object> res = connectionManager.read(getName(), RedisCommands.SMEMBERS, getName());
return res.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
Set<V> res = connectionManager.read(getName(), new ResultOperation<Set<V>, V>() {
@Override
public Future<Set<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.smembers(getName());
}
});
List<Object> res = connectionManager.read(getName(), RedisCommands.SMEMBERS, getName());
return res.toArray(a);
}
@Override
public boolean add(final V e) {
public boolean add(V e) {
return connectionManager.get(addAsync(e));
}
@Override
public Future<Boolean> addAsync(final V e) {
return connectionManager.writeAsync(getName(), new AsyncOperation<V, Boolean>() {
@Override
public void execute(final Promise<Boolean> promise, RedisAsyncConnection<Object, V> async) {
async.sadd(getName(), e).addListener(new OperationListener<V, Boolean, Long>(promise, async, this) {
@Override
public void onOperationComplete(Future<Long> future) throws Exception {
promise.setSuccess(future.get() > 0);
}
});
}
});
public Future<Boolean> addAsync(V e) {
return connectionManager.writeAsync(getName(), RedisCommands.SADD_SINGLE, getName(), e);
}
@Override
public Future<Boolean> removeAsync(final V e) {
return connectionManager.writeAsync(getName(), new AsyncOperation<V, Boolean>() {
@Override
public void execute(final Promise<Boolean> promise, RedisAsyncConnection<Object, V> async) {
async.srem(getName(), e).addListener(new OperationListener<V, Boolean, Long>(promise, async, this) {
@Override
public void onOperationComplete(Future<Long> future) throws Exception {
promise.setSuccess(future.get() > 0);
}
});
}
});
public Future<Boolean> removeAsync(V e) {
return connectionManager.writeAsync(getName(), RedisCommands.SREM_SINGLE, getName(), e);
}
@Override
@ -205,12 +159,10 @@ public class RedissonSet<V> extends RedissonExpirable implements RSet<V> {
return false;
}
Long res = connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
public Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.sadd(getName(), c.toArray());
}
});
List<Object> args = new ArrayList<Object>(c.size() + 1);
args.add(getName());
args.addAll(c);
Long res = connectionManager.write(getName(), RedisCommands.SADD, args.toArray());
return res > 0;
}
@ -230,13 +182,11 @@ public class RedissonSet<V> extends RedissonExpirable implements RSet<V> {
if (c.isEmpty()) {
return false;
}
Long res = connectionManager.write(getName(), new ResultOperation<Long, Object>() {
@Override
public Future<Long> execute(RedisAsyncConnection<Object, Object> async) {
return async.srem(getName(), c.toArray());
}
});
List<Object> args = new ArrayList<Object>(c.size() + 1);
args.add(getName());
args.addAll(c);
Long res = connectionManager.write(getName(), RedisCommands.SREM, args.toArray());
return res > 0;
}

@ -15,31 +15,33 @@
*/
package org.redisson;
import io.netty.channel.EventLoop;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.concurrent.TimeUnit;
import org.redisson.async.ResultOperation;
import org.redisson.async.SyncOperation;
import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.LongCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.connection.ConnectionManager;
import org.redisson.core.RSortedSet;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisMovedException;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/**
*
@ -97,27 +99,22 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
loadComparator();
connectionManager.write(getName(), new ResultOperation<Boolean, Object>() {
@Override
protected Future<Boolean> execute(RedisAsyncConnection<Object, Object> async) {
return async.setnx(getCurrentVersionKey(), 0L);
}
});
connectionManager.write(getName(), StringCodec.INSTANCE, RedisCommands.SETNX, getCurrentVersionKey(), 0L);
}
private void loadComparator() {
connectionManager.read(getName(), new SyncOperation<V, Void>() {
connectionManager.read(getName(), new SyncOperation<Void>() {
@Override
public Void execute(RedisConnection<Object, V> conn) {
public Void execute(Codec codec, RedisConnection conn) {
loadComparator(conn);
return null;
}
});
}
private void loadComparator(RedisConnection<Object, ?> connection) {
private void loadComparator(RedisConnection connection) {
try {
String comparatorSign = (String) connection.get(getComparatorKeyName());
String comparatorSign = connection.sync(StringCodec.INSTANCE, RedisCommands.GET, getComparatorKeyName());
if (comparatorSign != null) {
String[] parts = comparatorSign.split(":");
String className = parts[0];
@ -131,8 +128,6 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
Class<?> clazz = Class.forName(className);
comparator = (Comparator<V>) clazz.newInstance();
}
} catch (RedisMovedException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException(e);
}
@ -160,17 +155,12 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public int size() {
return connectionManager.read(getName(), new ResultOperation<Long, V>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, V> async) {
return async.llen(getName());
}
}).intValue();
Long size = connectionManager.read(getName(), RedisCommands.LLEN, getName());
return size.intValue();
}
private int size(RedisConnection<Object, ?> connection) {
return connection.llen(getName()).intValue();
private int size(RedisConnection connection) {
return connection.sync(RedisCommands.LLEN, getName()).intValue();
}
@Override
@ -180,10 +170,10 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public boolean contains(final Object o) {
return connectionManager.read(getName(), new SyncOperation<V, Boolean>() {
return connectionManager.read(getName(), new SyncOperation<Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, V> conn) {
return binarySearch((V)o, conn).getIndex() >= 0;
public Boolean execute(Codec codec, RedisConnection conn) {
return binarySearch((V)o, codec, conn).getIndex() >= 0;
}
});
}
@ -251,24 +241,25 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
}
private void remove(final int index) {
connectionManager.write(getName(), new SyncOperation<Object, V>() {
connectionManager.write(getName(), new SyncOperation<V>() {
@Override
public V execute(RedisConnection<Object, Object> conn) {
public V execute(Codec codec, RedisConnection conn) {
if (index == 0) {
return (V) conn.lpop(getName());
return conn.sync(codec, RedisCommands.LPOP, getName());
}
while (true) {
conn.watch(getName());
List<Object> tail = conn.lrange(getName(), index + 1, size());
conn.multi();
conn.ltrim(getName(), 0, index - 1);
conn.sync(RedisCommands.WATCH, getName());
List<Object> tail = conn.sync(codec, RedisCommands.LRANGE, getName(), index + 1, size());
conn.sync(RedisCommands.MULTI);
conn.sync(codec, RedisCommands.LTRIM, getName(), 0, index - 1);
if (tail.isEmpty()) {
if (conn.exec().size() == 1) {
if (((List<Object>)conn.sync(codec, RedisCommands.EXEC)).size() == 1) {
return null;
}
} else {
conn.rpush(getName(), tail.toArray());
if (conn.exec().size() == 2) {
tail.add(0, getName());
conn.sync(codec, RedisCommands.RPUSH, tail.toArray());
if (((List<Object>)conn.sync(codec, RedisCommands.EXEC)).size() == 2) {
return null;
}
}
@ -278,33 +269,18 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
}
private V get(final int index) {
return connectionManager.read(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lindex(getName(), index);
}
});
return connectionManager.read(getName(), RedisCommands.LINDEX, getName(), index);
}
@Override
public Object[] toArray() {
List<V> res = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), 0, -1);
}
});
List<V> res = connectionManager.read(getName(), RedisCommands.LRANGE, getName(), 0, -1);
return res.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
List<V> res = connectionManager.read(getName(), new ResultOperation<List<V>, V>() {
@Override
protected Future<List<V>> execute(RedisAsyncConnection<Object, V> async) {
return async.lrange(getName(), 0, -1);
}
});
List<V> res = connectionManager.read(getName(), RedisCommands.LRANGE, getName(), 0, -1);
return res.toArray(a);
}
@ -312,16 +288,16 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
return "redisson__sortedset__version__{" + getName() + "}";
}
private Long getCurrentVersion(RedisConnection<Object, Object> simpleConnection) {
return ((Number)simpleConnection.get(getCurrentVersionKey())).longValue();
private Long getCurrentVersion(Codec codec, RedisConnection simpleConnection) {
return simpleConnection.sync(LongCodec.INSTANCE, RedisCommands.GET, getCurrentVersionKey());
}
@Override
public boolean add(final V value) {
return connectionManager.write(getName(), new SyncOperation<V, Boolean>() {
return connectionManager.write(getName(), new SyncOperation<Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, V> conn) {
return add(value, conn);
public Boolean execute(Codec codec, RedisConnection conn) {
return add(value, codec, conn);
}
});
}
@ -345,20 +321,18 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
return promise;
}
boolean add(V value, RedisConnection<Object, V> connection) {
RedisConnection<Object, Object> simpleConnection = (RedisConnection<Object, Object>)connection;
boolean add(V value, Codec codec, RedisConnection connection) {
while (true) {
connection.watch(getName(), getComparatorKeyName());
connection.sync(RedisCommands.WATCH, getName(), getComparatorKeyName());
checkComparator(connection);
Long version = getCurrentVersion(simpleConnection);
BinarySearchResult<V> res = binarySearch(value, connection);
Long version = getCurrentVersion(codec, connection);
BinarySearchResult<V> res = binarySearch(value, codec, connection);
if (res.getIndex() < 0) {
// System.out.println("index: " + res.getIndex() + " value: " + value);
if (!version.equals(getCurrentVersion(simpleConnection))) {
connection.unwatch();
if (!version.equals(getCurrentVersion(codec, connection))) {
connection.sync(RedisCommands.UNWATCH);
continue;
}
// NewScore newScore = calcNewScore(res.getIndex(), connection);
@ -397,14 +371,14 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
if (index < size()) {
before = true;
pivot = connection.lindex(getName(), index);
pivot = connection.sync(codec, RedisCommands.LINDEX, getName(), index);
}
connection.multi();
connection.sync(RedisCommands.MULTI);
if (index >= size()) {
connection.rpush(getName(), value);
connection.sync(codec, RedisCommands.RPUSH, getName(), value);
} else {
connection.linsert(getName(), before, pivot, value);
connection.sync(codec, RedisCommands.LINSERT, getName(), before ? "BEFORE" : "AFTER", pivot, value);
}
// System.out.println("adding: " + newScore.getScore() + " " + value);
// connection.zadd(getName(), newScore.getScore(), value);
@ -413,8 +387,8 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
// } else {
// connection.del(leftScoreKey);
// }
connection.incr(getCurrentVersionKey());
List<Object> re = connection.exec();
connection.sync(RedisCommands.INCR, getCurrentVersionKey());
List<Object> re = connection.sync(codec, RedisCommands.EXEC);
if (re.size() == 2) {
// System.out.println("index: " + index + " value: " + value + " pivot: " + pivot);
return true;
@ -432,23 +406,23 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
// return val != null && val.intValue() > 0;
}
} else {
connection.unwatch();
connection.sync(RedisCommands.UNWATCH);
return false;
}
}
}
private void checkComparator(RedisConnection<Object, ?> connection) {
String comparatorSign = (String) connection.get(getComparatorKeyName());
private void checkComparator(RedisConnection connection) {
String comparatorSign = connection.sync(StringCodec.INSTANCE, RedisCommands.GET, getComparatorKeyName());
if (comparatorSign != null) {
String[] vals = comparatorSign.split(":");
String className = vals[0];
if (!comparator.getClass().getName().equals(className)) {
try {
// try {
loadComparator(connection);
} finally {
connection.unwatch();
}
// } finally {
// connection.sync(RedisCommands.UNWATCH);
// }
}
}
}
@ -465,10 +439,10 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public Future<Boolean> removeAsync(final V value) {
EventLoop loop = connectionManager.getGroup().next();
final Promise<Boolean> promise = loop.newPromise();
EventLoopGroup group = connectionManager.getGroup();
final Promise<Boolean> promise = group.next().newPromise();
loop.execute(new Runnable() {
connectionManager.getGroup().execute(new Runnable() {
@Override
public void run() {
try {
@ -485,42 +459,42 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public boolean remove(final Object value) {
return connectionManager.write(getName(), new SyncOperation<V, Boolean>() {
return connectionManager.write(getName(), new SyncOperation<Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, V> conn) {
return remove(value, conn);
public Boolean execute(Codec codec, RedisConnection conn) {
return remove(value, codec, conn);
}
});
}
boolean remove(Object value, RedisConnection<Object, V> conn) {
boolean remove(Object value, Codec codec, RedisConnection conn) {
while (true) {
conn.watch(getName());
BinarySearchResult<V> res = binarySearch((V) value, conn);
conn.sync(RedisCommands.WATCH, getName());
BinarySearchResult<V> res = binarySearch((V) value, codec, conn);
if (res.getIndex() < 0) {
conn.unwatch();
conn.sync(RedisCommands.UNWATCH);
return false;
}
if (res.getIndex() == 0) {
conn.multi();
conn.lpop(getName());
if (conn.exec().size() == 1) {
conn.sync(RedisCommands.MULTI);
conn.sync(codec, RedisCommands.LPOP, getName());
if (((List<Object>)conn.sync(codec, RedisCommands.EXEC)).size() == 1) {
return true;
}
}
RedisConnection<Object, Object> сonnection = (RedisConnection<Object, Object>)conn;
List<Object> tail = сonnection.lrange(getName(), res.getIndex() + 1, size());
сonnection.multi();
сonnection.ltrim(getName(), 0, res.getIndex() - 1);
List<Object> tail = conn.sync(codec, RedisCommands.LRANGE, getName(), res.getIndex() + 1, size());
conn.sync(RedisCommands.MULTI);
conn.sync(RedisCommands.LTRIM, getName(), 0, res.getIndex() - 1);
if (tail.isEmpty()) {
if (сonnection.exec().size() == 1) {
if (((List<Object>)conn.sync(codec, RedisCommands.EXEC)).size() == 1) {
return true;
}
} else {
сonnection.rpush(getName(), tail.toArray());
if (сonnection.exec().size() == 2) {
tail.add(0, getName());
conn.sync(codec, RedisCommands.RPUSH, tail.toArray());
if (((List<Object>)conn.sync(codec, RedisCommands.EXEC)).size() == 2) {
return true;
}
}
@ -600,12 +574,7 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public V first() {
V res = connectionManager.read(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lindex(getName(), 0);
}
});
V res = connectionManager.read(getName(), RedisCommands.LINDEX, getName(), 0);
if (res == null) {
throw new NoSuchElementException();
}
@ -614,12 +583,7 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
@Override
public V last() {
V res = connectionManager.read(getName(), new ResultOperation<V, V>() {
@Override
protected Future<V> execute(RedisAsyncConnection<Object, V> async) {
return async.lindex(getName(), -1);
}
});
V res = connectionManager.read(getName(), RedisCommands.LINDEX, getName(), -1);
if (res == null) {
throw new NoSuchElementException();
}
@ -635,32 +599,22 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
}
@Override
public boolean trySetComparator(final Comparator<? super V> comparator) {
return connectionManager.write(getName(), new SyncOperation<String, Boolean>() {
@Override
public Boolean execute(RedisConnection<Object, String> connection) {
connection.watch(getName(), getComparatorKeyName());
if (size(connection) > 0) {
connection.unwatch();
return false;
}
connection.multi();
String className = comparator.getClass().getName();
String comparatorSign = className + ":" + calcClassSign(className);
connection.set(getComparatorKeyName(), comparatorSign);
List<Object> res = connection.exec();
if (res.size() == 1) {
RedissonSortedSet.this.comparator = comparator;
return true;
}
return false;
}
});
public boolean trySetComparator(Comparator<? super V> comparator) {
String className = comparator.getClass().getName();
final String comparatorSign = className + ":" + calcClassSign(className);
Boolean res = connectionManager.eval(RedisCommands.EVAL_BOOLEAN,
"if redis.call('llen', KEYS[1]) == 0 then redis.call('set', KEYS[2], ARGV[1]); return true; "
+ "else return false; end",
Arrays.<Object>asList(getName(), getComparatorKeyName()), comparatorSign);
if (res) {
this.comparator = comparator;
}
return res;
}
private V getAtIndex(int index, RedisConnection<Object, V> connection) {
return connection.lindex(getName(), index);
private V getAtIndex(Codec codec, int index, RedisConnection connection) {
return connection.sync(codec, RedisCommands.LINDEX, getName(), index);
}
/**
@ -672,11 +626,11 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
* @param upperIndex
* @return
*/
private BinarySearchResult<V> binarySearch(V value, RedisConnection<Object, V> connection, int lowerIndex, int upperIndex) {
private BinarySearchResult<V> binarySearch(V value, Codec codec, RedisConnection connection, int lowerIndex, int upperIndex) {
while (lowerIndex <= upperIndex) {
int index = lowerIndex + (upperIndex - lowerIndex) / 2;
V res = getAtIndex(index, connection);
V res = getAtIndex(codec, index, connection);
int cmp = comparator.compare(value, res);
if (cmp == 0) {
@ -695,12 +649,12 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
return indexRes;
}
public BinarySearchResult<V> binarySearch(V value, RedisConnection<Object, V> connection) {
public BinarySearchResult<V> binarySearch(V value, Codec codec, RedisConnection connection) {
int upperIndex = size(connection) - 1;
return binarySearch(value, connection, 0, upperIndex);
return binarySearch(value, codec, connection, 0, upperIndex);
}
double score(V value, RedisConnection<Object, V> connection, int indexDiff, boolean tail) {
double score(V value, RedisConnection connection, int indexDiff, boolean tail) {
return -1;
// BinarySearchResult<V> res = binarySearch(value, connection);
// if (res.getIndex() < 0) {

@ -20,11 +20,9 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import org.redisson.RedissonSortedSet.BinarySearchResult;
import org.redisson.client.RedisConnection;
import org.redisson.connection.ConnectionManager;
import com.lambdaworks.redis.RedisConnection;
/**
*
* @author Nikita Koksharov
@ -51,31 +49,34 @@ class RedissonSubSortedSet<V> implements SortedSet<V> {
@Override
public int size() {
RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
try {
double headScore = getHeadScore(connection);
double tailScore = getTailScore(connection);
return connection.zcount(redissonSortedSet.getName(), headScore, tailScore).intValue();
} finally {
connectionManager.releaseRead(-1, connection);
}
throw new UnsupportedOperationException();
// RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
// try {
// double headScore = getHeadScore(connection);
// double tailScore = getTailScore(connection);
//
// return connection.zcount(redissonSortedSet.getName(), headScore, tailScore).intValue();
// } finally {
// connectionManager.releaseRead(-1, connection);
// }
}
private int getTailScore(RedisConnection<Object, V> connection) {
BinarySearchResult<V> res = redissonSortedSet.binarySearch(tailValue, connection);
if (res.getIndex() < 0) {
return 0;
}
return res.getIndex();
private int getTailScore(RedisConnection connection) {
throw new UnsupportedOperationException();
// BinarySearchResult<V> res = redissonSortedSet.binarySearch(tailValue, connection);
// if (res.getIndex() < 0) {
// return 0;
// }
// return res.getIndex();
}
private int getHeadScore(RedisConnection<Object, V> connection) {
BinarySearchResult<V> res = redissonSortedSet.binarySearch(headValue, connection);
if (res.getIndex() < 0) {
return 0;
}
return res.getIndex();
private int getHeadScore(RedisConnection connection) {
throw new UnsupportedOperationException();
// BinarySearchResult<V> res = redissonSortedSet.binarySearch(headValue, connection);
// if (res.getIndex() < 0) {
// return 0;
// }
// return res.getIndex();
}
@Override
@ -85,16 +86,17 @@ class RedissonSubSortedSet<V> implements SortedSet<V> {
@Override
public boolean contains(Object o) {
RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
try {
int headScore = getHeadScore(connection);
int tailScore = getTailScore(connection);
BinarySearchResult<V> res = redissonSortedSet.binarySearch((V)o, connection);
return res.getIndex() < tailScore && res.getIndex() > headScore;
} finally {
connectionManager.releaseRead(-1, connection);
}
throw new UnsupportedOperationException();
// RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
// try {
// int headScore = getHeadScore(connection);
// int tailScore = getTailScore(connection);
//
// BinarySearchResult<V> res = redissonSortedSet.binarySearch((V)o, connection);
// return res.getIndex() < tailScore && res.getIndex() > headScore;
// } finally {
// connectionManager.releaseRead(-1, connection);
// }
}
@Override
@ -112,26 +114,28 @@ class RedissonSubSortedSet<V> implements SortedSet<V> {
@Override
public Object[] toArray() {
RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
try {
double headScore = getHeadScore(connection);
double tailScore = getTailScore(connection);
return connection.zrangebyscore(redissonSortedSet.getName(), headScore, tailScore).toArray();
} finally {
connectionManager.releaseRead(-1, connection);
}
throw new UnsupportedOperationException();
// RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
// try {
// double headScore = getHeadScore(connection);
// double tailScore = getTailScore(connection);
// return connection.zrangebyscore(redissonSortedSet.getName(), headScore, tailScore).toArray();
// } finally {
// connectionManager.releaseRead(-1, connection);
// }
}
@Override
public <T> T[] toArray(T[] a) {
RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
try {
double headScore = getHeadScore(connection);
double tailScore = getTailScore(connection);
return connection.zrangebyscore(redissonSortedSet.getName(), headScore, tailScore).toArray(a);
} finally {
connectionManager.releaseRead(-1, connection);
}
throw new UnsupportedOperationException();
// RedisConnection<Object, V> connection = connectionManager.connectionReadOp(-1);
// try {
// double headScore = getHeadScore(connection);
// double tailScore = getTailScore(connection);
// return connection.zrangebyscore(redissonSortedSet.getName(), headScore, tailScore).toArray(a);
// } finally {
// connectionManager.releaseRead(-1, connection);
// }
}
@Override
@ -241,14 +245,15 @@ class RedissonSubSortedSet<V> implements SortedSet<V> {
@Override
public SortedSet<V> subSet(V fromElement, V toElement) {
throw new UnsupportedOperationException();
// TODO check bounds
if (fromElement == null) {
fromElement = headValue;
}
if (toElement == null) {
toElement = tailValue;
}
return new RedissonSubSortedSet<V>(redissonSortedSet, connectionManager, fromElement, toElement);
// if (fromElement == null) {
// fromElement = headValue;
// }
// if (toElement == null) {
// toElement = tailValue;
// }
// return new RedissonSubSortedSet<V>(redissonSortedSet, connectionManager, fromElement, toElement);
}
@Override

@ -15,15 +15,13 @@
*/
package org.redisson;
import io.netty.util.concurrent.Future;
import org.redisson.async.ResultOperation;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.PubSubConnectionEntry;
import org.redisson.core.MessageListener;
import org.redisson.core.RTopic;
import com.lambdaworks.redis.RedisAsyncConnection;
import io.netty.util.concurrent.Future;
/**
* Distributed topic implementation. Messages are delivered to all message listeners across Redis cluster.
@ -44,13 +42,8 @@ public class RedissonTopic<M> extends RedissonObject implements RTopic<M> {
}
@Override
public Future<Long> publishAsync(final M message) {
return connectionManager.writeAsync(getName(), new ResultOperation<Long, M>() {
@Override
protected Future<Long> execute(RedisAsyncConnection<Object, M> async) {
return async.publish(getName(), message);
}
});
public Future<Long> publishAsync(M message) {
return connectionManager.writeAsync(getName(), RedisCommands.PUBLISH, getName(), message);
}
@Override

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
package org.redisson;
import com.lambdaworks.redis.RedisConnection;
import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.Codec;
public interface SyncOperation<V, R> {
public interface SyncOperation<R> {
R execute(Codec codec, RedisConnection conn);
R execute(RedisConnection<Object, V> conn);
}

@ -1,26 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public interface AsyncOperation<V, R> {
void execute(Promise<R> promise, RedisAsyncConnection<Object, V> async);
}

@ -1,33 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public abstract class BaseResultListener<V, R, T> extends OperationListener<V, R, T> {
public BaseResultListener(Promise<R> promise, RedisAsyncConnection<Object, V> async,
AsyncOperation<V, R> timeoutCallback) {
super(promise, async, timeoutCallback);
}
@Override
public abstract void onOperationComplete(Future<T> future) throws Exception;
}

@ -1,70 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisTimeoutException;
public abstract class OperationListener<V, P, F> implements FutureListener<F> {
final Promise<P> promise;
final RedisAsyncConnection<Object, V> async;
final AsyncOperation<V, P> timeoutCallback;
public OperationListener(Promise<P> promise, RedisAsyncConnection<Object, V> async, AsyncOperation<V, P> timeoutCallback) {
super();
this.promise = promise;
this.async = async;
this.timeoutCallback = timeoutCallback;
}
@Override
public void operationComplete(Future<F> future) throws Exception {
if (isBreak(async, promise, future)) {
return;
}
onOperationComplete(future);
}
public abstract void onOperationComplete(Future<F> future) throws Exception;
protected boolean isBreak(RedisAsyncConnection<Object, V> async, Promise<P> promise, Future<F> future) {
if (!future.isSuccess()) {
if (future.cause() instanceof RedisTimeoutException) {
timeoutCallback.execute(promise, async);
return false;
} else {
promise.setFailure(future.cause());
return true;
}
}
if (promise.isCancelled()) {
if (async.isMultiMode()) {
async.discard();
}
return true;
}
return false;
}
}

@ -1,35 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public class ResultListener<V, R> extends BaseResultListener<V, R, R> {
public ResultListener(Promise<R> promise, RedisAsyncConnection<Object, V> async,
AsyncOperation<V, R> timeoutCallback) {
super(promise, async, timeoutCallback);
}
@Override
public void onOperationComplete(Future<R> future) throws Exception {
promise.setSuccess(future.get());
}
}

@ -1,33 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public abstract class ResultOperation<R, V> implements AsyncOperation<V, R> {
@Override
public void execute(Promise<R> promise, RedisAsyncConnection<Object, V> async) {
Future<R> future = execute(async);
future.addListener(new ResultListener<V, R>(promise, async, this));
}
protected abstract Future<R> execute(RedisAsyncConnection<Object, V> async);
}

@ -1,24 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import com.lambdaworks.redis.RedisConnection;
public interface SyncInterruptedOperation<V, R> {
R execute(RedisConnection<Object, V> conn) throws InterruptedException;
}

@ -1,35 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public class VoidListener<V, T> extends BaseResultListener<V, Void, T> {
public VoidListener(Promise<Void> promise, RedisAsyncConnection<Object, V> async,
AsyncOperation<V, Void> timeoutCallback) {
super(promise, async, timeoutCallback);
}
@Override
public void onOperationComplete(Future<T> future) throws Exception {
promise.setSuccess(null);
}
}

@ -1,33 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.async;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import com.lambdaworks.redis.RedisAsyncConnection;
public abstract class VoidOperation<V, R> implements AsyncOperation<V, Void> {
@Override
public void execute(Promise<Void> promise, RedisAsyncConnection<Object, V> async) {
Future<R> future = execute(async);
future.addListener(new VoidListener<V, R>(promise, async, this));
}
protected abstract Future<R> execute(RedisAsyncConnection<Object, V> async);
}

@ -59,18 +59,6 @@ public class RedisConnection implements RedisCommands {
return cmd.getNow();
}
// public <V> V get(Future<V> future) {
// future.awaitUninterruptibly();
// if (future.isSuccess()) {
// return future.getNow();
// }
//
// if (future.cause() instanceof RedisException) {
// throw (RedisException) future.cause();
// }
// throw new RedisException("Unexpected exception while processing command", future.cause());
// }
public <T> T sync(RedisStrictCommand<T> command, Object ... params) {
Future<T> r = async(null, command, params);
return await(r);
@ -95,12 +83,4 @@ public class RedisConnection implements RedisCommands {
return channel.close();
}
// public <R> Future<R> execute(Codec encoder, RedisCommand<R> command, Object ... params) {
// Promise<R> promise = bootstrap.group().next().<R>newPromise();
// channel.writeAndFlush(new RedisData<R, R>(promise, encoder, command, params));
// return promise;
//}
}

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client;
public class RedisConnectionException extends RedisException {

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client;
public class RedisMovedException extends RedisException {

@ -49,7 +49,7 @@ public class RedisPubSubConnection extends RedisConnection {
listeners.add(listener);
}
public void removeListener(RedisPubSubListener listener) {
public void removeListener(RedisPubSubListener<?> listener) {
listeners.remove(listener);
}

@ -31,6 +31,8 @@ import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.decoder.MultiDecoder;
import org.redisson.client.protocol.pubsub.PubSubMessage;
import org.redisson.client.protocol.pubsub.PubSubPatternMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
@ -45,6 +47,8 @@ import io.netty.util.CharsetUtil;
*/
public class RedisDecoder extends ReplayingDecoder<Void> {
private final Logger log = LoggerFactory.getLogger(getClass());
public static final char CR = '\r';
public static final char LF = '\n';
private static final char ZERO = '0';
@ -66,7 +70,9 @@ public class RedisDecoder extends ReplayingDecoder<Void> {
};
}
System.out.println("message " + in.writerIndex() + "-" + in.readerIndex() + " in: " + in.toString(0, in.writerIndex(), CharsetUtil.UTF_8));
if (log.isTraceEnabled()) {
log.trace("channel: {} message: {}", ctx.channel(), in.toString(0, in.writerIndex(), CharsetUtil.UTF_8));
}
try {
decode(in, data, null, pubSubConnection, currentDecoder);
@ -81,7 +87,10 @@ public class RedisDecoder extends ReplayingDecoder<Void> {
private void decode(ByteBuf in, RedisData<Object, Object> data, List<Object> parts, RedisPubSubConnection pubSubConnection, Decoder<Object> currentDecoder) throws IOException {
int code = in.readByte();
if (code == '+') {
Object result = data.getCommand().getReplayDecoder().decode(in);
String result = in.readBytes(in.bytesBefore((byte) '\r')).toString(CharsetUtil.UTF_8);
in.skipBytes(2);
// Object result = data.getCommand().getReplayDecoder().decode(in);
handleResult(data, parts, result);
} else if (code == '-') {
String error = in.readBytes(in.bytesBefore((byte) '\r')).toString(CharsetUtil.UTF_8);

@ -17,6 +17,8 @@ package org.redisson.client.handler;
import org.redisson.client.protocol.Encoder;
import org.redisson.client.protocol.StringParamsEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.redisson.client.protocol.RedisCommand.ValueType;
import io.netty.buffer.ByteBuf;
@ -32,6 +34,8 @@ import io.netty.util.CharsetUtil;
*/
public class RedisEncoder extends MessageToByteEncoder<RedisData<Object, Object>> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Encoder paramsEncoder = new StringParamsEncoder();
final char ARGS_PREFIX = '*';
@ -68,13 +72,14 @@ public class RedisEncoder extends MessageToByteEncoder<RedisData<Object, Object>
}
}
writeArgument(out, encoder.encode(i, param));
writeArgument(out, encoder.encode(param));
i++;
}
String o = out.toString(CharsetUtil.UTF_8);
System.out.println(o);
if (log.isTraceEnabled()) {
log.trace("channel: {} message: {}", ctx.channel(), out.toString(CharsetUtil.UTF_8));
}
}
private Encoder encoder(RedisData<Object, Object> msg, int param) {

@ -19,7 +19,7 @@ public class BooleanReplayConvertor implements Convertor<Boolean> {
@Override
public Boolean convert(Object obj) {
return Long.valueOf(1).equals(obj);
return Long.valueOf(1).equals(obj) || "OK".equals(obj);
}

@ -19,6 +19,6 @@ import java.io.IOException;
public interface Encoder {
byte[] encode(int paramIndex, Object in) throws IOException;
byte[] encode(Object in) throws IOException;
}

@ -19,7 +19,6 @@ import java.util.List;
import java.util.Map;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.decoder.BooleanStatusReplayDecoder;
import org.redisson.client.protocol.decoder.KeyValueObjectDecoder;
import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.client.protocol.decoder.ListScanResultReplayDecoder;
@ -37,6 +36,11 @@ import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
public interface RedisCommands {
RedisStrictCommand<Boolean> UNWATCH = new RedisStrictCommand<Boolean>("UNWATCH", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> WATCH = new RedisStrictCommand<Boolean>("WATCH", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> MULTI = new RedisStrictCommand<Boolean>("MULTI", new BooleanReplayConvertor());
RedisCommand<List<Object>> EXEC = new RedisCommand<List<Object>>("EXEC", new ObjectListReplayDecoder());
RedisCommand<Long> SREM = new RedisCommand<Long>("SREM", 2, ValueType.OBJECTS);
RedisCommand<Long> SADD = new RedisCommand<Long>("SADD", 2, ValueType.OBJECTS);
RedisCommand<Boolean> SADD_SINGLE = new RedisCommand<Boolean>("SADD", new BooleanReplayConvertor(), 2);
@ -49,7 +53,9 @@ public interface RedisCommands {
RedisCommand<Object> LPOP = new RedisCommand<Object>("LPOP");
RedisCommand<Long> LREM = new RedisCommand<Long>("LREM", 3);
RedisCommand<Object> LINDEX = new RedisCommand<Object>("LINDEX");
RedisCommand<Object> LINSERT = new RedisCommand<Object>("LINSERT", 3, ValueType.OBJECTS);
RedisStrictCommand<Long> LLEN = new RedisStrictCommand<Long>("LLEN");
RedisStrictCommand<Boolean> LTRIM = new RedisStrictCommand<Boolean>("LTRIM", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> EXPIRE = new RedisStrictCommand<Boolean>("EXPIRE", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> EXPIREAT = new RedisStrictCommand<Boolean>("EXPIREAT", new BooleanReplayConvertor());
@ -70,8 +76,8 @@ public interface RedisCommands {
RedisCommand<Long> RPUSH = new RedisCommand<Long>("RPUSH", 2, ValueType.OBJECTS);
RedisStrictCommand<String> SCRIPT_LOAD = new RedisStrictCommand<String>("SCRIPT", "LOAD", new StringDataDecoder());
RedisStrictCommand<Boolean> SCRIPT_KILL = new RedisStrictCommand<Boolean>("SCRIPT", "KILL", new BooleanStatusReplayDecoder());
RedisStrictCommand<Boolean> SCRIPT_FLUSH = new RedisStrictCommand<Boolean>("SCRIPT", "FLUSH", new BooleanStatusReplayDecoder());
RedisStrictCommand<Boolean> SCRIPT_KILL = new RedisStrictCommand<Boolean>("SCRIPT", "KILL", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> SCRIPT_FLUSH = new RedisStrictCommand<Boolean>("SCRIPT", "FLUSH", new BooleanReplayConvertor());
RedisStrictCommand<List<Object>> SCRIPT_EXISTS = new RedisStrictCommand<List<Object>>("SCRIPT", "EXISTS", new ObjectListReplayDecoder(), new BooleanReplayConvertor());
RedisStrictCommand<Boolean> EVAL_BOOLEAN = new RedisStrictCommand<Boolean>("EVAL", new BooleanReplayConvertor());
@ -88,9 +94,9 @@ public interface RedisCommands {
RedisStrictCommand<String> AUTH = new RedisStrictCommand<String>("AUTH", new StringReplayDecoder());
RedisStrictCommand<String> SELECT = new RedisStrictCommand<String>("SELECT", new StringReplayDecoder());
RedisStrictCommand<String> CLIENT_SETNAME = new RedisStrictCommand<String>("CLIENT", "SETNAME", new StringReplayDecoder());
RedisStrictCommand<Boolean> CLIENT_SETNAME = new RedisStrictCommand<Boolean>("CLIENT", "SETNAME", new BooleanReplayConvertor());
RedisStrictCommand<String> CLIENT_GETNAME = new RedisStrictCommand<String>("CLIENT", "GETNAME", new StringDataDecoder());
RedisStrictCommand<String> FLUSHDB = new RedisStrictCommand<String>("FLUSHDB", new StringReplayDecoder());
RedisStrictCommand<String> FLUSHDB = new RedisStrictCommand<String>("FLUSHDB");
RedisStrictCommand<List<String>> KEYS = new RedisStrictCommand<List<String>>("KEYS", new StringListReplayDecoder());
@ -110,13 +116,13 @@ public interface RedisCommands {
RedisStrictCommand<Boolean> DEL_SINGLE = new RedisStrictCommand<Boolean>("DEL", new BooleanReplayConvertor());
RedisCommand<Object> GET = new RedisCommand<Object>("GET");
RedisCommand<String> SET = new RedisCommand<String>("SET", new StringReplayDecoder(), 2);
RedisCommand<String> SET = new RedisCommand<String>("SET", 2);
RedisCommand<Boolean> SETNX = new RedisCommand<Boolean>("SETNX", new BooleanReplayConvertor(), 2);
RedisCommand<String> SETEX = new RedisCommand<String>("SETEX", new StringReplayDecoder(), 2);
RedisCommand<Boolean> SETEX = new RedisCommand<Boolean>("SETEX", new BooleanReplayConvertor(), 2);
RedisStrictCommand<Boolean> EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> RENAMENX = new RedisStrictCommand<Boolean>("RENAMENX", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> RENAME = new RedisStrictCommand<Boolean>("RENAME", new BooleanStatusReplayDecoder());
RedisStrictCommand<Boolean> RENAME = new RedisStrictCommand<Boolean>("RENAME", new BooleanReplayConvertor());
RedisCommand<Long> PUBLISH = new RedisCommand<Long>("PUBLISH", 2);

@ -41,7 +41,7 @@ public class StringCodec implements Codec {
public Encoder getValueEncoder() {
return new Encoder() {
@Override
public byte[] encode(int paramIndex, Object in) throws IOException {
public byte[] encode(Object in) throws IOException {
return in.toString().getBytes("UTF-8");
}
};

@ -20,7 +20,7 @@ import java.io.UnsupportedEncodingException;
public class StringParamsEncoder implements Encoder {
@Override
public byte[] encode(int paramIndex, Object in) {
public byte[] encode(Object in) {
try {
return in.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {

@ -1,17 +0,0 @@
package org.redisson.client.protocol.decoder;
import org.redisson.client.protocol.Decoder;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
public class BooleanStatusReplayDecoder implements Decoder<Boolean> {
@Override
public Boolean decode(ByteBuf buf) {
String status = buf.readBytes(buf.bytesBefore((byte) '\r')).toString(CharsetUtil.UTF_8);
buf.skipBytes(2);
return "OK".equals(status);
}
}

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
public class KeyValueMessage<K, V> {

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.List;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.List;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.List;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import org.redisson.client.protocol.Decoder;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.Map;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.List;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.io.IOException;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.List;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.HashMap;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.Arrays;

@ -1,3 +1,18 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.client.protocol.decoder;
import java.util.ArrayList;

@ -15,8 +15,11 @@
*/
package org.redisson.codec;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.io.IOException;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@ -30,12 +33,15 @@ import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
/**
*
* @author Nikita Koksharov
*
*/
public class JsonJacksonCodec implements RedissonCodec {
public class JsonJacksonCodec implements Codec {
private final ObjectMapper objectMapper = new ObjectMapper();
private ObjectMapper mapObjectMapper = new ObjectMapper();
@ -93,63 +99,67 @@ public class JsonJacksonCodec implements RedissonCodec {
}
@Override
public Object decodeKey(ByteBuffer bytes) {
return new String(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.limit(), Charset.forName("ASCII"));
}
public Decoder<Object> getMapValueDecoder() {
return new Decoder<Object>() {
@Override
public Object decodeValue(ByteBuffer bytes) {
return decode(bytes);
}
@Override
public Object decode(ByteBuf buf) throws IOException {
if (buf == null) {
return null;
}
private Object decode(ByteBuffer bytes) {
try {
return objectMapper.readValue(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.limit(), Object.class);
} catch (Exception e) {
throw new IllegalStateException(e);
}
return mapObjectMapper.readValue(new ByteBufInputStream(buf), Object.class);
}
};
}
@Override
public byte[] encodeKey(Object key) {
return key.toString().getBytes(Charset.forName("ASCII"));
}
public Encoder getMapValueEncoder() {
return new Encoder() {
@Override
public byte[] encodeValue(Object value) {
try {
return objectMapper.writeValueAsBytes(value);
} catch (Exception e) {
throw new IllegalStateException(e);
}
@Override
public byte[] encode(Object in) throws IOException {
return mapObjectMapper.writeValueAsBytes(in);
}
};
}
@Override
public byte[] encodeMapValue(Object value) {
try {
return mapObjectMapper.writeValueAsBytes(value);
} catch (Exception e) {
throw new IllegalStateException(e);
}
public Decoder<Object> getMapKeyDecoder() {
return getMapValueDecoder();
}
@Override
public byte[] encodeMapKey(Object key) {
return encodeMapValue(key);
public Encoder getMapKeyEncoder() {
return getMapValueEncoder();
}
@Override
public Object decodeMapValue(ByteBuffer bytes) {
try {
return mapObjectMapper.readValue(bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.limit(), Object.class);
} catch (Exception e) {
throw new IllegalStateException(e);
}
public Decoder<Object> getValueDecoder() {
// return new Decoder<Object>() {
//
// @Override
// public Object decode(ByteBuf buf) throws IOException {
// if (buf == null) {
// return null;
// }
//
// return objectMapper.readValue(new ByteBufInputStream(buf), Object.class);
// }
// };
return getMapValueDecoder();
}
@Override
public Object decodeMapKey(ByteBuffer bytes) {
return decodeMapValue(bytes);
public Encoder getValueEncoder() {
return getMapValueEncoder();
// return new Encoder() {
//
// @Override
// public byte[] encode(int paramIndex, Object in) throws IOException {
// return objectMapper.writeValueAsBytes(in);
// }
// };
}
}

@ -1,77 +0,0 @@
/**
* Copyright 2014 Nikita Koksharov, Nickolay Borbit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.codec;
import java.nio.ByteBuffer;
import com.lambdaworks.redis.codec.RedisCodec;
/**
*
* @author Nikita Koksharov
*
*/
public class RedisCodecWrapper extends RedisCodec<Object, Object> {
private final RedissonCodec redissonCodec;
public RedisCodecWrapper(RedissonCodec redissonCodec) {
this.redissonCodec = redissonCodec;
}
@Override
public Object decodeKey(ByteBuffer bytes) {
return redissonCodec.decodeKey(bytes);
}
@Override
public Object decodeValue(ByteBuffer bytes) {
return redissonCodec.decodeValue(bytes);
}
@Override
public byte[] encodeKey(Object key) {
return redissonCodec.encodeKey(key);
}
@Override
public byte[] encodeValue(Object value) {
return redissonCodec.encodeValue(value);
}
@Override
public byte[] encodeMapValue(Object value) {
return redissonCodec.encodeMapValue(value);
}
@Override
public byte[] encodeMapKey(Object key) {
return redissonCodec.encodeMapKey(key);
}
@Override
public Object decodeMapValue(ByteBuffer bytes) {
return redissonCodec.decodeMapValue(bytes);
}
@Override
public Object decodeMapKey(ByteBuffer bytes) {
return redissonCodec.decodeMapKey(bytes);
}
}

@ -24,27 +24,27 @@ import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.misc.ReclosableLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisConnectionException;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
abstract class BaseLoadBalancer implements LoadBalancer {
private final Logger log = LoggerFactory.getLogger(getClass());
private RedisCodec codec;
private Codec codec;
private MasterSlaveServersConfig config;
private final ReclosableLatch clientsEmpty = new ReclosableLatch();
final Queue<SubscribesConnectionEntry> clients = new ConcurrentLinkedQueue<SubscribesConnectionEntry>();
public void init(RedisCodec codec, MasterSlaveServersConfig config) {
public void init(Codec codec, MasterSlaveServersConfig config) {
this.codec = codec;
this.config = config;
}
@ -84,7 +84,7 @@ abstract class BaseLoadBalancer implements LoadBalancer {
if (connection == null) {
break;
}
connection.close();
connection.closeAsync();
}
// close all pub/sub connections
@ -93,7 +93,7 @@ abstract class BaseLoadBalancer implements LoadBalancer {
if (connection == null) {
break;
}
connection.close();
connection.closeAsync();
}
@ -116,7 +116,6 @@ abstract class BaseLoadBalancer implements LoadBalancer {
return Collections.emptyList();
}
@SuppressWarnings("unchecked")
public RedisPubSubConnection nextPubSubConnection() {
clientsEmpty.awaitUninterruptibly();
List<SubscribesConnectionEntry> clientsCopy = new ArrayList<SubscribesConnectionEntry>(clients);
@ -137,15 +136,15 @@ abstract class BaseLoadBalancer implements LoadBalancer {
if (conn != null) {
return conn;
}
conn = entry.getClient().connectPubSub(codec);
conn = entry.getClient().connectPubSub();
if (config.getPassword() != null) {
conn.auth(config.getPassword());
conn.sync(RedisCommands.AUTH, config.getPassword());
}
if (config.getDatabase() != 0) {
conn.select(config.getDatabase());
conn.sync(RedisCommands.SELECT, config.getDatabase());
}
if (config.getClientName() != null) {
conn.clientSetname(config.getClientName());
conn.sync(RedisCommands.CLIENT_SETNAME, config.getClientName());
}
entry.registerSubscribeConnection(conn);
@ -180,15 +179,15 @@ abstract class BaseLoadBalancer implements LoadBalancer {
return conn;
}
try {
conn = entry.getClient().connect(codec);
conn = entry.getClient().connect();
if (config.getPassword() != null) {
conn.auth(config.getPassword());
conn.sync(RedisCommands.AUTH, config.getPassword());
}
if (config.getDatabase() != 0) {
conn.select(config.getDatabase());
conn.sync(RedisCommands.SELECT, config.getDatabase());
}
if (config.getClientName() != null) {
conn.clientSetname(config.getClientName());
conn.sync(RedisCommands.CLIENT_SETNAME, config.getClientName());
}
return conn;
@ -208,7 +207,7 @@ abstract class BaseLoadBalancer implements LoadBalancer {
for (SubscribesConnectionEntry entry : clients) {
if (entry.getClient().equals(connection.getRedisClient())) {
if (entry.isFreezed()) {
connection.close();
connection.closeAsync();
} else {
entry.offerFreeSubscribeConnection(connection);
}
@ -222,7 +221,7 @@ abstract class BaseLoadBalancer implements LoadBalancer {
for (SubscribesConnectionEntry entry : clients) {
if (entry.getClient().equals(connection.getRedisClient())) {
if (entry.isFreezed()) {
connection.close();
connection.closeAsync();
} else {
entry.getConnections().add(connection);
}

@ -32,14 +32,14 @@ import java.util.concurrent.TimeUnit;
import org.redisson.ClusterServersConfig;
import org.redisson.Config;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ClusterNodeInfo.Flag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnectionException;
public class ClusterConnectionManager extends MasterSlaveConnectionManager {
private final Logger log = LoggerFactory.getLogger(getClass());
@ -56,8 +56,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
for (URI addr : cfg.getNodeAddresses()) {
RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getTimeout());
try {
RedisAsyncConnection<String, String> connection = client.connectAsync();
String nodesValue = get(connection.clusterNodes());
RedisConnection connection = client.connect();
String nodesValue = connection.sync(RedisCommands.CLUSTER_NODES);
Map<Integer, ClusterPartition> partitions = extractPartitions(nodesValue);
for (ClusterPartition partition : partitions.values()) {
@ -100,8 +100,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
for (URI addr : cfg.getNodeAddresses()) {
final RedisClient client = createClient(addr.getHost(), addr.getPort());
try {
RedisAsyncConnection<String, String> connection = client.connectAsync();
String nodesValue = get(connection.clusterNodes());
RedisConnection connection = client.connect();
String nodesValue = connection.sync(RedisCommands.CLUSTER_NODES);
log.debug("cluster nodes state: {}", nodesValue);

@ -19,8 +19,8 @@ import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
public class ConnectionEntry {
@ -29,12 +29,12 @@ public class ConnectionEntry {
private final Queue<RedisConnection> connections = new ConcurrentLinkedQueue<RedisConnection>();
private final Semaphore connectionsSemaphore;
public ConnectionEntry(RedisClient client, int poolSize) {
this.client = client;
this.connectionsSemaphore = new Semaphore(poolSize);
}
public RedisClient getClient() {
return client;
}
@ -54,5 +54,5 @@ public class ConnectionEntry {
public Queue<RedisConnection> getConnections() {
return connections;
}
}

@ -15,22 +15,23 @@
*/
package org.redisson.connection;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import org.redisson.SyncOperation;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import io.netty.channel.EventLoopGroup;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import org.redisson.async.AsyncOperation;
import org.redisson.async.SyncInterruptedOperation;
import org.redisson.async.SyncOperation;
import org.redisson.client.protocol.RedisCommand;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import java.util.concurrent.TimeUnit;
/**
*
* @author Nikita Koksharov
@ -39,47 +40,63 @@ import java.util.concurrent.TimeUnit;
//TODO ping support
public interface ConnectionManager {
Future<Void> writeAsyncVoid(String key, RedisCommand<String> command, Object ... params);
<R> R read(String key, SyncOperation<R> operation);
<T, R> Future<R> writeAsync(String key, RedisCommand<T> command, Object ... params);
<R> R write(String key, SyncOperation<R> operation);
<T, R> Future<R> readAsync(String key, RedisCommand<T> command, Object ... params);
<T, R> Future<R> writeAsync(RedisCommand<T> command, Object ... params);
RedisClient createClient(String host, int port, int timeout);
<T, R> R write(RedisCommand<T> command, Object ... params);
RedisClient createClient(String host, int port);
<T, R> R write(Codec codec, RedisCommand<T> command, Object ... params);
<V> V get(Future<V> future);
<T, R> Future<R> writeAsync(Codec codec, RedisCommand<T> command, Object ... params);
<V, R> R read(String key, SyncOperation<V, R> operation);
<T, R> R eval(RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params);
<V, R> R write(String key, SyncInterruptedOperation<V, R> operation) throws InterruptedException;
<T, R> Future<R> evalAsync(RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params);
<V, R> R write(String key, SyncOperation<V, R> operation);
<T, R> Future<R> evalAsync(Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params);
<V, R> R write(String key, AsyncOperation<V, R> asyncOperation);
<T, R> R read(String key, Codec codec, RedisCommand<T> command, Object ... params);
<V, T> Future<T> writeAllAsync(AsyncOperation<V, T> asyncOperation);
<T, R> Future<R> readAsync(String key, Codec codec, RedisCommand<T> command, Object ... params);
<V, T> T read(String key, AsyncOperation<V, T> asyncOperation);
<T, R> R read(String key, RedisCommand<T> command, Object ... params);
<V, T> Future<T> readAsync(String key, AsyncOperation<V, T> asyncOperation);
<T, R> R eval(Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params);
<V, T> Future<T> readAsync(AsyncOperation<V, T> asyncOperation);
<T, R> Future<R> writeAsync(String key, Codec codec, RedisCommand<T> command, Object ... params);
<V, T> Future<T> writeAsync(String key, AsyncOperation<V, T> asyncOperation);
<T, R> R write(String key, Codec codec, RedisCommand<T> command, Object ... params);
<V, T> Future<T> writeAsync(AsyncOperation<V, T> asyncOperation);
<T, R> R write(String key, RedisCommand<T> command, Object ... params);
<T> Future<Queue<Object>> readAllAsync(RedisCommand<T> command, Object ... params);
<T> Future<Boolean> writeAllAsync(RedisCommand<T> command, Object ... params);
<T> Future<Void> writeAsyncVoid(String key, RedisCommand<T> command, Object ... params);
<T, R> Future<R> writeAsync(String key, RedisCommand<T> command, Object ... params);
<T, R> Future<R> readAsync(String key, RedisCommand<T> command, Object ... params);
RedisClient createClient(String host, int port, int timeout);
RedisClient createClient(String host, int port);
<V> V get(Future<V> future);
<K, V> RedisConnection<K, V> connectionReadOp(int slot);
RedisConnection connectionReadOp(int slot);
PubSubConnectionEntry getEntry(String channelName);
<K, V> PubSubConnectionEntry subscribe(String channelName);
PubSubConnectionEntry subscribe(String channelName);
<K, V> PubSubConnectionEntry psubscribe(String pattern);
PubSubConnectionEntry psubscribe(String pattern);
<K, V> PubSubConnectionEntry subscribe(RedisPubSubAdapter<V> listener, String channelName);
<V> Future<PubSubStatusMessage> subscribe(RedisPubSubListener<V> listener, String channelName);
Future unsubscribe(String channelName);

@ -18,10 +18,9 @@ package org.redisson.connection;
import java.util.Collection;
import org.redisson.MasterSlaveServersConfig;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.Codec;
public interface LoadBalancer {
@ -31,7 +30,7 @@ public interface LoadBalancer {
Collection<RedisPubSubConnection> freeze(String host, int port);
void init(RedisCodec codec, MasterSlaveServersConfig config);
void init(Codec codec, MasterSlaveServersConfig config);
void add(SubscribesConnectionEntry entry);

@ -15,12 +15,17 @@
*/
package org.redisson.connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
@ -29,29 +34,25 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.Config;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.async.AsyncOperation;
import org.redisson.async.SyncInterruptedOperation;
import org.redisson.async.SyncOperation;
import org.redisson.SyncOperation;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisException;
import org.redisson.client.RedisMovedException;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.RedisTimeoutException;
import org.redisson.client.handler.RedisData;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.StringCodec;
import org.redisson.codec.RedisCodecWrapper;
import org.redisson.client.protocol.decoder.MultiDecoder;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisConnectionException;
import com.lambdaworks.redis.RedisException;
import com.lambdaworks.redis.RedisMovedException;
import com.lambdaworks.redis.RedisTimeoutException;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import com.lambdaworks.redis.pubsub.RedisPubSubListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollSocketChannel;
@ -61,6 +62,7 @@ import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
@ -76,7 +78,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
private final HashedWheelTimer timer = new HashedWheelTimer();
protected RedisCodec codec;
protected Codec codec;
protected EventLoopGroup group;
@ -115,7 +117,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
this.group = new NioEventLoopGroup(cfg.getThreads());
this.socketChannelClass = NioSocketChannel.class;
}
this.codec = new RedisCodecWrapper(cfg.getCodec());
this.codec = cfg.getCodec();
}
public RedisClient createClient(String host, int port) {
@ -148,210 +150,158 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
};
}
public <T> FutureListener<T> createReleaseReadListener(final int slot, final org.redisson.client.RedisConnection conn,
final Timeout timeout) {
return new FutureListener<T>() {
public <T> Future<Queue<Object>> readAllAsync(RedisCommand<T> command, Object ... params) {
final Promise<Queue<Object>> mainPromise = getGroup().next().newPromise();
Promise<Object> promise = new DefaultPromise<Object>() {
Queue<Object> results = new ConcurrentLinkedQueue<Object>();
AtomicInteger counter = new AtomicInteger(entries.keySet().size());
@Override
public void operationComplete(io.netty.util.concurrent.Future<T> future) throws Exception {
timeout.cancel();
releaseRead(slot, conn);
public Promise<Object> setSuccess(Object result) {
if (result instanceof Collection) {
results.addAll((Collection)result);
} else {
results.add(result);
}
if (counter.decrementAndGet() == 0
&& !mainPromise.isDone()) {
mainPromise.setSuccess(results);
}
return this;
}
};
}
public <V, T> Future<T> writeAllAsync(AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
AtomicInteger counter = new AtomicInteger(entries.keySet().size());
for (Integer slot : entries.keySet()) {
writeAllAsync(slot, asyncOperation, counter, mainPromise, 0);
async(true, slot, null, new StringCodec(), command, params, promise, 0);
}
return mainPromise;
}
private <V, T> void writeAllAsync(final int slot, final AsyncOperation<V, T> asyncOperation, final AtomicInteger counter, final Promise<T> mainPromise, final int attempt) {
final Promise<T> promise = getGroup().next().newPromise();
final AtomicReference<RedisException> ex = new AtomicReference<RedisException>();
public <T> Future<Boolean> writeAllAsync(RedisCommand<T> command, Object ... params) {
return allAsync(false, command, params);
}
TimerTask timerTask = new TimerTask() {
public <T> Future<Boolean> allAsync(boolean readOnlyMode, RedisCommand<T> command, Object ... params) {
final Promise<Boolean> mainPromise = getGroup().next().newPromise();
Promise<Object> promise = new DefaultPromise<Object>() {
AtomicInteger counter = new AtomicInteger(entries.keySet().size());
@Override
public void run(Timeout timeout) throws Exception {
if (promise.isDone()) {
return;
}
if (attempt == config.getRetryAttempts()) {
promise.setFailure(ex.get());
return;
public Promise<Object> setSuccess(Object result) {
if (counter.decrementAndGet() == 0
&& !mainPromise.isDone()) {
mainPromise.setSuccess(true);
}
promise.cancel(true);
int count = attempt + 1;
writeAllAsync(slot, asyncOperation, counter, mainPromise, count);
return this;
}
};
for (Integer slot : entries.keySet()) {
async(readOnlyMode, slot, null, new StringCodec(), command, params, promise, 0);
}
return mainPromise;
}
try {
RedisConnection<Object, V> connection = connectionWriteOp(slot);
RedisAsyncConnection<Object, V> async = connection.getAsync();
asyncOperation.execute(promise, async);
ex.set(new RedisTimeoutException());
Timeout timeout = timer.newTimeout(timerTask, config.getTimeout(), TimeUnit.MILLISECONDS);
promise.addListener(createReleaseWriteListener(slot, connection, timeout));
} catch (RedisConnectionException e) {
ex.set(e);
timer.newTimeout(timerTask, config.getRetryInterval(), TimeUnit.MILLISECONDS);
private int calcSlot(String key) {
if (entries.size() == 1) {
return -1;
}
promise.addListener(new FutureListener<T>() {
@Override
public void operationComplete(Future<T> future) throws Exception {
if (future.isCancelled()) {
return;
}
if (future.cause() instanceof RedisMovedException) {
RedisMovedException ex = (RedisMovedException)future.cause();
writeAllAsync(ex.getSlot(), asyncOperation, counter, mainPromise, attempt);
return;
}
int start = key.indexOf('{');
if (start != -1) {
int end = key.indexOf('}');
key = key.substring(start+1, end);
}
if (future.isSuccess()) {
if (counter.decrementAndGet() == 0
&& !mainPromise.isDone()) {
mainPromise.setSuccess(future.getNow());
}
} else {
mainPromise.setFailure(future.cause());
}
}
});
int result = CRC16.crc16(key.getBytes()) % 16384;
log.debug("slot {} for {}", result, key);
return result;
}
public <V, T> Future<T> writeAsync(String key, AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
writeAsync(slot, asyncOperation, mainPromise, 0);
return mainPromise;
public <V> V get(Future<V> future) {
future.awaitUninterruptibly();
if (future.isSuccess()) {
return future.getNow();
}
throw future.cause() instanceof RedisException ?
(RedisException) future.cause() :
new RedisException("Unexpected exception while processing command", future.cause());
}
public <V, T> Future<T> writeAsync(AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
writeAsync(-1, asyncOperation, mainPromise, 0);
return mainPromise;
public <T, R> R read(String key, RedisCommand<T> command, Object ... params) {
return read(key, codec, command, params);
}
private <V, T> void writeAsync(final int slot, final AsyncOperation<V, T> asyncOperation, final Promise<T> mainPromise, final int attempt) {
final Promise<T> promise = getGroup().next().newPromise();
final AtomicReference<RedisException> ex = new AtomicReference<RedisException>();
TimerTask timerTask = new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (promise.isDone()) {
return;
}
if (attempt == config.getRetryAttempts()) {
promise.setFailure(ex.get());
return;
}
promise.cancel(true);
public <T, R> R read(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = readAsync(key, codec, command, params);
return get(res);
}
int count = attempt + 1;
writeAsync(slot, asyncOperation, mainPromise, count);
}
};
public <T, R> Future<R> readAsync(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Promise<R> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
async(true, slot, null, codec, command, params, mainPromise, 0);
return mainPromise;
}
try {
RedisConnection<Object, V> connection = connectionWriteOp(slot);
RedisAsyncConnection<Object, V> async = connection.getAsync();
log.debug("writeAsync for slot {} using {}", slot, connection.getRedisClient().getAddr());
asyncOperation.execute(promise, async);
public <T, R> Future<R> readAsync(String key, RedisCommand<T> command, Object ... params) {
return readAsync(key, codec, command, params);
}
ex.set(new RedisTimeoutException());
Timeout timeout = timer.newTimeout(timerTask, config.getTimeout(), TimeUnit.MILLISECONDS);
promise.addListener(createReleaseWriteListener(slot, connection, timeout));
} catch (RedisConnectionException e) {
ex.set(e);
timer.newTimeout(timerTask, config.getRetryInterval(), TimeUnit.MILLISECONDS);
}
promise.addListener(new FutureListener<T>() {
public <T> Future<Void> writeAsyncVoid(String key, RedisCommand<T> command, Object ... params) {
final Promise<Void> voidPromise = getGroup().next().newPromise();
Promise<String> mainPromise = getGroup().next().newPromise();
mainPromise.addListener(new FutureListener<String>() {
@Override
public void operationComplete(Future<T> future) throws Exception {
public void operationComplete(Future<String> future) throws Exception {
if (future.isCancelled()) {
return;
}
if (future.cause() instanceof RedisMovedException) {
RedisMovedException ex = (RedisMovedException)future.cause();
writeAsync(ex.getSlot(), asyncOperation, mainPromise, attempt);
return;
}
if (future.isSuccess()) {
mainPromise.setSuccess(future.getNow());
voidPromise.cancel(true);
} else {
mainPromise.setFailure(future.cause());
if (future.isSuccess()) {
voidPromise.setSuccess(null);
} else {
voidPromise.setFailure(future.cause());
}
}
}
});
}
public <V, R> R write(String key, SyncInterruptedOperation<V, R> operation) throws InterruptedException {
int slot = calcSlot(key);
return write(slot, operation, 0);
async(false, slot, null, codec, command, params, mainPromise, 0);
return voidPromise;
}
private <V, R> R write(int slot, SyncInterruptedOperation<V, R> operation, int attempt) throws InterruptedException {
try {
RedisConnection<Object, V> connection = connectionWriteOp(slot);
try {
return operation.execute(connection);
} catch (RedisMovedException e) {
return write(e.getSlot(), operation, attempt);
} catch (RedisTimeoutException e) {
if (attempt == config.getRetryAttempts()) {
throw e;
}
attempt++;
return write(slot, operation, attempt);
} catch (InterruptedException e) {
throw e;
} finally {
releaseWrite(slot, connection);
}
} catch (RedisConnectionException e) {
if (attempt == config.getRetryAttempts()) {
throw e;
}
try {
Thread.sleep(config.getRetryInterval());
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
}
attempt++;
return write(slot, operation, attempt);
}
public <R> R write(String key, SyncOperation<R> operation) {
int slot = calcSlot(key);
return async(false, slot, operation, 0);
}
public <V, R> R write(String key, SyncOperation<V, R> operation) {
public <R> R read(String key, SyncOperation<R> operation) {
int slot = calcSlot(key);
return write(slot, operation, 0);
return async(true, slot, operation, 0);
}
private <V, R> R write(int slot, SyncOperation<V, R> operation, int attempt) {
private <R> R async(boolean readOnlyMode, int slot, SyncOperation<R> operation, int attempt) {
try {
RedisConnection<Object, V> connection = connectionWriteOp(slot);
RedisConnection connection;
if (readOnlyMode) {
connection = connectionReadOp(slot);
} else {
connection = connectionWriteOp(slot);
}
try {
return operation.execute(connection);
return operation.execute(codec, connection);
} catch (RedisMovedException e) {
return write(e.getSlot(), operation, attempt);
return async(readOnlyMode, e.getSlot(), operation, attempt);
} catch (RedisTimeoutException e) {
if (attempt == config.getRetryAttempts()) {
throw e;
}
attempt++;
return write(slot, operation, attempt);
return async(readOnlyMode, slot, operation, attempt);
} finally {
releaseWrite(slot, connection);
if (readOnlyMode) {
releaseRead(slot, connection);
} else {
releaseWrite(slot, connection);
}
}
} catch (RedisConnectionException e) {
if (attempt == config.getRetryAttempts()) {
@ -363,192 +313,81 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
Thread.currentThread().interrupt();
}
attempt++;
return write(slot, operation, attempt);
return async(readOnlyMode, slot, operation, attempt);
}
}
public <V, R> R read(String key, SyncOperation<V, R> operation) {
int slot = calcSlot(key);
return read(slot, operation, 0);
public <T, R> R write(String key, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(key, command, params);
return get(res);
}
private <V, R> R read(int slot, SyncOperation<V, R> operation, int attempt) {
try {
RedisConnection<Object, V> connection = connectionReadOp(slot);
try {
return operation.execute(connection);
} catch (RedisMovedException e) {
return read(e.getSlot(), operation, attempt);
} catch (RedisTimeoutException e) {
if (attempt == config.getRetryAttempts()) {
throw e;
}
attempt++;
return read(slot, operation, attempt);
} finally {
releaseRead(slot, connection);
}
} catch (RedisConnectionException e) {
if (attempt == config.getRetryAttempts()) {
throw e;
}
try {
Thread.sleep(config.getRetryInterval());
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
}
attempt++;
return read(slot, operation, attempt);
}
public <T, R> Future<R> evalAsync(RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
return evalAsync(codec, evalCommandType, script, keys, params);
}
private int calcSlot(String key) {
if (entries.size() == 1) {
return -1;
}
int start = key.indexOf('{');
if (start != -1) {
int end = key.indexOf('}');
key = key.substring(start+1, end);
}
public <T, R> Future<R> evalAsync(Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
Promise<R> mainPromise = getGroup().next().newPromise();
List<Object> args = new ArrayList<Object>(2 + keys.size() + params.length);
args.add(script);
args.add(keys.size());
args.addAll(keys);
args.addAll(Arrays.asList(params));
async(false, -1, null, codec, evalCommandType, args.toArray(), mainPromise, 0);
return mainPromise;
}
int result = CRC16.crc16(key.getBytes()) % 16384;
log.debug("slot {} for {}", result, key);
return result;
public <T, R> R eval(RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
return eval(codec, evalCommandType, script, keys, params);
}
public <V, R> R write(String key, AsyncOperation<V, R> asyncOperation) {
Promise<R> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
writeAsync(slot, asyncOperation, mainPromise, 0);
return get(mainPromise);
public <T, R> R eval(Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
Future<R> res = evalAsync(codec, evalCommandType, script, keys, params);
return get(res);
}
public <V> V get(Future<V> future) {
future.awaitUninterruptibly();
if (future.isSuccess()) {
return future.getNow();
}
throw future.cause() instanceof RedisException ?
(RedisException) future.cause() :
new RedisException("Unexpected exception while processing command", future.cause());
public <T, R> Future<R> writeAsync(String key, RedisCommand<T> command, Object ... params) {
return writeAsync(key, codec, command, params);
}
public <V, T> T read(String key, AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
readAsync(slot, asyncOperation, mainPromise, 0);
return get(mainPromise);
public <T, R> R write(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(key, codec, command, params);
return get(res);
}
public <V, T> Future<T> readAsync(String key, AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
public <T, R> Future<R> writeAsync(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Promise<R> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
readAsync(slot, asyncOperation, mainPromise, 0);
async(false, slot, null, codec, command, params, mainPromise, 0);
return mainPromise;
}
public <V, T> Future<T> readAsync(AsyncOperation<V, T> asyncOperation) {
Promise<T> mainPromise = getGroup().next().newPromise();
readAsync(-1, asyncOperation, mainPromise, 0);
return mainPromise;
public <T, R> R write(RedisCommand<T> command, Object ... params) {
return write(codec, command, params);
}
private <V, T> void readAsync(final int slot, final AsyncOperation<V, T> asyncOperation, final Promise<T> mainPromise, final int attempt) {
final Promise<T> promise = getGroup().next().newPromise();
final AtomicReference<RedisException> ex = new AtomicReference<RedisException>();
TimerTask timerTask = new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (promise.isDone()) {
return;
}
if (attempt == config.getRetryAttempts()) {
promise.setFailure(ex.get());
return;
}
promise.cancel(true);
int count = attempt + 1;
readAsync(slot, asyncOperation, mainPromise, count);
}
};
try {
RedisConnection<Object, V> connection = connectionReadOp(slot);
RedisAsyncConnection<Object, V> async = connection.getAsync();
log.debug("readAsync for slot {} using {}", slot, connection.getRedisClient().getAddr());
asyncOperation.execute(promise, async);
ex.set(new RedisTimeoutException());
Timeout timeout = timer.newTimeout(timerTask, config.getTimeout(), TimeUnit.MILLISECONDS);
promise.addListener(createReleaseReadListener(slot, connection, timeout));
} catch (RedisConnectionException e) {
ex.set(e);
timer.newTimeout(timerTask, config.getRetryInterval(), TimeUnit.MILLISECONDS);
}
promise.addListener(new FutureListener<T>() {
@Override
public void operationComplete(Future<T> future) throws Exception {
if (future.isCancelled()) {
return;
}
// TODO cancel timeout
if (future.cause() instanceof RedisMovedException) {
RedisMovedException ex = (RedisMovedException)future.cause();
readAsync(ex.getSlot(), asyncOperation, mainPromise, attempt);
return;
}
public <T, R> R write(Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(codec, command, params);
return get(res);
}
if (future.isSuccess()) {
mainPromise.setSuccess(future.getNow());
} else {
mainPromise.setFailure(future.cause());
}
}
});
public <T, R> Future<R> writeAsync(RedisCommand<T> command, Object ... params) {
return writeAsync(codec, command, params);
}
public <T, R> Future<R> readAsync(String key, RedisCommand<T> command, Object ... params) {
public <T, R> Future<R> writeAsync(Codec codec, RedisCommand<T> command, Object ... params) {
Promise<R> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
async(true, slot, new StringCodec(), command, params, mainPromise, 0);
return mainPromise;
}
public Future<Void> writeAsyncVoid(String key, RedisCommand<String> command, Object ... params) {
final Promise<Void> voidPromise = getGroup().next().newPromise();
Promise<String> mainPromise = getGroup().next().newPromise();
mainPromise.addListener(new FutureListener<String>() {
@Override
public void operationComplete(Future<String> future) throws Exception {
if (future.isCancelled()) {
voidPromise.cancel(true);
} else {
if (future.isSuccess()) {
voidPromise.setSuccess(null);
} else {
voidPromise.setFailure(future.cause());
}
}
}
});
int slot = calcSlot(key);
async(false, slot, new StringCodec(), command, params, mainPromise, 0);
return voidPromise;
}
for (Integer slot : entries.keySet()) {
async(false, slot, null, codec, command, params, mainPromise, 0);
}
public <T, R> Future<R> writeAsync(String key, RedisCommand<T> command, Object ... params) {
Promise<R> mainPromise = getGroup().next().newPromise();
int slot = calcSlot(key);
async(false, slot, new StringCodec(), command, params, mainPromise, 0);
return mainPromise;
}
private <V, R> void async(final boolean readOnlyMode, final int slot, final Codec codec, final RedisCommand<V> command,
private <V, R> void async(final boolean readOnlyMode, final int slot, final MultiDecoder<Object> messageDecoder, final Codec codec, final RedisCommand<V> command,
final Object[] params, final Promise<R> mainPromise, final int attempt) {
final Promise<R> attemptPromise = getGroup().next().newPromise();
final AtomicReference<RedisException> ex = new AtomicReference<RedisException>();
@ -566,23 +405,28 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
attemptPromise.cancel(true);
int count = attempt + 1;
async(readOnlyMode, slot, codec, command, params, mainPromise, count);
async(readOnlyMode, slot, messageDecoder, codec, command, params, mainPromise, count);
}
};
try {
org.redisson.client.RedisConnection connection;
if (readOnlyMode) {
connection = connectionReadOp2(slot);
connection = connectionReadOp(slot);
} else {
connection = connectionReadOp2(slot);
connection = connectionWriteOp(slot);
}
log.debug("readAsync for slot {} using {}", slot, connection.getRedisClient().getAddr());
connection.send(new RedisData<V, R>(attemptPromise, codec, command, params));
connection.send(new RedisData<V, R>(attemptPromise, messageDecoder, codec, command, params));
ex.set(new RedisTimeoutException());
Timeout timeout = timer.newTimeout(timerTask, config.getTimeout(), TimeUnit.MILLISECONDS);
attemptPromise.addListener(createReleaseReadListener(slot, connection, timeout));
if (readOnlyMode) {
attemptPromise.addListener(createReleaseReadListener(slot, connection, timeout));
} else {
attemptPromise.addListener(createReleaseWriteListener(slot, connection, timeout));
}
} catch (RedisConnectionException e) {
ex.set(e);
timer.newTimeout(timerTask, config.getRetryInterval(), TimeUnit.MILLISECONDS);
@ -597,7 +441,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
if (future.cause() instanceof RedisMovedException) {
RedisMovedException ex = (RedisMovedException)future.cause();
async(readOnlyMode, ex.getSlot(), codec, command, params, mainPromise, attempt);
async(readOnlyMode, ex.getSlot(), messageDecoder, codec, command, params, mainPromise, attempt);
return;
}
@ -617,7 +461,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
@Override
public <K, V> PubSubConnectionEntry subscribe(String channelName) {
public PubSubConnectionEntry subscribe(String channelName) {
// multiple channel names per PubSubConnections allowed
PubSubConnectionEntry сonnEntry = name2PubSubConnection.get(channelName);
if (сonnEntry != null) {
@ -638,14 +482,14 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
entry.release();
return subscribe(channelName);
}
entry.subscribe(channelName);
entry.subscribe(codec, channelName);
return entry;
}
}
}
int slot = -1;
RedisPubSubConnection<K, V> conn = nextPubSubConnection(slot);
RedisPubSubConnection conn = nextPubSubConnection(slot);
PubSubConnectionEntry entry = new PubSubConnectionEntry(conn, config.getSubscriptionsPerConnection());
entry.tryAcquire();
@ -660,13 +504,13 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
entry.release();
return subscribe(channelName);
}
entry.subscribe(channelName);
entry.subscribe(codec, channelName);
return entry;
}
}
@Override
public <K, V> PubSubConnectionEntry psubscribe(String channelName) {
public PubSubConnectionEntry psubscribe(String channelName) {
// multiple channel names per PubSubConnections allowed
PubSubConnectionEntry сonnEntry = name2PubSubConnection.get(channelName);
if (сonnEntry != null) {
@ -687,14 +531,14 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
entry.release();
return psubscribe(channelName);
}
entry.psubscribe(channelName);
entry.psubscribe(codec, channelName);
return entry;
}
}
}
int slot = -1;
RedisPubSubConnection<K, V> conn = nextPubSubConnection(slot);
RedisPubSubConnection conn = nextPubSubConnection(slot);
PubSubConnectionEntry entry = new PubSubConnectionEntry(conn, config.getSubscriptionsPerConnection());
entry.tryAcquire();
@ -709,17 +553,16 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
entry.release();
return psubscribe(channelName);
}
entry.psubscribe(channelName);
entry.psubscribe(codec, channelName);
return entry;
}
}
@Override
public <K, V> PubSubConnectionEntry subscribe(RedisPubSubAdapter<V> listener, String channelName) {
public Future<PubSubStatusMessage> subscribe(RedisPubSubListener listener, String channelName) {
PubSubConnectionEntry сonnEntry = name2PubSubConnection.get(channelName);
if (сonnEntry != null) {
сonnEntry.subscribe(listener, channelName);
return сonnEntry;
return сonnEntry.subscribe(codec, listener, channelName);
}
Set<PubSubConnectionEntry> entries = new HashSet<PubSubConnectionEntry>(name2PubSubConnection.values());
@ -728,36 +571,34 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
PubSubConnectionEntry oldEntry = name2PubSubConnection.putIfAbsent(channelName, entry);
if (oldEntry != null) {
entry.release();
return oldEntry;
return group.next().newSucceededFuture(new PubSubStatusMessage(Type.SUBSCRIBE, Arrays.asList(channelName)));
}
synchronized (entry) {
if (!entry.isActive()) {
entry.release();
return subscribe(listener, channelName);
}
entry.subscribe(listener, channelName);
return entry;
return entry.subscribe(codec, listener, channelName);
}
}
}
int slot = -1;
RedisPubSubConnection<K, V> conn = nextPubSubConnection(slot);
RedisPubSubConnection conn = nextPubSubConnection(slot);
PubSubConnectionEntry entry = new PubSubConnectionEntry(conn, config.getSubscriptionsPerConnection());
entry.tryAcquire();
PubSubConnectionEntry oldEntry = name2PubSubConnection.putIfAbsent(channelName, entry);
if (oldEntry != null) {
returnSubscribeConnection(slot, entry);
return oldEntry;
return group.next().newSucceededFuture(new PubSubStatusMessage(Type.SUBSCRIBE, Arrays.asList(channelName)));
}
synchronized (entry) {
if (!entry.isActive()) {
entry.release();
return subscribe(listener, channelName);
}
entry.subscribe(listener, channelName);
return entry;
return entry.subscribe(codec, listener, channelName);
}
}
@ -860,23 +701,15 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
return entries.remove(endSlot);
}
protected <K, V> RedisConnection<K, V> connectionWriteOp(int slot) {
protected RedisConnection connectionWriteOp(int slot) {
return getEntry(slot).connectionWriteOp();
}
@Override
public <K, V> RedisConnection<K, V> connectionReadOp(int slot) {
public RedisConnection connectionReadOp(int slot) {
return getEntry(slot).connectionReadOp();
}
public org.redisson.client.RedisConnection connectionReadOp2(int slot) {
return null;
}
protected org.redisson.client.RedisConnection connectionWriteOp2(int slot) {
return null;
}
RedisPubSubConnection nextPubSubConnection(int slot) {
return getEntry(slot).nextPubSubConnection();
}
@ -893,11 +726,6 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
getEntry(slot).releaseRead(connection);
}
public void releaseRead(int slot, org.redisson.client.RedisConnection connection) {
// getEntry(slot).releaseRead(connection);
}
@Override
public void shutdown() {
for (MasterSlaveEntry entry : entries.values()) {

@ -21,15 +21,15 @@ import java.util.Collection;
import java.util.List;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.RedisCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisConnectionException;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
/**
*
* @author Nikita Koksharov
@ -44,10 +44,10 @@ public class MasterSlaveEntry {
volatile ConnectionEntry masterEntry;
final MasterSlaveServersConfig config;
final RedisCodec codec;
final Codec codec;
final ConnectionManager connectionManager;
public MasterSlaveEntry(RedisCodec codec, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
public MasterSlaveEntry(Codec codec, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
this.codec = codec;
this.connectionManager = connectionManager;
this.config = config;
@ -107,7 +107,7 @@ public class MasterSlaveEntry {
ConnectionEntry oldMaster = masterEntry;
setupMasterEntry(host, port);
slaveDown(host, port);
oldMaster.getClient().shutdown();
oldMaster.getClient().shutdownAsync();
}
public void shutdownMasterAsync() {
@ -115,24 +115,24 @@ public class MasterSlaveEntry {
slaveBalancer.shutdown();
}
public <K, V> RedisConnection<K, V> connectionWriteOp() {
public RedisConnection connectionWriteOp() {
acquireMasterConnection();
RedisConnection<K, V> conn = masterEntry.getConnections().poll();
RedisConnection conn = masterEntry.getConnections().poll();
if (conn != null) {
return conn;
}
try {
conn = masterEntry.getClient().connect(codec);
conn = masterEntry.getClient().connect();
if (config.getPassword() != null) {
conn.auth(config.getPassword());
conn.sync(RedisCommands.AUTH, config.getPassword());
}
if (config.getDatabase() != 0) {
conn.select(config.getDatabase());
conn.sync(RedisCommands.SELECT, config.getDatabase());
}
if (config.getClientName() != null) {
conn.clientSetname((K) config.getClientName());
conn.sync(RedisCommands.CLIENT_SETNAME, config.getClientName());
}
return conn;
} catch (RedisConnectionException e) {
@ -141,7 +141,7 @@ public class MasterSlaveEntry {
}
}
public <K, V> RedisConnection<K, V> connectionReadOp() {
public RedisConnection connectionReadOp() {
return slaveBalancer.nextConnection();
}
@ -166,7 +166,7 @@ public class MasterSlaveEntry {
public void releaseWrite(RedisConnection connection) {
// may changed during changeMaster call
if (!masterEntry.getClient().equals(connection.getRedisClient())) {
connection.close();
connection.closeAsync();
return;
}

@ -27,13 +27,13 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Semaphore;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import com.lambdaworks.redis.pubsub.RedisPubSubListener;
public class PubSubConnectionEntry {
public enum Status {ACTIVE, INACTIVE}
@ -65,7 +65,7 @@ public class PubSubConnectionEntry {
return new ArrayList<RedisPubSubListener>(result);
}
public void addListener(String channelName, RedisPubSubListener listener) {
public void addListener(String channelName, RedisPubSubListener<?> listener) {
Queue<RedisPubSubListener> queue = channelListeners.get(channelName);
if (queue == null) {
queue = new ConcurrentLinkedQueue<RedisPubSubListener>();
@ -123,43 +123,32 @@ public class PubSubConnectionEntry {
subscribedChannelsAmount.release();
}
public void subscribe(final String channelName) {
conn.addListener(new RedisPubSubAdapter() {
public void subscribe(Codec codec, final String channelName) {
Future<PubSubStatusMessage> result = conn.subscribe(codec, channelName);
result.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void subscribed(String channel, long count) {
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
log.debug("subscribed to '{}' channel on server '{}'", channelName, conn.getRedisClient().getAddr());
}
@Override
public void unsubscribed(String channel, long count) {
log.debug("unsubscribed from '{}' channel on server '{}'", channelName, conn.getRedisClient().getAddr());
}
});
conn.subscribe(channelName);
}
public void psubscribe(final String pattern) {
conn.addListener(new RedisPubSubAdapter() {
@Override
public void psubscribed(String channel, long count) {
log.debug("psubscribed to '{}' pattern", pattern);
}
@Override
public void punsubscribed(String channel, long count) {
log.debug("punsubscribed from '{}' pattern", pattern);
}
public void psubscribe(Codec codec, final String pattern) {
Future<PubSubStatusMessage> result = conn.psubscribe(codec, pattern);
result.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
log.debug("punsubscribed from '{}' pattern on server '{}'", pattern, conn.getRedisClient().getAddr());
}
});
conn.psubscribe(pattern);
}
public void subscribe(RedisPubSubAdapter listener, String channel) {
public Future<PubSubStatusMessage> subscribe(Codec codec, RedisPubSubListener listener, String channel) {
addListener(channel, listener);
conn.subscribe(channel);
return conn.subscribe(codec, channel);
}
public Future unsubscribe(final String channel) {
public Future<PubSubStatusMessage> unsubscribe(final String channel) {
Queue<RedisPubSubListener> listeners = channelListeners.get(channel);
if (listeners != null) {
for (RedisPubSubListener listener : listeners) {
@ -167,17 +156,17 @@ public class PubSubConnectionEntry {
}
}
Future future = conn.unsubscribe(channel);
future.addListener(new FutureListener() {
Future<PubSubStatusMessage> future = conn.unsubscribe(channel);
future.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future future) throws Exception {
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
subscribedChannelsAmount.release();
}
});
return future;
}
public Future punsubscribe(final String channel) {
public Future<PubSubStatusMessage> punsubscribe(final String channel) {
Queue<RedisPubSubListener> listeners = channelListeners.get(channel);
if (listeners != null) {
for (RedisPubSubListener listener : listeners) {
@ -185,10 +174,10 @@ public class PubSubConnectionEntry {
}
}
Future future = conn.punsubscribe(channel);
future.addListener(new FutureListener() {
Future<PubSubStatusMessage> future = conn.punsubscribe(channel);
future.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future future) throws Exception {
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
subscribedChannelsAmount.release();
}
});

@ -27,13 +27,18 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.Config;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.SentinelServersConfig;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.StringCodec;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.pubsub.RedisPubSubAdapter;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
public class SentinelConnectionManager extends MasterSlaveConnectionManager {
@ -59,17 +64,17 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
final Set<String> addedSlaves = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
for (URI addr : cfg.getSentinelAddresses()) {
RedisClient client = createClient(addr.getHost(), addr.getPort(), c.getTimeout());
RedisAsyncConnection<String, String> connection = client.connectAsync();
RedisConnection connection = client.connect();
// TODO async
List<String> master = get(connection.getMasterAddrByKey(cfg.getMasterName()));
List<String> master = connection.sync(RedisCommands.SENTINEL_GET_MASTER_ADDR_BY_NAME, cfg.getMasterName());
String masterHost = master.get(0) + ":" + master.get(1);
c.setMasterAddress(masterHost);
log.info("master: {} added", masterHost);
// c.addSlaveAddress(masterHost);
// TODO async
List<Map<String, String>> slaves = get(connection.slaves(cfg.getMasterName()));
List<Map<String, String>> slaves = connection.sync(RedisCommands.SENTINEL_SLAVES, cfg.getMasterName());
for (Map<String, String> map : slaves) {
String ip = map.get("ip");
String port = map.get("port");
@ -103,15 +108,11 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
RedisClient client = createClient(addr.getHost(), addr.getPort());
sentinels.add(client);
RedisPubSubConnection<String, String> pubsub = client.connectPubSub();
pubsub.addListener(new RedisPubSubAdapter<String>() {
@Override
public void subscribed(String channel, long count) {
log.info("subscribed to channel: {} from Sentinel {}:{}", channel, addr.getHost(), addr.getPort());
}
RedisPubSubConnection pubsub = client.connectPubSub();
pubsub.addListener(new RedisPubSubListener<String>() {
@Override
public void message(String channel, String msg) {
public void onMessage(String channel, String msg) {
if ("+slave".equals(channel)) {
onSlaveAdded(addedSlaves, addr, msg);
}
@ -126,8 +127,18 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
}
@Override
public void onPatternMessage(String pattern, String channel, String message) {
}
});
Future<PubSubStatusMessage> res = pubsub.subscribe(StringCodec.INSTANCE, "+switch-master", "+sdown", "-sdown", "+slave");
res.addListener(new FutureListener<PubSubStatusMessage>() {
@Override
public void operationComplete(Future<PubSubStatusMessage> future) throws Exception {
log.info("subscribed to channel: {} from Sentinel {}:{}", future.getNow().getChannels(), addr.getHost(), addr.getPort());
}
});
pubsub.subscribe("+switch-master", "+sdown", "-sdown", "+slave");
}
}

@ -16,20 +16,20 @@
package org.redisson.connection;
import org.redisson.MasterSlaveServersConfig;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.Codec;
import org.redisson.client.protocol.RedisCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.RedisConnectionException;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
public class SingleEntry extends MasterSlaveEntry {
private final Logger log = LoggerFactory.getLogger(getClass());
public SingleEntry(RedisCodec codec, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
public SingleEntry(Codec codec, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
super(codec, connectionManager, config);
}
@ -59,16 +59,17 @@ public class SingleEntry extends MasterSlaveEntry {
}
try {
conn = masterEntry.getClient().connectPubSub(codec);
conn = masterEntry.getClient().connectPubSub();
if (config.getPassword() != null) {
conn.auth(config.getPassword());
conn.sync(RedisCommands.AUTH, config.getPassword());
}
if (config.getDatabase() != 0) {
conn.select(config.getDatabase());
conn.sync(RedisCommands.SELECT, config.getDatabase());
}
if (config.getClientName() != null) {
conn.clientSetname(config.getClientName());
conn.sync(RedisCommands.CLIENT_SETNAME, config.getClientName());
}
return conn;
} catch (RedisConnectionException e) {
((SubscribesConnectionEntry)masterEntry).getSubscribeConnectionsSemaphore().release();
@ -83,7 +84,7 @@ public class SingleEntry extends MasterSlaveEntry {
}
@Override
public <K, V> RedisConnection<K, V> connectionReadOp() {
public RedisConnection connectionReadOp() {
return super.connectionWriteOp();
}

@ -19,11 +19,11 @@ import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisPubSubConnection;
public class SubscribesConnectionEntry extends ConnectionEntry {
private final Semaphore subscribeConnectionsSemaphore;
private final Queue<RedisPubSubConnection> allSubscribeConnections = new ConcurrentLinkedQueue<RedisPubSubConnection>();
private final Queue<RedisPubSubConnection> freeSubscribeConnections = new ConcurrentLinkedQueue<RedisPubSubConnection>();
@ -36,22 +36,22 @@ public class SubscribesConnectionEntry extends ConnectionEntry {
public Queue<RedisPubSubConnection> getAllSubscribeConnections() {
return allSubscribeConnections;
}
public void registerSubscribeConnection(RedisPubSubConnection connection) {
allSubscribeConnections.offer(connection);
}
public RedisPubSubConnection pollFreeSubscribeConnection() {
return freeSubscribeConnections.poll();
}
public void offerFreeSubscribeConnection(RedisPubSubConnection connection) {
freeSubscribeConnections.offer(connection);
}
public Semaphore getSubscribeConnectionsSemaphore() {
return subscribeConnectionsSemaphore;
}
}

@ -21,24 +21,24 @@ import java.util.Collection;
public interface RHyperLogLog<V> extends RObject {
long add(V obj);
boolean add(V obj);
long addAll(Collection<V> objects);
boolean addAll(Collection<V> objects);
long count();
long countWith(String ... otherLogNames);
long mergeWith(String ... otherLogNames);
void mergeWith(String ... otherLogNames);
Future<Long> addAsync(V obj);
Future<Boolean> addAsync(V obj);
Future<Long> addAllAsync(Collection<V> objects);
Future<Boolean> addAllAsync(Collection<V> objects);
Future<Long> countAsync();
Future<Long> countWithAsync(String ... otherLogNames);
Future<Long> mergeWithAsync(String ... otherLogNames);
Future<Void> mergeWithAsync(String ... otherLogNames);
}

@ -146,7 +146,7 @@ public interface RMap<K, V> extends ConcurrentMap<K, V>, RExpirable {
Future<V> replaceAsync(K key, V value);
Future<V> replaceAsync(K key, V oldValue, V newValue);
Future<Boolean> replaceAsync(K key, V oldValue, V newValue);
Future<Long> removeAsync(Object key, Object value);

@ -19,40 +19,58 @@ import io.netty.util.concurrent.Future;
import java.util.List;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
public interface RScript {
enum ReturnType {BOOLEAN, INTEGER, MULTI, STATUS, VALUE, MAPVALUE, MAPVALUELIST};
enum ReturnType {
BOOLEAN(RedisCommands.EVAL_BOOLEAN),
INTEGER(RedisCommands.EVAL_INTEGER),
MULTI(RedisCommands.EVAL_LIST),
STATUS(RedisCommands.EVAL_STRING),
VALUE(RedisCommands.EVAL_OBJECT),
MAPVALUE(RedisCommands.EVAL_MAP_VALUE),
MAPVALUELIST(RedisCommands.EVAL_MAP_VALUE_LIST);
RedisCommand<?> command;
ReturnType(RedisCommand<?> command) {
this.command = command;
}
public RedisCommand<?> getCommand() {
return command;
}
};
List<Boolean> scriptExists(String ... shaDigests);
Future<List<Boolean>> scriptExistsAsync(String ... shaDigests);
String scriptFlush();
Future<String> scriptFlushAsync();
String scriptKill();
Future<String> scriptKillAsync();
String scriptLoad(String luaScript);
Future<String> scriptLoadAsync(String luaScript);
<R> R evalR(String luaScript, ReturnType returnType, List<Object> keys, List<?> values, List<?> rawValues);
boolean scriptFlush();
Future<Boolean> scriptFlushAsync();
boolean scriptKill();
<R> Future<R> evalAsyncR(String luaScript, ReturnType returnType, List<Object> keys, List<?> values, List<?> rawValues);
Future<Boolean> scriptKillAsync();
String scriptLoad(String luaScript);
Future<String> scriptLoadAsync(String luaScript);
<R> R evalSha(String shaDigest, ReturnType returnType);
<R> R evalSha(String shaDigest, ReturnType returnType, List<Object> keys, Object... values);
<R> Future<R> evalShaAsync(String shaDigest, ReturnType returnType, List<Object> keys, Object... values);
<R> Future<R> evalAsync(String luaScript, ReturnType returnType, List<Object> keys, Object... values);
<R> R eval(String luaScript, ReturnType returnType);
<R> R eval(String luaScript, ReturnType returnType, List<Object> keys, Object... values);
}

Loading…
Cancel
Save