Merge branch 'master' of https://github.com/mrniko/redisson into redisson-reference

# Conflicts:
#	redisson/pom.xml
#	redisson/src/main/java/org/redisson/command/CommandAsyncExecutor.java
#	redisson/src/main/java/org/redisson/command/CommandAsyncService.java
pull/605/head
jackygurui 9 years ago
commit 62042c4b95

@ -2,6 +2,24 @@ Redisson Releases History
================================ ================================
####Please Note: trunk is current development branch. ####Please Note: trunk is current development branch.
####24-Aug-2016 - version 2.3.0 released
Starting from this version Redisson could be run as standalone node to execute distributed tasks. More features will be added to it in future. Read docs about it [here](https://github.com/mrniko/redisson/wiki/12.-Standalone-node)
Feature - __new service added__ `RExecutorService`. More info about it [here](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#93-distributed-executor-service)
Feature - __new service added__ `RScheduledExecutorService`. More info about it
[here](https://github.com/mrniko/redisson/wiki/9.-distributed-services#94-distributed-scheduled-executor-service)
Feature - __new service added__ `RLiveObjectService`. More info about it
[here](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#92-live-object-service) (big thanks to Rui Gu for this amazing feature)
Feature - __new object added__ `RBoundedBlockingQueue`. More info about it [here](https://github.com/mrniko/redisson/wiki/7.-distributed-collections/#711-bounded-blocking-queue)
Feature - __Redis deployment tool__. More info about it
[here](https://github.com/mrniko/redisson/wiki/13.-Tools#131-redis-deployment-tool)
Feature - __Cluster management tool__. More info about it [here](https://github.com/mrniko/redisson/wiki/13.-Tools#132-cluster-management-tool)
Feature - Avro and Smile codecs added
__Breaking api change__ - all config classes moved to `org.redisson.config` package
__Breaking api change__ - all classes moved from `org.redisson.core` to `org.redisson.api` package
__Breaking api change__ - switched from `io.netty.util.concurrent.Future` to `org.redisson.api.RFuture` interface
Fixed - division by zero in WeightedRoundRobinBalancer (thanks to Shailender R Bathula)
####08-Aug-2016 - version 2.2.24 released ####08-Aug-2016 - version 2.2.24 released
Fixed - PubSub connection in cluster mode should be connected to node according slot derived from channel name Fixed - PubSub connection in cluster mode should be connected to node according slot derived from channel name
Fixed - `RLock.tryLock` could block forever under some conditions Fixed - `RLock.tryLock` could block forever under some conditions

@ -3,12 +3,9 @@ Redis based In-Memory Data Grid for Java. Redisson.
[![Maven Central](https://img.shields.io/maven-central/v/org.redisson/redisson.svg?style=flat-square)](https://maven-badges.herokuapp.com/maven-central/org.redisson/redisson/) [![Maven Central](https://img.shields.io/maven-central/v/org.redisson/redisson.svg?style=flat-square)](https://maven-badges.herokuapp.com/maven-central/org.redisson/redisson/)
Use familiar Java data structures with power of [Redis](http://redis.io). Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework.
Based on high-performance async and lock-free Java Redis client and [Netty 4](http://netty.io) framework.
Redis 2.8+ and JDK 1.6+ compatible. Redis 2.8+ and JDK 1.6+ compatible.
Please read [documentation](https://github.com/mrniko/redisson/wiki) for more details. Please read [documentation](https://github.com/mrniko/redisson/wiki) for more details.
Redisson [releases history](https://github.com/mrniko/redisson/blob/master/CHANGELOG.md). Redisson [releases history](https://github.com/mrniko/redisson/blob/master/CHANGELOG.md).
@ -37,43 +34,37 @@ Features
5. automatic sentinel servers discovery 5. automatic sentinel servers discovery
* Master with Slave servers mode * Master with Slave servers mode
* Single server mode * Single server mode
* Distributed implementation of `java.util.BitSet`
* Distributed implementation of `java.util.List`
* Distributed implementation of `java.util.Set` with TTL support for each entry
* Distributed implementation of `java.util.SortedSet`
* Distributed implementation of `java.util.Queue`
* Distributed implementation of `java.util.concurrent.BlockingQueue`
* Distributed implementation of `java.util.Deque`
* Distributed implementation of `java.util.concurrent.BlockingDeque`
* Distributed implementation of `java.util.Map` with TTL support for each entry
* Distributed implementation of `java.util.concurrent.ConcurrentMap` with TTL support for each entry
* Distributed implementation of reentrant `java.util.concurrent.locks.Lock` with TTL support
* Distributed implementation of reentrant `java.util.concurrent.locks.ReadWriteLock` with TTL support
* Distributed alternative to the `java.util.concurrent.atomic.AtomicLong`
* Distributed alternative to the `java.util.concurrent.CountDownLatch`
* Distributed alternative to the `java.util.concurrent.Semaphore`
* Distributed publish/subscribe messaging via `org.redisson.core.RTopic`
* Distributed HyperLogLog via `org.redisson.core.RHyperLogLog`
* Asynchronous interface for each object * Asynchronous interface for each object
* Asynchronous connection pool * Asynchronous connection pool
* Thread-safe implementation * Thread-safe implementation
* All commands executes in an atomic way
* Lua scripting * Lua scripting
* [Spring cache](https://github.com/mrniko/redisson/wiki/10.-additional-features/#104-spring-cache-integration) integration * [Distributed objects](https://github.com/mrniko/redisson/wiki/6.-Distributed-objects)
* Supports [Reactive Streams](http://www.reactive-streams.org) * [Distributed collections](https://github.com/mrniko/redisson/wiki/7.-Distributed-collections)
* Supports [Redis pipelining](http://redis.io/topics/pipelining) (command batches) * [Distributed locks and synchronizers](https://github.com/mrniko/redisson/wiki/8.-Distributed-locks-and-synchronizers)
* Supports [Remote services](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#91-remote-service) * [Distributed services](https://github.com/mrniko/redisson/wiki/9.-distributed-services)
* [Scheduler service](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#94-scheduled-executor-service)
* [Spring cache](https://github.com/mrniko/redisson/wiki/14.-Integration%20with%20frameworks/#141-spring-cache) integration
* [Hibernate](https://github.com/mrniko/redisson/wiki/14.-Integration%20with%20frameworks/#142-hibernate) integration
* [Reactive Streams](https://github.com/mrniko/redisson/wiki/3.-operations-execution#32-reactive-way)
* [Redis pipelining](https://github.com/mrniko/redisson/wiki/10.-additional-features#102-execution-batches-of-commands) (command batches)
* Supports Android platform * Supports Android platform
* Supports auto-reconnect * Supports auto-reconnect
* Supports failed to send command auto-retry * Supports failed to send command auto-retry
* Supports OSGi * Supports OSGi
* Supports many popular codecs ([Jackson JSON](https://github.com/FasterXML/jackson), [Avro](http://avro.apache.org/), [Smile](http://wiki.fasterxml.com/SmileFormatSpec), [CBOR](http://cbor.io/), [MsgPack](http://msgpack.org/), [Kryo](https://github.com/EsotericSoftware/kryo), [FST](https://github.com/RuedigerMoeller/fast-serialization), [LZ4](https://github.com/jpountz/lz4-java), [Snappy](https://github.com/xerial/snappy-java) and JDK Serialization) * Supports many popular codecs ([Jackson JSON](https://github.com/FasterXML/jackson), [Avro](http://avro.apache.org/), [Smile](http://wiki.fasterxml.com/SmileFormatSpec), [CBOR](http://cbor.io/), [MsgPack](http://msgpack.org/), [Kryo](https://github.com/EsotericSoftware/kryo), [FST](https://github.com/RuedigerMoeller/fast-serialization), [LZ4](https://github.com/jpountz/lz4-java), [Snappy](https://github.com/xerial/snappy-java) and JDK Serialization)
* With over 500 unit tests * With over 900 unit tests
Projects using Redisson Projects using Redisson
================================ ================================
[Setronica](http://setronica.com/), [Monits](http://monits.com/), [Brookhaven National Laboratory](http://bnl.gov/), [Netflix Dyno client] (https://github.com/Netflix/dyno), [武林Q传](http://www.nbrpg.com/), [Ocous](http://www.ocous.com/), [Invaluable](http://www.invaluable.com/), [Clover](https://www.clover.com/) , [Apache Karaf Decanter](https://karaf.apache.org/projects.html#decanter), [Atmosphere Framework](http://async-io.org/) [Setronica](http://setronica.com/), [Monits](http://monits.com/), [Brookhaven National Laboratory](http://bnl.gov/), [Netflix Dyno client] (https://github.com/Netflix/dyno), [武林Q传](http://www.nbrpg.com/), [Ocous](http://www.ocous.com/), [Invaluable](http://www.invaluable.com/), [Clover](https://www.clover.com/) , [Apache Karaf Decanter](https://karaf.apache.org/projects.html#decanter), [Atmosphere Framework](http://async-io.org/)
### Articles
[Java data structures powered by Redis. Introduction to Redisson. PDF](http://redisson.org/Redisson.pdf)
[Introducing Redisson Live Objects (Object Hash Mapping)](https://dzone.com/articles/introducing-redisson-live-object-object-hash-mappi)
[Java Remote Method Invocation with Redisson](https://dzone.com/articles/java-remote-method-invocation-with-redisson)
[Java Multimaps With Redis](https://dzone.com/articles/multimaps-with-redis)
### Maven ### Maven
Include the following to your dependency list: Include the following to your dependency list:
@ -81,12 +72,17 @@ Include the following to your dependency list:
<dependency> <dependency>
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>
<artifactId>redisson</artifactId> <artifactId>redisson</artifactId>
<version>2.2.24</version> <version>2.3.0</version>
</dependency> </dependency>
### Gradle ### Gradle
compile 'org.redisson:redisson:2.2.24' compile 'org.redisson:redisson:2.3.0'
### Downloads
[Redisson 2.3.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.3.0&e=jar)
[Redisson node 2.3.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.3.0&e=jar)
### Supported by ### Supported by

@ -3,7 +3,7 @@
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId> <artifactId>redisson-parent</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>2.3.1-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Redisson</name> <name>Redisson</name>

@ -0,0 +1,5 @@
## Redisson standalone node
Redisson offers ability to run as standalone node and participate in distributed computing. Such standalone nodes could be used to run [ExecutorService](./9.-distributed-services#93-executor-service), [ScheduledExecutorService](https://github.com/mrniko/redisson/wiki/9.-distributed-services#94-scheduled-executor-service) tasks or [RemoteService](./9.-distributed-services#91-remote-service) services. It's just a single jar and could be downloaded from [here](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.3.0&e=jar)
[Documentation](https://github.com/mrniko/redisson/wiki/12.-Standalone-node) about Redisson standalone node.

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId> <artifactId>redisson-parent</artifactId>
<version>0.9.1-SNAPSHOT</version> <version>2.3.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId> <artifactId>redisson-parent</artifactId>
<version>2.3.0</version> <version>2.3.1-SNAPSHOT</version>
<relativePath>../</relativePath> <relativePath>../</relativePath>
</parent> </parent>
@ -41,33 +41,33 @@
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId> <artifactId>netty-transport-native-epoll</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-common</artifactId> <artifactId>netty-common</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId> <artifactId>netty-codec</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId> <artifactId>netty-buffer</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId> <artifactId>netty-transport</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId> <artifactId>netty-handler</artifactId>
<version>4.0.40.Final</version> <version>4.0.41.Final</version>
</dependency> </dependency>
<dependency> <dependency>
@ -106,6 +106,12 @@
<version>1.7.12</version> <version>1.7.12</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.27</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>net.jpountz.lz4</groupId> <groupId>net.jpountz.lz4</groupId>

@ -33,6 +33,7 @@ import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor; import org.redisson.command.CommandExecutor;
import org.redisson.executor.RemotePromise; import org.redisson.executor.RemotePromise;
import org.redisson.misc.RPromise;
import org.redisson.remote.RRemoteServiceResponse; import org.redisson.remote.RRemoteServiceResponse;
import org.redisson.remote.RemoteServiceAck; import org.redisson.remote.RemoteServiceAck;
import org.redisson.remote.RemoteServiceAckTimeoutException; import org.redisson.remote.RemoteServiceAckTimeoutException;
@ -47,7 +48,6 @@ import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.ThreadLocalRandom; import io.netty.util.internal.ThreadLocalRandom;
/** /**
@ -200,7 +200,7 @@ public abstract class BaseRemoteService {
} }
if (optionsCopy.isAckExpected()) { if (optionsCopy.isAckExpected()) {
Future<Boolean> future = commandExecutor.evalWriteAsync(responseName, LongCodec.INSTANCE, RFuture<Boolean> future = commandExecutor.evalWriteAsync(responseName, LongCodec.INSTANCE,
RedisCommands.EVAL_BOOLEAN, RedisCommands.EVAL_BOOLEAN,
"if redis.call('setnx', KEYS[1], 1) == 1 then " "if redis.call('setnx', KEYS[1], 1) == 1 then "
+ "redis.call('pexpire', KEYS[1], ARGV[2]);" + "redis.call('pexpire', KEYS[1], ARGV[2]);"
@ -250,7 +250,7 @@ public abstract class BaseRemoteService {
result.setRequestId(requestId); result.setRequestId(requestId);
Future<Boolean> addFuture = addAsync(requestQueue, request, result); RFuture<Boolean> addFuture = addAsync(requestQueue, request, result);
addFuture.addListener(new FutureListener<Boolean>() { addFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
@ -262,7 +262,7 @@ public abstract class BaseRemoteService {
if (optionsCopy.isAckExpected()) { if (optionsCopy.isAckExpected()) {
final RBlockingQueue<RemoteServiceAck> responseQueue = redisson.getBlockingQueue(responseName, getCodec()); final RBlockingQueue<RemoteServiceAck> responseQueue = redisson.getBlockingQueue(responseName, getCodec());
Future<RemoteServiceAck> ackFuture = responseQueue.pollAsync(optionsCopy.getAckTimeoutInMillis(), TimeUnit.MILLISECONDS); RFuture<RemoteServiceAck> ackFuture = responseQueue.pollAsync(optionsCopy.getAckTimeoutInMillis(), TimeUnit.MILLISECONDS);
ackFuture.addListener(new FutureListener<RemoteServiceAck>() { ackFuture.addListener(new FutureListener<RemoteServiceAck>() {
@Override @Override
public void operationComplete(Future<RemoteServiceAck> future) throws Exception { public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
@ -273,7 +273,7 @@ public abstract class BaseRemoteService {
RemoteServiceAck ack = future.getNow(); RemoteServiceAck ack = future.getNow();
if (ack == null) { if (ack == null) {
Future<RemoteServiceAck> ackFutureAttempt = RFuture<RemoteServiceAck> ackFutureAttempt =
tryPollAckAgainAsync(optionsCopy, responseQueue, ackName); tryPollAckAgainAsync(optionsCopy, responseQueue, ackName);
ackFutureAttempt.addListener(new FutureListener<RemoteServiceAck>() { ackFutureAttempt.addListener(new FutureListener<RemoteServiceAck>() {
@ -318,7 +318,7 @@ public abstract class BaseRemoteService {
private void awaitResultAsync(final RemoteInvocationOptions optionsCopy, final RemotePromise<Object> result, private void awaitResultAsync(final RemoteInvocationOptions optionsCopy, final RemotePromise<Object> result,
final RemoteServiceRequest request, final String responseName, final String ackName) { final RemoteServiceRequest request, final String responseName, final String ackName) {
Future<Boolean> deleteFuture = redisson.getBucket(ackName).deleteAsync(); RFuture<Boolean> deleteFuture = redisson.getBucket(ackName).deleteAsync();
deleteFuture.addListener(new FutureListener<Boolean>() { deleteFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -340,7 +340,7 @@ public abstract class BaseRemoteService {
} }
RBlockingQueue<RRemoteServiceResponse> responseQueue = redisson.getBlockingQueue(responseName, getCodec()); RBlockingQueue<RRemoteServiceResponse> responseQueue = redisson.getBlockingQueue(responseName, getCodec());
Future<RRemoteServiceResponse> responseFuture = responseQueue RFuture<RRemoteServiceResponse> responseFuture = responseQueue
.pollAsync(optionsCopy.getExecutionTimeoutInMillis(), TimeUnit.MILLISECONDS); .pollAsync(optionsCopy.getExecutionTimeoutInMillis(), TimeUnit.MILLISECONDS);
responseFuture.addListener(new FutureListener<RRemoteServiceResponse>() { responseFuture.addListener(new FutureListener<RRemoteServiceResponse>() {
@ -448,7 +448,7 @@ public abstract class BaseRemoteService {
private RemoteServiceAck tryPollAckAgain(RemoteInvocationOptions optionsCopy, private RemoteServiceAck tryPollAckAgain(RemoteInvocationOptions optionsCopy,
RBlockingQueue<? extends RRemoteServiceResponse> responseQueue, String ackName) RBlockingQueue<? extends RRemoteServiceResponse> responseQueue, String ackName)
throws InterruptedException { throws InterruptedException {
Future<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(ackName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, RFuture<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(ackName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if redis.call('setnx', KEYS[1], 1) == 1 then " "if redis.call('setnx', KEYS[1], 1) == 1 then "
+ "redis.call('pexpire', KEYS[1], ARGV[1]);" + "redis.call('pexpire', KEYS[1], ARGV[1]);"
+ "return 0;" + "return 0;"
@ -464,11 +464,11 @@ public abstract class BaseRemoteService {
return null; return null;
} }
private Future<RemoteServiceAck> tryPollAckAgainAsync(RemoteInvocationOptions optionsCopy, private RFuture<RemoteServiceAck> tryPollAckAgainAsync(RemoteInvocationOptions optionsCopy,
final RBlockingQueue<RemoteServiceAck> responseQueue, String ackName) final RBlockingQueue<RemoteServiceAck> responseQueue, String ackName)
throws InterruptedException { throws InterruptedException {
final Promise<RemoteServiceAck> promise = commandExecutor.getConnectionManager().newPromise(); final RPromise<RemoteServiceAck> promise = commandExecutor.getConnectionManager().newPromise();
Future<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(ackName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, RFuture<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(ackName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if redis.call('setnx', KEYS[1], 1) == 1 then " "if redis.call('setnx', KEYS[1], 1) == 1 then "
+ "redis.call('pexpire', KEYS[1], ARGV[1]);" + "redis.call('pexpire', KEYS[1], ARGV[1]);"
+ "return 0;" + "return 0;"
@ -485,7 +485,7 @@ public abstract class BaseRemoteService {
} }
if (future.getNow()) { if (future.getNow()) {
Future<RemoteServiceAck> pollFuture = responseQueue.pollAsync(); RFuture<RemoteServiceAck> pollFuture = responseQueue.pollAsync();
pollFuture.addListener(new FutureListener<RemoteServiceAck>() { pollFuture.addListener(new FutureListener<RemoteServiceAck>() {
@Override @Override
public void operationComplete(Future<RemoteServiceAck> future) throws Exception { public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
@ -512,9 +512,9 @@ public abstract class BaseRemoteService {
return ByteBufUtil.hexDump(id); return ByteBufUtil.hexDump(id);
} }
protected Future<Boolean> addAsync(RBlockingQueue<RemoteServiceRequest> requestQueue, RemoteServiceRequest request, protected RFuture<Boolean> addAsync(RBlockingQueue<RemoteServiceRequest> requestQueue, RemoteServiceRequest request,
RemotePromise<Object> result) { RemotePromise<Object> result) {
Future<Boolean> future = requestQueue.addAsync(request); RFuture<Boolean> future = requestQueue.addAsync(request);
result.setAddFuture(future); result.setAddFuture(future);
return future; return future;
} }

@ -21,6 +21,7 @@ import java.util.LinkedList;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
import org.redisson.client.codec.LongCodec; import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
@ -70,7 +71,7 @@ public class EvictionScheduler {
@Override @Override
public void run() { public void run() {
Future<Integer> future = cleanupExpiredEntires(name, timeoutSetName, maxIdleSetName, keysLimit, multimap); RFuture<Integer> future = cleanupExpiredEntires(name, timeoutSetName, maxIdleSetName, keysLimit, multimap);
future.addListener(new FutureListener<Integer>() { future.addListener(new FutureListener<Integer>() {
@Override @Override
@ -169,7 +170,7 @@ public class EvictionScheduler {
return; return;
} }
Future<Integer> future = cleanupExpiredEntires(name, timeoutSetName, null, valuesAmountToClean, false); RFuture<Integer> future = cleanupExpiredEntires(name, timeoutSetName, null, valuesAmountToClean, false);
future.addListener(new FutureListener<Integer>() { future.addListener(new FutureListener<Integer>() {
@Override @Override
@ -189,7 +190,7 @@ public class EvictionScheduler {
}); });
} }
private Future<Integer> cleanupExpiredEntires(String name, String timeoutSetName, String maxIdleSetName, int keysLimit, boolean multimap) { private RFuture<Integer> cleanupExpiredEntires(String name, String timeoutSetName, String maxIdleSetName, int keysLimit, boolean multimap) {
if (multimap) { if (multimap) {
return executor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_INTEGER, return executor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_INTEGER,
"local expiredKeys = redis.call('zrangebyscore', KEYS[2], 0, ARGV[1], 'limit', 0, ARGV[2]); " "local expiredKeys = redis.call('zrangebyscore', KEYS[2], 0, ARGV[1], 'limit', 0, ARGV[2]); "

@ -15,7 +15,7 @@
*/ */
package org.redisson; package org.redisson;
import io.netty.util.concurrent.Promise; import org.redisson.misc.RPromise;
public interface PubSubEntry<E> { public interface PubSubEntry<E> {
@ -23,6 +23,6 @@ public interface PubSubEntry<E> {
int release(); int release();
Promise<E> getPromise(); RPromise<E> getPromise();
} }

@ -26,15 +26,16 @@ import java.util.concurrent.CountDownLatch;
import org.redisson.api.Node; import org.redisson.api.Node;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.api.NodesGroup; import org.redisson.api.NodesGroup;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionListener; import org.redisson.connection.ConnectionListener;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.RedisClientEntry; import org.redisson.connection.RedisClientEntry;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
public class RedisNodes<N extends Node> implements NodesGroup<N> { public class RedisNodes<N extends Node> implements NodesGroup<N> {
@ -65,21 +66,21 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
@Override @Override
public boolean pingAll() { public boolean pingAll() {
List<RedisClientEntry> clients = new ArrayList<RedisClientEntry>(connectionManager.getClients()); List<RedisClientEntry> clients = new ArrayList<RedisClientEntry>(connectionManager.getClients());
final Map<RedisConnection, Future<String>> result = new ConcurrentHashMap<RedisConnection, Future<String>>(clients.size()); final Map<RedisConnection, RFuture<String>> result = new ConcurrentHashMap<RedisConnection, RFuture<String>>(clients.size());
final CountDownLatch latch = new CountDownLatch(clients.size()); final CountDownLatch latch = new CountDownLatch(clients.size());
for (RedisClientEntry entry : clients) { for (RedisClientEntry entry : clients) {
Future<RedisConnection> f = entry.getClient().connectAsync(); RFuture<RedisConnection> f = entry.getClient().connectAsync();
f.addListener(new FutureListener<RedisConnection>() { f.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
final RedisConnection c = future.getNow(); final RedisConnection c = future.getNow();
Promise<RedisConnection> connectionFuture = connectionManager.newPromise(); RPromise<RedisConnection> connectionFuture = connectionManager.newPromise();
connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig()); connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig());
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
Future<String> r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING); RFuture<String> r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING);
result.put(c, r); result.put(c, r);
latch.countDown(); latch.countDown();
} }
@ -99,7 +100,7 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
} }
if (System.currentTimeMillis() - time >= connectionManager.getConfig().getConnectTimeout()) { if (System.currentTimeMillis() - time >= connectionManager.getConfig().getConnectTimeout()) {
for (Entry<RedisConnection, Future<String>> entry : result.entrySet()) { for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
entry.getKey().closeAsync(); entry.getKey().closeAsync();
} }
return false; return false;
@ -107,8 +108,8 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
time = System.currentTimeMillis(); time = System.currentTimeMillis();
boolean res = true; boolean res = true;
for (Entry<RedisConnection, Future<String>> entry : result.entrySet()) { for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
Future<String> f = entry.getValue(); RFuture<String> f = entry.getValue();
f.awaitUninterruptibly(); f.awaitUninterruptibly();
if (!"PONG".equals(f.getNow())) { if (!"PONG".equals(f.getNow())) {
res = false; res = false;

@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.redisson.api.ClusterNodesGroup; import org.redisson.api.ClusterNodesGroup;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.Node; import org.redisson.api.Node;
import org.redisson.api.NodesGroup; import org.redisson.api.NodesGroup;
import org.redisson.api.RAtomicDouble; import org.redisson.api.RAtomicDouble;
@ -42,6 +43,7 @@ import org.redisson.api.RList;
import org.redisson.api.RListMultimap; import org.redisson.api.RListMultimap;
import org.redisson.api.RListMultimapCache; import org.redisson.api.RListMultimapCache;
import org.redisson.api.RLiveObjectService; import org.redisson.api.RLiveObjectService;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RMap; import org.redisson.api.RMap;
import org.redisson.api.RMapCache; import org.redisson.api.RMapCache;
@ -222,6 +224,16 @@ public class Redisson implements RedissonClient {
return new RedissonListMultimap<K, V>(codec, commandExecutor, name); return new RedissonListMultimap<K, V>(codec, commandExecutor, name);
} }
@Override
public <K, V> RLocalCachedMap<K, V> getLocalCachedMap(String name, LocalCachedMapOptions options) {
return new RedissonLocalCachedMap<K, V>(this, commandExecutor, name, options);
}
@Override
public <K, V> RLocalCachedMap<K, V> getLocalCachedMap(String name, Codec codec, LocalCachedMapOptions options) {
return new RedissonLocalCachedMap<K, V>(this, codec, commandExecutor, name, options);
}
@Override @Override
public <K, V> RMap<K, V> getMap(String name) { public <K, V> RMap<K, V> getMap(String name) {
return new RedissonMap<K, V>(commandExecutor, name); return new RedissonMap<K, V>(commandExecutor, name);

@ -45,8 +45,6 @@ import org.redisson.client.codec.Codec;
import org.redisson.command.CommandBatchService; import org.redisson.command.CommandBatchService;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import io.netty.util.concurrent.Future;
/** /**
* *
* *

@ -93,7 +93,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/ */
@Override @Override
public V take() throws InterruptedException { public V take() throws InterruptedException {
Future<V> res = takeAsync(); RFuture<V> res = takeAsync();
return res.await().getNow(); return res.await().getNow();
} }
@ -108,7 +108,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/ */
@Override @Override
public V poll(long timeout, TimeUnit unit) throws InterruptedException { public V poll(long timeout, TimeUnit unit) throws InterruptedException {
Future<V> res = pollAsync(timeout, unit); RFuture<V> res = pollAsync(timeout, unit);
return res.await().getNow(); return res.await().getNow();
} }
@ -118,7 +118,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/ */
@Override @Override
public V pollFromAny(long timeout, TimeUnit unit, String ... queueNames) throws InterruptedException { public V pollFromAny(long timeout, TimeUnit unit, String ... queueNames) throws InterruptedException {
Future<V> res = pollFromAnyAsync(timeout, unit, queueNames); RFuture<V> res = pollFromAnyAsync(timeout, unit, queueNames);
return res.await().getNow(); return res.await().getNow();
} }
@ -144,7 +144,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
@Override @Override
public V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException { public V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException {
Future<V> res = pollLastAndOfferFirstToAsync(queueName, timeout, unit); RFuture<V> res = pollLastAndOfferFirstToAsync(queueName, timeout, unit);
return res.await().getNow(); return res.await().getNow();
} }

@ -178,9 +178,9 @@ public class RedissonBloomFilter<T> extends RedissonExpirable implements RBloomF
@Override @Override
public int count() { public int count() {
CommandBatchService executorService = new CommandBatchService(commandExecutor.getConnectionManager()); CommandBatchService executorService = new CommandBatchService(commandExecutor.getConnectionManager());
Future<Map<String, String>> configFuture = executorService.readAsync(getConfigName(), StringCodec.INSTANCE, RFuture<Map<String, String>> configFuture = executorService.readAsync(getConfigName(), StringCodec.INSTANCE,
new RedisCommand<Map<Object, Object>>("HGETALL", new ObjectMapReplayDecoder()), getConfigName()); new RedisCommand<Map<Object, Object>>("HGETALL", new ObjectMapReplayDecoder()), getConfigName());
Future<Long> cardinalityFuture = executorService.readAsync(getName(), codec, RedisCommands.BITCOUNT, getName()); RFuture<Long> cardinalityFuture = executorService.readAsync(getName(), codec, RedisCommands.BITCOUNT, getName());
executorService.execute(); executorService.execute();
readConfig(configFuture.getNow()); readConfig(configFuture.getNow());
@ -194,7 +194,7 @@ public class RedissonBloomFilter<T> extends RedissonExpirable implements RBloomF
} }
private void readConfig() { private void readConfig() {
Future<Map<String, String>> future = commandExecutor.readAsync(getConfigName(), StringCodec.INSTANCE, RFuture<Map<String, String>> future = commandExecutor.readAsync(getConfigName(), StringCodec.INSTANCE,
new RedisCommand<Map<Object, Object>>("HGETALL", new ObjectMapReplayDecoder()), getConfigName()); new RedisCommand<Map<Object, Object>>("HGETALL", new ObjectMapReplayDecoder()), getConfigName());
Map<String, String> config = commandExecutor.get(future); Map<String, String> config = commandExecutor.get(future);

@ -26,6 +26,7 @@ import java.util.Map.Entry;
import org.redisson.api.RBucket; import org.redisson.api.RBucket;
import org.redisson.api.RBuckets; import org.redisson.api.RBuckets;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.codec.DelegateDecoderCodec; import org.redisson.client.codec.DelegateDecoderCodec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
@ -34,8 +35,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor; import org.redisson.command.CommandExecutor;
import org.redisson.connection.decoder.MapGetAllDecoder; import org.redisson.connection.decoder.MapGetAllDecoder;
import io.netty.util.concurrent.Future;
public class RedissonBuckets implements RBuckets { public class RedissonBuckets implements RBuckets {
private final Codec codec; private final Codec codec;
@ -73,7 +72,7 @@ public class RedissonBuckets implements RBuckets {
} }
RedisCommand<Map<Object, Object>> command = new RedisCommand<Map<Object, Object>>("MGET", new MapGetAllDecoder(Arrays.<Object>asList(keys), 0), ValueType.OBJECTS); RedisCommand<Map<Object, Object>> command = new RedisCommand<Map<Object, Object>>("MGET", new MapGetAllDecoder(Arrays.<Object>asList(keys), 0), ValueType.OBJECTS);
Future<Map<String, V>> future = commandExecutor.readAsync(keys[0], new DelegateDecoderCodec(codec), command, keys); RFuture<Map<String, V>> future = commandExecutor.readAsync(keys[0], new DelegateDecoderCodec(codec), command, keys);
return commandExecutor.get(future); return commandExecutor.get(future);
} }

@ -26,8 +26,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
import org.redisson.pubsub.CountDownLatchPubSub; import org.redisson.pubsub.CountDownLatchPubSub;
import io.netty.util.concurrent.Future;
/** /**
* Distributed alternative to the {@link java.util.concurrent.CountDownLatch} * Distributed alternative to the {@link java.util.concurrent.CountDownLatch}
* *
@ -52,7 +50,7 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
} }
public void await() throws InterruptedException { public void await() throws InterruptedException {
Future<RedissonCountDownLatchEntry> promise = subscribe(); RFuture<RedissonCountDownLatchEntry> promise = subscribe();
try { try {
get(promise); get(promise);
@ -70,7 +68,7 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
@Override @Override
public boolean await(long time, TimeUnit unit) throws InterruptedException { public boolean await(long time, TimeUnit unit) throws InterruptedException {
Future<RedissonCountDownLatchEntry> promise = subscribe(); RFuture<RedissonCountDownLatchEntry> promise = subscribe();
try { try {
if (!await(promise, time, unit)) { if (!await(promise, time, unit)) {
return false; return false;
@ -102,11 +100,11 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
return PUBSUB.getEntry(getEntryName()); return PUBSUB.getEntry(getEntryName());
} }
private Future<RedissonCountDownLatchEntry> subscribe() { private RFuture<RedissonCountDownLatchEntry> subscribe() {
return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager()); return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
} }
private void unsubscribe(Future<RedissonCountDownLatchEntry> future) { private void unsubscribe(RFuture<RedissonCountDownLatchEntry> future) {
PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager()); PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
} }

@ -15,18 +15,17 @@
*/ */
package org.redisson; package org.redisson;
import org.redisson.misc.RPromise;
import org.redisson.misc.ReclosableLatch; import org.redisson.misc.ReclosableLatch;
import io.netty.util.concurrent.Promise;
public class RedissonCountDownLatchEntry implements PubSubEntry<RedissonCountDownLatchEntry> { public class RedissonCountDownLatchEntry implements PubSubEntry<RedissonCountDownLatchEntry> {
private int counter; private int counter;
private final ReclosableLatch latch; private final ReclosableLatch latch;
private final Promise<RedissonCountDownLatchEntry> promise; private final RPromise<RedissonCountDownLatchEntry> promise;
public RedissonCountDownLatchEntry(Promise<RedissonCountDownLatchEntry> promise) { public RedissonCountDownLatchEntry(RPromise<RedissonCountDownLatchEntry> promise) {
super(); super();
this.latch = new ReclosableLatch(); this.latch = new ReclosableLatch();
this.promise = promise; this.promise = promise;
@ -40,7 +39,7 @@ public class RedissonCountDownLatchEntry implements PubSubEntry<RedissonCountDow
return --counter; return --counter;
} }
public Promise<RedissonCountDownLatchEntry> getPromise() { public RPromise<RedissonCountDownLatchEntry> getPromise() {
return promise; return promise;
} }

@ -19,6 +19,7 @@ import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -67,7 +68,6 @@ import org.slf4j.LoggerFactory;
import io.netty.util.Timeout; import io.netty.util.Timeout;
import io.netty.util.TimerTask; import io.netty.util.TimerTask;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
/** /**
@ -439,10 +439,14 @@ public class RedissonExecutorService implements RScheduledExecutorService {
if (task.getClass().isAnonymousClass()) { if (task.getClass().isAnonymousClass()) {
throw new IllegalArgumentException("Task can't be created using anonymous class"); throw new IllegalArgumentException("Task can't be created using anonymous class");
} }
if (task.getClass().isMemberClass()
&& !Modifier.isStatic(task.getClass().getModifiers())) {
throw new IllegalArgumentException("Task class is an inner class and it should be static");
}
} }
private <T> void execute(RemotePromise<T> promise) { private <T> void execute(RemotePromise<T> promise) {
io.netty.util.concurrent.Future<Boolean> addFuture = promise.getAddFuture(); RFuture<Boolean> addFuture = promise.getAddFuture();
addFuture.syncUninterruptibly(); addFuture.syncUninterruptibly();
Boolean res = addFuture.getNow(); Boolean res = addFuture.getNow();
if (!res) { if (!res) {
@ -451,9 +455,9 @@ public class RedissonExecutorService implements RScheduledExecutorService {
} }
@Override @Override
public <T> Future<T> submit(Runnable task, final T result) { public <T> RFuture<T> submit(Runnable task, final T result) {
final Promise<T> resultFuture = connectionManager.newPromise(); final RPromise<T> resultFuture = connectionManager.newPromise();
io.netty.util.concurrent.Future<Object> future = (io.netty.util.concurrent.Future<Object>) submit(task); RFuture<Object> future = (RFuture<Object>) submit(task);
future.addListener(new FutureListener<Object>() { future.addListener(new FutureListener<Object>() {
@Override @Override
public void operationComplete(io.netty.util.concurrent.Future<Object> future) throws Exception { public void operationComplete(io.netty.util.concurrent.Future<Object> future) throws Exception {
@ -487,7 +491,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
@Override @Override
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) { public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAsync(task, delay, unit); RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAsync(task, delay, unit);
execute((RemotePromise<?>)future.getInnerFuture()); execute((RemotePromise<?>)future.getInnerPromise());
return future; return future;
} }
@ -505,7 +509,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
@Override @Override
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) { public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
RedissonScheduledFuture<V> future = (RedissonScheduledFuture<V>) scheduleAsync(task, delay, unit); RedissonScheduledFuture<V> future = (RedissonScheduledFuture<V>) scheduleAsync(task, delay, unit);
execute((RemotePromise<V>)future.getInnerFuture()); execute((RemotePromise<V>)future.getInnerPromise());
return future; return future;
} }
@ -523,7 +527,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
@Override @Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) { public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAtFixedRateAsync(task, initialDelay, period, unit); RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAtFixedRateAsync(task, initialDelay, period, unit);
execute((RemotePromise<?>)future.getInnerFuture()); execute((RemotePromise<?>)future.getInnerPromise());
return future; return future;
} }
@ -541,7 +545,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
@Override @Override
public RScheduledFuture<?> schedule(Runnable task, CronSchedule cronSchedule) { public RScheduledFuture<?> schedule(Runnable task, CronSchedule cronSchedule) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAsync(task, cronSchedule); RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAsync(task, cronSchedule);
execute((RemotePromise<?>)future.getInnerFuture()); execute((RemotePromise<?>)future.getInnerPromise());
return future; return future;
} }
@ -564,7 +568,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
@Override @Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) { public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleWithFixedDelayAsync(task, initialDelay, delay, unit); RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleWithFixedDelayAsync(task, initialDelay, delay, unit);
execute((RemotePromise<?>)future.getInnerFuture()); execute((RemotePromise<?>)future.getInnerPromise());
return future; return future;
} }
@ -661,7 +665,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
} }
}; };
for (Future<T> future : futures) { for (Future<T> future : futures) {
io.netty.util.concurrent.Future<T> f = (io.netty.util.concurrent.Future<T>) future; RFuture<T> f = (RFuture<T>) future;
f.addListener(listener); f.addListener(listener);
} }
@ -672,7 +676,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
} }
for (Future<T> future : futures) { for (Future<T> future : futures) {
io.netty.util.concurrent.Future<T> f = (io.netty.util.concurrent.Future<T>) future; RFuture<T> f = (RFuture<T>) future;
f.removeListener(listener); f.removeListener(listener);
} }
@ -760,7 +764,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
if (millis <= 0) { if (millis <= 0) {
int remainFutures = tasks.size() - futures.size(); int remainFutures = tasks.size() - futures.size();
for (int i = 0; i < remainFutures; i++) { for (int i = 0; i < remainFutures; i++) {
Promise<T> cancelledFuture = connectionManager.newPromise(); RPromise<T> cancelledFuture = connectionManager.newPromise();
cancelledFuture.cancel(true); cancelledFuture.cancel(true);
futures.add(cancelledFuture); futures.add(cancelledFuture);

@ -28,8 +28,6 @@ import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.command.CommandExecutor; import org.redisson.command.CommandExecutor;
import org.redisson.pubsub.LockPubSub; import org.redisson.pubsub.LockPubSub;
import io.netty.util.concurrent.Future;
/** /**
* Distributed implementation of {@link java.util.concurrent.locks.Lock} * Distributed implementation of {@link java.util.concurrent.locks.Lock}
* Implements reentrant lock.<br> * Implements reentrant lock.<br>
@ -63,13 +61,13 @@ public class RedissonFairLock extends RedissonLock implements RLock {
} }
@Override @Override
protected Future<RedissonLockEntry> subscribe(long threadId) { protected RFuture<RedissonLockEntry> subscribe(long threadId) {
return PUBSUB.subscribe(getEntryName() + ":" + threadId, return PUBSUB.subscribe(getEntryName() + ":" + threadId,
getChannelName() + ":" + getLockName(threadId), commandExecutor.getConnectionManager()); getChannelName() + ":" + getLockName(threadId), commandExecutor.getConnectionManager());
} }
@Override @Override
protected void unsubscribe(Future<RedissonLockEntry> future, long threadId) { protected void unsubscribe(RFuture<RedissonLockEntry> future, long threadId) {
PUBSUB.unsubscribe(future.getNow(), getEntryName() + ":" + threadId, PUBSUB.unsubscribe(future.getNow(), getEntryName() + ":" + threadId,
getChannelName() + ":" + getLockName(threadId), commandExecutor.getConnectionManager()); getChannelName() + ":" + getLockName(threadId), commandExecutor.getConnectionManager());
} }

@ -43,7 +43,6 @@ import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
public class RedissonKeys implements RKeys { public class RedissonKeys implements RKeys {
@ -255,7 +254,7 @@ public class RedissonKeys implements RKeys {
executorService.writeAsync(entry.getKey(), null, RedisCommands.DEL, key); executorService.writeAsync(entry.getKey(), null, RedisCommands.DEL, key);
} }
Future<List<?>> future = executorService.executeAsync(); RFuture<List<?>> future = executorService.executeAsync();
future.addListener(listener); future.addListener(listener);
} }
@ -303,7 +302,7 @@ public class RedissonKeys implements RKeys {
return commandExecutor.writeAllAsync(RedisCommands.FLUSHALL); return commandExecutor.writeAllAsync(RedisCommands.FLUSHALL);
} }
private void checkExecution(final Promise<Long> result, final AtomicReference<Throwable> failed, private void checkExecution(final RPromise<Long> result, final AtomicReference<Throwable> failed,
final AtomicLong count, final AtomicLong executed) { final AtomicLong count, final AtomicLong executed) {
if (executed.decrementAndGet() == 0) { if (executed.decrementAndGet() == 0) {
if (failed.get() != null) { if (failed.get() != null) {

@ -339,27 +339,34 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
@Override @Override
public V remove(int index) { public V remove(int index) {
return remove((long) index);
}
public V remove(long index) {
return get(removeAsync(index));
}
public RFuture<V> removeAsync(long index) {
if (index == 0) { if (index == 0) {
RFuture<V> f = commandExecutor.writeAsync(getName(), codec, LPOP, getName()); return commandExecutor.writeAsync(getName(), codec, LPOP, getName());
return get(f);
} }
RFuture<V> f = commandExecutor.evalWriteAsync(getName(), codec, EVAL_OBJECT, return commandExecutor.evalWriteAsync(getName(), codec, EVAL_OBJECT,
"local v = redis.call('lindex', KEYS[1], ARGV[1]); " + "local v = redis.call('lindex', KEYS[1], ARGV[1]); " +
"redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" + "redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" +
"redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');" + "redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');" +
"return v", "return v",
Collections.<Object>singletonList(getName()), index); Collections.<Object>singletonList(getName()), index);
return get(f);
} }
@Override @Override
public void fastRemove(int index) { public void fastRemove(int index) {
get(fastRemoveAsync(index)); get(fastRemoveAsync(index));
} }
@Override @Override
public RFuture<Void> fastRemoveAsync(int index) { public RFuture<Void> fastRemoveAsync(long index) {
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID, return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID,
"redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" + "redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" +
"redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');", "redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');",
@ -376,7 +383,7 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
return indexOfAsync(o, new BooleanNumberReplayConvertor(-1L)); return indexOfAsync(o, new BooleanNumberReplayConvertor(-1L));
} }
private <R> RFuture<R> indexOfAsync(Object o, Convertor<R> convertor) { public <R> RFuture<R> indexOfAsync(Object o, Convertor<R> convertor) {
return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4), return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4),
"local key = KEYS[1] " + "local key = KEYS[1] " +
"local obj = ARGV[1] " + "local obj = ARGV[1] " +
@ -415,13 +422,27 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
Collections.<Object>singletonList(getName()), o); Collections.<Object>singletonList(getName()), o);
} }
public <R> RFuture<R> lastIndexOfAsync(Object o, Convertor<R> convertor) {
return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4),
"local key = KEYS[1] " +
"local obj = ARGV[1] " +
"local items = redis.call('lrange', key, 0, -1) " +
"for i = #items, 1, -1 do " +
"if items[i] == obj then " +
"return i - 1 " +
"end " +
"end " +
"return -1",
Collections.<Object>singletonList(getName()), o);
}
@Override @Override
public void trim(int fromIndex, int toIndex) { public void trim(int fromIndex, int toIndex) {
get(trimAsync(fromIndex, toIndex)); get(trimAsync(fromIndex, toIndex));
} }
@Override @Override
public RFuture<Void> trimAsync(int fromIndex, int toIndex) { public RFuture<Void> trimAsync(long fromIndex, long toIndex) {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.LTRIM, getName(), fromIndex, toIndex); return commandExecutor.writeAsync(getName(), codec, RedisCommands.LTRIM, getName(), fromIndex, toIndex);
} }

@ -432,27 +432,30 @@ public class RedissonListMultimapValues<V> extends RedissonExpirable implements
@Override @Override
public V remove(int index) { public V remove(int index) {
return get(removeAsync(index));
}
@Override
public RFuture<V> removeAsync(long index) {
if (index == 0) { if (index == 0) {
RFuture<V> f = commandExecutor.writeAsync(getName(), codec, LPOP, getName()); return commandExecutor.writeAsync(getName(), codec, LPOP, getName());
return get(f);
} }
RFuture<V> f = commandExecutor.evalWriteAsync(getName(), codec, EVAL_OBJECT, return commandExecutor.evalWriteAsync(getName(), codec, EVAL_OBJECT,
"local v = redis.call('lindex', KEYS[1], ARGV[1]); " + "local v = redis.call('lindex', KEYS[1], ARGV[1]); " +
"redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" + "redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" +
"redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');" + "redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');" +
"return v", "return v",
Collections.<Object>singletonList(getName()), index); Collections.<Object>singletonList(getName()), index);
return get(f);
} }
@Override @Override
public void fastRemove(int index) { public void fastRemove(int index) {
get(fastRemoveAsync(index)); get(fastRemoveAsync((long)index));
} }
@Override @Override
public RFuture<Void> fastRemoveAsync(int index) { public RFuture<Void> fastRemoveAsync(long index) {
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID, return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID,
"redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" + "redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" +
"redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');", "redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');",
@ -528,7 +531,7 @@ public class RedissonListMultimapValues<V> extends RedissonExpirable implements
} }
@Override @Override
public RFuture<Void> trimAsync(int fromIndex, int toIndex) { public RFuture<Void> trimAsync(long fromIndex, long toIndex) {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.LTRIM, getName(), fromIndex, toIndex); return commandExecutor.writeAsync(getName(), codec, RedisCommands.LTRIM, getName(), fromIndex, toIndex);
} }

@ -0,0 +1,690 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.LocalCachedMapOptions.EvictionPolicy;
import org.redisson.api.RFuture;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RMap;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.Cache;
import org.redisson.misc.Hash;
import org.redisson.misc.LFUCacheMap;
import org.redisson.misc.LRUCacheMap;
import org.redisson.misc.NoneCacheMap;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
*/
public class RedissonLocalCachedMap<K, V> extends RedissonExpirable implements RLocalCachedMap<K, V> {
public static class LocalCachedMapClear {
}
public static class LocalCachedMapInvalidate {
private byte[] keyHash;
public LocalCachedMapInvalidate() {
}
public LocalCachedMapInvalidate(byte[] keyHash) {
super();
this.keyHash = keyHash;
}
public byte[] getKeyHash() {
return keyHash;
}
}
public static class CacheKey {
private final byte[] keyHash;
public CacheKey(byte[] keyHash) {
super();
this.keyHash = keyHash;
}
public byte[] getKeyHash() {
return keyHash;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(keyHash);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheKey other = (CacheKey) obj;
if (!Arrays.equals(keyHash, other.keyHash))
return false;
return true;
}
@Override
public String toString() {
return "CacheKey [keyHash=" + Arrays.toString(keyHash) + "]";
}
}
public static class CacheValue {
private final Object key;
private final Object value;
public CacheValue(Object key, Object value) {
super();
this.key = key;
this.value = value;
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheValue other = (CacheValue) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
@Override
public String toString() {
return "CacheValue [key=" + key + ", value=" + value + "]";
}
}
private static final RedisCommand<Object> EVAL_PUT = new RedisCommand<Object>("EVAL", -1, ValueType.OBJECT, ValueType.MAP_VALUE);
private static final RedisCommand<Object> EVAL_REMOVE = new RedisCommand<Object>("EVAL", -1, ValueType.OBJECT, ValueType.MAP_VALUE);
private RTopic<Object> invalidationTopic;
private RMap<K, V> map;
private Cache<CacheKey, CacheValue> cache;
private int invalidateEntryOnChange;
protected RedissonLocalCachedMap(RedissonClient redisson, CommandAsyncExecutor commandExecutor, String name, LocalCachedMapOptions options) {
super(commandExecutor, name);
init(redisson, name, options);
}
protected RedissonLocalCachedMap(RedissonClient redisson, Codec codec, CommandAsyncExecutor connectionManager, String name, LocalCachedMapOptions options) {
super(codec, connectionManager, name);
init(redisson, name, options);
}
private void init(RedissonClient redisson, String name, LocalCachedMapOptions options) {
map = redisson.getMap(name);
if (options.isInvalidateEntryOnChange()) {
invalidateEntryOnChange = 1;
}
if (options.getEvictionPolicy() == EvictionPolicy.NONE) {
cache = new NoneCacheMap<CacheKey, CacheValue>(options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
if (options.getEvictionPolicy() == EvictionPolicy.LRU) {
cache = new LRUCacheMap<CacheKey, CacheValue>(options.getCacheSize(), options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
if (options.getEvictionPolicy() == EvictionPolicy.LFU) {
cache = new LFUCacheMap<CacheKey, CacheValue>(options.getCacheSize(), options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
invalidationTopic = redisson.getTopic(name + ":topic");
invalidationTopic.addListener(new MessageListener<Object>() {
@Override
public void onMessage(String channel, Object msg) {
if (msg instanceof LocalCachedMapClear) {
cache.clear();
}
if (msg instanceof LocalCachedMapInvalidate) {
CacheKey key = new CacheKey(((LocalCachedMapInvalidate)msg).getKeyHash());
cache.remove(key);
}
}
});
}
@Override
public int size() {
return get(sizeAsync());
}
@Override
public RFuture<Integer> sizeAsync() {
return map.sizeAsync();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return get(containsKeyAsync(key));
}
private CacheKey toCacheKey(Object key) {
byte[] encoded = encodeMapKey(key);
return toCacheKey(encoded);
}
private CacheKey toCacheKey(byte[] encodedKey) {
return new CacheKey(Hash.hash(encodedKey));
}
@Override
public RFuture<Boolean> containsKeyAsync(Object key) {
CacheKey cacheKey = toCacheKey(key);
if (!cache.containsKey(cacheKey)) {
return map.containsKeyAsync(key);
}
return newSucceededFuture(true);
}
@Override
public boolean containsValue(Object value) {
return get(containsValueAsync(value));
}
@Override
public RFuture<Boolean> containsValueAsync(Object value) {
CacheValue cacheValue = new CacheValue(null, value);
if (!cache.containsValue(cacheValue)) {
return map.containsValueAsync(value);
}
return newSucceededFuture(true);
}
@Override
public V get(Object key) {
return get(getAsync(key));
}
@Override
public RFuture<V> getAsync(final Object key) {
if (key == null) {
throw new NullPointerException();
}
final CacheKey cacheKey = toCacheKey(key);
CacheValue cacheValue = cache.get(cacheKey);
if (cacheValue != null && cacheValue.getValue() != null) {
return newSucceededFuture((V)cacheValue.getValue());
}
RFuture<V> future = map.getAsync((K)key);
future.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
return;
}
V value = future.getNow();
if (value != null) {
cache.put(cacheKey, new CacheValue(key, value));
}
}
});
return future;
}
@Override
public V put(K key, V value) {
return get(putAsync(key, value));
}
@Override
public RFuture<V> putAsync(K key, V value) {
if (key == null) {
throw new NullPointerException();
}
if (value == null) {
throw new NullPointerException();
}
byte[] mapKey = encodeMapKey(key);
CacheKey cacheKey = toCacheKey(mapKey);
byte[] msg = encode(new LocalCachedMapInvalidate(cacheKey.getKeyHash()));
CacheValue cacheValue = new CacheValue(key, value);
cache.put(cacheKey, cacheValue);
return commandExecutor.evalWriteAsync(getName(), codec, EVAL_PUT,
"local v = redis.call('hget', KEYS[1], ARGV[1]); "
+ "if redis.call('hset', KEYS[1], ARGV[1], ARGV[2]) == 0 and ARGV[4] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[3]); "
+ "end; "
+ "return v; ",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
mapKey, encodeMapValue(value), msg, invalidateEntryOnChange);
}
@Override
public boolean fastPut(K key, V value) {
return get(fastPutAsync(key, value));
}
@Override
public RFuture<Boolean> fastPutAsync(K key, V value) {
if (key == null) {
throw new NullPointerException();
}
if (value == null) {
throw new NullPointerException();
}
byte[] encodedKey = encodeMapKey(key);
byte[] encodedValue = encodeMapKey(value);
CacheKey cacheKey = toCacheKey(encodedKey);
byte[] msg = encode(new LocalCachedMapInvalidate(cacheKey.getKeyHash()));
CacheValue cacheValue = new CacheValue(key, value);
cache.put(cacheKey, cacheValue);
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN,
"if redis.call('hset', KEYS[1], ARGV[1], ARGV[2]) == 0 then "
+ "if ARGV[4] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[3]); "
+ "end;"
+ "return 0; "
+ "end; "
+ "return 1; ",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
encodedKey, encodedValue, msg, invalidateEntryOnChange);
}
@Override
public V remove(Object key) {
return get(removeAsync((K)key));
}
@Override
public RFuture<V> removeAsync(K key) {
if (key == null) {
throw new NullPointerException();
}
byte[] keyEncoded = encodeMapKey(key);
CacheKey cacheKey = toCacheKey(keyEncoded);
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(cacheKey.getKeyHash()));
cache.remove(cacheKey);
return commandExecutor.evalWriteAsync(getName(), codec, EVAL_REMOVE,
"local v = redis.call('hget', KEYS[1], ARGV[1]); "
+ "if redis.call('hdel', KEYS[1], ARGV[1]) == 1 and ARGV[3] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[2]); "
+ "end; "
+ "return v",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
keyEncoded, msgEncoded, invalidateEntryOnChange);
}
@Override
public boolean fastRemove(Object key) {
return get(fastRemoveAsync((K)key));
}
@Override
public RFuture<Boolean> fastRemoveAsync(K key) {
if (key == null) {
throw new NullPointerException();
}
byte[] keyEncoded = encodeMapKey(key);
CacheKey cacheKey = toCacheKey(keyEncoded);
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(cacheKey.getKeyHash()));
cache.remove(cacheKey);
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN,
"if redis.call('hdel', KEYS[1], ARGV[1]) == 1 then "
+ "if ARGV[3] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[2]); "
+ "end; "
+ "return 1;"
+ "end;"
+ "return 0;",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
keyEncoded, msgEncoded, invalidateEntryOnChange);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
Map<CacheKey, CacheValue> cacheMap = new HashMap<CacheKey, CacheValue>(m.size());
for (java.util.Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
CacheKey cacheKey = toCacheKey(entry.getKey());
CacheValue cacheValue = new CacheValue(entry.getKey(), entry.getValue());
cacheMap.put(cacheKey, cacheValue);
}
cache.putAll(cacheMap);
map.putAll(m);
for (CacheKey cacheKey : cacheMap.keySet()) {
invalidationTopic.publish(new LocalCachedMapInvalidate(cacheKey.getKeyHash()));
}
}
@Override
public void clear() {
delete();
}
@Override
public RFuture<Boolean> deleteAsync() {
cache.clear();
byte[] msgEncoded = encode(new LocalCachedMapClear());
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if redis.call('del', KEYS[1]) == 1 and ARGV[2] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[1]); "
+ "end; ",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
msgEncoded, invalidateEntryOnChange);
}
@Override
public Set<K> keySet() {
return new KeySet();
}
@Override
public Collection<V> values() {
return new Values();
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
return new EntrySet();
}
private Iterator<Map.Entry<K,V>> cacheEntrySetIterator() {
final Iterator<Map.Entry<CacheKey, CacheValue>> iter = cache.entrySet().iterator();
return new Iterator<Map.Entry<K,V>>() {
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public java.util.Map.Entry<K, V> next() {
Map.Entry<CacheKey, CacheValue> entry = iter.next();
return new AbstractMap.SimpleEntry(entry.getValue().getKey(), entry.getValue().getValue());
}
@Override
public void remove() {
iter.remove();
}
};
}
private Iterator<K> cacheKeySetIterator() {
final Iterator<CacheValue> iter = cache.values().iterator();
return new Iterator<K>() {
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public K next() {
CacheValue value = iter.next();
return (K) value.getKey();
}
@Override
public void remove() {
iter.remove();
}
};
}
final class KeySet extends AbstractSet<K> {
@Override
public Iterator<K> iterator() {
return new CompositeIterable<K>(cacheKeySetIterator(), map.keySet().iterator()) {
@Override
boolean isCacheContains(Object object) {
CacheKey cacheKey = toCacheKey(object);
return cache.containsKey(cacheKey);
}
};
}
@Override
public boolean contains(Object o) {
return RedissonLocalCachedMap.this.containsKey(o);
}
@Override
public boolean remove(Object o) {
return RedissonLocalCachedMap.this.remove(o) != null;
}
@Override
public int size() {
return RedissonLocalCachedMap.this.size();
}
@Override
public void clear() {
RedissonLocalCachedMap.this.clear();
}
}
final class Values extends AbstractCollection<V> {
@Override
public Iterator<V> iterator() {
final Iterator<Map.Entry<K, V>> iter = RedissonLocalCachedMap.this.entrySet().iterator();
return new Iterator<V>() {
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public V next() {
return iter.next().getValue();
}
@Override
public void remove() {
iter.remove();
}
};
}
@Override
public boolean contains(Object o) {
return RedissonLocalCachedMap.this.containsValue(o);
}
@Override
public int size() {
return RedissonLocalCachedMap.this.size();
}
@Override
public void clear() {
RedissonLocalCachedMap.this.clear();
}
}
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final Iterator<Map.Entry<K,V>> iterator() {
return new CompositeIterable<Map.Entry<K,V>>(cacheEntrySetIterator(), map.entrySet().iterator()) {
@Override
boolean isCacheContains(Map.Entry<K,V> entry) {
CacheKey cacheKey = toCacheKey(entry.getKey());
return cache.containsKey(cacheKey);
}
};
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
V value = get(key);
return value != null && value.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return RedissonLocalCachedMap.this.map.remove(key, value);
}
return false;
}
public final int size() {
return RedissonLocalCachedMap.this.size();
}
public final void clear() {
RedissonLocalCachedMap.this.clear();
}
}
abstract class CompositeIterable<T> implements Iterator<T> {
private T currentObject;
private Iterator<T> cacheIterator;
private Iterator<T> mapIterator;
public CompositeIterable(Iterator<T> cacheIterator, Iterator<T> mapIterator) {
this.cacheIterator = cacheIterator;
this.mapIterator = mapIterator;
}
@Override
public boolean hasNext() {
if (!cacheIterator.hasNext()) {
while (true) {
if (mapIterator.hasNext()) {
currentObject = mapIterator.next();
if (!isCacheContains(currentObject)) {
return true;
}
} else {
break;
}
}
return false;
}
return true;
}
abstract boolean isCacheContains(T object);
@Override
public T next() {
if (currentObject != null) {
T val = currentObject;
currentObject = null;
return val;
}
if (!hasNext()) {
throw new NoSuchElementException();
}
return cacheIterator.next();
}
@Override
public void remove() {
if (currentObject != null) {
mapIterator.remove();
currentObject = null;
return;
}
cacheIterator.remove();
}
}
}

@ -40,7 +40,6 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask; import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
/** /**
@ -121,7 +120,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
} }
long threadId = Thread.currentThread().getId(); long threadId = Thread.currentThread().getId();
Future<RedissonLockEntry> future = subscribe(threadId); RFuture<RedissonLockEntry> future = subscribe(threadId);
get(future); get(future);
try { try {
@ -171,11 +170,11 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return ttlRemainingFuture; return ttlRemainingFuture;
} }
private <T> Future<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) { private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
if (leaseTime != -1) { if (leaseTime != -1) {
return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG); return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
} }
Future<Long> ttlRemainingFuture = tryLockInnerAsync(LOCK_EXPIRATION_INTERVAL_SECONDS, TimeUnit.SECONDS, threadId, RedisCommands.EVAL_LONG); RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(LOCK_EXPIRATION_INTERVAL_SECONDS, TimeUnit.SECONDS, threadId, RedisCommands.EVAL_LONG);
ttlRemainingFuture.addListener(new FutureListener<Long>() { ttlRemainingFuture.addListener(new FutureListener<Long>() {
@Override @Override
public void operationComplete(Future<Long> future) throws Exception { public void operationComplete(Future<Long> future) throws Exception {
@ -206,7 +205,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() { Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override @Override
public void run(Timeout timeout) throws Exception { public void run(Timeout timeout) throws Exception {
Future<Boolean> future = expireAsync(internalLockLeaseTime, TimeUnit.MILLISECONDS); RFuture<Boolean> future = expireAsync(internalLockLeaseTime, TimeUnit.MILLISECONDS);
future.addListener(new FutureListener<Boolean>() { future.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -265,14 +264,14 @@ public class RedissonLock extends RedissonExpirable implements RLock {
} }
final long threadId = Thread.currentThread().getId(); final long threadId = Thread.currentThread().getId();
Future<RedissonLockEntry> future = subscribe(threadId); final RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
if (!await(future, time, TimeUnit.MILLISECONDS)) { if (!await(subscribeFuture, time, TimeUnit.MILLISECONDS)) {
if (!future.cancel(false)) { if (!subscribeFuture.cancel(false)) {
future.addListener(new FutureListener<RedissonLockEntry>() { subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override @Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception { public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (future.isSuccess()) { if (subscribeFuture.isSuccess()) {
unsubscribe(future, threadId); unsubscribe(subscribeFuture, threadId);
} }
} }
}); });
@ -304,7 +303,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
time -= elapsed; time -= elapsed;
} }
} finally { } finally {
unsubscribe(future, threadId); unsubscribe(subscribeFuture, threadId);
} }
// return get(tryLockAsync(waitTime, leaseTime, unit)); // return get(tryLockAsync(waitTime, leaseTime, unit));
} }
@ -313,11 +312,11 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return PUBSUB.getEntry(getEntryName()); return PUBSUB.getEntry(getEntryName());
} }
protected Future<RedissonLockEntry> subscribe(long threadId) { protected RFuture<RedissonLockEntry> subscribe(long threadId) {
return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager()); return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
} }
protected void unsubscribe(Future<RedissonLockEntry> future, long threadId) { protected void unsubscribe(RFuture<RedissonLockEntry> future, long threadId) {
PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager()); PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager());
} }
@ -421,7 +420,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
public RFuture<Void> unlockAsync(final long threadId) { public RFuture<Void> unlockAsync(final long threadId) {
final RPromise<Void> result = newPromise(); final RPromise<Void> result = newPromise();
Future<Boolean> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('exists', KEYS[1]) == 0) then " + "if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " + "redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " + "return 1; " +
@ -477,7 +476,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
public RFuture<Void> lockAsync(final long leaseTime, final TimeUnit unit, final long currentThreadId) { public RFuture<Void> lockAsync(final long leaseTime, final TimeUnit unit, final long currentThreadId) {
final RPromise<Void> result = newPromise(); final RPromise<Void> result = newPromise();
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId); RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() { ttlFuture.addListener(new FutureListener<Long>() {
@Override @Override
public void operationComplete(Future<Long> future) throws Exception { public void operationComplete(Future<Long> future) throws Exception {
@ -494,7 +493,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return; return;
} }
final Future<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId); final RFuture<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() { subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override @Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception { public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
@ -514,8 +513,8 @@ public class RedissonLock extends RedissonExpirable implements RLock {
} }
private void lockAsync(final long leaseTime, final TimeUnit unit, private void lockAsync(final long leaseTime, final TimeUnit unit,
final Future<RedissonLockEntry> subscribeFuture, final Promise<Void> result, final long currentThreadId) { final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Void> result, final long currentThreadId) {
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId); RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() { ttlFuture.addListener(new FutureListener<Long>() {
@Override @Override
public void operationComplete(Future<Long> future) throws Exception { public void operationComplete(Future<Long> future) throws Exception {
@ -596,7 +595,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
final RPromise<Boolean> result = newPromise(); final RPromise<Boolean> result = newPromise();
final AtomicLong time = new AtomicLong(unit.toMillis(waitTime)); final AtomicLong time = new AtomicLong(unit.toMillis(waitTime));
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId); RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() { ttlFuture.addListener(new FutureListener<Long>() {
@Override @Override
public void operationComplete(Future<Long> future) throws Exception { public void operationComplete(Future<Long> future) throws Exception {
@ -615,7 +614,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>(); final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Future<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId); final RFuture<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() { subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override @Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception { public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
@ -660,8 +659,8 @@ public class RedissonLock extends RedissonExpirable implements RLock {
} }
private void tryLockAsync(final AtomicLong time, final long leaseTime, final TimeUnit unit, private void tryLockAsync(final AtomicLong time, final long leaseTime, final TimeUnit unit,
final Future<RedissonLockEntry> subscribeFuture, final Promise<Boolean> result, final long currentThreadId) { final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Boolean> result, final long currentThreadId) {
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId); RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() { ttlFuture.addListener(new FutureListener<Long>() {
@Override @Override
public void operationComplete(Future<Long> future) throws Exception { public void operationComplete(Future<Long> future) throws Exception {

@ -15,20 +15,22 @@
*/ */
package org.redisson; package org.redisson;
import io.netty.util.concurrent.Promise;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> { public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> {
private int counter; private int counter;
private final Semaphore latch; private final Semaphore latch;
private final Promise<RedissonLockEntry> promise; private final RPromise<RedissonLockEntry> promise;
private final ConcurrentLinkedQueue<Runnable> listeners = new ConcurrentLinkedQueue<Runnable>(); private final ConcurrentLinkedQueue<Runnable> listeners = new ConcurrentLinkedQueue<Runnable>();
public RedissonLockEntry(Promise<RedissonLockEntry> promise) { public RedissonLockEntry(RPromise<RedissonLockEntry> promise) {
super(); super();
this.latch = new Semaphore(0); this.latch = new Semaphore(0);
this.promise = promise; this.promise = promise;
@ -42,7 +44,7 @@ public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> {
return --counter; return --counter;
} }
public Promise<RedissonLockEntry> getPromise() { public RPromise<RedissonLockEntry> getPromise() {
return promise; return promise;
} }

@ -534,7 +534,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
MapScanResult<ScanObjectEntry, ScanObjectEntry> scanIterator(String name, InetSocketAddress client, long startPos) { MapScanResult<ScanObjectEntry, ScanObjectEntry> scanIterator(String name, InetSocketAddress client, long startPos) {
RedisCommand<MapCacheScanResult<Object, Object>> EVAL_HSCAN = new RedisCommand<MapCacheScanResult<Object, Object>>("EVAL", RedisCommand<MapCacheScanResult<Object, Object>> EVAL_HSCAN = new RedisCommand<MapCacheScanResult<Object, Object>>("EVAL",
new ListMultiDecoder(new LongMultiDecoder(), new ObjectMapDecoder(new ScanCodec(codec)), new ObjectListDecoder(codec), new MapCacheScanResultReplayDecoder()), ValueType.MAP); new ListMultiDecoder(new LongMultiDecoder(), new ObjectMapDecoder(new ScanCodec(codec)), new ObjectListDecoder(codec), new MapCacheScanResultReplayDecoder()), ValueType.MAP);
Future<MapCacheScanResult<ScanObjectEntry, ScanObjectEntry>> f = commandExecutor.evalReadAsync(client, getName(), codec, EVAL_HSCAN, RFuture<MapCacheScanResult<ScanObjectEntry, ScanObjectEntry>> f = commandExecutor.evalReadAsync(client, getName(), codec, EVAL_HSCAN,
"local result = {}; " "local result = {}; "
+ "local idleKeys = {}; " + "local idleKeys = {}; "
+ "local res = redis.call('hscan', KEYS[1], ARGV[2]); " + "local res = redis.call('hscan', KEYS[1], ARGV[2]); "

@ -21,8 +21,8 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -30,14 +30,15 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import org.redisson.api.RFuture;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonFuture; import org.redisson.misc.RedissonFuture;
import org.redisson.misc.RedissonPromise; import org.redisson.misc.RedissonPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor; import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
/** /**
* Groups multiple independent locks and manages them as one lock. * Groups multiple independent locks and manages them as one lock.
@ -80,7 +81,7 @@ public class RedissonMultiLock implements Lock {
} }
public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException { public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
Promise<Void> promise = ImmediateEventExecutor.INSTANCE.newPromise(); RPromise<Void> promise = new RedissonPromise<Void>(ImmediateEventExecutor.INSTANCE.<Void>newPromise());
long currentThreadId = Thread.currentThread().getId(); long currentThreadId = Thread.currentThread().getId();
Queue<RLock> lockedLocks = new ConcurrentLinkedQueue<RLock>(); Queue<RLock> lockedLocks = new ConcurrentLinkedQueue<RLock>();
@ -94,7 +95,7 @@ public class RedissonMultiLock implements Lock {
lockInterruptibly(-1, null); lockInterruptibly(-1, null);
} }
private void lock(final Promise<Void> promise, final long waitTime, final long leaseTime, final TimeUnit unit, private void lock(final RPromise<Void> promise, final long waitTime, final long leaseTime, final TimeUnit unit,
final List<RLock> locks, final long currentThreadId, final Queue<RLock> lockedLocks) throws InterruptedException { final List<RLock> locks, final long currentThreadId, final Queue<RLock> lockedLocks) throws InterruptedException {
final AtomicInteger tryLockRequestsAmount = new AtomicInteger(); final AtomicInteger tryLockRequestsAmount = new AtomicInteger();
final Map<Future<Boolean>, RLock> tryLockFutures = new HashMap<Future<Boolean>, RLock>(locks.size()); final Map<Future<Boolean>, RLock> tryLockFutures = new HashMap<Future<Boolean>, RLock>(locks.size());
@ -145,7 +146,7 @@ public class RedissonMultiLock implements Lock {
} }
} }
protected void tryLockAgain(final Promise<Void> promise, final long waitTime, final long leaseTime, protected void tryLockAgain(final RPromise<Void> promise, final long waitTime, final long leaseTime,
final TimeUnit unit, final long currentThreadId, final Map<Future<Boolean>, RLock> tryLockFutures) throws InterruptedException { final TimeUnit unit, final long currentThreadId, final Map<Future<Boolean>, RLock> tryLockFutures) throws InterruptedException {
lockedLocks.clear(); lockedLocks.clear();
if (failed.get() != null) { if (failed.get() != null) {
@ -176,9 +177,9 @@ public class RedissonMultiLock implements Lock {
tryLockRequestsAmount.incrementAndGet(); tryLockRequestsAmount.incrementAndGet();
Future<Boolean> future; Future<Boolean> future;
if (waitTime > 0 || leaseTime > 0) { if (waitTime > 0 || leaseTime > 0) {
future = ((RedissonLock)lock).tryLockAsync(waitTime, leaseTime, unit, currentThreadId); future = ((RedissonPromise)((RedissonLock)lock).tryLockAsync(waitTime, leaseTime, unit, currentThreadId)).getInnerPromise();
} else { } else {
future = ((RedissonLock)lock).tryLockAsync(currentThreadId); future = ((RedissonPromise)(((RedissonLock)lock).tryLockAsync(currentThreadId))).getInnerPromise();
} }
if (future instanceof RedissonPromise) { if (future instanceof RedissonPromise) {
@ -197,7 +198,7 @@ public class RedissonMultiLock implements Lock {
@Override @Override
public boolean tryLock() { public boolean tryLock() {
Map<RLock, Future<Boolean>> tryLockFutures = new HashMap<RLock, Future<Boolean>>(locks.size()); Map<RLock, RFuture<Boolean>> tryLockFutures = new HashMap<RLock, RFuture<Boolean>>(locks.size());
for (RLock lock : locks) { for (RLock lock : locks) {
tryLockFutures.put(lock, lock.tryLockAsync()); tryLockFutures.put(lock, lock.tryLockAsync());
} }
@ -205,10 +206,10 @@ public class RedissonMultiLock implements Lock {
return sync(tryLockFutures); return sync(tryLockFutures);
} }
protected boolean sync(Map<RLock, Future<Boolean>> tryLockFutures) { protected boolean sync(Map<RLock, RFuture<Boolean>> tryLockFutures) {
List<RLock> lockedLocks = new ArrayList<RLock>(tryLockFutures.size()); List<RLock> lockedLocks = new ArrayList<RLock>(tryLockFutures.size());
RuntimeException latestException = null; RuntimeException latestException = null;
for (Entry<RLock, Future<Boolean>> entry : tryLockFutures.entrySet()) { for (Entry<RLock, RFuture<Boolean>> entry : tryLockFutures.entrySet()) {
try { try {
if (entry.getValue().syncUninterruptibly().getNow()) { if (entry.getValue().syncUninterruptibly().getNow()) {
lockedLocks.add(entry.getKey()); lockedLocks.add(entry.getKey());
@ -230,12 +231,12 @@ public class RedissonMultiLock implements Lock {
} }
protected void unlockInner(Collection<RLock> locks) { protected void unlockInner(Collection<RLock> locks) {
List<Future<Void>> futures = new ArrayList<Future<Void>>(locks.size()); List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>(locks.size());
for (RLock lock : locks) { for (RLock lock : locks) {
futures.add(lock.unlockAsync()); futures.add(lock.unlockAsync());
} }
for (Future<Void> unlockFuture : futures) { for (RFuture<Void> unlockFuture : futures) {
unlockFuture.awaitUninterruptibly(); unlockFuture.awaitUninterruptibly();
} }
} }
@ -246,7 +247,7 @@ public class RedissonMultiLock implements Lock {
} }
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException { public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
Map<RLock, Future<Boolean>> tryLockFutures = new HashMap<RLock, Future<Boolean>>(locks.size()); Map<RLock, RFuture<Boolean>> tryLockFutures = new HashMap<RLock, RFuture<Boolean>>(locks.size());
for (RLock lock : locks) { for (RLock lock : locks) {
tryLockFutures.put(lock, lock.tryLockAsync(waitTime, leaseTime, unit)); tryLockFutures.put(lock, lock.tryLockAsync(waitTime, leaseTime, unit));
} }
@ -257,13 +258,13 @@ public class RedissonMultiLock implements Lock {
@Override @Override
public void unlock() { public void unlock() {
List<Future<Void>> futures = new ArrayList<Future<Void>>(locks.size()); List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>(locks.size());
for (RLock lock : locks) { for (RLock lock : locks) {
futures.add(lock.unlockAsync()); futures.add(lock.unlockAsync());
} }
for (Future<Void> future : futures) { for (RFuture<Void> future : futures) {
future.syncUninterruptibly(); future.syncUninterruptibly();
} }
} }

@ -41,8 +41,6 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.Hash; import org.redisson.misc.Hash;
import io.netty.util.concurrent.Future;
/** /**
* @author Nikita Koksharov * @author Nikita Koksharov
* *
@ -250,7 +248,7 @@ public abstract class RedissonMultimap<K, V> extends RedissonExpirable implement
MapScanResult<ScanObjectEntry, ScanObjectEntry> scanIterator(InetSocketAddress client, long startPos) { MapScanResult<ScanObjectEntry, ScanObjectEntry> scanIterator(InetSocketAddress client, long startPos) {
Future<MapScanResult<ScanObjectEntry, ScanObjectEntry>> f = commandExecutor.readAsync(client, getName(), new ScanCodec(codec, StringCodec.INSTANCE), RedisCommands.HSCAN, getName(), startPos); RFuture<MapScanResult<ScanObjectEntry, ScanObjectEntry>> f = commandExecutor.readAsync(client, getName(), new ScanCodec(codec, StringCodec.INSTANCE), RedisCommands.HSCAN, getName(), startPos);
return get(f); return get(f);
} }

@ -23,6 +23,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.config.RedissonNodeConfig; import org.redisson.config.RedissonNodeConfig;
@ -33,7 +34,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.internal.ThreadLocalRandom; import io.netty.util.internal.ThreadLocalRandom;
/** /**
@ -157,7 +157,7 @@ public class RedissonNode {
private void retrieveAdresses() { private void retrieveAdresses() {
ConnectionManager connectionManager = ((Redisson)redisson).getConnectionManager(); ConnectionManager connectionManager = ((Redisson)redisson).getConnectionManager();
for (MasterSlaveEntry entry : connectionManager.getEntrySet()) { for (MasterSlaveEntry entry : connectionManager.getEntrySet()) {
Future<RedisConnection> readFuture = entry.connectionReadOp(); RFuture<RedisConnection> readFuture = entry.connectionReadOp();
if (readFuture.awaitUninterruptibly((long)connectionManager.getConfig().getConnectTimeout()) if (readFuture.awaitUninterruptibly((long)connectionManager.getConfig().getConnectTimeout())
&& readFuture.isSuccess()) { && readFuture.isSuccess()) {
RedisConnection connection = readFuture.getNow(); RedisConnection connection = readFuture.getNow();
@ -166,7 +166,7 @@ public class RedissonNode {
localAddress = (InetSocketAddress) connection.getChannel().localAddress(); localAddress = (InetSocketAddress) connection.getChannel().localAddress();
return; return;
} }
Future<RedisConnection> writeFuture = entry.connectionWriteOp(); RFuture<RedisConnection> writeFuture = entry.connectionWriteOp();
if (writeFuture.awaitUninterruptibly((long)connectionManager.getConfig().getConnectTimeout()) if (writeFuture.awaitUninterruptibly((long)connectionManager.getConfig().getConnectTimeout())
&& writeFuture.isSuccess()) { && writeFuture.isSuccess()) {
RedisConnection connection = writeFuture.getNow(); RedisConnection connection = writeFuture.getNow();

@ -25,9 +25,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.RPromise; import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/** /**
* Base Redisson object * Base Redisson object
* *
@ -50,11 +47,11 @@ abstract class RedissonObject implements RObject {
this(commandExecutor.getConnectionManager().getCodec(), commandExecutor, name); this(commandExecutor.getConnectionManager().getCodec(), commandExecutor, name);
} }
protected boolean await(Future<?> future, long timeout, TimeUnit timeoutUnit) throws InterruptedException { protected boolean await(RFuture<?> future, long timeout, TimeUnit timeoutUnit) throws InterruptedException {
return commandExecutor.await(future, timeout, timeoutUnit); return commandExecutor.await(future, timeout, timeoutUnit);
} }
protected <V> V get(Future<V> future) { protected <V> V get(RFuture<V> future) {
return commandExecutor.get(future); return commandExecutor.get(future);
} }
@ -144,4 +141,20 @@ abstract class RedissonObject implements RObject {
} }
} }
protected byte[] encodeMapKey(Object value) {
try {
return codec.getMapKeyEncoder().encode(value);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
protected byte[] encodeMapValue(Object value) {
try {
return codec.getMapValueEncoder().encode(value);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
} }

@ -18,6 +18,7 @@ package org.redisson;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.redisson.api.RFuture;
import org.redisson.api.RPatternTopic; import org.redisson.api.RPatternTopic;
import org.redisson.api.listener.PatternMessageListener; import org.redisson.api.listener.PatternMessageListener;
import org.redisson.api.listener.PatternStatusListener; import org.redisson.api.listener.PatternStatusListener;
@ -27,8 +28,6 @@ import org.redisson.command.CommandExecutor;
import org.redisson.connection.PubSubConnectionEntry; import org.redisson.connection.PubSubConnectionEntry;
import org.redisson.pubsub.AsyncSemaphore; import org.redisson.pubsub.AsyncSemaphore;
import io.netty.util.concurrent.Future;
/** /**
* Distributed topic implementation. Messages are delivered to all message listeners across Redis cluster. * Distributed topic implementation. Messages are delivered to all message listeners across Redis cluster.
* *
@ -64,7 +63,7 @@ public class RedissonPatternTopic<M> implements RPatternTopic<M> {
} }
private int addListener(RedisPubSubListener<?> pubSubListener) { private int addListener(RedisPubSubListener<?> pubSubListener) {
Future<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().psubscribe(name, codec, pubSubListener); RFuture<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().psubscribe(name, codec, pubSubListener);
future.syncUninterruptibly(); future.syncUninterruptibly();
return System.identityHashCode(pubSubListener); return System.identityHashCode(pubSubListener);
} }

@ -28,6 +28,7 @@ import org.redisson.api.RBitSetReactive;
import org.redisson.api.RBlockingQueueReactive; import org.redisson.api.RBlockingQueueReactive;
import org.redisson.api.RBucketReactive; import org.redisson.api.RBucketReactive;
import org.redisson.api.RDequeReactive; import org.redisson.api.RDequeReactive;
import org.redisson.api.RFuture;
import org.redisson.api.RHyperLogLogReactive; import org.redisson.api.RHyperLogLogReactive;
import org.redisson.api.RKeysReactive; import org.redisson.api.RKeysReactive;
import org.redisson.api.RLexSortedSetReactive; import org.redisson.api.RLexSortedSetReactive;
@ -68,8 +69,6 @@ import org.redisson.reactive.RedissonSetCacheReactive;
import org.redisson.reactive.RedissonSetReactive; import org.redisson.reactive.RedissonSetReactive;
import org.redisson.reactive.RedissonTopicReactive; import org.redisson.reactive.RedissonTopicReactive;
import io.netty.util.concurrent.Future;
/** /**
* Main infrastructure class allows to get access * Main infrastructure class allows to get access
* to all Redisson objects on top of Redis server. * to all Redisson objects on top of Redis server.
@ -116,7 +115,7 @@ public class RedissonReactive implements RedissonReactiveClient {
@Override @Override
public <V> List<RBucketReactive<V>> findBuckets(String pattern) { public <V> List<RBucketReactive<V>> findBuckets(String pattern) {
Future<Collection<String>> r = commandExecutor.readAllAsync(RedisCommands.KEYS, pattern); RFuture<Collection<String>> r = commandExecutor.readAllAsync(RedisCommands.KEYS, pattern);
Collection<String> keys = commandExecutor.get(r); Collection<String> keys = commandExecutor.get(r);
List<RBucketReactive<V>> buckets = new ArrayList<RBucketReactive<V>>(keys.size()); List<RBucketReactive<V>> buckets = new ArrayList<RBucketReactive<V>>(keys.size());

@ -22,6 +22,7 @@ import java.util.Map.Entry;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
@ -47,10 +48,10 @@ public class RedissonRedLock extends RedissonMultiLock {
super(locks); super(locks);
} }
protected boolean sync(Map<RLock, Future<Boolean>> tryLockFutures) { protected boolean sync(Map<RLock, RFuture<Boolean>> tryLockFutures) {
List<RLock> lockedLocks = new ArrayList<RLock>(tryLockFutures.size()); List<RLock> lockedLocks = new ArrayList<RLock>(tryLockFutures.size());
RuntimeException latestException = null; RuntimeException latestException = null;
for (Entry<RLock, Future<Boolean>> entry : tryLockFutures.entrySet()) { for (Entry<RLock, RFuture<Boolean>> entry : tryLockFutures.entrySet()) {
try { try {
if (entry.getValue().syncUninterruptibly().getNow()) { if (entry.getValue().syncUninterruptibly().getNow()) {
lockedLocks.add(entry.getKey()); lockedLocks.add(entry.getKey());

@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RBatch; import org.redisson.api.RBatch;
import org.redisson.api.RBlockingQueue; import org.redisson.api.RBlockingQueue;
import org.redisson.api.RBlockingQueueAsync; import org.redisson.api.RBlockingQueueAsync;
import org.redisson.api.RFuture;
import org.redisson.api.RRemoteService; import org.redisson.api.RRemoteService;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
@ -107,7 +108,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
private <T> void subscribe(final Class<T> remoteInterface, final RBlockingQueue<RemoteServiceRequest> requestQueue, private <T> void subscribe(final Class<T> remoteInterface, final RBlockingQueue<RemoteServiceRequest> requestQueue,
final ExecutorService executor) { final ExecutorService executor) {
Future<RemoteServiceRequest> take = requestQueue.takeAsync(); RFuture<RemoteServiceRequest> take = requestQueue.takeAsync();
take.addListener(new FutureListener<RemoteServiceRequest>() { take.addListener(new FutureListener<RemoteServiceRequest>() {
@Override @Override
public void operationComplete(Future<RemoteServiceRequest> future) throws Exception { public void operationComplete(Future<RemoteServiceRequest> future) throws Exception {
@ -139,7 +140,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
// send the ack only if expected // send the ack only if expected
if (request.getOptions().isAckExpected()) { if (request.getOptions().isAckExpected()) {
String ackName = getAckName(remoteInterface, request.getRequestId()); String ackName = getAckName(remoteInterface, request.getRequestId());
Future<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(responseName, RFuture<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(responseName,
LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if redis.call('setnx', KEYS[1], 1) == 1 then " "if redis.call('setnx', KEYS[1], 1) == 1 then "
+ "redis.call('pexpire', KEYS[1], ARGV[2]);" + "redis.call('pexpire', KEYS[1], ARGV[2]);"
@ -188,7 +189,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
if (executor != null) { if (executor != null) {
RBlockingQueue<RemoteServiceCancelRequest> cancelRequestQueue = RBlockingQueue<RemoteServiceCancelRequest> cancelRequestQueue =
redisson.getBlockingQueue(getCancelRequestQueueName(remoteInterface, request.getRequestId()), getCodec()); redisson.getBlockingQueue(getCancelRequestQueueName(remoteInterface, request.getRequestId()), getCodec());
final Future<RemoteServiceCancelRequest> cancelRequestFuture = cancelRequestQueue.takeAsync(); final RFuture<RemoteServiceCancelRequest> cancelRequestFuture = cancelRequestQueue.takeAsync();
final AtomicReference<RRemoteServiceResponse> responseHolder = new AtomicReference<RRemoteServiceResponse>(); final AtomicReference<RRemoteServiceResponse> responseHolder = new AtomicReference<RRemoteServiceResponse>();
@ -230,7 +231,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
private <T> void invokeMethod(final Class<T> remoteInterface, private <T> void invokeMethod(final Class<T> remoteInterface,
final RBlockingQueue<RemoteServiceRequest> requestQueue, final RemoteServiceRequest request, final RBlockingQueue<RemoteServiceRequest> requestQueue, final RemoteServiceRequest request,
RemoteServiceMethod method, String responseName, final ExecutorService executor, RemoteServiceMethod method, String responseName, final ExecutorService executor,
Future<RemoteServiceCancelRequest> cancelRequestFuture, final AtomicReference<RRemoteServiceResponse> responseHolder) { RFuture<RemoteServiceCancelRequest> cancelRequestFuture, final AtomicReference<RRemoteServiceResponse> responseHolder) {
try { try {
if (method.getBean() instanceof RemoteParams) { if (method.getBean() instanceof RemoteParams) {
((RemoteParams)method.getBean()).setRequestId(request.getRequestId()); ((RemoteParams)method.getBean()).setRequestId(request.getRequestId());
@ -258,7 +259,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
timeout = request.getOptions().getExecutionTimeoutInMillis(); timeout = request.getOptions().getExecutionTimeoutInMillis();
} }
Future<List<?>> clientsFuture = send(timeout, responseName, RFuture<List<?>> clientsFuture = send(timeout, responseName,
responseHolder.get()); responseHolder.get());
clientsFuture.addListener(new FutureListener<List<?>>() { clientsFuture.addListener(new FutureListener<List<?>>() {
@Override @Override
@ -282,7 +283,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
} }
} }
private <T extends RRemoteServiceResponse> Future<List<?>> send(long timeout, String responseName, T response) { private <T extends RRemoteServiceResponse> RFuture<List<?>> send(long timeout, String responseName, T response) {
RBatch batch = redisson.createBatch(); RBatch batch = redisson.createBatch();
RBlockingQueueAsync<T> queue = batch.getBlockingQueue(responseName, getCodec()); RBlockingQueueAsync<T> queue = batch.getBlockingQueue(responseName, getCodec());
queue.putAsync(response); queue.putAsync(response);

@ -30,18 +30,16 @@ import java.util.Map.Entry;
import org.redisson.api.RFuture; import org.redisson.api.RFuture;
import org.redisson.api.RScoredSortedSet; import org.redisson.api.RScoredSortedSet;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.codec.DoubleCodec;
import org.redisson.client.codec.ScoredCodec; import org.redisson.client.codec.ScoredCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.ScoredEntry; import org.redisson.client.protocol.ScoredEntry;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.convertor.BooleanReplayConvertor; import org.redisson.client.protocol.convertor.BooleanReplayConvertor;
import org.redisson.client.protocol.decoder.ListScanResult; import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.command.CommandAsyncExecutor; import org.redisson.command.CommandAsyncExecutor;
import io.netty.util.concurrent.Future;
public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RScoredSortedSet<V> { public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RScoredSortedSet<V> {
public RedissonScoredSortedSet(CommandAsyncExecutor commandExecutor, String name) { public RedissonScoredSortedSet(CommandAsyncExecutor commandExecutor, String name) {
@ -253,7 +251,7 @@ public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RSc
} }
private ListScanResult<V> scanIterator(InetSocketAddress client, long startPos) { private ListScanResult<V> scanIterator(InetSocketAddress client, long startPos) {
Future<ListScanResult<V>> f = commandExecutor.readAsync(client, getName(), codec, RedisCommands.ZSCAN, getName(), startPos); RFuture<ListScanResult<V>> f = commandExecutor.readAsync(client, getName(), codec, RedisCommands.ZSCAN, getName(), startPos);
return get(f); return get(f);
} }
@ -359,8 +357,8 @@ public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RSc
@Override @Override
public RFuture<Double> addScoreAsync(V object, Number value) { public RFuture<Double> addScoreAsync(V object, Number value) {
return commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.ZINCRBY, return commandExecutor.writeAsync(getName(), DoubleCodec.INSTANCE, RedisCommands.ZINCRBY,
getName(), new BigDecimal(value.toString()).toPlainString(), object); getName(), new BigDecimal(value.toString()).toPlainString(), encode(object));
} }
@Override @Override

@ -35,7 +35,6 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask; import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/** /**
* Distributed and concurrent implementation of {@link java.util.concurrent.Semaphore}. * Distributed and concurrent implementation of {@link java.util.concurrent.Semaphore}.
@ -79,7 +78,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
return; return;
} }
Future<RedissonLockEntry> future = subscribe(); RFuture<RedissonLockEntry> future = subscribe();
get(future); get(future);
try { try {
while (true) { while (true) {
@ -103,7 +102,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
@Override @Override
public RFuture<Void> acquireAsync(final int permits) { public RFuture<Void> acquireAsync(final int permits) {
final RPromise<Void> result = newPromise(); final RPromise<Void> result = newPromise();
Future<Boolean> tryAcquireFuture = tryAcquireAsync(permits); RFuture<Boolean> tryAcquireFuture = tryAcquireAsync(permits);
tryAcquireFuture.addListener(new FutureListener<Boolean>() { tryAcquireFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -117,7 +116,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
return; return;
} }
final Future<RedissonLockEntry> subscribeFuture = subscribe(); final RFuture<RedissonLockEntry> subscribeFuture = subscribe();
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() { subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override @Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception { public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
@ -135,8 +134,8 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
return result; return result;
} }
private void tryAcquireAsync(final AtomicLong time, final int permits, final Future<RedissonLockEntry> subscribeFuture, final Promise<Boolean> result) { private void tryAcquireAsync(final AtomicLong time, final int permits, final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Boolean> result) {
Future<Boolean> tryAcquireFuture = tryAcquireAsync(permits); RFuture<Boolean> tryAcquireFuture = tryAcquireAsync(permits);
tryAcquireFuture.addListener(new FutureListener<Boolean>() { tryAcquireFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -206,8 +205,8 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
} }
private void acquireAsync(final int permits, final Future<RedissonLockEntry> subscribeFuture, final Promise<Void> result) { private void acquireAsync(final int permits, final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Void> result) {
Future<Boolean> tryAcquireFuture = tryAcquireAsync(permits); RFuture<Boolean> tryAcquireFuture = tryAcquireAsync(permits);
tryAcquireFuture.addListener(new FutureListener<Boolean>() { tryAcquireFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -284,7 +283,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
} }
long time = unit.toMillis(waitTime); long time = unit.toMillis(waitTime);
Future<RedissonLockEntry> future = subscribe(); RFuture<RedissonLockEntry> future = subscribe();
if (!await(future, time, TimeUnit.MILLISECONDS)) { if (!await(future, time, TimeUnit.MILLISECONDS)) {
return false; return false;
} }
@ -317,7 +316,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
public RFuture<Boolean> tryAcquireAsync(final int permits, long waitTime, TimeUnit unit) { public RFuture<Boolean> tryAcquireAsync(final int permits, long waitTime, TimeUnit unit) {
final RPromise<Boolean> result = newPromise(); final RPromise<Boolean> result = newPromise();
final AtomicLong time = new AtomicLong(unit.toMillis(waitTime)); final AtomicLong time = new AtomicLong(unit.toMillis(waitTime));
Future<Boolean> tryAcquireFuture = tryAcquireAsync(permits); RFuture<Boolean> tryAcquireFuture = tryAcquireAsync(permits);
tryAcquireFuture.addListener(new FutureListener<Boolean>() { tryAcquireFuture.addListener(new FutureListener<Boolean>() {
@Override @Override
public void operationComplete(Future<Boolean> future) throws Exception { public void operationComplete(Future<Boolean> future) throws Exception {
@ -333,7 +332,7 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
final long current = System.currentTimeMillis(); final long current = System.currentTimeMillis();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>(); final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Future<RedissonLockEntry> subscribeFuture = subscribe(); final RFuture<RedissonLockEntry> subscribeFuture = subscribe();
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() { subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override @Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception { public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
@ -381,11 +380,11 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
return semaphorePubSub.getEntry(getName()); return semaphorePubSub.getEntry(getName());
} }
private Future<RedissonLockEntry> subscribe() { private RFuture<RedissonLockEntry> subscribe() {
return semaphorePubSub.subscribe(getName(), getChannelName(), commandExecutor.getConnectionManager()); return semaphorePubSub.subscribe(getName(), getChannelName(), commandExecutor.getConnectionManager());
} }
private void unsubscribe(Future<RedissonLockEntry> future) { private void unsubscribe(RFuture<RedissonLockEntry> future) {
semaphorePubSub.unsubscribe(future.getNow(), getName(), getChannelName(), commandExecutor.getConnectionManager()); semaphorePubSub.unsubscribe(future.getNow(), getName(), getChannelName(), commandExecutor.getConnectionManager());
} }

@ -323,7 +323,7 @@ public class RedissonSubList<V> extends RedissonList<V> implements RList<V> {
return get(f); return get(f);
} }
private <R> RFuture<R> indexOfAsync(Object o, Convertor<R> convertor) { public <R> RFuture<R> indexOfAsync(Object o, Convertor<R> convertor) {
return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4), return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4),
"local items = redis.call('lrange', KEYS[1], tonumber(ARGV[2]), tonumber(ARGV[3])) " + "local items = redis.call('lrange', KEYS[1], tonumber(ARGV[2]), tonumber(ARGV[3])) " +
"for i=1,#items do " + "for i=1,#items do " +
@ -470,7 +470,7 @@ public class RedissonSubList<V> extends RedissonList<V> implements RList<V> {
} }
@Override @Override
public RFuture<Void> trimAsync(int fromIndex, int toIndex) { public RFuture<Void> trimAsync(long fromIndex, long toIndex) {
if (fromIndex < this.fromIndex || toIndex >= this.toIndex.get()) { if (fromIndex < this.fromIndex || toIndex >= this.toIndex.get()) {
throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " toIndex: " + toIndex); throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " toIndex: " + toIndex);
} }

@ -29,8 +29,6 @@ import org.redisson.command.CommandAsyncExecutor;
import org.redisson.connection.PubSubConnectionEntry; import org.redisson.connection.PubSubConnectionEntry;
import org.redisson.pubsub.AsyncSemaphore; import org.redisson.pubsub.AsyncSemaphore;
import io.netty.util.concurrent.Future;
/** /**
* Distributed topic implementation. Messages are delivered to all message listeners across Redis cluster. * Distributed topic implementation. Messages are delivered to all message listeners across Redis cluster.
* *
@ -80,7 +78,7 @@ public class RedissonTopic<M> implements RTopic<M> {
} }
private int addListener(RedisPubSubListener<?> pubSubListener) { private int addListener(RedisPubSubListener<?> pubSubListener) {
Future<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().subscribe(codec, name, pubSubListener); RFuture<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().subscribe(codec, name, pubSubListener);
future.syncUninterruptibly(); future.syncUninterruptibly();
return System.identityHashCode(pubSubListener); return System.identityHashCode(pubSubListener);
} }

@ -0,0 +1,174 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.api;
import java.util.concurrent.TimeUnit;
/**
* RLocalCachedMap options object. Used to specify RLocalCachedMap settings.
*
* @author Nikita Koksharov
*
*/
public class LocalCachedMapOptions {
public enum EvictionPolicy {NONE, LRU, LFU};
private boolean invalidateEntryOnChange;
private EvictionPolicy evictionPolicy;
private int cacheSize;
private long timeToLiveInMillis;
private long maxIdleInMillis;
private LocalCachedMapOptions() {
}
protected LocalCachedMapOptions(LocalCachedMapOptions copy) {
this.invalidateEntryOnChange = copy.invalidateEntryOnChange;
this.evictionPolicy = copy.evictionPolicy;
this.cacheSize = copy.cacheSize;
this.timeToLiveInMillis = copy.timeToLiveInMillis;
this.maxIdleInMillis = copy.maxIdleInMillis;
}
/**
* Creates a new instance of LocalCachedMapOptions with default options.
* <p/>
* This is equivalent to:
* <pre>
* new LocalCachedMapOptions()
* .cacheSize(0).timeToLive(0).maxIdle(0)
* .evictionPolicy(EvictionPolicy.NONE)
* .invalidateEntryOnChange(true);
* </pre>
*/
public static LocalCachedMapOptions defaults() {
return new LocalCachedMapOptions()
.cacheSize(0).timeToLive(0).maxIdle(0)
.evictionPolicy(EvictionPolicy.NONE)
.invalidateEntryOnChange(true);
}
public boolean isInvalidateEntryOnChange() {
return invalidateEntryOnChange;
}
public EvictionPolicy getEvictionPolicy() {
return evictionPolicy;
}
public int getCacheSize() {
return cacheSize;
}
public long getTimeToLiveInMillis() {
return timeToLiveInMillis;
}
public long getMaxIdleInMillis() {
return maxIdleInMillis;
}
/**
* Sets cache size. If size is <code>0</code> then cache is unbounded.
*
* @param cacheSize
* @return
*/
public LocalCachedMapOptions cacheSize(int cacheSize) {
this.cacheSize = cacheSize;
return this;
}
/**
* Sets entry invalidation behavior.
*
* @param value - if <code>true</code> then invalidation message which removes corresponding entry from cache
* will be sent to all other RLocalCachedMap instances on each entry update/remove operation.
* if <code>false</code> then invalidation message won't be sent
* @return
*/
public LocalCachedMapOptions invalidateEntryOnChange(boolean value) {
this.invalidateEntryOnChange = value;
return this;
}
/**
* Sets eviction policy.
*
* @param evictionPolicy
* <p><code>LRU</code> - uses cache with LRU (least recently used) eviction policy.
* <p><code>LFU</code> - uses cache with LFU (least frequently used) eviction policy.
* <p><code>NONE</code> - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working.
* @return
*/
public LocalCachedMapOptions evictionPolicy(EvictionPolicy evictionPolicy) {
if (evictionPolicy == null) {
throw new NullPointerException("evictionPolicy can't be null");
}
this.evictionPolicy = evictionPolicy;
return this;
}
/**
* Sets time to live in milliseconds for each map entry in cache.
* If value equals to <code>0<code> then timeout is not applied
*
* @param timeToLiveInMillis
* @return
*/
public LocalCachedMapOptions timeToLive(long timeToLiveInMillis) {
this.timeToLiveInMillis = timeToLiveInMillis;
return this;
}
/**
* Sets time to live for each map entry in cache.
* If value equals to <code>0<code> then timeout is not applied
*
* @param timeToLive
* @param timeUnit
* @return
*/
public LocalCachedMapOptions timeToLive(long timeToLive, TimeUnit timeUnit) {
return timeToLive(timeUnit.toMillis(timeToLive));
}
/**
* Sets max idle time in milliseconds for each map entry in cache.
* If value equals to <code>0<code> then timeout is not applied
*
* @param maxIdleInMillis
* @return
*/
public LocalCachedMapOptions maxIdle(long maxIdleInMillis) {
this.maxIdleInMillis = maxIdleInMillis;
return this;
}
/**
* Sets max idle time for each map entry in cache.
* If value equals to <code>0<code> then timeout is not applied
*
* @param maxIdleInMillis
* @return
*/
public LocalCachedMapOptions maxIdle(long maxIdle, TimeUnit timeUnit) {
return timeToLive(timeUnit.toMillis(maxIdle));
}
}

@ -15,7 +15,9 @@
*/ */
package org.redisson.api; package org.redisson.api;
import io.netty.util.concurrent.Future; import java.util.concurrent.TimeUnit;
import io.netty.util.concurrent.FutureListener;
/** /**
* Represents the result of an asynchronous computation * Represents the result of an asynchronous computation
@ -24,6 +26,136 @@ import io.netty.util.concurrent.Future;
* *
* @param <V> * @param <V>
*/ */
public interface RFuture<V> extends Future<V> { public interface RFuture<V> extends java.util.concurrent.Future<V> {
/**
* Returns {@code true} if and only if the I/O operation was completed
* successfully.
*/
boolean isSuccess();
/**
* Returns the cause of the failed I/O operation if the I/O operation has
* failed.
*
* @return the cause of the failure.
* {@code null} if succeeded or this future is not
* completed yet.
*/
Throwable cause();
/**
* Return the result without blocking. If the future is not done yet this will return {@code null}.
*
* As it is possible that a {@code null} value is used to mark the future as successful you also need to check
* if the future is really done with {@link #isDone()} and not relay on the returned {@code null} value.
*/
V getNow();
/**
* Waits for this future to be completed within the
* specified time limit.
*
* @return {@code true} if and only if the future was completed within
* the specified time limit
*
* @throws InterruptedException
* if the current thread was interrupted
*/
boolean await(long timeout, TimeUnit unit) throws InterruptedException;
/**
* Waits for this future to be completed within the
* specified time limit.
*
* @return {@code true} if and only if the future was completed within
* the specified time limit
*
* @throws InterruptedException
* if the current thread was interrupted
*/
boolean await(long timeoutMillis) throws InterruptedException;
/**
* Adds the specified listener to this future. The
* specified listener is notified when this future is
* {@linkplain #isDone() done}. If this future is already
* completed, the specified listener is notified immediately.
*/
RFuture<V> addListener(FutureListener<? super V> listener);
/**
* Adds the specified listeners to this future. The
* specified listeners are notified when this future is
* {@linkplain #isDone() done}. If this future is already
* completed, the specified listeners are notified immediately.
*/
RFuture<V> addListeners(FutureListener<? super V>... listeners);
/**
* Removes the first occurrence of the specified listener from this future.
* The specified listener is no longer notified when this
* future is {@linkplain #isDone() done}. If the specified
* listener is not associated with this future, this method
* does nothing and returns silently.
*/
RFuture<V> removeListener(FutureListener<? super V> listener);
/**
* Removes the first occurrence for each of the listeners from this future.
* The specified listeners are no longer notified when this
* future is {@linkplain #isDone() done}. If the specified
* listeners are not associated with this future, this method
* does nothing and returns silently.
*/
RFuture<V> removeListeners(FutureListener<? super V>... listeners);
/**
* Waits for this future until it is done, and rethrows the cause of the failure if this future
* failed.
*/
RFuture<V> sync() throws InterruptedException;
/**
* Waits for this future until it is done, and rethrows the cause of the failure if this future
* failed.
*/
RFuture<V> syncUninterruptibly();
/**
* Waits for this future to be completed.
*
* @throws InterruptedException
* if the current thread was interrupted
*/
RFuture<V> await() throws InterruptedException;
/**
* Waits for this future to be completed without
* interruption. This method catches an {@link InterruptedException} and
* discards it silently.
*/
RFuture<V> awaitUninterruptibly();
/**
* Waits for this future to be completed within the
* specified time limit without interruption. This method catches an
* {@link InterruptedException} and discards it silently.
*
* @return {@code true} if and only if the future was completed within
* the specified time limit
*/
boolean awaitUninterruptibly(long timeout, TimeUnit unit);
/**
* Waits for this future to be completed within the
* specified time limit without interruption. This method catches an
* {@link InterruptedException} and discards it silently.
*
* @return {@code true} if and only if the future was completed within
* the specified time limit
*/
boolean awaitUninterruptibly(long timeoutMillis);
} }

@ -81,8 +81,10 @@ public interface RListAsync<V> extends RCollectionAsync<V>, RandomAccess {
* @param toIndex * @param toIndex
* @return * @return
*/ */
RFuture<Void> trimAsync(int fromIndex, int toIndex); RFuture<Void> trimAsync(long fromIndex, long toIndex);
RFuture<Void> fastRemoveAsync(int index); RFuture<Void> fastRemoveAsync(long index);
RFuture<V> removeAsync(long index);
} }

@ -0,0 +1,58 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.api;
import java.util.Map;
/**
* Map object with entry cache support.
* <p>
* Each instance maintains local cache to achieve fast read operations.
* Suitable for maps which used mostly for read operations and network roundtrip delays are undesirable.
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public interface RLocalCachedMap<K, V> extends Map<K, V>, RExpirable, RLocalCachedMapAsync<K, V> {
/**
* Associates the specified <code>value</code> with the specified <code>key</code>.
* <p>
* Works faster than <code>RLocalCachedMap.put</code> but not returning
* the previous value associated with <code>key</code>
*
* @param key
* @param value
* @return <code>true</code> if key is a new key in the hash and value was set.
* <code>false</code> if key already exists in the hash and the value was updated.
*/
boolean fastPut(K key, V value);
/**
* Removes <code>key</code> from map
* <p>
* Works faster than <code>RLocalCachedMap.remove</code> but not returning
* the value associated with <code>key</code>
*
* @param key
* @return <code>true</code> if key has been deleted.
* <code>false</code> if key doesn't exist.
*/
boolean fastRemove(Object key);
}

@ -0,0 +1,100 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.api;
/**
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public interface RLocalCachedMapAsync<K, V> extends RExpirableAsync {
/**
* Returns map size
*
* @return
*/
RFuture<Integer> sizeAsync();
/**
* Checks if map contains the specified <code>key</code>
*
* @return <code>true</code> if map contains <code>key</code>.
* <code>false</code> if map doesn't contain <code>key</code>.
*/
RFuture<Boolean> containsKeyAsync(Object key);
/**
* Checks if map contains the specified <code>value</code>
*
* @return <code>true</code> if map contains <code>value</code>.
* <code>false</code> if map doesn't contain <code>value</code>.
*/
RFuture<Boolean> containsValueAsync(Object value);
/**
* Returns value associated with <code>key</code>
*
* @param key
* @return
*/
RFuture<V> getAsync(Object key);
/**
* Associates the specified <code>value</code> with the specified <code>key</code>.
*
* @param key
* @param value
* @return previous value associated with <code>key</code>
*/
RFuture<V> putAsync(K key, V value);
/**
* Removes <code>key</code> from map.
*
* @param key
* @return removed value associated with <code>key</code>
*/
RFuture<V> removeAsync(K key);
/**
* Removes <code>key</code> from map
* <p>
* Works faster than <code>RLocalCachedMap.remove</code> but not returning
* the value associated with <code>key</code>
*
* @param key
* @return <code>true</code> if key has been deleted.
* <code>false</code> if key doesn't exist.
*/
RFuture<Boolean> fastRemoveAsync(K key);
/**
* Associates the specified <code>value</code> with the specified <code>key</code>.
* <p>
* Works faster than <code>RLocalCachedMap.put</code> but not returning
* the previous value associated with <code>key</code>
*
* @param key
* @param value
* @return <code>true</code> if key is a new key in the hash and value was set.
* <code>false</code> if key already exists in the hash and the value was updated.
*/
RFuture<Boolean> fastPutAsync(K key, V value);
}

@ -207,6 +207,27 @@ public interface RedissonClient {
*/ */
<K, V> RListMultimapCache<K, V> getListMultimapCache(String name, Codec codec); <K, V> RListMultimapCache<K, V> getListMultimapCache(String name, Codec codec);
/**
* Returns local cached map instance by name.
* Configured by parameters of options-object.
*
* @param name
* @param options
* @return
*/
<K, V> RLocalCachedMap<K, V> getLocalCachedMap(String name, LocalCachedMapOptions options);
/**
* Returns local cached map instance by name
* using provided codec. Configured by parameters of options-object.
*
* @param name
* @param codec
* @param options
* @return
*/
<K, V> RLocalCachedMap<K, V> getLocalCachedMap(String name, Codec codec, LocalCachedMapOptions options);
/** /**
* Returns map instance by name. * Returns map instance by name.
* *

@ -15,10 +15,10 @@
*/ */
package org.redisson.client; package org.redisson.client;
import io.netty.util.concurrent.Promise; import org.redisson.misc.RPromise;
public interface ReconnectListener { public interface ReconnectListener {
void onReconnect(RedisConnection redisConnection, Promise<RedisConnection> connectionFuture) throws RedisException; void onReconnect(RedisConnection redisConnection, RPromise<RedisConnection> connectionFuture) throws RedisException;
} }

@ -19,12 +19,15 @@ import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import org.redisson.api.RFuture;
import org.redisson.client.handler.CommandBatchEncoder; import org.redisson.client.handler.CommandBatchEncoder;
import org.redisson.client.handler.CommandDecoder; import org.redisson.client.handler.CommandDecoder;
import org.redisson.client.handler.CommandEncoder; import org.redisson.client.handler.CommandEncoder;
import org.redisson.client.handler.CommandsQueue; import org.redisson.client.handler.CommandsQueue;
import org.redisson.client.handler.ConnectionWatchdog; import org.redisson.client.handler.ConnectionWatchdog;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.redisson.misc.URIBuilder; import org.redisson.misc.URIBuilder;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
@ -43,10 +46,9 @@ import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.HashedWheelTimer; import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer; import io.netty.util.Timer;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.ImmediateEventExecutor; import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
/** /**
* Low-level Redis client * Low-level Redis client
@ -128,8 +130,8 @@ public class RedisClient {
} }
} }
public Future<RedisConnection> connectAsync() { public RFuture<RedisConnection> connectAsync() {
final Promise<RedisConnection> f = ImmediateEventExecutor.INSTANCE.newPromise(); final RPromise<RedisConnection> f = new RedissonPromise<RedisConnection>(ImmediateEventExecutor.INSTANCE.<RedisConnection>newPromise());
ChannelFuture channelFuture = bootstrap.connect(); ChannelFuture channelFuture = bootstrap.connect();
channelFuture.addListener(new ChannelFutureListener() { channelFuture.addListener(new ChannelFutureListener() {
@Override @Override
@ -155,8 +157,8 @@ public class RedisClient {
} }
} }
public Future<RedisPubSubConnection> connectPubSubAsync() { public RFuture<RedisPubSubConnection> connectPubSubAsync() {
final Promise<RedisPubSubConnection> f = ImmediateEventExecutor.INSTANCE.newPromise(); final RPromise<RedisPubSubConnection> f = new RedissonPromise<RedisPubSubConnection>(ImmediateEventExecutor.INSTANCE.<RedisPubSubConnection>newPromise());
ChannelFuture channelFuture = bootstrap.connect(); ChannelFuture channelFuture = bootstrap.connect();
channelFuture.addListener(new ChannelFutureListener() { channelFuture.addListener(new ChannelFutureListener() {
@Override @Override
@ -206,12 +208,12 @@ public class RedisClient {
* @return A future for a map extracted from each response line splitting by * @return A future for a map extracted from each response line splitting by
* ':' symbol * ':' symbol
*/ */
public Future<Map<String, String>> serverInfoAsync() { public RFuture<Map<String, String>> serverInfoAsync() {
final RedisConnection connection = connect(); final RedisConnection connection = connect();
Promise<Map<String, String>> async = (Promise) connection.async(RedisCommands.SERVER_INFO); RFuture<Map<String, String>> async = connection.async(RedisCommands.SERVER_INFO);
async.addListener(new GenericFutureListener<Promise<Map<String, String>>>() { async.addListener(new FutureListener<Map<String, String>>() {
@Override @Override
public void operationComplete(Promise<Map<String, String>> future) throws Exception { public void operationComplete(Future<Map<String, String>> future) throws Exception {
connection.closeAsync(); connection.closeAsync();
} }
}); });

@ -18,6 +18,7 @@ package org.redisson.client;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.handler.CommandsQueue; import org.redisson.client.handler.CommandsQueue;
import org.redisson.client.protocol.CommandData; import org.redisson.client.protocol.CommandData;
@ -26,6 +27,9 @@ import org.redisson.client.protocol.QueueCommand;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand; import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonFuture;
import org.redisson.misc.RedissonPromise;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@ -49,7 +53,7 @@ public class RedisConnection implements RedisCommands {
private ReconnectListener reconnectListener; private ReconnectListener reconnectListener;
private long lastUsageTime; private long lastUsageTime;
private final Future<?> acquireFuture = ImmediateEventExecutor.INSTANCE.newSucceededFuture(this); private final RFuture<?> acquireFuture = new RedissonFuture(ImmediateEventExecutor.INSTANCE.newSucceededFuture(this));
public RedisConnection(RedisClient redisClient, Channel channel) { public RedisConnection(RedisClient redisClient, Channel channel) {
super(); super();
@ -109,7 +113,7 @@ public class RedisConnection implements RedisCommands {
return redisClient; return redisClient;
} }
public <R> R await(Future<R> future) { public <R> R await(RFuture<R> future) {
final CountDownLatch l = new CountDownLatch(1); final CountDownLatch l = new CountDownLatch(1);
future.addListener(new FutureListener<R>() { future.addListener(new FutureListener<R>() {
@Override @Override
@ -151,25 +155,25 @@ public class RedisConnection implements RedisCommands {
} }
public <T, R> R sync(Codec encoder, RedisCommand<T> command, Object ... params) { public <T, R> R sync(Codec encoder, RedisCommand<T> command, Object ... params) {
Promise<R> promise = ImmediateEventExecutor.INSTANCE.newPromise(); RPromise<R> promise = new RedissonPromise<R>(ImmediateEventExecutor.INSTANCE.<R>newPromise());
send(new CommandData<T, R>(promise, encoder, command, params)); send(new CommandData<T, R>(promise, encoder, command, params));
return await(promise); return await(promise);
} }
public <T, R> Future<R> async(RedisCommand<T> command, Object ... params) { public <T, R> RFuture<R> async(RedisCommand<T> command, Object ... params) {
return async(null, command, params); return async(null, command, params);
} }
public <T, R> Future<R> async(long timeout, RedisCommand<T> command, Object ... params) { public <T, R> RFuture<R> async(long timeout, RedisCommand<T> command, Object ... params) {
return async(null, command, params); return async(null, command, params);
} }
public <T, R> Future<R> async(Codec encoder, RedisCommand<T> command, Object ... params) { public <T, R> RFuture<R> async(Codec encoder, RedisCommand<T> command, Object ... params) {
return async(-1, encoder, command, params); return async(-1, encoder, command, params);
} }
public <T, R> Future<R> async(long timeout, Codec encoder, RedisCommand<T> command, Object ... params) { public <T, R> RFuture<R> async(long timeout, Codec encoder, RedisCommand<T> command, Object ... params) {
final Promise<R> promise = ImmediateEventExecutor.INSTANCE.newPromise(); final RPromise<R> promise = new RedissonPromise<R>(ImmediateEventExecutor.INSTANCE.<R>newPromise());
if (timeout == -1) { if (timeout == -1) {
timeout = redisClient.getCommandTimeout(); timeout = redisClient.getCommandTimeout();
} }
@ -193,7 +197,7 @@ public class RedisConnection implements RedisCommands {
} }
public <T, R> CommandData<T, R> create(Codec encoder, RedisCommand<T> command, Object ... params) { public <T, R> CommandData<T, R> create(Codec encoder, RedisCommand<T> command, Object ... params) {
Promise<R> promise = ImmediateEventExecutor.INSTANCE.newPromise(); RPromise<R> promise = new RedissonPromise<R>(ImmediateEventExecutor.INSTANCE.<R>newPromise());
return new CommandData<T, R>(promise, encoder, command, params); return new CommandData<T, R>(promise, encoder, command, params);
} }
@ -237,7 +241,7 @@ public class RedisConnection implements RedisCommands {
return getClass().getSimpleName() + "@" + System.identityHashCode(this) + " [redisClient=" + redisClient + ", channel=" + channel + "]"; return getClass().getSimpleName() + "@" + System.identityHashCode(this) + " [redisClient=" + redisClient + ", channel=" + channel + "]";
} }
public Future<?> getAcquireFuture() { public RFuture<?> getAcquireFuture() {
return acquireFuture; return acquireFuture;
} }

@ -23,6 +23,11 @@ import org.redisson.client.protocol.Encoder;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
/**
*
* @author Nikita Koksharov
*
*/
public class BitSetCodec implements Codec { public class BitSetCodec implements Codec {
public static final BitSetCodec INSTANCE = new BitSetCodec(); public static final BitSetCodec INSTANCE = new BitSetCodec();

@ -23,6 +23,11 @@ import org.redisson.client.protocol.Encoder;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
/**
*
* @author Nikita Koksharov
*
*/
public class ByteArrayCodec implements Codec { public class ByteArrayCodec implements Codec {
public static final ByteArrayCodec INSTANCE = new ByteArrayCodec(); public static final ByteArrayCodec INSTANCE = new ByteArrayCodec();

@ -25,6 +25,11 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
/**
*
* @author Nikita Koksharov
*
*/
public class ScanCodec implements Codec { public class ScanCodec implements Codec {
private final Codec delegate; private final Codec delegate;

@ -43,6 +43,7 @@ import org.redisson.client.protocol.pubsub.Message;
import org.redisson.client.protocol.pubsub.PubSubMessage; import org.redisson.client.protocol.pubsub.PubSubMessage;
import org.redisson.client.protocol.pubsub.PubSubPatternMessage; import org.redisson.client.protocol.pubsub.PubSubPatternMessage;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage; import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -51,7 +52,6 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.ReplayingDecoder;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
/** /**
@ -192,7 +192,7 @@ public class CommandDecoder extends ReplayingDecoder<State> {
} }
if (i == commandBatch.getCommands().size()) { if (i == commandBatch.getCommands().size()) {
Promise<Void> promise = commandBatch.getPromise(); RPromise<Void> promise = commandBatch.getPromise();
if (error != null) { if (error != null) {
if (!promise.tryFailure(error) && promise.cause() instanceof RedisTimeoutException) { if (!promise.tryFailure(error) && promise.cause() instanceof RedisTimeoutException) {
log.warn("response has been skipped due to timeout! channel: {}, command: {}", ctx.channel(), data); log.warn("response has been skipped due to timeout! channel: {}, command: {}", ctx.channel(), data);

@ -23,6 +23,8 @@ import org.redisson.client.RedisException;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.CommandData; import org.redisson.client.protocol.CommandData;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -39,7 +41,6 @@ import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor; import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { public class ConnectionWatchdog extends ChannelInboundHandlerAdapter {
@ -125,7 +126,7 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter {
if (connection.getReconnectListener() != null) { if (connection.getReconnectListener() != null) {
// new connection used only for channel init // new connection used only for channel init
RedisConnection rc = new RedisConnection(connection.getRedisClient(), channel); RedisConnection rc = new RedisConnection(connection.getRedisClient(), channel);
Promise<RedisConnection> connectionFuture = ImmediateEventExecutor.INSTANCE.newPromise(); RPromise<RedisConnection> connectionFuture = new RedissonPromise<RedisConnection>(ImmediateEventExecutor.INSTANCE.<RedisConnection>newPromise());
connection.getReconnectListener().onReconnect(rc, connectionFuture); connection.getReconnectListener().onReconnect(rc, connectionFuture);
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override

@ -19,15 +19,14 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.client.RedisRedirectException; import org.redisson.client.RedisRedirectException;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class BatchCommandData<T, R> extends CommandData<T, R> implements Comparable<BatchCommandData<T, R>> { public class BatchCommandData<T, R> extends CommandData<T, R> implements Comparable<BatchCommandData<T, R>> {
private final int index; private final int index;
private final AtomicReference<RedisRedirectException> redirectError = new AtomicReference<RedisRedirectException>(); private final AtomicReference<RedisRedirectException> redirectError = new AtomicReference<RedisRedirectException>();
public BatchCommandData(Promise<R> promise, Codec codec, RedisCommand<T> command, Object[] params, int index) { public BatchCommandData(RPromise<R> promise, Codec codec, RedisCommand<T> command, Object[] params, int index) {
super(promise, codec, command, params); super(promise, codec, command, params);
this.index = index; this.index = index;
} }

@ -21,22 +21,21 @@ import java.util.List;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.decoder.MultiDecoder; import org.redisson.client.protocol.decoder.MultiDecoder;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class CommandData<T, R> implements QueueCommand { public class CommandData<T, R> implements QueueCommand {
final Promise<R> promise; final RPromise<R> promise;
final RedisCommand<T> command; final RedisCommand<T> command;
final Object[] params; final Object[] params;
final Codec codec; final Codec codec;
final MultiDecoder<Object> messageDecoder; final MultiDecoder<Object> messageDecoder;
public CommandData(Promise<R> promise, Codec codec, RedisCommand<T> command, Object[] params) { public CommandData(RPromise<R> promise, Codec codec, RedisCommand<T> command, Object[] params) {
this(promise, null, codec, command, params); this(promise, null, codec, command, params);
} }
public CommandData(Promise<R> promise, MultiDecoder<Object> messageDecoder, Codec codec, RedisCommand<T> command, Object[] params) { public CommandData(RPromise<R> promise, MultiDecoder<Object> messageDecoder, Codec codec, RedisCommand<T> command, Object[] params) {
this.promise = promise; this.promise = promise;
this.command = command; this.command = command;
this.params = params; this.params = params;
@ -56,7 +55,7 @@ public class CommandData<T, R> implements QueueCommand {
return messageDecoder; return messageDecoder;
} }
public Promise<R> getPromise() { public RPromise<R> getPromise() {
return promise; return promise;
} }

@ -18,20 +18,20 @@ package org.redisson.client.protocol;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.netty.util.concurrent.Promise; import org.redisson.misc.RPromise;
public class CommandsData implements QueueCommand { public class CommandsData implements QueueCommand {
private final List<CommandData<?, ?>> commands; private final List<CommandData<?, ?>> commands;
private final Promise<Void> promise; private final RPromise<Void> promise;
public CommandsData(Promise<Void> promise, List<CommandData<?, ?>> commands) { public CommandsData(RPromise<Void> promise, List<CommandData<?, ?>> commands) {
super(); super();
this.promise = promise; this.promise = promise;
this.commands = commands; this.commands = commands;
} }
public Promise<Void> getPromise() { public RPromise<Void> getPromise() {
return promise; return promise;
} }

@ -113,7 +113,7 @@ public interface RedisCommands {
RedisCommand<List<ScoredEntry<Object>>> ZRANGE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGE", new ScoredSortedSetReplayDecoder<Object>()); RedisCommand<List<ScoredEntry<Object>>> ZRANGE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGE", new ScoredSortedSetReplayDecoder<Object>());
RedisCommand<List<ScoredEntry<Object>>> ZRANGEBYSCORE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGEBYSCORE", new ScoredSortedSetReplayDecoder<Object>()); RedisCommand<List<ScoredEntry<Object>>> ZRANGEBYSCORE_ENTRY = new RedisCommand<List<ScoredEntry<Object>>>("ZRANGEBYSCORE", new ScoredSortedSetReplayDecoder<Object>());
RedisCommand<ListScanResult<Object>> ZSCAN = new RedisCommand<ListScanResult<Object>>("ZSCAN", new NestedMultiDecoder(new ScoredSortedSetScanDecoder<Object>(), new ScoredSortedSetScanReplayDecoder()), ValueType.OBJECT); RedisCommand<ListScanResult<Object>> ZSCAN = new RedisCommand<ListScanResult<Object>>("ZSCAN", new NestedMultiDecoder(new ScoredSortedSetScanDecoder<Object>(), new ScoredSortedSetScanReplayDecoder()), ValueType.OBJECT);
RedisStrictCommand<Double> ZINCRBY = new RedisStrictCommand<Double>("ZINCRBY", new DoubleReplayConvertor(), 4); RedisStrictCommand<Double> ZINCRBY = new RedisStrictCommand<Double>("ZINCRBY", new DoubleReplayConvertor());
RedisCommand<ListScanResult<String>> SCAN = new RedisCommand<ListScanResult<String>>("SCAN", new NestedMultiDecoder(new ObjectListReplayDecoder<String>(), new ListScanResultReplayDecoder()), ValueType.OBJECT); RedisCommand<ListScanResult<String>> SCAN = new RedisCommand<ListScanResult<String>>("SCAN", new NestedMultiDecoder(new ObjectListReplayDecoder<String>(), new ListScanResultReplayDecoder()), ValueType.OBJECT);
RedisStrictCommand<String> RANDOM_KEY = new RedisStrictCommand<String>("RANDOMKEY", new StringDataDecoder()); RedisStrictCommand<String> RANDOM_KEY = new RedisStrictCommand<String>("RANDOMKEY", new StringDataDecoder());

@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException; import org.redisson.client.RedisConnectionException;
@ -46,13 +47,13 @@ import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import org.redisson.connection.MasterSlaveConnectionManager; import org.redisson.connection.MasterSlaveConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.SingleEntry; import org.redisson.connection.SingleEntry;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture; import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
@ -77,7 +78,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Exception lastException = null; Exception lastException = null;
for (URI addr : cfg.getNodeAddresses()) { for (URI addr : cfg.getNodeAddresses()) {
Future<RedisConnection> connectionFuture = connect(cfg, addr); RFuture<RedisConnection> connectionFuture = connect(cfg, addr);
try { try {
RedisConnection connection = connectionFuture.syncUninterruptibly().getNow(); RedisConnection connection = connectionFuture.syncUninterruptibly().getNow();
List<ClusterNodeInfo> nodes = connection.sync(RedisCommands.CLUSTER_NODES); List<ClusterNodeInfo> nodes = connection.sync(RedisCommands.CLUSTER_NODES);
@ -93,21 +94,21 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
lastClusterNode = addr; lastClusterNode = addr;
Collection<ClusterPartition> partitions = parsePartitions(nodes); Collection<ClusterPartition> partitions = parsePartitions(nodes);
List<Future<Collection<Future<Void>>>> futures = new ArrayList<Future<Collection<Future<Void>>>>(); List<RFuture<Collection<RFuture<Void>>>> futures = new ArrayList<RFuture<Collection<RFuture<Void>>>>();
for (ClusterPartition partition : partitions) { for (ClusterPartition partition : partitions) {
if (partition.isMasterFail()) { if (partition.isMasterFail()) {
continue; continue;
} }
Future<Collection<Future<Void>>> masterFuture = addMasterEntry(partition, cfg); RFuture<Collection<RFuture<Void>>> masterFuture = addMasterEntry(partition, cfg);
futures.add(masterFuture); futures.add(masterFuture);
} }
for (Future<Collection<Future<Void>>> masterFuture : futures) { for (RFuture<Collection<RFuture<Void>>> masterFuture : futures) {
masterFuture.awaitUninterruptibly(); masterFuture.awaitUninterruptibly();
if (!masterFuture.isSuccess()) { if (!masterFuture.isSuccess()) {
continue; continue;
} }
for (Future<Void> future : masterFuture.getNow()) { for (RFuture<Void> future : masterFuture.getNow()) {
future.awaitUninterruptibly(); future.awaitUninterruptibly();
if (!future.isSuccess()) { if (!future.isSuccess()) {
continue; continue;
@ -140,15 +141,15 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
} }
private Future<RedisConnection> connect(ClusterServersConfig cfg, final URI addr) { private RFuture<RedisConnection> connect(ClusterServersConfig cfg, final URI addr) {
RedisConnection connection = nodeConnections.get(addr); RedisConnection connection = nodeConnections.get(addr);
if (connection != null) { if (connection != null) {
return newSucceededFuture(connection); return newSucceededFuture(connection);
} }
RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts());
final Promise<RedisConnection> result = newPromise(); final RPromise<RedisConnection> result = newPromise();
Future<RedisConnection> future = client.connectAsync(); RFuture<RedisConnection> future = client.connectAsync();
future.addListener(new FutureListener<RedisConnection>() { future.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -158,7 +159,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
RedisConnection connection = future.getNow(); RedisConnection connection = future.getNow();
Promise<RedisConnection> promise = newPromise(); RPromise<RedisConnection> promise = newPromise();
connectListener.onConnect(promise, connection, null, config); connectListener.onConnect(promise, connection, null, config);
promise.addListener(new FutureListener<RedisConnection>() { promise.addListener(new FutureListener<RedisConnection>() {
@Override @Override
@ -188,7 +189,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
protected void initEntry(MasterSlaveServersConfig config) { protected void initEntry(MasterSlaveServersConfig config) {
} }
private Future<Collection<Future<Void>>> addMasterEntry(final ClusterPartition partition, final ClusterServersConfig cfg) { private RFuture<Collection<RFuture<Void>>> addMasterEntry(final ClusterPartition partition, final ClusterServersConfig cfg) {
if (partition.isMasterFail()) { if (partition.isMasterFail()) {
RedisException e = new RedisException("Failed to add master: " + RedisException e = new RedisException("Failed to add master: " +
partition.getMasterAddress() + " for slot ranges: " + partition.getMasterAddress() + " for slot ranges: " +
@ -201,8 +202,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return newFailedFuture(e); return newFailedFuture(e);
} }
final Promise<Collection<Future<Void>>> result = newPromise(); final RPromise<Collection<RFuture<Void>>> result = newPromise();
Future<RedisConnection> connectionFuture = connect(cfg, partition.getMasterAddress()); RFuture<RedisConnection> connectionFuture = connect(cfg, partition.getMasterAddress());
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -213,7 +214,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
final RedisConnection connection = future.getNow(); final RedisConnection connection = future.getNow();
Future<Map<String, String>> clusterFuture = connection.async(RedisCommands.CLUSTER_INFO); RFuture<Map<String, String>> clusterFuture = connection.async(RedisCommands.CLUSTER_INFO);
clusterFuture.addListener(new FutureListener<Map<String, String>>() { clusterFuture.addListener(new FutureListener<Map<String, String>>() {
@Override @Override
@ -238,7 +239,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
config.setMasterAddress(partition.getMasterAddress()); config.setMasterAddress(partition.getMasterAddress());
final MasterSlaveEntry e; final MasterSlaveEntry e;
List<Future<Void>> futures = new ArrayList<Future<Void>>(); List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>();
if (config.getReadMode() == ReadMode.MASTER) { if (config.getReadMode() == ReadMode.MASTER) {
e = new SingleEntry(partition.getSlotRanges(), ClusterConnectionManager.this, config); e = new SingleEntry(partition.getSlotRanges(), ClusterConnectionManager.this, config);
} else { } else {
@ -246,7 +247,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
e = new MasterSlaveEntry(partition.getSlotRanges(), ClusterConnectionManager.this, config); e = new MasterSlaveEntry(partition.getSlotRanges(), ClusterConnectionManager.this, config);
List<Future<Void>> fs = e.initSlaveBalancer(partition.getFailedSlaveAddresses()); List<RFuture<Void>> fs = e.initSlaveBalancer(partition.getFailedSlaveAddresses());
futures.addAll(fs); futures.addAll(fs);
if (!partition.getSlaveAddresses().isEmpty()) { if (!partition.getSlaveAddresses().isEmpty()) {
log.info("slaves: {} added for slot ranges: {}", partition.getSlaveAddresses(), partition.getSlotRanges()); log.info("slaves: {} added for slot ranges: {}", partition.getSlaveAddresses(), partition.getSlotRanges());
@ -256,8 +257,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
} }
Future<Void> f = e.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); RFuture<Void> f = e.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort());
final Promise<Void> initFuture = newPromise(); final RPromise<Void> initFuture = newPromise();
futures.add(initFuture); futures.add(initFuture);
f.addListener(new FutureListener<Void>() { f.addListener(new FutureListener<Void>() {
@Override @Override
@ -295,9 +296,6 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
if (nodesIterator == null) { if (nodesIterator == null) {
List<URI> nodes = new ArrayList<URI>(); List<URI> nodes = new ArrayList<URI>();
List<URI> slaves = new ArrayList<URI>(); List<URI> slaves = new ArrayList<URI>();
if (lastPartitions.isEmpty()) {
System.out.println("lastPartitions.isEmpty()");
}
for (ClusterPartition partition : getLastPartitions()) { for (ClusterPartition partition : getLastPartitions()) {
if (!partition.isMasterFail()) { if (!partition.isMasterFail()) {
@ -327,7 +325,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return; return;
} }
final URI uri = iterator.next(); final URI uri = iterator.next();
Future<RedisConnection> connectionFuture = connect(cfg, uri); RFuture<RedisConnection> connectionFuture = connect(cfg, uri);
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -344,7 +342,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
private void updateClusterState(final ClusterServersConfig cfg, final RedisConnection connection, final Iterator<URI> iterator, final URI uri) { private void updateClusterState(final ClusterServersConfig cfg, final RedisConnection connection, final Iterator<URI> iterator, final URI uri) {
Future<List<ClusterNodeInfo>> future = connection.async(RedisCommands.CLUSTER_NODES); RFuture<List<ClusterNodeInfo>> future = connection.async(RedisCommands.CLUSTER_NODES);
future.addListener(new FutureListener<List<ClusterNodeInfo>>() { future.addListener(new FutureListener<List<ClusterNodeInfo>>() {
@Override @Override
public void operationComplete(Future<List<ClusterNodeInfo>> future) throws Exception { public void operationComplete(Future<List<ClusterNodeInfo>> future) throws Exception {
@ -367,7 +365,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
final Collection<ClusterPartition> newPartitions = parsePartitions(nodes); final Collection<ClusterPartition> newPartitions = parsePartitions(nodes);
Future<Void> masterFuture = checkMasterNodesChange(cfg, newPartitions); RFuture<Void> masterFuture = checkMasterNodesChange(cfg, newPartitions);
checkSlaveNodesChange(newPartitions); checkSlaveNodesChange(newPartitions);
masterFuture.addListener(new FutureListener<Void>() { masterFuture.addListener(new FutureListener<Void>() {
@Override @Override
@ -390,17 +388,18 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
MasterSlaveEntry entry = getEntry(currentPart.getMasterAddr()); MasterSlaveEntry entry = getEntry(currentPart.getMasterAddr());
// should be invoked first in order to remove stale failedSlaveAddresses // should be invoked first in order to remove stale failedSlaveAddresses
addRemoveSlaves(entry, currentPart, newPart); Set<URI> addedSlaves = addRemoveSlaves(entry, currentPart, newPart);
// Does some slaves change failed state to alive? // Do some slaves have changed state from failed to alive?
upDownSlaves(entry, currentPart, newPart); upDownSlaves(entry, currentPart, newPart, addedSlaves);
break; break;
} }
} }
} }
private void upDownSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart) { private void upDownSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart, Set<URI> addedSlaves) {
Set<URI> aliveSlaves = new HashSet<URI>(currentPart.getFailedSlaveAddresses()); Set<URI> aliveSlaves = new HashSet<URI>(currentPart.getFailedSlaveAddresses());
aliveSlaves.removeAll(addedSlaves);
aliveSlaves.removeAll(newPart.getFailedSlaveAddresses()); aliveSlaves.removeAll(newPart.getFailedSlaveAddresses());
for (URI uri : aliveSlaves) { for (URI uri : aliveSlaves) {
currentPart.removeFailedSlaveAddress(uri); currentPart.removeFailedSlaveAddress(uri);
@ -419,7 +418,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
} }
private void addRemoveSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart) { private Set<URI> addRemoveSlaves(final MasterSlaveEntry entry, final ClusterPartition currentPart, final ClusterPartition newPart) {
Set<URI> removedSlaves = new HashSet<URI>(currentPart.getSlaveAddresses()); Set<URI> removedSlaves = new HashSet<URI>(currentPart.getSlaveAddresses());
removedSlaves.removeAll(newPart.getSlaveAddresses()); removedSlaves.removeAll(newPart.getSlaveAddresses());
@ -434,7 +433,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Set<URI> addedSlaves = new HashSet<URI>(newPart.getSlaveAddresses()); Set<URI> addedSlaves = new HashSet<URI>(newPart.getSlaveAddresses());
addedSlaves.removeAll(currentPart.getSlaveAddresses()); addedSlaves.removeAll(currentPart.getSlaveAddresses());
for (final URI uri : addedSlaves) { for (final URI uri : addedSlaves) {
Future<Void> future = entry.addSlave(uri.getHost(), uri.getPort()); RFuture<Void> future = entry.addSlave(uri.getHost(), uri.getPort());
future.addListener(new FutureListener<Void>() { future.addListener(new FutureListener<Void>() {
@Override @Override
public void operationComplete(Future<Void> future) throws Exception { public void operationComplete(Future<Void> future) throws Exception {
@ -449,6 +448,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
} }
}); });
} }
return addedSlaves;
} }
private Collection<Integer> slots(Collection<ClusterPartition> partitions) { private Collection<Integer> slots(Collection<ClusterPartition> partitions) {
@ -470,7 +470,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return null; return null;
} }
private Future<Void> checkMasterNodesChange(ClusterServersConfig cfg, Collection<ClusterPartition> newPartitions) { private RFuture<Void> checkMasterNodesChange(ClusterServersConfig cfg, Collection<ClusterPartition> newPartitions) {
List<ClusterPartition> newMasters = new ArrayList<ClusterPartition>(); List<ClusterPartition> newMasters = new ArrayList<ClusterPartition>();
for (final ClusterPartition newPart : newPartitions) { for (final ClusterPartition newPart : newPartitions) {
boolean masterFound = false; boolean masterFound = false;
@ -509,21 +509,21 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return newSucceededFuture(null); return newSucceededFuture(null);
} }
final Promise<Void> result = newPromise(); final RPromise<Void> result = newPromise();
final AtomicInteger masters = new AtomicInteger(newMasters.size()); final AtomicInteger masters = new AtomicInteger(newMasters.size());
final Queue<Future<Void>> futures = new ConcurrentLinkedQueue<Future<Void>>(); final Queue<RFuture<Void>> futures = new ConcurrentLinkedQueue<RFuture<Void>>();
for (ClusterPartition newPart : newMasters) { for (ClusterPartition newPart : newMasters) {
Future<Collection<Future<Void>>> future = addMasterEntry(newPart, cfg); RFuture<Collection<RFuture<Void>>> future = addMasterEntry(newPart, cfg);
future.addListener(new FutureListener<Collection<Future<Void>>>() { future.addListener(new FutureListener<Collection<RFuture<Void>>>() {
@Override @Override
public void operationComplete(Future<Collection<Future<Void>>> future) throws Exception { public void operationComplete(Future<Collection<RFuture<Void>>> future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
futures.addAll(future.getNow()); futures.addAll(future.getNow());
} }
if (masters.decrementAndGet() == 0) { if (masters.decrementAndGet() == 0) {
final AtomicInteger nodes = new AtomicInteger(futures.size()); final AtomicInteger nodes = new AtomicInteger(futures.size());
for (Future<Void> nodeFuture : futures) { for (RFuture<Void> nodeFuture : futures) {
nodeFuture.addListener(new FutureListener<Void>() { nodeFuture.addListener(new FutureListener<Void>() {
@Override @Override
public void operationComplete(Future<Void> future) throws Exception { public void operationComplete(Future<Void> future) throws Exception {

@ -34,6 +34,11 @@ import com.esotericsoftware.kryo.io.Output;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufInputStream;
/**
*
* @author Nikita Koksharov
*
*/
public class KryoCodec implements Codec { public class KryoCodec implements Codec {
public interface KryoPool { public interface KryoPool {

@ -17,32 +17,32 @@ package org.redisson.command;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisException; import org.redisson.client.RedisException;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.decoder.MultiDecoder;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.NodeSource; import org.redisson.connection.NodeSource;
import org.redisson.misc.RPromise;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.util.Timeout; import io.netty.util.Timeout;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
public class AsyncDetails<V, R> { public class AsyncDetails<V, R> {
static final ConcurrentLinkedQueue<AsyncDetails> queue = new ConcurrentLinkedQueue<AsyncDetails>(); static final ConcurrentLinkedQueue<AsyncDetails> queue = new ConcurrentLinkedQueue<AsyncDetails>();
Future<RedisConnection> connectionFuture; RFuture<RedisConnection> connectionFuture;
ConnectionManager connectionManager; ConnectionManager connectionManager;
Promise<R> attemptPromise; RPromise<R> attemptPromise;
boolean readOnlyMode; boolean readOnlyMode;
NodeSource source; NodeSource source;
Codec codec; Codec codec;
RedisCommand<V> command; RedisCommand<V> command;
Object[] params; Object[] params;
Promise<R> mainPromise; RPromise<R> mainPromise;
int attempt; int attempt;
@ -69,10 +69,10 @@ public class AsyncDetails<V, R> {
// queue.add(details); // queue.add(details);
} }
public void init(Future<RedisConnection> connectionFuture, public void init(RFuture<RedisConnection> connectionFuture,
Promise<R> attemptPromise, boolean readOnlyMode, NodeSource source, RPromise<R> attemptPromise, boolean readOnlyMode, NodeSource source,
Codec codec, RedisCommand<V> command, Object[] params, Codec codec, RedisCommand<V> command, Object[] params,
Promise<R> mainPromise, int attempt) { RPromise<R> mainPromise, int attempt) {
this.connectionFuture = connectionFuture; this.connectionFuture = connectionFuture;
this.attemptPromise = attemptPromise; this.attemptPromise = attemptPromise;
this.readOnlyMode = readOnlyMode; this.readOnlyMode = readOnlyMode;
@ -108,11 +108,11 @@ public class AsyncDetails<V, R> {
this.timeout = timeout; this.timeout = timeout;
} }
public Future<RedisConnection> getConnectionFuture() { public RFuture<RedisConnection> getConnectionFuture() {
return connectionFuture; return connectionFuture;
} }
public Promise<R> getAttemptPromise() { public RPromise<R> getAttemptPromise() {
return attemptPromise; return attemptPromise;
} }
@ -136,7 +136,7 @@ public class AsyncDetails<V, R> {
return params; return params;
} }
public Promise<R> getMainPromise() { public RPromise<R> getMainPromise() {
return mainPromise; return mainPromise;
} }

@ -42,11 +42,11 @@ public interface CommandAsyncExecutor {
CommandAsyncExecutor enableRedissonReferenceSupport(Redisson redisson); CommandAsyncExecutor enableRedissonReferenceSupport(Redisson redisson);
<V> RedisException convertException(Future<V> RFuture); <V> RedisException convertException(RFuture<V> RFuture);
boolean await(Future<?> RFuture, long timeout, TimeUnit timeoutUnit) throws InterruptedException; boolean await(RFuture<?> RFuture, long timeout, TimeUnit timeoutUnit) throws InterruptedException;
<V> V get(Future<V> RFuture); <V> V get(RFuture<V> RFuture);
<T, R> RFuture<R> writeAsync(MasterSlaveEntry entry, Codec codec, RedisCommand<T> command, Object ... params); <T, R> RFuture<R> writeAsync(MasterSlaveEntry entry, Codec codec, RedisCommand<T> command, Object ... params);

@ -95,7 +95,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} }
@Override @Override
public <V> V get(Future<V> future) { public <V> V get(RFuture<V> future) {
final CountDownLatch l = new CountDownLatch(1); final CountDownLatch l = new CountDownLatch(1);
future.addListener(new FutureListener<V>() { future.addListener(new FutureListener<V>() {
@Override @Override
@ -127,7 +127,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} }
@Override @Override
public boolean await(Future<?> future, long timeout, TimeUnit timeoutUnit) throws InterruptedException { public boolean await(RFuture<?> future, long timeout, TimeUnit timeoutUnit) throws InterruptedException {
final CountDownLatch l = new CountDownLatch(1); final CountDownLatch l = new CountDownLatch(1);
future.addListener(new FutureListener<Object>() { future.addListener(new FutureListener<Object>() {
@Override @Override
@ -186,7 +186,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}; };
for (MasterSlaveEntry entry : nodes) { for (MasterSlaveEntry entry : nodes) {
Promise<R> promise = connectionManager.newPromise(); RPromise<R> promise = connectionManager.newPromise();
promise.addListener(listener); promise.addListener(listener);
async(true, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0); async(true, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0);
} }
@ -203,7 +203,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
return mainPromise; return mainPromise;
} }
private <R, T> void retryReadRandomAsync(final RedisCommand<T> command, final Promise<R> mainPromise, private <R, T> void retryReadRandomAsync(final RedisCommand<T> command, final RPromise<R> mainPromise,
final List<MasterSlaveEntry> nodes, final Object... params) { final List<MasterSlaveEntry> nodes, final Object... params) {
final RPromise<R> attemptPromise = connectionManager.newPromise(); final RPromise<R> attemptPromise = connectionManager.newPromise();
attemptPromise.addListener(new FutureListener<R>() { attemptPromise.addListener(new FutureListener<R>() {
@ -270,14 +270,14 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}; };
for (MasterSlaveEntry entry : nodes) { for (MasterSlaveEntry entry : nodes) {
Promise<T> promise = connectionManager.newPromise(); RPromise<T> promise = connectionManager.newPromise();
promise.addListener(listener); promise.addListener(listener);
async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0); async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0);
} }
return mainPromise; return mainPromise;
} }
public <V> RedisException convertException(Future<V> future) { public <V> RedisException convertException(RFuture<V> future) {
return future.cause() instanceof RedisException ? return future.cause() instanceof RedisException ?
(RedisException) future.cause() : (RedisException) future.cause() :
new RedisException("Unexpected exception while processing command", future.cause()); new RedisException("Unexpected exception while processing command", future.cause());
@ -398,7 +398,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
args.addAll(keys); args.addAll(keys);
args.addAll(Arrays.asList(params)); args.addAll(Arrays.asList(params));
for (MasterSlaveEntry entry : entries) { for (MasterSlaveEntry entry : entries) {
Promise<T> promise = connectionManager.newPromise(); RPromise<T> promise = connectionManager.newPromise();
promise.addListener(listener); promise.addListener(listener);
async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, args.toArray(), promise, 0); async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, args.toArray(), promise, 0);
} }
@ -430,7 +430,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} }
protected <V, R> void async(final boolean readOnlyMode, final NodeSource source, final Codec codec, protected <V, R> void async(final boolean readOnlyMode, final NodeSource source, final Codec codec,
final RedisCommand<V> command, final Object[] params, final Promise<R> mainPromise, final int attempt) { final RedisCommand<V> command, final Object[] params, final RPromise<R> mainPromise, final int attempt) {
if (mainPromise.isCancelled()) { if (mainPromise.isCancelled()) {
return; return;
} }
@ -440,9 +440,9 @@ public class CommandAsyncService implements CommandAsyncExecutor {
return; return;
} }
final Promise<R> attemptPromise = connectionManager.newPromise(); final RPromise<R> attemptPromise = connectionManager.newPromise();
final Future<RedisConnection> connectionFuture; final RFuture<RedisConnection> connectionFuture;
if (readOnlyMode) { if (readOnlyMode) {
connectionFuture = connectionManager.connectionReadOp(source, command); connectionFuture = connectionManager.connectionReadOp(source, command);
} else { } else {
@ -518,22 +518,22 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if (!connFuture.isSuccess()) { if (!connFuture.isSuccess()) {
connectionManager.getShutdownLatch().release(); connectionManager.getShutdownLatch().release();
details.setException(convertException(connFuture)); details.setException(convertException(connectionFuture));
return; return;
} }
if (details.getAttemptPromise().isDone() || details.getMainPromise().isDone()) { if (details.getAttemptPromise().isDone() || details.getMainPromise().isDone()) {
releaseConnection(source, connFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details); releaseConnection(source, connectionFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details);
return; return;
} }
final RedisConnection connection = connFuture.getNow(); final RedisConnection connection = connFuture.getNow();
if (details.getSource().getRedirect() == Redirect.ASK) { if (details.getSource().getRedirect() == Redirect.ASK) {
List<CommandData<?, ?>> list = new ArrayList<CommandData<?, ?>>(2); List<CommandData<?, ?>> list = new ArrayList<CommandData<?, ?>>(2);
Promise<Void> promise = connectionManager.newPromise(); RPromise<Void> promise = connectionManager.newPromise();
list.add(new CommandData<Void, Void>(promise, details.getCodec(), RedisCommands.ASKING, new Object[] {})); list.add(new CommandData<Void, Void>(promise, details.getCodec(), RedisCommands.ASKING, new Object[] {}));
list.add(new CommandData<V, R>(details.getAttemptPromise(), details.getCodec(), details.getCommand(), details.getParams())); list.add(new CommandData<V, R>(details.getAttemptPromise(), details.getCodec(), details.getCommand(), details.getParams()));
Promise<Void> main = connectionManager.newPromise(); RPromise<Void> main = connectionManager.newPromise();
ChannelFuture future = connection.send(new CommandsData(main, list)); ChannelFuture future = connection.send(new CommandsData(main, list));
details.setWriteFuture(future); details.setWriteFuture(future);
} else { } else {
@ -552,7 +552,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} }
}); });
releaseConnection(source, connFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details); releaseConnection(source, connectionFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details);
} }
}); });
@ -666,8 +666,8 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} }
} }
protected <V, R> void releaseConnection(final NodeSource source, final Future<RedisConnection> connectionFuture, protected <V, R> void releaseConnection(final NodeSource source, final RFuture<RedisConnection> connectionFuture,
final boolean isReadOnly, Promise<R> attemptPromise, final AsyncDetails<V, R> details) { final boolean isReadOnly, RPromise<R> attemptPromise, final AsyncDetails<V, R> details) {
attemptPromise.addListener(new FutureListener<R>() { attemptPromise.addListener(new FutureListener<R>() {
@Override @Override
public void operationComplete(Future<R> future) throws Exception { public void operationComplete(Future<R> future) throws Exception {

@ -93,7 +93,7 @@ public class CommandBatchService extends CommandReactiveService {
@Override @Override
protected <V, R> void async(boolean readOnlyMode, NodeSource nodeSource, protected <V, R> void async(boolean readOnlyMode, NodeSource nodeSource,
Codec codec, RedisCommand<V> command, Object[] params, Promise<R> mainPromise, int attempt) { Codec codec, RedisCommand<V> command, Object[] params, RPromise<R> mainPromise, int attempt) {
if (executed) { if (executed) {
throw new IllegalStateException("Batch already has been executed!"); throw new IllegalStateException("Batch already has been executed!");
} }
@ -153,7 +153,7 @@ public class CommandBatchService extends CommandReactiveService {
} }
executed = true; executed = true;
Promise<Void> voidPromise = connectionManager.newPromise(); RPromise<Void> voidPromise = connectionManager.newPromise();
final RPromise<List<?>> promise = connectionManager.newPromise(); final RPromise<List<?>> promise = connectionManager.newPromise();
voidPromise.addListener(new FutureListener<Void>() { voidPromise.addListener(new FutureListener<Void>() {
@Override @Override
@ -185,7 +185,7 @@ public class CommandBatchService extends CommandReactiveService {
return promise; return promise;
} }
public void execute(final Entry entry, final NodeSource source, final Promise<Void> mainPromise, final AtomicInteger slots, final int attempt) { public void execute(final Entry entry, final NodeSource source, final RPromise<Void> mainPromise, final AtomicInteger slots, final int attempt) {
if (mainPromise.isCancelled()) { if (mainPromise.isCancelled()) {
return; return;
} }
@ -195,11 +195,11 @@ public class CommandBatchService extends CommandReactiveService {
return; return;
} }
final Promise<Void> attemptPromise = connectionManager.newPromise(); final RPromise<Void> attemptPromise = connectionManager.newPromise();
final AsyncDetails details = new AsyncDetails(); final AsyncDetails details = new AsyncDetails();
final Future<RedisConnection> connectionFuture; final RFuture<RedisConnection> connectionFuture;
if (entry.isReadOnlyMode()) { if (entry.isReadOnlyMode()) {
connectionFuture = connectionManager.connectionReadOp(source, null); connectionFuture = connectionManager.connectionReadOp(source, null);
} else { } else {
@ -254,7 +254,7 @@ public class CommandBatchService extends CommandReactiveService {
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> connFuture) throws Exception { public void operationComplete(Future<RedisConnection> connFuture) throws Exception {
checkConnectionFuture(entry, source, mainPromise, attemptPromise, details, connFuture); checkConnectionFuture(entry, source, mainPromise, attemptPromise, details, connectionFuture);
} }
}); });
} }
@ -296,7 +296,7 @@ public class CommandBatchService extends CommandReactiveService {
}); });
} }
private void checkWriteFuture(final Promise<Void> attemptPromise, AsyncDetails details, private void checkWriteFuture(final RPromise<Void> attemptPromise, AsyncDetails details,
final RedisConnection connection, ChannelFuture future) { final RedisConnection connection, ChannelFuture future) {
if (attemptPromise.isDone() || future.isCancelled()) { if (attemptPromise.isDone() || future.isCancelled()) {
return; return;
@ -319,8 +319,8 @@ public class CommandBatchService extends CommandReactiveService {
} }
private void checkConnectionFuture(final Entry entry, final NodeSource source, private void checkConnectionFuture(final Entry entry, final NodeSource source,
final Promise<Void> mainPromise, final Promise<Void> attemptPromise, final AsyncDetails details, final RPromise<Void> mainPromise, final RPromise<Void> attemptPromise, final AsyncDetails details,
Future<RedisConnection> connFuture) { RFuture<RedisConnection> connFuture) {
if (attemptPromise.isDone() || mainPromise.isCancelled() || connFuture.isCancelled()) { if (attemptPromise.isDone() || mainPromise.isCancelled() || connFuture.isCancelled()) {
return; return;
} }
@ -335,7 +335,7 @@ public class CommandBatchService extends CommandReactiveService {
List<CommandData<?, ?>> list = new ArrayList<CommandData<?, ?>>(entry.getCommands().size() + 1); List<CommandData<?, ?>> list = new ArrayList<CommandData<?, ?>>(entry.getCommands().size() + 1);
if (source.getRedirect() == Redirect.ASK) { if (source.getRedirect() == Redirect.ASK) {
Promise<Void> promise = connectionManager.newPromise(); RPromise<Void> promise = connectionManager.newPromise();
list.add(new CommandData<Void, Void>(promise, StringCodec.INSTANCE, RedisCommands.ASKING, new Object[] {})); list.add(new CommandData<Void, Void>(promise, StringCodec.INSTANCE, RedisCommands.ASKING, new Object[] {}));
} }
for (BatchCommandData<?, ?> c : entry.getCommands()) { for (BatchCommandData<?, ?> c : entry.getCommands()) {

@ -21,13 +21,12 @@ import java.util.List;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.redisson.SlotCallback; import org.redisson.SlotCallback;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import io.netty.util.concurrent.Future;
/** /**
* *
* @author Nikita Koksharov * @author Nikita Koksharov
@ -35,7 +34,7 @@ import io.netty.util.concurrent.Future;
*/ */
public interface CommandReactiveExecutor extends CommandAsyncExecutor { public interface CommandReactiveExecutor extends CommandAsyncExecutor {
<R> Publisher<R> reactive(Future<R> future); <R> Publisher<R> reactive(RFuture<R> future);
ConnectionManager getConnectionManager(); ConnectionManager getConnectionManager();

@ -21,14 +21,13 @@ import java.util.List;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.redisson.SlotCallback; import org.redisson.SlotCallback;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import org.redisson.reactive.NettyFuturePublisher; import org.redisson.reactive.NettyFuturePublisher;
import io.netty.util.concurrent.Future;
/** /**
* *
* @author Nikita Koksharov * @author Nikita Koksharov
@ -42,29 +41,29 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override @Override
public <T, R> Publisher<R> evalWriteAllReactive(RedisCommand<T> command, SlotCallback<T, R> callback, String script, List<Object> keys, Object ... params) { public <T, R> Publisher<R> evalWriteAllReactive(RedisCommand<T> command, SlotCallback<T, R> callback, String script, List<Object> keys, Object ... params) {
Future<R> f = evalWriteAllAsync(command, callback, script, keys, params); RFuture<R> f = evalWriteAllAsync(command, callback, script, keys, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
public <R> Publisher<R> reactive(Future<R> future) { public <R> Publisher<R> reactive(RFuture<R> future) {
return new NettyFuturePublisher<R>(future); return new NettyFuturePublisher<R>(future);
} }
@Override @Override
public <T, R> Publisher<Collection<R>> readAllReactive(RedisCommand<T> command, Object ... params) { public <T, R> Publisher<Collection<R>> readAllReactive(RedisCommand<T> command, Object ... params) {
Future<Collection<R>> f = readAllAsync(command, params); RFuture<Collection<R>> f = readAllAsync(command, params);
return new NettyFuturePublisher<Collection<R>>(f); return new NettyFuturePublisher<Collection<R>>(f);
} }
@Override @Override
public <T, R> Publisher<R> readRandomReactive(RedisCommand<T> command, Object ... params) { public <T, R> Publisher<R> readRandomReactive(RedisCommand<T> command, Object ... params) {
Future<R> f = readRandomAsync(command, params); RFuture<R> f = readRandomAsync(command, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@Override @Override
public <T, R> Publisher<R> readReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> Publisher<R> readReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> f = readAsync(client, key, codec, command, params); RFuture<R> f = readAsync(client, key, codec, command, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@ -75,13 +74,13 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override @Override
public <T, R> Publisher<R> writeReactive(String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> Publisher<R> writeReactive(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> f = writeAsync(key, codec, command, params); RFuture<R> f = writeAsync(key, codec, command, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@Override @Override
public <T, R> Publisher<R> writeReactive(MasterSlaveEntry entry, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> Publisher<R> writeReactive(MasterSlaveEntry entry, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> f = writeAsync(entry, codec, command, params); RFuture<R> f = writeAsync(entry, codec, command, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@ -92,21 +91,21 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override @Override
public <T, R> Publisher<R> readReactive(String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> Publisher<R> readReactive(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> f = readAsync(key, codec, command, params); RFuture<R> f = readAsync(key, codec, command, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@Override @Override
public <T, R> Publisher<R> evalReadReactive(String key, Codec codec, RedisCommand<T> evalCommandType, public <T, R> Publisher<R> evalReadReactive(String key, Codec codec, RedisCommand<T> evalCommandType,
String script, List<Object> keys, Object... params) { String script, List<Object> keys, Object... params) {
Future<R> f = evalReadAsync(key, codec, evalCommandType, script, keys, params); RFuture<R> f = evalReadAsync(key, codec, evalCommandType, script, keys, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@Override @Override
public <T, R> Publisher<R> evalReadReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> evalCommandType, public <T, R> Publisher<R> evalReadReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> evalCommandType,
String script, List<Object> keys, Object ... params) { String script, List<Object> keys, Object ... params) {
Future<R> f = evalReadAsync(client, key, codec, evalCommandType, script, keys, params); RFuture<R> f = evalReadAsync(client, key, codec, evalCommandType, script, keys, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@ -114,19 +113,19 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override @Override
public <T, R> Publisher<R> evalWriteReactive(String key, Codec codec, RedisCommand<T> evalCommandType, public <T, R> Publisher<R> evalWriteReactive(String key, Codec codec, RedisCommand<T> evalCommandType,
String script, List<Object> keys, Object... params) { String script, List<Object> keys, Object... params) {
Future<R> f = evalWriteAsync(key, codec, evalCommandType, script, keys, params); RFuture<R> f = evalWriteAsync(key, codec, evalCommandType, script, keys, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }
@Override @Override
public <T> Publisher<Void> writeAllReactive(RedisCommand<T> command, Object ... params) { public <T> Publisher<Void> writeAllReactive(RedisCommand<T> command, Object ... params) {
Future<Void> f = writeAllAsync(command, params); RFuture<Void> f = writeAllAsync(command, params);
return new NettyFuturePublisher<Void>(f); return new NettyFuturePublisher<Void>(f);
} }
@Override @Override
public <R, T> Publisher<R> writeAllReactive(RedisCommand<T> command, SlotCallback<T, R> callback, Object ... params) { public <R, T> Publisher<R> writeAllReactive(RedisCommand<T> command, SlotCallback<T, R> callback, Object ... params) {
Future<R> f = writeAllAsync(command, callback, params); RFuture<R> f = writeAllAsync(command, callback, params);
return new NettyFuturePublisher<R>(f); return new NettyFuturePublisher<R>(f);
} }

@ -18,12 +18,11 @@ package org.redisson.command;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List; import java.util.List;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import io.netty.util.concurrent.Future;
/** /**
* *
* @author Nikita Koksharov * @author Nikita Koksharov
@ -31,7 +30,7 @@ import io.netty.util.concurrent.Future;
*/ */
public interface CommandSyncExecutor { public interface CommandSyncExecutor {
<V> V get(Future<V> future); <V> V get(RFuture<V> future);
<T, R> R write(Integer slot, Codec codec, RedisCommand<T> command, Object ... params); <T, R> R write(Integer slot, Codec codec, RedisCommand<T> command, Object ... params);

@ -18,14 +18,13 @@ package org.redisson.command;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List; import java.util.List;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec; import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future;
/** /**
* *
* @author Nikita Koksharov * @author Nikita Koksharov
@ -46,19 +45,19 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override @Override
public <T, R> R read(String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> R read(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = readAsync(key, codec, command, params); RFuture<R> res = readAsync(key, codec, command, params);
return get(res); return get(res);
} }
@Override @Override
public <T, R> R read(InetSocketAddress client, String key, RedisCommand<T> command, Object ... params) { public <T, R> R read(InetSocketAddress client, String key, RedisCommand<T> command, Object ... params) {
Future<R> res = readAsync(client, key, connectionManager.getCodec(), command, params); RFuture<R> res = readAsync(client, key, connectionManager.getCodec(), command, params);
return get(res); return get(res);
} }
@Override @Override
public <T, R> R read(InetSocketAddress client, String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> R read(InetSocketAddress client, String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = readAsync(client, key, codec, command, params); RFuture<R> res = readAsync(client, key, codec, command, params);
return get(res); return get(res);
} }
@ -69,7 +68,7 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override @Override
public <T, R> R evalRead(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) { public <T, R> R evalRead(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
Future<R> res = evalReadAsync(key, codec, evalCommandType, script, keys, params); RFuture<R> res = evalReadAsync(key, codec, evalCommandType, script, keys, params);
return get(res); return get(res);
} }
@ -80,25 +79,25 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override @Override
public <T, R> R evalWrite(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) { public <T, R> R evalWrite(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params) {
Future<R> res = evalWriteAsync(key, codec, evalCommandType, script, keys, params); RFuture<R> res = evalWriteAsync(key, codec, evalCommandType, script, keys, params);
return get(res); return get(res);
} }
@Override @Override
public <T, R> R write(Integer slot, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> R write(Integer slot, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(slot, codec, command, params); RFuture<R> res = writeAsync(slot, codec, command, params);
return get(res); return get(res);
} }
@Override @Override
public <T, R> R write(String key, Codec codec, RedisCommand<T> command, Object ... params) { public <T, R> R write(String key, Codec codec, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(key, codec, command, params); RFuture<R> res = writeAsync(key, codec, command, params);
return get(res); return get(res);
} }
@Override @Override
public <T, R> R write(String key, RedisCommand<T> command, Object ... params) { public <T, R> R write(String key, RedisCommand<T> command, Object ... params) {
Future<R> res = writeAsync(key, command, params); RFuture<R> res = writeAsync(key, command, params);
return get(res); return get(res);
} }

@ -20,17 +20,18 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.ReconnectListener; import org.redisson.client.ReconnectListener;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise; import io.netty.util.concurrent.Promise;
public class ClientConnectionsEntry { public class ClientConnectionsEntry {
@ -138,9 +139,9 @@ public class ClientConnectionsEntry {
freeConnections.add(connection); freeConnections.add(connection);
} }
public Future<RedisConnection> connect() { public RFuture<RedisConnection> connect() {
final Promise<RedisConnection> connectionFuture = connectionManager.newPromise(); final RPromise<RedisConnection> connectionFuture = connectionManager.newPromise();
Future<RedisConnection> future = client.connectAsync(); RFuture<RedisConnection> future = client.connectAsync();
future.addListener(new FutureListener<RedisConnection>() { future.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -158,18 +159,18 @@ public class ClientConnectionsEntry {
return connectionFuture; return connectionFuture;
} }
private <T extends RedisConnection> void addReconnectListener(Promise<T> connectionFuture, T conn) { private <T extends RedisConnection> void addReconnectListener(RPromise<T> connectionFuture, T conn) {
addFireEventListener(conn, connectionFuture); addFireEventListener(conn, connectionFuture);
conn.setReconnectListener(new ReconnectListener() { conn.setReconnectListener(new ReconnectListener() {
@Override @Override
public void onReconnect(RedisConnection conn, Promise<RedisConnection> connectionFuture) { public void onReconnect(RedisConnection conn, RPromise<RedisConnection> connectionFuture) {
addFireEventListener(conn, connectionFuture); addFireEventListener(conn, connectionFuture);
} }
}); });
} }
private <T extends RedisConnection> void addFireEventListener(T conn, Promise<T> connectionFuture) { private <T extends RedisConnection> void addFireEventListener(T conn, RPromise<T> connectionFuture) {
connectionManager.getConnectListener().onConnect(connectionFuture, conn, nodeType, connectionManager.getConfig()); connectionManager.getConnectListener().onConnect(connectionFuture, conn, nodeType, connectionManager.getConfig());
if (connectionFuture.isSuccess()) { if (connectionFuture.isSuccess()) {
@ -191,9 +192,9 @@ public class ClientConnectionsEntry {
return connectionManager.getConfig(); return connectionManager.getConfig();
} }
public Future<RedisPubSubConnection> connectPubSub() { public RFuture<RedisPubSubConnection> connectPubSub() {
final Promise<RedisPubSubConnection> connectionFuture = connectionManager.newPromise(); final RPromise<RedisPubSubConnection> connectionFuture = connectionManager.newPromise();
Future<RedisPubSubConnection> future = client.connectPubSubAsync(); RFuture<RedisPubSubConnection> future = client.connectPubSubAsync();
future.addListener(new FutureListener<RedisPubSubConnection>() { future.addListener(new FutureListener<RedisPubSubConnection>() {
@Override @Override
public void operationComplete(Future<RedisPubSubConnection> future) throws Exception { public void operationComplete(Future<RedisPubSubConnection> future) throws Exception {

@ -18,11 +18,10 @@ package org.redisson.connection;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public interface ConnectionInitializer { public interface ConnectionInitializer {
<T extends RedisConnection> void onConnect(Promise<T> connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config); <T extends RedisConnection> void onConnect(RPromise<T> connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config);
} }

@ -36,7 +36,6 @@ import org.redisson.pubsub.AsyncSemaphore;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.util.Timeout; import io.netty.util.Timeout;
import io.netty.util.TimerTask; import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
/** /**
* *
@ -59,9 +58,9 @@ public interface ConnectionManager {
boolean isShuttingDown(); boolean isShuttingDown();
Future<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener); RFuture<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener);
Future<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore); RFuture<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore);
ConnectionInitializer getConnectListener(); ConnectionInitializer getConnectListener();
@ -89,9 +88,9 @@ public interface ConnectionManager {
void releaseWrite(NodeSource source, RedisConnection connection); void releaseWrite(NodeSource source, RedisConnection connection);
Future<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command); RFuture<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command);
Future<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command); RFuture<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command);
RedisClient createClient(String host, int port, int timeout, int commandTimeout); RedisClient createClient(String host, int port, int timeout, int commandTimeout);
@ -101,9 +100,9 @@ public interface ConnectionManager {
PubSubConnectionEntry getPubSubEntry(String channelName); PubSubConnectionEntry getPubSubEntry(String channelName);
Future<PubSubConnectionEntry> psubscribe(String pattern, Codec codec, RedisPubSubListener<?> listener); RFuture<PubSubConnectionEntry> psubscribe(String pattern, Codec codec, RedisPubSubListener<?> listener);
Future<PubSubConnectionEntry> psubscribe(String pattern, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore); RFuture<PubSubConnectionEntry> psubscribe(String pattern, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore);
Codec unsubscribe(String channelName, AsyncSemaphore lock); Codec unsubscribe(String channelName, AsyncSemaphore lock);
@ -123,6 +122,6 @@ public interface ConnectionManager {
InfinitySemaphoreLatch getShutdownLatch(); InfinitySemaphoreLatch getShutdownLatch();
Future<Boolean> getShutdownPromise(); RFuture<Boolean> getShutdownPromise();
} }

@ -20,12 +20,11 @@ import org.redisson.client.RedisConnection;
import org.redisson.client.RedisException; import org.redisson.client.RedisException;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class DefaultConnectionListener implements ConnectionInitializer { public class DefaultConnectionListener implements ConnectionInitializer {
public final <T extends RedisConnection> void onConnect(Promise<T> connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config) { public final <T extends RedisConnection> void onConnect(RPromise<T> connectionFuture, T conn, NodeType nodeType, MasterSlaveServersConfig config) {
FutureConnectionListener<T> listener = new FutureConnectionListener<T>(connectionFuture, conn); FutureConnectionListener<T> listener = new FutureConnectionListener<T>(connectionFuture, conn);
doConnect(config, nodeType, listener); doConnect(config, nodeType, listener);
listener.executeCommands(); listener.executeCommands();

@ -30,11 +30,11 @@ import org.redisson.config.BaseMasterSlaveServersConfig;
import org.redisson.config.Config; import org.redisson.config.Config;
import org.redisson.config.ElasticacheServersConfig; import org.redisson.config.ElasticacheServersConfig;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture; import io.netty.util.concurrent.ScheduledFuture;
/** /**
@ -110,7 +110,7 @@ public class ElasticacheConnectionManager extends MasterSlaveConnectionManager {
RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts()); RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts());
try { try {
connection = client.connect(); connection = client.connect();
Promise<RedisConnection> future = newPromise(); RPromise<RedisConnection> future = newPromise();
connectListener.onConnect(future, connection, null, config); connectListener.onConnect(future, connection, null, config);
future.syncUninterruptibly(); future.syncUninterruptibly();
nodeConnections.put(addr, connection); nodeConnections.put(addr, connection);

@ -19,22 +19,23 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommand;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
public class FutureConnectionListener<T extends RedisConnection> implements FutureListener<Object> { public class FutureConnectionListener<T extends RedisConnection> implements FutureListener<Object> {
private final AtomicInteger commandsCounter = new AtomicInteger(); private final AtomicInteger commandsCounter = new AtomicInteger();
private final Promise<T> connectionPromise; private final RPromise<T> connectionPromise;
private final T connection; private final T connection;
private final List<Runnable> commands = new ArrayList<Runnable>(4); private final List<Runnable> commands = new ArrayList<Runnable>(4);
public FutureConnectionListener(Promise<T> connectionFuture, T connection) { public FutureConnectionListener(RPromise<T> connectionFuture, T connection) {
super(); super();
this.connectionPromise = connectionFuture; this.connectionPromise = connectionFuture;
this.connection = connection; this.connection = connection;
@ -45,7 +46,7 @@ public class FutureConnectionListener<T extends RedisConnection> implements Futu
commands.add(new Runnable() { commands.add(new Runnable() {
@Override @Override
public void run() { public void run() {
Future<Object> future = connection.async(command, params); RFuture<Object> future = connection.async(command, params);
future.addListener(FutureConnectionListener.this); future.addListener(FutureConnectionListener.this);
} }
}); });

@ -70,7 +70,6 @@ import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor; import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
/** /**
@ -131,7 +130,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
private final Map<Integer, MasterSlaveEntry> entries = PlatformDependent.newConcurrentHashMap(); private final Map<Integer, MasterSlaveEntry> entries = PlatformDependent.newConcurrentHashMap();
private final Promise<Boolean> shutdownPromise; private final RPromise<Boolean> shutdownPromise;
private final InfinitySemaphoreLatch shutdownLatch = new InfinitySemaphoreLatch(); private final InfinitySemaphoreLatch shutdownLatch = new InfinitySemaphoreLatch();
@ -245,7 +244,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
MasterSlaveEntry entry; MasterSlaveEntry entry;
if (config.getReadMode() == ReadMode.MASTER) { if (config.getReadMode() == ReadMode.MASTER) {
entry = new SingleEntry(slots, this, config); entry = new SingleEntry(slots, this, config);
Future<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); RFuture<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort());
f.syncUninterruptibly(); f.syncUninterruptibly();
} else { } else {
entry = createMasterSlaveEntry(config, slots); entry = createMasterSlaveEntry(config, slots);
@ -259,11 +258,11 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config, protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config,
HashSet<ClusterSlotRange> slots) { HashSet<ClusterSlotRange> slots) {
MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config); MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config);
List<Future<Void>> fs = entry.initSlaveBalancer(java.util.Collections.<URI>emptySet()); List<RFuture<Void>> fs = entry.initSlaveBalancer(java.util.Collections.<URI>emptySet());
for (Future<Void> future : fs) { for (RFuture<Void> future : fs) {
future.syncUninterruptibly(); future.syncUninterruptibly();
} }
Future<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); RFuture<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort());
f.syncUninterruptibly(); f.syncUninterruptibly();
return entry; return entry;
} }
@ -322,40 +321,40 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public Future<PubSubConnectionEntry> psubscribe(final String channelName, final Codec codec, final RedisPubSubListener<?> listener) { public RFuture<PubSubConnectionEntry> psubscribe(final String channelName, final Codec codec, final RedisPubSubListener<?> listener) {
final AsyncSemaphore lock = getSemaphore(channelName); final AsyncSemaphore lock = getSemaphore(channelName);
final Promise<PubSubConnectionEntry> result = newPromise(); final RPromise<PubSubConnectionEntry> result = newPromise();
lock.acquire(new Runnable() { lock.acquire(new Runnable() {
@Override @Override
public void run() { public void run() {
Future<PubSubConnectionEntry> future = psubscribe(channelName, codec, listener, lock); RFuture<PubSubConnectionEntry> future = psubscribe(channelName, codec, listener, lock);
future.addListener(new TransferListener<PubSubConnectionEntry>(result)); future.addListener(new TransferListener<PubSubConnectionEntry>(result));
} }
}); });
return result; return result;
} }
public Future<PubSubConnectionEntry> psubscribe(String channelName, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) { public RFuture<PubSubConnectionEntry> psubscribe(String channelName, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
Promise<PubSubConnectionEntry> promise = newPromise(); RPromise<PubSubConnectionEntry> promise = newPromise();
subscribe(codec, channelName, listener, promise, PubSubType.PSUBSCRIBE, semaphore); subscribe(codec, channelName, listener, promise, PubSubType.PSUBSCRIBE, semaphore);
return promise; return promise;
} }
public Future<PubSubConnectionEntry> subscribe(final Codec codec, final String channelName, final RedisPubSubListener<?> listener) { public RFuture<PubSubConnectionEntry> subscribe(final Codec codec, final String channelName, final RedisPubSubListener<?> listener) {
final AsyncSemaphore lock = getSemaphore(channelName); final AsyncSemaphore lock = getSemaphore(channelName);
final Promise<PubSubConnectionEntry> result = newPromise(); final RPromise<PubSubConnectionEntry> result = newPromise();
lock.acquire(new Runnable() { lock.acquire(new Runnable() {
@Override @Override
public void run() { public void run() {
Future<PubSubConnectionEntry> future = subscribe(codec, channelName, listener, lock); RFuture<PubSubConnectionEntry> future = subscribe(codec, channelName, listener, lock);
future.addListener(new TransferListener<PubSubConnectionEntry>(result)); future.addListener(new TransferListener<PubSubConnectionEntry>(result));
} }
}); });
return result; return result;
} }
public Future<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) { public RFuture<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
Promise<PubSubConnectionEntry> promise = newPromise(); RPromise<PubSubConnectionEntry> promise = newPromise();
subscribe(codec, channelName, listener, promise, PubSubType.SUBSCRIBE, semaphore); subscribe(codec, channelName, listener, promise, PubSubType.SUBSCRIBE, semaphore);
return promise; return promise;
} }
@ -365,7 +364,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
private void subscribe(final Codec codec, final String channelName, final RedisPubSubListener<?> listener, private void subscribe(final Codec codec, final String channelName, final RedisPubSubListener<?> listener,
final Promise<PubSubConnectionEntry> promise, final PubSubType type, final AsyncSemaphore lock) { final RPromise<PubSubConnectionEntry> promise, final PubSubType type, final AsyncSemaphore lock) {
final PubSubConnectionEntry сonnEntry = name2PubSubConnection.get(channelName); final PubSubConnectionEntry сonnEntry = name2PubSubConnection.get(channelName);
if (сonnEntry != null) { if (сonnEntry != null) {
сonnEntry.addListener(channelName, listener); сonnEntry.addListener(channelName, listener);
@ -439,9 +438,9 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
private void connect(final Codec codec, final String channelName, final RedisPubSubListener<?> listener, private void connect(final Codec codec, final String channelName, final RedisPubSubListener<?> listener,
final Promise<PubSubConnectionEntry> promise, final PubSubType type, final AsyncSemaphore lock) { final RPromise<PubSubConnectionEntry> promise, final PubSubType type, final AsyncSemaphore lock) {
final int slot = calcSlot(channelName); final int slot = calcSlot(channelName);
Future<RedisPubSubConnection> connFuture = nextPubSubConnection(slot); RFuture<RedisPubSubConnection> connFuture = nextPubSubConnection(slot);
connFuture.addListener(new FutureListener<RedisPubSubConnection>() { connFuture.addListener(new FutureListener<RedisPubSubConnection>() {
@Override @Override
@ -614,7 +613,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public Future<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command) { public RFuture<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command) {
MasterSlaveEntry entry = source.getEntry(); MasterSlaveEntry entry = source.getEntry();
if (entry == null) { if (entry == null) {
entry = getEntry(source); entry = getEntry(source);
@ -640,7 +639,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public Future<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command) { public RFuture<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command) {
MasterSlaveEntry entry = source.getEntry(); MasterSlaveEntry entry = source.getEntry();
if (entry == null && source.getSlot() != null) { if (entry == null && source.getSlot() != null) {
entry = getEntry(source.getSlot()); entry = getEntry(source.getSlot());
@ -651,7 +650,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
return entry.connectionReadOp(); return entry.connectionReadOp();
} }
Future<RedisPubSubConnection> nextPubSubConnection(int slot) { RFuture<RedisPubSubConnection> nextPubSubConnection(int slot) {
return getEntry(slot).nextPubSubConnection(); return getEntry(slot).nextPubSubConnection();
} }
@ -746,7 +745,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
} }
@Override @Override
public Future<Boolean> getShutdownPromise() { public RFuture<Boolean> getShutdownPromise() {
return shutdownPromise; return shutdownPromise;
} }

@ -25,6 +25,7 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
@ -79,13 +80,13 @@ public class MasterSlaveEntry {
writeConnectionHolder = new MasterConnectionPool(config, connectionManager, this); writeConnectionHolder = new MasterConnectionPool(config, connectionManager, this);
} }
public List<Future<Void>> initSlaveBalancer(Collection<URI> disconnectedNodes) { public List<RFuture<Void>> initSlaveBalancer(Collection<URI> disconnectedNodes) {
boolean freezeMasterAsSlave = !config.getSlaveAddresses().isEmpty() boolean freezeMasterAsSlave = !config.getSlaveAddresses().isEmpty()
&& config.getReadMode() == ReadMode.SLAVE && config.getReadMode() == ReadMode.SLAVE
&& disconnectedNodes.size() < config.getSlaveAddresses().size(); && disconnectedNodes.size() < config.getSlaveAddresses().size();
List<Future<Void>> result = new LinkedList<Future<Void>>(); List<RFuture<Void>> result = new LinkedList<RFuture<Void>>();
Future<Void> f = addSlave(config.getMasterAddress().getHost(), config.getMasterAddress().getPort(), freezeMasterAsSlave, NodeType.MASTER); RFuture<Void> f = addSlave(config.getMasterAddress().getHost(), config.getMasterAddress().getPort(), freezeMasterAsSlave, NodeType.MASTER);
result.add(f); result.add(f);
for (URI address : config.getSlaveAddresses()) { for (URI address : config.getSlaveAddresses()) {
f = addSlave(address.getHost(), address.getPort(), disconnectedNodes.contains(address), NodeType.SLAVE); f = addSlave(address.getHost(), address.getPort(), disconnectedNodes.contains(address), NodeType.SLAVE);
@ -94,7 +95,7 @@ public class MasterSlaveEntry {
return result; return result;
} }
public Future<Void> setupMasterEntry(String host, int port) { public RFuture<Void> setupMasterEntry(String host, int port) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, host, port); RedisClient client = connectionManager.createClient(NodeType.MASTER, host, port);
masterEntry = new ClientConnectionsEntry(client, config.getMasterConnectionMinimumIdleSize(), config.getMasterConnectionPoolSize(), masterEntry = new ClientConnectionsEntry(client, config.getMasterConnectionMinimumIdleSize(), config.getMasterConnectionPoolSize(),
0, 0, connectionManager, NodeType.MASTER); 0, 0, connectionManager, NodeType.MASTER);
@ -180,7 +181,7 @@ public class MasterSlaveEntry {
return; return;
} }
Future<PubSubConnectionEntry> subscribeFuture = connectionManager.subscribe(subscribeCodec, channelName, null); RFuture<PubSubConnectionEntry> subscribeFuture = connectionManager.subscribe(subscribeCodec, channelName, null);
subscribeFuture.addListener(new FutureListener<PubSubConnectionEntry>() { subscribeFuture.addListener(new FutureListener<PubSubConnectionEntry>() {
@Override @Override
@ -203,7 +204,7 @@ public class MasterSlaveEntry {
final Collection<RedisPubSubListener<?>> listeners) { final Collection<RedisPubSubListener<?>> listeners) {
Codec subscribeCodec = connectionManager.punsubscribe(channelName); Codec subscribeCodec = connectionManager.punsubscribe(channelName);
if (!listeners.isEmpty()) { if (!listeners.isEmpty()) {
Future<PubSubConnectionEntry> future = connectionManager.psubscribe(channelName, subscribeCodec, null); RFuture<PubSubConnectionEntry> future = connectionManager.psubscribe(channelName, subscribeCodec, null);
future.addListener(new FutureListener<PubSubConnectionEntry>() { future.addListener(new FutureListener<PubSubConnectionEntry>() {
@Override @Override
public void operationComplete(Future<PubSubConnectionEntry> future) public void operationComplete(Future<PubSubConnectionEntry> future)
@ -231,7 +232,7 @@ public class MasterSlaveEntry {
return; return;
} }
Future<RedisConnection> newConnection = connectionReadOp(); RFuture<RedisConnection> newConnection = connectionReadOp();
newConnection.addListener(new FutureListener<RedisConnection>() { newConnection.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -268,11 +269,11 @@ public class MasterSlaveEntry {
}); });
} }
public Future<Void> addSlave(String host, int port) { public RFuture<Void> addSlave(String host, int port) {
return addSlave(host, port, true, NodeType.SLAVE); return addSlave(host, port, true, NodeType.SLAVE);
} }
private Future<Void> addSlave(String host, int port, boolean freezed, NodeType mode) { private RFuture<Void> addSlave(String host, int port, boolean freezed, NodeType mode) {
RedisClient client = connectionManager.createClient(NodeType.SLAVE, host, port); RedisClient client = connectionManager.createClient(NodeType.SLAVE, host, port);
ClientConnectionsEntry entry = new ClientConnectionsEntry(client, ClientConnectionsEntry entry = new ClientConnectionsEntry(client,
this.config.getSlaveConnectionMinimumIdleSize(), this.config.getSlaveConnectionMinimumIdleSize(),
@ -356,20 +357,19 @@ public class MasterSlaveEntry {
slaveBalancer.shutdownAsync(); slaveBalancer.shutdownAsync();
} }
public Future<RedisConnection> connectionWriteOp() { public RFuture<RedisConnection> connectionWriteOp() {
return writeConnectionHolder.get(); return writeConnectionHolder.get();
} }
public Future<RedisConnection> connectionReadOp() { public RFuture<RedisConnection> connectionReadOp() {
return slaveBalancer.nextConnection(); return slaveBalancer.nextConnection();
} }
public Future<RedisConnection> connectionReadOp(InetSocketAddress addr) { public RFuture<RedisConnection> connectionReadOp(InetSocketAddress addr) {
return slaveBalancer.getConnection(addr); return slaveBalancer.getConnection(addr);
} }
RFuture<RedisPubSubConnection> nextPubSubConnection() {
Future<RedisPubSubConnection> nextPubSubConnection() {
return slaveBalancer.nextPubSubConnection(); return slaveBalancer.nextPubSubConnection();
} }

@ -15,16 +15,15 @@
*/ */
package org.redisson.connection; package org.redisson.connection;
import io.netty.util.concurrent.Promise; import java.net.InetSocketAddress;
import java.util.Map;
import org.redisson.api.ClusterNode; import org.redisson.api.ClusterNode;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.misc.RPromise;
import java.net.InetSocketAddress;
import java.util.Map;
public class RedisClientEntry implements ClusterNode { public class RedisClientEntry implements ClusterNode {
@ -55,7 +54,7 @@ public class RedisClientEntry implements ClusterNode {
private RedisConnection connect() { private RedisConnection connect() {
RedisConnection c = client.connect(); RedisConnection c = client.connect();
Promise<RedisConnection> future = manager.newPromise(); RPromise<RedisConnection> future = manager.newPromise();
manager.getConnectListener().onConnect(future, c, null, manager.getConfig()); manager.getConnectListener().onConnect(future, c, null, manager.getConfig());
future.syncUninterruptibly(); future.syncUninterruptibly();
return future.getNow(); return future.getNow();

@ -25,6 +25,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.client.BaseRedisPubSubListener; import org.redisson.client.BaseRedisPubSubListener;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
@ -115,13 +116,13 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
} }
init(c); init(c);
List<Future<RedisPubSubConnection>> connectionFutures = new ArrayList<Future<RedisPubSubConnection>>(cfg.getSentinelAddresses().size()); List<RFuture<RedisPubSubConnection>> connectionFutures = new ArrayList<RFuture<RedisPubSubConnection>>(cfg.getSentinelAddresses().size());
for (URI addr : cfg.getSentinelAddresses()) { for (URI addr : cfg.getSentinelAddresses()) {
Future<RedisPubSubConnection> future = registerSentinel(cfg, addr, c); RFuture<RedisPubSubConnection> future = registerSentinel(cfg, addr, c);
connectionFutures.add(future); connectionFutures.add(future);
} }
for (Future<RedisPubSubConnection> future : connectionFutures) { for (RFuture<RedisPubSubConnection> future : connectionFutures) {
future.awaitUninterruptibly(); future.awaitUninterruptibly();
} }
} }
@ -130,23 +131,23 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config, protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config,
HashSet<ClusterSlotRange> slots) { HashSet<ClusterSlotRange> slots) {
MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config); MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config);
List<Future<Void>> fs = entry.initSlaveBalancer(disconnectedSlaves); List<RFuture<Void>> fs = entry.initSlaveBalancer(disconnectedSlaves);
for (Future<Void> future : fs) { for (RFuture<Void> future : fs) {
future.syncUninterruptibly(); future.syncUninterruptibly();
} }
Future<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort()); RFuture<Void> f = entry.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort());
f.syncUninterruptibly(); f.syncUninterruptibly();
return entry; return entry;
} }
private Future<RedisPubSubConnection> registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) { private RFuture<RedisPubSubConnection> registerSentinel(final SentinelServersConfig cfg, final URI addr, final MasterSlaveServersConfig c) {
RedisClient client = createClient(addr.getHost(), addr.getPort(), c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts()); RedisClient client = createClient(addr.getHost(), addr.getPort(), c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts());
RedisClient oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client); RedisClient oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client);
if (oldClient != null) { if (oldClient != null) {
return newSucceededFuture(null); return newSucceededFuture(null);
} }
Future<RedisPubSubConnection> pubsubFuture = client.connectPubSubAsync(); RFuture<RedisPubSubConnection> pubsubFuture = client.connectPubSubAsync();
pubsubFuture.addListener(new FutureListener<RedisPubSubConnection>() { pubsubFuture.addListener(new FutureListener<RedisPubSubConnection>() {
@Override @Override
public void operationComplete(Future<RedisPubSubConnection> future) throws Exception { public void operationComplete(Future<RedisPubSubConnection> future) throws Exception {
@ -218,7 +219,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
// to avoid addition twice // to avoid addition twice
if (slaves.putIfAbsent(slaveAddr, true) == null && config.getReadMode() != ReadMode.MASTER) { if (slaves.putIfAbsent(slaveAddr, true) == null && config.getReadMode() != ReadMode.MASTER) {
Future<Void> future = getEntry(singleSlotRange.getStartSlot()).addSlave(ip, Integer.valueOf(port)); RFuture<Void> future = getEntry(singleSlotRange.getStartSlot()).addSlave(ip, Integer.valueOf(port));
future.addListener(new FutureListener<Void>() { future.addListener(new FutureListener<Void>() {
@Override @Override
public void operationComplete(Future<Void> future) throws Exception { public void operationComplete(Future<Void> future) throws Exception {

@ -20,6 +20,7 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient; import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
@ -27,10 +28,10 @@ import org.redisson.cluster.ClusterSlotRange;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.connection.pool.PubSubConnectionPool; import org.redisson.connection.pool.PubSubConnectionPool;
import org.redisson.connection.pool.SinglePubSubConnectionPool; import org.redisson.connection.pool.SinglePubSubConnectionPool;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
public class SingleEntry extends MasterSlaveEntry { public class SingleEntry extends MasterSlaveEntry {
@ -42,16 +43,16 @@ public class SingleEntry extends MasterSlaveEntry {
} }
@Override @Override
public Future<Void> setupMasterEntry(String host, int port) { public RFuture<Void> setupMasterEntry(String host, int port) {
RedisClient masterClient = connectionManager.createClient(NodeType.MASTER, host, port); RedisClient masterClient = connectionManager.createClient(NodeType.MASTER, host, port);
masterEntry = new ClientConnectionsEntry(masterClient, masterEntry = new ClientConnectionsEntry(masterClient,
config.getMasterConnectionMinimumIdleSize(), config.getMasterConnectionMinimumIdleSize(),
config.getMasterConnectionPoolSize(), config.getMasterConnectionPoolSize(),
config.getSlaveConnectionMinimumIdleSize(), config.getSlaveConnectionMinimumIdleSize(),
config.getSlaveSubscriptionConnectionPoolSize(), connectionManager, NodeType.MASTER); config.getSlaveSubscriptionConnectionPoolSize(), connectionManager, NodeType.MASTER);
final Promise<Void> res = connectionManager.newPromise(); final RPromise<Void> res = connectionManager.newPromise();
Future<Void> f = writeConnectionHolder.add(masterEntry); RFuture<Void> f = writeConnectionHolder.add(masterEntry);
Future<Void> s = pubSubConnectionHolder.add(masterEntry); RFuture<Void> s = pubSubConnectionHolder.add(masterEntry);
FutureListener<Void> listener = new FutureListener<Void>() { FutureListener<Void> listener = new FutureListener<Void>() {
AtomicInteger counter = new AtomicInteger(2); AtomicInteger counter = new AtomicInteger(2);
@Override @Override
@ -71,7 +72,7 @@ public class SingleEntry extends MasterSlaveEntry {
} }
@Override @Override
Future<RedisPubSubConnection> nextPubSubConnection() { RFuture<RedisPubSubConnection> nextPubSubConnection() {
return pubSubConnectionHolder.get(); return pubSubConnectionHolder.get();
} }
@ -81,12 +82,12 @@ public class SingleEntry extends MasterSlaveEntry {
} }
@Override @Override
public Future<RedisConnection> connectionReadOp(InetSocketAddress addr) { public RFuture<RedisConnection> connectionReadOp(InetSocketAddress addr) {
return super.connectionWriteOp(); return super.connectionWriteOp();
} }
@Override @Override
public Future<RedisConnection> connectionReadOp() { public RFuture<RedisConnection> connectionReadOp() {
return super.connectionWriteOp(); return super.connectionWriteOp();
} }

@ -17,16 +17,15 @@ package org.redisson.connection.balancer;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
import org.redisson.connection.ClientConnectionsEntry; import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.ClientConnectionsEntry.FreezeReason; import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import io.netty.util.concurrent.Future;
public interface LoadBalancerManager { public interface LoadBalancerManager {
Future<RedisConnection> getConnection(InetSocketAddress addr); RFuture<RedisConnection> getConnection(InetSocketAddress addr);
int getAvailableClients(); int getAvailableClients();
@ -40,11 +39,11 @@ public interface LoadBalancerManager {
ClientConnectionsEntry freeze(String host, int port, FreezeReason freezeReason); ClientConnectionsEntry freeze(String host, int port, FreezeReason freezeReason);
Future<Void> add(ClientConnectionsEntry entry); RFuture<Void> add(ClientConnectionsEntry entry);
Future<RedisConnection> nextConnection(); RFuture<RedisConnection> nextConnection();
Future<RedisPubSubConnection> nextPubSubConnection(); RFuture<RedisPubSubConnection> nextPubSubConnection();
void returnConnection(RedisConnection connection); void returnConnection(RedisConnection connection);

@ -19,6 +19,7 @@ import java.net.InetSocketAddress;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException; import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
@ -29,12 +30,12 @@ import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.pool.PubSubConnectionPool; import org.redisson.connection.pool.PubSubConnectionPool;
import org.redisson.connection.pool.SlaveConnectionPool; import org.redisson.connection.pool.SlaveConnectionPool;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
public class LoadBalancerManagerImpl implements LoadBalancerManager { public class LoadBalancerManagerImpl implements LoadBalancerManager {
@ -52,8 +53,8 @@ public class LoadBalancerManagerImpl implements LoadBalancerManager {
pubSubConnectionPool = new PubSubConnectionPool(config, connectionManager, entry); pubSubConnectionPool = new PubSubConnectionPool(config, connectionManager, entry);
} }
public Future<Void> add(final ClientConnectionsEntry entry) { public RFuture<Void> add(final ClientConnectionsEntry entry) {
final Promise<Void> result = connectionManager.newPromise(); final RPromise<Void> result = connectionManager.newPromise();
FutureListener<Void> listener = new FutureListener<Void>() { FutureListener<Void> listener = new FutureListener<Void>() {
AtomicInteger counter = new AtomicInteger(2); AtomicInteger counter = new AtomicInteger(2);
@Override @Override
@ -69,9 +70,9 @@ public class LoadBalancerManagerImpl implements LoadBalancerManager {
} }
}; };
Future<Void> slaveFuture = slaveConnectionPool.add(entry); RFuture<Void> slaveFuture = slaveConnectionPool.add(entry);
slaveFuture.addListener(listener); slaveFuture.addListener(listener);
Future<Void> pubSubFuture = pubSubConnectionPool.add(entry); RFuture<Void> pubSubFuture = pubSubConnectionPool.add(entry);
pubSubFuture.addListener(listener); pubSubFuture.addListener(listener);
return result; return result;
} }
@ -136,11 +137,11 @@ public class LoadBalancerManagerImpl implements LoadBalancerManager {
return connectionEntry; return connectionEntry;
} }
public Future<RedisPubSubConnection> nextPubSubConnection() { public RFuture<RedisPubSubConnection> nextPubSubConnection() {
return pubSubConnectionPool.get(); return pubSubConnectionPool.get();
} }
public Future<RedisConnection> getConnection(InetSocketAddress addr) { public RFuture<RedisConnection> getConnection(InetSocketAddress addr) {
ClientConnectionsEntry entry = addr2Entry.get(addr); ClientConnectionsEntry entry = addr2Entry.get(addr);
if (entry != null) { if (entry != null) {
return slaveConnectionPool.get(entry); return slaveConnectionPool.get(entry);
@ -149,7 +150,7 @@ public class LoadBalancerManagerImpl implements LoadBalancerManager {
return connectionManager.newFailedFuture(exception); return connectionManager.newFailedFuture(exception);
} }
public Future<RedisConnection> nextConnection() { public RFuture<RedisConnection> nextConnection() {
return slaveConnectionPool.get(); return slaveConnectionPool.get();
} }

@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.NodeType; import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection; import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException; import org.redisson.client.RedisConnectionException;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
@ -31,6 +32,7 @@ import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.ClientConnectionsEntry.FreezeReason; import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import org.redisson.misc.RPromise;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -38,7 +40,6 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask; import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
abstract class ConnectionPool<T extends RedisConnection> { abstract class ConnectionPool<T extends RedisConnection> {
@ -58,8 +59,8 @@ abstract class ConnectionPool<T extends RedisConnection> {
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
} }
public Future<Void> add(final ClientConnectionsEntry entry) { public RFuture<Void> add(final ClientConnectionsEntry entry) {
final Promise<Void> promise = connectionManager.newPromise(); final RPromise<Void> promise = connectionManager.newPromise();
promise.addListener(new FutureListener<Void>() { promise.addListener(new FutureListener<Void>() {
@Override @Override
public void operationComplete(Future<Void> future) throws Exception { public void operationComplete(Future<Void> future) throws Exception {
@ -70,7 +71,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return promise; return promise;
} }
private void initConnections(final ClientConnectionsEntry entry, final Promise<Void> initPromise, boolean checkFreezed) { private void initConnections(final ClientConnectionsEntry entry, final RPromise<Void> initPromise, boolean checkFreezed) {
final int minimumIdleSize = getMinimumIdleSize(entry); final int minimumIdleSize = getMinimumIdleSize(entry);
if (minimumIdleSize == 0 || (checkFreezed && entry.isFreezed())) { if (minimumIdleSize == 0 || (checkFreezed && entry.isFreezed())) {
@ -86,7 +87,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
} }
} }
private void createConnection(final boolean checkFreezed, final AtomicInteger requests, final ClientConnectionsEntry entry, final Promise<Void> initPromise, private void createConnection(final boolean checkFreezed, final AtomicInteger requests, final ClientConnectionsEntry entry, final RPromise<Void> initPromise,
final int minimumIdleSize, final AtomicInteger initializedConnections) { final int minimumIdleSize, final AtomicInteger initializedConnections) {
if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) { if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) {
@ -97,7 +98,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return; return;
} }
Future<T> promise = createConnection(entry); RFuture<T> promise = createConnection(entry);
promise.addListener(new FutureListener<T>() { promise.addListener(new FutureListener<T>() {
@Override @Override
public void operationComplete(Future<T> future) throws Exception { public void operationComplete(Future<T> future) throws Exception {
@ -135,7 +136,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return config.getLoadBalancer().getEntry(entries); return config.getLoadBalancer().getEntry(entries);
} }
public Future<T> get() { public RFuture<T> get() {
for (int j = entries.size() - 1; j >= 0; j--) { for (int j = entries.size() - 1; j >= 0; j--) {
ClientConnectionsEntry entry = getEntry(); ClientConnectionsEntry entry = getEntry();
if (!entry.isFreezed() && tryAcquireConnection(entry)) { if (!entry.isFreezed() && tryAcquireConnection(entry)) {
@ -165,7 +166,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return connectionManager.newFailedFuture(exception); return connectionManager.newFailedFuture(exception);
} }
public Future<T> get(ClientConnectionsEntry entry) { public RFuture<T> get(ClientConnectionsEntry entry) {
if (((entry.getNodeType() == NodeType.MASTER && entry.getFreezeReason() == FreezeReason.SYSTEM) || !entry.isFreezed()) if (((entry.getNodeType() == NodeType.MASTER && entry.getFreezeReason() == FreezeReason.SYSTEM) || !entry.isFreezed())
&& tryAcquireConnection(entry)) { && tryAcquireConnection(entry)) {
return connectTo(entry); return connectTo(entry);
@ -184,11 +185,11 @@ abstract class ConnectionPool<T extends RedisConnection> {
return (T) entry.pollConnection(); return (T) entry.pollConnection();
} }
protected Future<T> connect(ClientConnectionsEntry entry) { protected RFuture<T> connect(ClientConnectionsEntry entry) {
return (Future<T>) entry.connect(); return (RFuture<T>) entry.connect();
} }
private Future<T> connectTo(ClientConnectionsEntry entry) { private RFuture<T> connectTo(ClientConnectionsEntry entry) {
T conn = poll(entry); T conn = poll(entry);
if (conn != null) { if (conn != null) {
if (!conn.isActive()) { if (!conn.isActive()) {
@ -201,9 +202,9 @@ abstract class ConnectionPool<T extends RedisConnection> {
return createConnection(entry); return createConnection(entry);
} }
private Future<T> createConnection(final ClientConnectionsEntry entry) { private RFuture<T> createConnection(final ClientConnectionsEntry entry) {
final Promise<T> promise = connectionManager.newPromise(); final RPromise<T> promise = connectionManager.newPromise();
Future<T> connFuture = connect(entry); RFuture<T> connFuture = connect(entry);
connFuture.addListener(new FutureListener<T>() { connFuture.addListener(new FutureListener<T>() {
@Override @Override
public void operationComplete(Future<T> future) throws Exception { public void operationComplete(Future<T> future) throws Exception {
@ -226,7 +227,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return promise; return promise;
} }
private void promiseSuccessful(ClientConnectionsEntry entry, Promise<T> promise, T conn) { private void promiseSuccessful(ClientConnectionsEntry entry, RPromise<T> promise, T conn) {
entry.resetFailedAttempts(); entry.resetFailedAttempts();
if (!promise.trySuccess(conn)) { if (!promise.trySuccess(conn)) {
releaseConnection(entry, conn); releaseConnection(entry, conn);
@ -234,12 +235,12 @@ abstract class ConnectionPool<T extends RedisConnection> {
} }
} }
private Future<T> promiseSuccessful(ClientConnectionsEntry entry, T conn) { private RFuture<T> promiseSuccessful(ClientConnectionsEntry entry, T conn) {
entry.resetFailedAttempts(); entry.resetFailedAttempts();
return (Future<T>) conn.getAcquireFuture(); return (RFuture<T>) conn.getAcquireFuture();
} }
private void promiseFailure(ClientConnectionsEntry entry, Promise<T> promise, Throwable cause) { private void promiseFailure(ClientConnectionsEntry entry, RPromise<T> promise, Throwable cause) {
if (entry.incFailedAttempts() == config.getFailedAttempts()) { if (entry.incFailedAttempts() == config.getFailedAttempts()) {
checkForReconnect(entry); checkForReconnect(entry);
} }
@ -247,7 +248,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
promise.tryFailure(cause); promise.tryFailure(cause);
} }
private void promiseFailure(ClientConnectionsEntry entry, Promise<T> promise, T conn) { private void promiseFailure(ClientConnectionsEntry entry, RPromise<T> promise, T conn) {
int attempts = entry.incFailedAttempts(); int attempts = entry.incFailedAttempts();
if (attempts == config.getFailedAttempts()) { if (attempts == config.getFailedAttempts()) {
checkForReconnect(entry); checkForReconnect(entry);
@ -261,7 +262,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
promise.tryFailure(cause); promise.tryFailure(cause);
} }
private Future<T> promiseFailure(ClientConnectionsEntry entry, T conn) { private RFuture<T> promiseFailure(ClientConnectionsEntry entry, T conn) {
int attempts = entry.incFailedAttempts(); int attempts = entry.incFailedAttempts();
if (attempts == config.getFailedAttempts()) { if (attempts == config.getFailedAttempts()) {
checkForReconnect(entry); checkForReconnect(entry);
@ -301,7 +302,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return; return;
} }
Future<RedisConnection> connectionFuture = entry.getClient().connectAsync(); RFuture<RedisConnection> connectionFuture = entry.getClient().connectAsync();
connectionFuture.addListener(new FutureListener<RedisConnection>() { connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override @Override
public void operationComplete(Future<RedisConnection> future) throws Exception { public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -332,7 +333,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
if (future.isSuccess() && "PONG".equals(future.getNow())) { if (future.isSuccess() && "PONG".equals(future.getNow())) {
entry.resetFailedAttempts(); entry.resetFailedAttempts();
Promise<Void> promise = connectionManager.newPromise(); RPromise<Void> promise = connectionManager.newPromise();
promise.addListener(new FutureListener<Void>() { promise.addListener(new FutureListener<Void>() {
@Override @Override
public void operationComplete(Future<Void> future) public void operationComplete(Future<Void> future)
@ -362,10 +363,10 @@ abstract class ConnectionPool<T extends RedisConnection> {
}; };
if (entry.getConfig().getPassword() != null) { if (entry.getConfig().getPassword() != null) {
Future<Void> temp = c.async(RedisCommands.AUTH, config.getPassword()); RFuture<Void> temp = c.async(RedisCommands.AUTH, config.getPassword());
FutureListener<Void> listener = new FutureListener<Void> () { FutureListener<Void> listener = new FutureListener<Void>() {
@Override public void operationComplete (Future < Void > future)throws Exception { @Override public void operationComplete(Future<Void> future)throws Exception {
ping(c, pingListener); ping(c, pingListener);
} }
}; };
@ -381,7 +382,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
} }
private void ping(RedisConnection c, final FutureListener<String> pingListener) { private void ping(RedisConnection c, final FutureListener<String> pingListener) {
Future<String> f = c.async(RedisCommands.PING); RFuture<String> f = c.async(RedisCommands.PING);
f.addListener(pingListener); f.addListener(pingListener);
} }

@ -15,13 +15,12 @@
*/ */
package org.redisson.connection.pool; package org.redisson.connection.pool;
import org.redisson.api.RFuture;
import org.redisson.client.RedisPubSubConnection; import org.redisson.client.RedisPubSubConnection;
import org.redisson.config.MasterSlaveServersConfig; import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry; import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.ClientConnectionsEntry;
import io.netty.util.concurrent.Future;
public class PubSubConnectionPool extends ConnectionPool<RedisPubSubConnection> { public class PubSubConnectionPool extends ConnectionPool<RedisPubSubConnection> {
@ -40,7 +39,7 @@ public class PubSubConnectionPool extends ConnectionPool<RedisPubSubConnection>
} }
@Override @Override
protected Future<RedisPubSubConnection> connect(ClientConnectionsEntry entry) { protected RFuture<RedisPubSubConnection> connect(ClientConnectionsEntry entry) {
return entry.connectPubSub(); return entry.connectPubSub();
} }

@ -26,11 +26,11 @@ import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec; import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor; import org.redisson.command.CommandExecutor;
import org.redisson.misc.RPromise;
import org.redisson.remote.RemoteServiceRequest; import org.redisson.remote.RemoteServiceRequest;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/** /**
* *
@ -60,10 +60,10 @@ public class ExecutorRemoteService extends BaseRemoteService {
} }
@Override @Override
protected final Future<Boolean> addAsync(RBlockingQueue<RemoteServiceRequest> requestQueue, protected final RFuture<Boolean> addAsync(RBlockingQueue<RemoteServiceRequest> requestQueue,
RemoteServiceRequest request, RemotePromise<Object> result) { RemoteServiceRequest request, RemotePromise<Object> result) {
final Promise<Boolean> promise = commandExecutor.getConnectionManager().newPromise(); final RPromise<Boolean> promise = commandExecutor.getConnectionManager().newPromise();
Future<Boolean> future = addAsync(requestQueue, request); RFuture<Boolean> future = addAsync(requestQueue, request);
result.setAddFuture(future); result.setAddFuture(future);
future.addListener(new FutureListener<Boolean>() { future.addListener(new FutureListener<Boolean>() {

@ -19,7 +19,7 @@ import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.redisson.api.RScheduledFuture; import org.redisson.api.RScheduledFuture;
import org.redisson.misc.RedissonFuture; import org.redisson.misc.PromiseDelegator;
/** /**
* *
@ -27,7 +27,7 @@ import org.redisson.misc.RedissonFuture;
* *
* @param <V> * @param <V>
*/ */
public class RedissonScheduledFuture<V> extends RedissonFuture<V> implements RScheduledFuture<V> { public class RedissonScheduledFuture<V> extends PromiseDelegator<V> implements RScheduledFuture<V> {
private final long scheduledExecutionTime; private final long scheduledExecutionTime;
private final String taskId; private final String taskId;

@ -15,10 +15,9 @@
*/ */
package org.redisson.executor; package org.redisson.executor;
import org.redisson.api.RFuture;
import org.redisson.misc.PromiseDelegator; import org.redisson.misc.PromiseDelegator;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/** /**
* *
@ -28,9 +27,9 @@ import io.netty.util.concurrent.Promise;
public class RemotePromise<T> extends PromiseDelegator<T> { public class RemotePromise<T> extends PromiseDelegator<T> {
private String requestId; private String requestId;
private Future<Boolean> addFuture; private RFuture<Boolean> addFuture;
public RemotePromise(Promise<T> promise) { public RemotePromise(RPromise<T> promise) {
super(promise); super(promise);
} }
@ -41,10 +40,10 @@ public class RemotePromise<T> extends PromiseDelegator<T> {
return requestId; return requestId;
} }
public void setAddFuture(Future<Boolean> addFuture) { public void setAddFuture(RFuture<Boolean> addFuture) {
this.addFuture = addFuture; this.addFuture = addFuture;
} }
public Future<Boolean> getAddFuture() { public RFuture<Boolean> getAddFuture() {
return addFuture; return addFuture;
} }

@ -0,0 +1,520 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
import java.util.AbstractCollection;
import java.util.AbstractMap.SimpleEntry;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import io.netty.util.internal.PlatformDependent;
/**
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
public static class CachedValue {
private final Object key;
private final Object value;
long ttl;
long maxIdleTime;
long creationTime;
long lastAccess;
public CachedValue(Object key, Object value, long ttl, long maxIdleTime) {
this.value = value;
this.ttl = ttl;
this.key = key;
this.maxIdleTime = maxIdleTime;
creationTime = System.currentTimeMillis();
lastAccess = creationTime;
}
public boolean isExpired() {
boolean result = false;
long currentTime = System.currentTimeMillis();
if (ttl != 0 && creationTime + ttl < currentTime) {
result = true;
}
if (maxIdleTime != 0 && lastAccess + maxIdleTime < currentTime) {
result = true;
}
return result;
}
public Object getKey() {
return key;
}
public Object getValue() {
lastAccess = System.currentTimeMillis();
return value;
}
@Override
public String toString() {
return "CachedValue [key=" + key + ", value=" + value + "]";
}
}
final int size;
final ConcurrentMap<K, CachedValue> map = PlatformDependent.newConcurrentHashMap();
private final long timeToLiveInMillis;
private final long maxIdleInMillis;
public AbstractCacheMap(int size, long timeToLiveInMillis, long maxIdleInMillis) {
if (size < 0) {
throw new IllegalArgumentException("Size can't be " + size);
}
this.size = size;
this.maxIdleInMillis = maxIdleInMillis;
this.timeToLiveInMillis = timeToLiveInMillis;
}
protected void onValueRead(CachedValue value) {
}
protected void onValueRemove(CachedValue value) {
}
/*
* (non-Javadoc)
* @see java.util.Map#size()
*/
@Override
public int size() {
return map.size();
}
/*
* (non-Javadoc)
* @see java.util.Map#isEmpty()
*/
@Override
public boolean isEmpty() {
return map.isEmpty();
}
/*
* (non-Javadoc)
* @see java.util.Map#containsKey(java.lang.Object)
*/
@Override
public boolean containsKey(Object key) {
if (key == null) {
throw new NullPointerException();
}
CachedValue entry = map.get(key);
if (entry == null) {
return false;
}
if (entry.isExpired()) {
if (map.remove(key, entry)) {
onValueRemove(entry);
return false;
}
return containsKey(key);
}
return true;
}
/*
* (non-Javadoc)
* @see java.util.Map#containsValue(java.lang.Object)
*/
@Override
public boolean containsValue(Object value) {
if (value == null) {
throw new NullPointerException();
}
for (Map.Entry<K, CachedValue> entry : map.entrySet()) {
CachedValue cachedValue = entry.getValue();
if (cachedValue.getValue().equals(value)) {
if (cachedValue.isExpired()) {
if (map.remove(cachedValue.getKey(), cachedValue)) {
onValueRemove(cachedValue);
}
} else {
readValue(cachedValue);
return true;
}
}
}
return false;
}
/*
* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(Object key) {
if (key == null) {
throw new NullPointerException();
}
CachedValue entry = map.get(key);
if (entry == null) {
return null;
}
if (entry.isExpired()) {
if (map.remove(key, entry)) {
onValueRemove(entry);
return null;
}
return get(key);
}
return readValue(entry);
}
@SuppressWarnings("unchecked")
protected V readValue(CachedValue entry) {
onValueRead(entry);
return (V) entry.getValue();
}
/*
* (non-Javadoc)
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public V put(K key, V value) {
return put(key, value, timeToLiveInMillis, TimeUnit.MILLISECONDS, maxIdleInMillis, TimeUnit.MILLISECONDS);
}
@SuppressWarnings("unchecked")
@Override
public V put(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
CachedValue entry = create(key, value, ttlUnit.toMillis(ttl), maxIdleUnit.toMillis(maxIdleTime));
if (isFull(key)) {
if (!removeExpiredEntries()) {
onMapFull();
}
}
onValueCreate(entry);
CachedValue prevCachedValue = map.put(key, entry);
if (prevCachedValue != null) {
onValueRemove(prevCachedValue);
if (!prevCachedValue.isExpired()) {
return (V) prevCachedValue.getValue();
}
}
return null;
}
protected CachedValue create(K key, V value, long ttl, long maxIdleTime) {
return new CachedValue(key, value, ttl, maxIdleTime);
}
protected void onValueCreate(CachedValue entry) {
}
private boolean removeExpiredEntries() {
boolean removed = false;
// TODO optimize
for (CachedValue value : map.values()) {
if (value.isExpired()) {
if (map.remove(value.getKey(), value)) {
onValueRemove(value);
removed = true;
}
}
}
return removed;
}
protected abstract void onMapFull();
boolean isFull() {
if (size == 0) {
return false;
}
return map.size() >= size;
}
private boolean isFull(K key) {
if (size == 0) {
return false;
}
if (map.size() >= size) {
return !map.containsKey(key);
}
return false;
}
/*
* (non-Javadoc)
* @see java.util.Map#remove(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public V remove(Object key) {
CachedValue entry = map.remove(key);
if (entry != null) {
onValueRemove(entry);
if (!entry.isExpired()) {
return (V) entry.getValue();
}
}
return null;
}
/*
* (non-Javadoc)
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
public void putAll(Map<? extends K, ? extends V> m) {
removeExpiredEntries();
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
/*
* (non-Javadoc)
* @see java.util.Map#clear()
*/
@Override
public void clear() {
map.clear();
}
/*
* (non-Javadoc)
* @see java.util.Map#keySet()
*/
@Override
public Set<K> keySet() {
removeExpiredEntries();
return new KeySet();
}
/*
* (non-Javadoc)
* @see java.util.Map#values()
*/
@Override
public Collection<V> values() {
removeExpiredEntries();
return new Values();
}
/*
* (non-Javadoc)
* @see java.util.Map#entrySet()
*/
@Override
public Set<Map.Entry<K, V>> entrySet() {
removeExpiredEntries();
return new EntrySet();
}
abstract class MapIterator<M> implements Iterator<M> {
final Iterator<Map.Entry<K, CachedValue>> keyIterator = map.entrySet().iterator();
Map.Entry<K, CachedValue> mapEntry;
@Override
public boolean hasNext() {
if (mapEntry != null) {
return true;
}
mapEntry = null;
while (keyIterator.hasNext()) {
Map.Entry<K, CachedValue> entry = keyIterator.next();
if (entry.getValue().isExpired()) {
continue;
}
mapEntry = entry;
break;
}
return mapEntry != null;
}
}
final class KeySet extends AbstractSet<K> {
@Override
public Iterator<K> iterator() {
return new MapIterator<K>() {
@Override
public K next() {
if (mapEntry == null) {
throw new NoSuchElementException();
}
K key = mapEntry.getKey();
mapEntry = null;
return key;
}
@Override
public void remove() {
if (mapEntry == null) {
throw new IllegalStateException();
}
map.remove(mapEntry.getKey());
mapEntry = null;
}
};
}
@Override
public boolean contains(Object o) {
return AbstractCacheMap.this.containsKey(o);
}
@Override
public boolean remove(Object o) {
return AbstractCacheMap.this.remove(o) != null;
}
@Override
public int size() {
return AbstractCacheMap.this.size();
}
@Override
public void clear() {
AbstractCacheMap.this.clear();
}
}
final class Values extends AbstractCollection<V> {
@Override
public Iterator<V> iterator() {
return new MapIterator<V>() {
@Override
public V next() {
if (mapEntry == null) {
throw new NoSuchElementException();
}
V value = readValue(mapEntry.getValue());
mapEntry = null;
return value;
}
@Override
public void remove() {
if (mapEntry == null) {
throw new IllegalStateException();
}
map.remove(mapEntry.getKey(), mapEntry.getValue());
mapEntry = null;
}
};
}
@Override
public boolean contains(Object o) {
return AbstractCacheMap.this.containsValue(o);
}
@Override
public int size() {
return AbstractCacheMap.this.size();
}
@Override
public void clear() {
AbstractCacheMap.this.clear();
}
}
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final Iterator<Map.Entry<K,V>> iterator() {
return new MapIterator<Map.Entry<K,V>>() {
@Override
public Map.Entry<K,V> next() {
if (mapEntry == null) {
throw new NoSuchElementException();
}
SimpleEntry<K, V> result = new SimpleEntry<K, V>(mapEntry.getKey(), readValue(mapEntry.getValue()));
mapEntry = null;
return result;
}
@Override
public void remove() {
if (mapEntry == null) {
throw new IllegalStateException();
}
map.remove(mapEntry.getKey(), mapEntry.getValue());
mapEntry = null;
}
};
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
V value = get(key);
return value != null && value.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return AbstractCacheMap.this.map.remove(key, value);
}
return false;
}
public final int size() {
return AbstractCacheMap.this.size();
}
public final void clear() {
AbstractCacheMap.this.clear();
}
}
}

@ -0,0 +1,32 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public interface Cache<K, V> extends Map<K, V> {
V put(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit);
}

@ -26,6 +26,19 @@ public class Hash {
private Hash() { private Hash() {
} }
public static byte[] hash(byte[] objectState) {
long h1 = LongHashFunction.farmUo().hashBytes(objectState);
long h2 = LongHashFunction.xx_r39().hashBytes(objectState);
ByteBuf buf = Unpooled.buffer((2 * Long.SIZE) / Byte.SIZE).writeLong(h1).writeLong(h2);
try {
return buf.array();
} finally {
buf.release();
}
}
public static String hashToBase64(byte[] objectState) { public static String hashToBase64(byte[] objectState) {
long h1 = LongHashFunction.farmUo().hashBytes(objectState); long h1 = LongHashFunction.farmUo().hashBytes(objectState);
long h2 = LongHashFunction.xx_r39().hashBytes(objectState); long h2 = LongHashFunction.xx_r39().hashBytes(objectState);

@ -0,0 +1,157 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* LFU (least frequently used) cache.
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public class LFUCacheMap<K, V> extends AbstractCacheMap<K, V> {
public static class MapKey implements Comparable<MapKey> {
private Long accessCount;
private LFUCachedValue cachedValue;
public MapKey(Long accessCount, LFUCachedValue cachedValue) {
super();
this.accessCount = accessCount;
this.cachedValue = cachedValue;
}
@Override
public int compareTo(MapKey o) {
int compare = accessCount.compareTo(o.accessCount);
if (compare == 0) {
return cachedValue.id.compareTo(o.cachedValue.id);
}
return compare;
}
@Override
public String toString() {
return "MapKey [accessCount=" + accessCount + "]";
}
}
public static class LFUCachedValue extends CachedValue {
Long id;
long accessCount;
public LFUCachedValue(long id, Object key, Object value, long ttl, long maxIdleTime) {
super(key, value, ttl, maxIdleTime);
this.id = id;
}
public void addAccessCount(long value) {
accessCount += value;
}
}
private final AtomicLong idGenerator = new AtomicLong();
private final ConcurrentNavigableMap<MapKey, LFUCachedValue> accessMap = new ConcurrentSkipListMap<MapKey, LFUCachedValue>();
public LFUCacheMap(int size, long timeToLiveInMillis, long maxIdleInMillis) {
super(size, timeToLiveInMillis, maxIdleInMillis);
}
@Override
protected CachedValue create(K key, V value, long ttl, long maxIdleTime) {
return new LFUCachedValue(idGenerator.incrementAndGet(), key, value, ttl, maxIdleTime);
}
@Override
protected void onValueCreate(CachedValue value) {
MapKey key = toKey((LFUCachedValue)value);
accessMap.put(key, (LFUCachedValue)value);
}
@Override
protected void onValueRead(CachedValue value) {
addAccessCount((LFUCachedValue)value, 1);
}
private MapKey toKey(LFUCachedValue value) {
return new MapKey(value.accessCount, value);
}
@Override
protected void onValueRemove(CachedValue value) {
synchronized (value) {
MapKey key = toKey((LFUCachedValue)value);
accessMap.remove(key);
}
}
private void addAccessCount(LFUCachedValue value, long count) {
synchronized (value) {
if (count < 0 && value.accessCount == 0) {
return;
}
MapKey key = toKey(value);
if (accessMap.remove(key) == null) {
return;
}
if (count < 0) {
count = -Math.min(value.accessCount, -count);
}
value.addAccessCount(count);
key = toKey(value);
accessMap.put(key, value);
}
}
@Override
protected void onMapFull() {
Map.Entry<MapKey, LFUCachedValue> entry = accessMap.pollFirstEntry();
if (entry == null) {
return;
}
map.remove(entry.getValue().getKey(), entry.getValue());
if (entry.getValue().accessCount == 0) {
return;
}
// TODO optimize
// decrease all values
for (LFUCachedValue value : accessMap.values()) {
addAccessCount(value, -entry.getValue().accessCount);
}
}
@Override
public void clear() {
accessMap.clear();
super.clear();
}
}

@ -0,0 +1,69 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* LRU (least recently used) cache.
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public class LRUCacheMap<K, V> extends AbstractCacheMap<K, V> {
private final Queue<CachedValue> queue = new ConcurrentLinkedQueue<CachedValue>();
public LRUCacheMap(int size, long timeToLiveInMillis, long maxIdleInMillis) {
super(size, timeToLiveInMillis, maxIdleInMillis);
}
@Override
protected void onValueCreate(CachedValue value) {
queue.add(value);
}
@Override
protected void onValueRemove(CachedValue value) {
queue.remove(value);
}
@Override
protected void onValueRead(CachedValue value) {
// move value to tail of queue
if (queue.remove(value)) {
queue.add(value);
}
}
@Override
protected void onMapFull() {
CachedValue value = queue.poll();
if (value != null) {
map.remove(value.getKey(), value);
}
}
@Override
public void clear() {
queue.clear();
super.clear();
}
}

@ -0,0 +1,35 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
/**
*
* @author Nikita Koksharov
*
* @param <K>
* @param <V>
*/
public class NoneCacheMap<K, V> extends AbstractCacheMap<K, V> {
public NoneCacheMap(long timeToLiveInMillis, long maxIdleInMillis) {
super(0, timeToLiveInMillis, maxIdleInMillis);
}
@Override
protected void onMapFull() {
}
}

@ -19,123 +19,143 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise; import io.netty.util.concurrent.Promise;
public class PromiseDelegator<T> implements RPromise<T> { public class PromiseDelegator<T> implements RPromise<T> {
private final Promise<T> promise; private final RPromise<T> promise;
public PromiseDelegator(Promise<T> promise) { public PromiseDelegator(RPromise<T> promise) {
super(); super();
this.promise = promise; this.promise = promise;
} }
public Promise<T> getInnerPromise() { public RPromise<T> getInnerPromise() {
return promise; return promise;
} }
public Promise<T> setSuccess(T result) { @Override
public RPromise<T> setSuccess(T result) {
return promise.setSuccess(result); return promise.setSuccess(result);
} }
@Override
public boolean isSuccess() { public boolean isSuccess() {
return promise.isSuccess(); return promise.isSuccess();
} }
@Override
public boolean trySuccess(T result) { public boolean trySuccess(T result) {
return promise.trySuccess(result); return promise.trySuccess(result);
} }
public boolean isCancellable() { @Override
return promise.isCancellable();
}
public Throwable cause() { public Throwable cause() {
return promise.cause(); return promise.cause();
} }
@Override
public Promise<T> setFailure(Throwable cause) { public Promise<T> setFailure(Throwable cause) {
return promise.setFailure(cause); return promise.setFailure(cause);
} }
@Override
public boolean tryFailure(Throwable cause) { public boolean tryFailure(Throwable cause) {
return promise.tryFailure(cause); return promise.tryFailure(cause);
} }
@Override
public boolean setUncancellable() { public boolean setUncancellable() {
return promise.setUncancellable(); return promise.setUncancellable();
} }
public Promise<T> addListener(GenericFutureListener<? extends Future<? super T>> listener) { @Override
public RPromise<T> addListener(FutureListener<? super T> listener) {
return promise.addListener(listener); return promise.addListener(listener);
} }
public Promise<T> addListeners(GenericFutureListener<? extends Future<? super T>>... listeners) { @Override
public RPromise<T> addListeners(FutureListener<? super T>... listeners) {
return promise.addListeners(listeners); return promise.addListeners(listeners);
} }
public Promise<T> removeListener(GenericFutureListener<? extends Future<? super T>> listener) { @Override
public RPromise<T> removeListener(FutureListener<? super T> listener) {
return promise.removeListener(listener); return promise.removeListener(listener);
} }
public Promise<T> removeListeners(GenericFutureListener<? extends Future<? super T>>... listeners) { @Override
public RPromise<T> removeListeners(FutureListener<? super T>... listeners) {
return promise.removeListeners(listeners); return promise.removeListeners(listeners);
} }
public Promise<T> await() throws InterruptedException { @Override
public RPromise<T> await() throws InterruptedException {
return promise.await(); return promise.await();
} }
public Promise<T> awaitUninterruptibly() { @Override
public RPromise<T> awaitUninterruptibly() {
return promise.awaitUninterruptibly(); return promise.awaitUninterruptibly();
} }
public Promise<T> sync() throws InterruptedException { @Override
public RPromise<T> sync() throws InterruptedException {
return promise.sync(); return promise.sync();
} }
public Promise<T> syncUninterruptibly() { @Override
public RPromise<T> syncUninterruptibly() {
return promise.syncUninterruptibly(); return promise.syncUninterruptibly();
} }
@Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return promise.await(timeout, unit); return promise.await(timeout, unit);
} }
@Override
public boolean isCancelled() { public boolean isCancelled() {
return promise.isCancelled(); return promise.isCancelled();
} }
@Override
public boolean isDone() { public boolean isDone() {
return promise.isDone(); return promise.isDone();
} }
@Override
public boolean await(long timeoutMillis) throws InterruptedException { public boolean await(long timeoutMillis) throws InterruptedException {
return promise.await(timeoutMillis); return promise.await(timeoutMillis);
} }
@Override
public T get() throws InterruptedException, ExecutionException { public T get() throws InterruptedException, ExecutionException {
return promise.get(); return promise.get();
} }
@Override
public boolean awaitUninterruptibly(long timeout, TimeUnit unit) { public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
return promise.awaitUninterruptibly(timeout, unit); return promise.awaitUninterruptibly(timeout, unit);
} }
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return promise.get(timeout, unit); return promise.get(timeout, unit);
} }
@Override
public boolean awaitUninterruptibly(long timeoutMillis) { public boolean awaitUninterruptibly(long timeoutMillis) {
return promise.awaitUninterruptibly(timeoutMillis); return promise.awaitUninterruptibly(timeoutMillis);
} }
@Override
public T getNow() { public T getNow() {
return promise.getNow(); return promise.getNow();
} }
@Override
public boolean cancel(boolean mayInterruptIfRunning) { public boolean cancel(boolean mayInterruptIfRunning) {
return promise.cancel(mayInterruptIfRunning); return promise.cancel(mayInterruptIfRunning);
} }

@ -17,6 +17,7 @@ package org.redisson.misc;
import org.redisson.api.RFuture; import org.redisson.api.RFuture;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise; import io.netty.util.concurrent.Promise;
/** /**
@ -25,6 +26,74 @@ import io.netty.util.concurrent.Promise;
* *
* @param <T> * @param <T>
*/ */
public interface RPromise<T> extends Promise<T>, RFuture<T> { public interface RPromise<T> extends RFuture<T> {
/**
* Marks this future as a success and notifies all
* listeners.
*
* If it is success or failed already it will throw an {@link IllegalStateException}.
*/
RPromise<T> setSuccess(T result);
/**
* Marks this future as a success and notifies all
* listeners.
*
* @return {@code true} if and only if successfully marked this future as
* a success. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
*/
boolean trySuccess(T result);
/**
* Marks this future as a failure and notifies all
* listeners.
*
* If it is success or failed already it will throw an {@link IllegalStateException}.
*/
Promise<T> setFailure(Throwable cause);
/**
* Marks this future as a failure and notifies all
* listeners.
*
* @return {@code true} if and only if successfully marked this future as
* a failure. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
*/
boolean tryFailure(Throwable cause);
/**
* Make this future impossible to cancel.
*
* @return {@code true} if and only if successfully marked this future as uncancellable or it is already done
* without being cancelled. {@code false} if this future has been cancelled already.
*/
boolean setUncancellable();
@Override
RPromise<T> addListener(FutureListener<? super T> listener);
@Override
RPromise<T> addListeners(FutureListener<? super T>... listeners);
@Override
RPromise<T> removeListener(FutureListener<? super T> listener);
@Override
RPromise<T> removeListeners(FutureListener<? super T>... listeners);
@Override
RPromise<T> await() throws InterruptedException;
@Override
RPromise<T> awaitUninterruptibly();
@Override
RPromise<T> sync() throws InterruptedException;
@Override
RPromise<T> syncUninterruptibly();
} }

@ -22,7 +22,7 @@ import java.util.concurrent.TimeoutException;
import org.redisson.api.RFuture; import org.redisson.api.RFuture;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.FutureListener;
/** /**
* *
@ -55,36 +55,44 @@ public class RedissonFuture<T> implements RFuture<T> {
return future.cause(); return future.cause();
} }
public Future<T> addListener(GenericFutureListener<? extends Future<? super T>> listener) { public RFuture<T> addListener(FutureListener<? super T> listener) {
return future.addListener(listener); future.addListener(listener);
return this;
} }
public Future<T> addListeners(GenericFutureListener<? extends Future<? super T>>... listeners) { public RFuture<T> addListeners(FutureListener<? super T>... listeners) {
return future.addListeners(listeners); future.addListeners(listeners);
return this;
} }
public Future<T> removeListener(GenericFutureListener<? extends Future<? super T>> listener) { public RFuture<T> removeListener(FutureListener<? super T> listener) {
return future.removeListener(listener); future.removeListener(listener);
return this;
} }
public Future<T> removeListeners(GenericFutureListener<? extends Future<? super T>>... listeners) { public RFuture<T> removeListeners(FutureListener<? super T>... listeners) {
return future.removeListeners(listeners); future.removeListeners(listeners);
return this;
} }
public Future<T> sync() throws InterruptedException { public RFuture<T> sync() throws InterruptedException {
return future.sync(); future.sync();
return this;
} }
public Future<T> syncUninterruptibly() { public RFuture<T> syncUninterruptibly() {
return future.syncUninterruptibly(); future.syncUninterruptibly();
return this;
} }
public Future<T> await() throws InterruptedException { public RFuture<T> await() throws InterruptedException {
return future.await(); future.await();
return this;
} }
public Future<T> awaitUninterruptibly() { public RFuture<T> awaitUninterruptibly() {
return future.awaitUninterruptibly(); future.awaitUninterruptibly();
return this;
} }
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { public boolean await(long timeout, TimeUnit unit) throws InterruptedException {

@ -15,6 +15,11 @@
*/ */
package org.redisson.misc; package org.redisson.misc;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise; import io.netty.util.concurrent.Promise;
/** /**
@ -23,10 +28,150 @@ import io.netty.util.concurrent.Promise;
* *
* @param <T> * @param <T>
*/ */
public class RedissonPromise<T> extends PromiseDelegator<T> implements RPromise<T> { public class RedissonPromise<T> implements RPromise<T> {
private final Promise<T> promise;
public RedissonPromise(Promise<T> promise) { public RedissonPromise(Promise<T> promise) {
super(promise); this.promise = promise;
}
public Promise<T> getInnerPromise() {
return promise;
}
@Override
public RPromise<T> setSuccess(T result) {
promise.setSuccess(result);
return this;
}
@Override
public boolean isSuccess() {
return promise.isSuccess();
}
@Override
public boolean trySuccess(T result) {
return promise.trySuccess(result);
}
@Override
public Throwable cause() {
return promise.cause();
}
@Override
public Promise<T> setFailure(Throwable cause) {
return promise.setFailure(cause);
}
@Override
public boolean tryFailure(Throwable cause) {
return promise.tryFailure(cause);
}
@Override
public boolean setUncancellable() {
return promise.setUncancellable();
}
@Override
public RPromise<T> addListener(FutureListener<? super T> listener) {
promise.addListener(listener);
return this;
}
@Override
public RPromise<T> addListeners(FutureListener<? super T>... listeners) {
promise.addListeners(listeners);
return this;
}
@Override
public RPromise<T> removeListener(FutureListener<? super T> listener) {
promise.removeListener(listener);
return this;
}
@Override
public RPromise<T> removeListeners(FutureListener<? super T>... listeners) {
promise.removeListeners(listeners);
return this;
}
@Override
public RPromise<T> await() throws InterruptedException {
promise.await();
return this;
}
@Override
public RPromise<T> awaitUninterruptibly() {
promise.awaitUninterruptibly();
return this;
}
@Override
public RPromise<T> sync() throws InterruptedException {
promise.sync();
return this;
}
@Override
public RPromise<T> syncUninterruptibly() {
promise.syncUninterruptibly();
return this;
}
@Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return promise.await(timeout, unit);
}
@Override
public boolean isCancelled() {
return promise.isCancelled();
}
@Override
public boolean isDone() {
return promise.isDone();
}
@Override
public boolean await(long timeoutMillis) throws InterruptedException {
return promise.await(timeoutMillis);
}
@Override
public T get() throws InterruptedException, ExecutionException {
return promise.get();
}
@Override
public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
return promise.awaitUninterruptibly(timeout, unit);
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return promise.get(timeout, unit);
}
@Override
public boolean awaitUninterruptibly(long timeoutMillis) {
return promise.awaitUninterruptibly(timeoutMillis);
}
@Override
public T getNow() {
return promise.getNow();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return promise.cancel(mayInterruptIfRunning);
} }
} }

@ -17,13 +17,12 @@ package org.redisson.pubsub;
import org.redisson.RedissonCountDownLatch; import org.redisson.RedissonCountDownLatch;
import org.redisson.RedissonCountDownLatchEntry; import org.redisson.RedissonCountDownLatchEntry;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class CountDownLatchPubSub extends PublishSubscribe<RedissonCountDownLatchEntry> { public class CountDownLatchPubSub extends PublishSubscribe<RedissonCountDownLatchEntry> {
@Override @Override
protected RedissonCountDownLatchEntry createEntry(Promise<RedissonCountDownLatchEntry> newPromise) { protected RedissonCountDownLatchEntry createEntry(RPromise<RedissonCountDownLatchEntry> newPromise) {
return new RedissonCountDownLatchEntry(newPromise); return new RedissonCountDownLatchEntry(newPromise);
} }

@ -16,15 +16,14 @@
package org.redisson.pubsub; package org.redisson.pubsub;
import org.redisson.RedissonLockEntry; import org.redisson.RedissonLockEntry;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class LockPubSub extends PublishSubscribe<RedissonLockEntry> { public class LockPubSub extends PublishSubscribe<RedissonLockEntry> {
public static final Long unlockMessage = 0L; public static final Long unlockMessage = 0L;
@Override @Override
protected RedissonLockEntry createEntry(Promise<RedissonLockEntry> newPromise) { protected RedissonLockEntry createEntry(RPromise<RedissonLockEntry> newPromise) {
return new RedissonLockEntry(newPromise); return new RedissonLockEntry(newPromise);
} }

@ -19,15 +19,15 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.redisson.PubSubEntry; import org.redisson.PubSubEntry;
import org.redisson.api.RFuture;
import org.redisson.client.BaseRedisPubSubListener; import org.redisson.client.BaseRedisPubSubListener;
import org.redisson.client.RedisPubSubListener; import org.redisson.client.RedisPubSubListener;
import org.redisson.client.codec.LongCodec; import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.pubsub.PubSubType; import org.redisson.client.protocol.pubsub.PubSubType;
import org.redisson.connection.ConnectionManager; import org.redisson.connection.ConnectionManager;
import org.redisson.misc.PromiseDelegator; import org.redisson.misc.PromiseDelegator;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
abstract class PublishSubscribe<E extends PubSubEntry<E>> { abstract class PublishSubscribe<E extends PubSubEntry<E>> {
@ -58,10 +58,10 @@ abstract class PublishSubscribe<E extends PubSubEntry<E>> {
return entries.get(entryName); return entries.get(entryName);
} }
public Future<E> subscribe(final String entryName, final String channelName, final ConnectionManager connectionManager) { public RFuture<E> subscribe(final String entryName, final String channelName, final ConnectionManager connectionManager) {
final AtomicReference<Runnable> listenerHolder = new AtomicReference<Runnable>(); final AtomicReference<Runnable> listenerHolder = new AtomicReference<Runnable>();
final AsyncSemaphore semaphore = connectionManager.getSemaphore(channelName); final AsyncSemaphore semaphore = connectionManager.getSemaphore(channelName);
final Promise<E> newPromise = new PromiseDelegator<E>(connectionManager.<E>newPromise()) { final RPromise<E> newPromise = new PromiseDelegator<E>(connectionManager.<E>newPromise()) {
@Override @Override
public boolean cancel(boolean mayInterruptIfRunning) { public boolean cancel(boolean mayInterruptIfRunning) {
return semaphore.remove(listenerHolder.get()); return semaphore.remove(listenerHolder.get());
@ -101,7 +101,7 @@ abstract class PublishSubscribe<E extends PubSubEntry<E>> {
return newPromise; return newPromise;
} }
protected abstract E createEntry(Promise<E> newPromise); protected abstract E createEntry(RPromise<E> newPromise);
protected abstract void onMessage(E value, Long message); protected abstract void onMessage(E value, Long message);

@ -16,13 +16,12 @@
package org.redisson.pubsub; package org.redisson.pubsub;
import org.redisson.RedissonLockEntry; import org.redisson.RedissonLockEntry;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class SemaphorePubSub extends PublishSubscribe<RedissonLockEntry> { public class SemaphorePubSub extends PublishSubscribe<RedissonLockEntry> {
@Override @Override
protected RedissonLockEntry createEntry(Promise<RedissonLockEntry> newPromise) { protected RedissonLockEntry createEntry(RPromise<RedissonLockEntry> newPromise) {
return new RedissonLockEntry(newPromise); return new RedissonLockEntry(newPromise);
} }

@ -15,9 +15,10 @@
*/ */
package org.redisson.pubsub; package org.redisson.pubsub;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/** /**
* *
@ -27,9 +28,9 @@ import io.netty.util.concurrent.Promise;
*/ */
public class TransferListener<T> implements FutureListener<T> { public class TransferListener<T> implements FutureListener<T> {
private Promise<T> promise; private RPromise<T> promise;
public TransferListener(Promise<T> promise) { public TransferListener(RPromise<T> promise) {
super(); super();
this.promise = promise; this.promise = promise;
} }

@ -16,6 +16,7 @@
package org.redisson.reactive; package org.redisson.reactive;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import org.redisson.api.RFuture;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.FutureListener;
@ -26,9 +27,9 @@ import reactor.rx.subscription.ReactiveSubscription;
public class NettyFuturePublisher<T> extends Stream<T> { public class NettyFuturePublisher<T> extends Stream<T> {
private final Future<? extends T> that; private final RFuture<? extends T> that;
public NettyFuturePublisher(Future<? extends T> that) { public NettyFuturePublisher(RFuture<? extends T> that) {
this.that = that; this.that = that;
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save