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.
####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
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

@ -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/)
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 4](http://netty.io) framework.
Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework.
Redis 2.8+ and JDK 1.6+ compatible.
Please read [documentation](https://github.com/mrniko/redisson/wiki) for more details.
Redisson [releases history](https://github.com/mrniko/redisson/blob/master/CHANGELOG.md).
@ -37,43 +34,37 @@ Features
5. automatic sentinel servers discovery
* Master with Slave servers 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 connection pool
* Thread-safe implementation
* All commands executes in an atomic way
* Lua scripting
* [Spring cache](https://github.com/mrniko/redisson/wiki/10.-additional-features/#104-spring-cache-integration) integration
* Supports [Reactive Streams](http://www.reactive-streams.org)
* Supports [Redis pipelining](http://redis.io/topics/pipelining) (command batches)
* Supports [Remote services](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#91-remote-service)
* [Distributed objects](https://github.com/mrniko/redisson/wiki/6.-Distributed-objects)
* [Distributed collections](https://github.com/mrniko/redisson/wiki/7.-Distributed-collections)
* [Distributed locks and synchronizers](https://github.com/mrniko/redisson/wiki/8.-Distributed-locks-and-synchronizers)
* [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 auto-reconnect
* Supports failed to send command auto-retry
* 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)
* With over 500 unit tests
* With over 900 unit tests
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/)
### 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
Include the following to your dependency list:
@ -81,12 +72,17 @@ Include the following to your dependency list:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.2.24</version>
<version>2.3.0</version>
</dependency>
### 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

@ -3,7 +3,7 @@
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>0.9.1-SNAPSHOT</version>
<version>2.3.1-SNAPSHOT</version>
<packaging>pom</packaging>
<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>
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>0.9.1-SNAPSHOT</version>
<version>2.3.1-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

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

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

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

@ -15,7 +15,7 @@
*/
package org.redisson;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
public interface PubSubEntry<E> {
@ -23,6 +23,6 @@ public interface PubSubEntry<E> {
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.NodeType;
import org.redisson.api.NodesGroup;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionListener;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.RedisClientEntry;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
public class RedisNodes<N extends Node> implements NodesGroup<N> {
@ -65,21 +66,21 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
@Override
public boolean pingAll() {
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());
for (RedisClientEntry entry : clients) {
Future<RedisConnection> f = entry.getClient().connectAsync();
RFuture<RedisConnection> f = entry.getClient().connectAsync();
f.addListener(new FutureListener<RedisConnection>() {
@Override
public void operationComplete(Future<RedisConnection> future) throws Exception {
if (future.isSuccess()) {
final RedisConnection c = future.getNow();
Promise<RedisConnection> connectionFuture = connectionManager.newPromise();
RPromise<RedisConnection> connectionFuture = connectionManager.newPromise();
connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig());
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
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);
latch.countDown();
}
@ -99,7 +100,7 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
}
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();
}
return false;
@ -107,8 +108,8 @@ public class RedisNodes<N extends Node> implements NodesGroup<N> {
time = System.currentTimeMillis();
boolean res = true;
for (Entry<RedisConnection, Future<String>> entry : result.entrySet()) {
Future<String> f = entry.getValue();
for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
RFuture<String> f = entry.getValue();
f.awaitUninterruptibly();
if (!"PONG".equals(f.getNow())) {
res = false;

@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.redisson.api.ClusterNodesGroup;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.Node;
import org.redisson.api.NodesGroup;
import org.redisson.api.RAtomicDouble;
@ -42,6 +43,7 @@ import org.redisson.api.RList;
import org.redisson.api.RListMultimap;
import org.redisson.api.RListMultimapCache;
import org.redisson.api.RLiveObjectService;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
@ -222,6 +224,16 @@ public class Redisson implements RedissonClient {
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
public <K, V> RMap<K, V> getMap(String 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.connection.ConnectionManager;
import io.netty.util.concurrent.Future;
/**
*
*

@ -93,7 +93,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/
@Override
public V take() throws InterruptedException {
Future<V> res = takeAsync();
RFuture<V> res = takeAsync();
return res.await().getNow();
}
@ -108,7 +108,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/
@Override
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();
}
@ -118,7 +118,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
*/
@Override
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();
}
@ -144,7 +144,7 @@ public class RedissonBlockingQueue<V> extends RedissonQueue<V> implements RBlock
@Override
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();
}

@ -178,9 +178,9 @@ public class RedissonBloomFilter<T> extends RedissonExpirable implements RBloomF
@Override
public int count() {
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());
Future<Long> cardinalityFuture = executorService.readAsync(getName(), codec, RedisCommands.BITCOUNT, getName());
RFuture<Long> cardinalityFuture = executorService.readAsync(getName(), codec, RedisCommands.BITCOUNT, getName());
executorService.execute();
readConfig(configFuture.getNow());
@ -194,7 +194,7 @@ public class RedissonBloomFilter<T> extends RedissonExpirable implements RBloomF
}
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());
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.RBuckets;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.DelegateDecoderCodec;
import org.redisson.client.protocol.RedisCommand;
@ -34,8 +35,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor;
import org.redisson.connection.decoder.MapGetAllDecoder;
import io.netty.util.concurrent.Future;
public class RedissonBuckets implements RBuckets {
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);
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);
}

@ -26,8 +26,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.pubsub.CountDownLatchPubSub;
import io.netty.util.concurrent.Future;
/**
* 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 {
Future<RedissonCountDownLatchEntry> promise = subscribe();
RFuture<RedissonCountDownLatchEntry> promise = subscribe();
try {
get(promise);
@ -70,7 +68,7 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
@Override
public boolean await(long time, TimeUnit unit) throws InterruptedException {
Future<RedissonCountDownLatchEntry> promise = subscribe();
RFuture<RedissonCountDownLatchEntry> promise = subscribe();
try {
if (!await(promise, time, unit)) {
return false;
@ -102,11 +100,11 @@ public class RedissonCountDownLatch extends RedissonObject implements RCountDown
return PUBSUB.getEntry(getEntryName());
}
private Future<RedissonCountDownLatchEntry> subscribe() {
private RFuture<RedissonCountDownLatchEntry> subscribe() {
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());
}

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

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

@ -28,8 +28,6 @@ import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.command.CommandExecutor;
import org.redisson.pubsub.LockPubSub;
import io.netty.util.concurrent.Future;
/**
* Distributed implementation of {@link java.util.concurrent.locks.Lock}
* Implements reentrant lock.<br>
@ -63,13 +61,13 @@ public class RedissonFairLock extends RedissonLock implements RLock {
}
@Override
protected Future<RedissonLockEntry> subscribe(long threadId) {
protected RFuture<RedissonLockEntry> subscribe(long threadId) {
return PUBSUB.subscribe(getEntryName() + ":" + threadId,
getChannelName() + ":" + getLockName(threadId), commandExecutor.getConnectionManager());
}
@Override
protected void unsubscribe(Future<RedissonLockEntry> future, long threadId) {
protected void unsubscribe(RFuture<RedissonLockEntry> future, long threadId) {
PUBSUB.unsubscribe(future.getNow(), getEntryName() + ":" + threadId,
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.FutureListener;
import io.netty.util.concurrent.Promise;
public class RedissonKeys implements RKeys {
@ -255,7 +254,7 @@ public class RedissonKeys implements RKeys {
executorService.writeAsync(entry.getKey(), null, RedisCommands.DEL, key);
}
Future<List<?>> future = executorService.executeAsync();
RFuture<List<?>> future = executorService.executeAsync();
future.addListener(listener);
}
@ -303,7 +302,7 @@ public class RedissonKeys implements RKeys {
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) {
if (executed.decrementAndGet() == 0) {
if (failed.get() != null) {

@ -339,27 +339,34 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
@Override
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) {
RFuture<V> f = commandExecutor.writeAsync(getName(), codec, LPOP, getName());
return get(f);
return commandExecutor.writeAsync(getName(), codec, LPOP, getName());
}
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]); " +
"redis.call('lset', KEYS[1], ARGV[1], 'DELETED_BY_REDISSON');" +
"redis.call('lrem', KEYS[1], 1, 'DELETED_BY_REDISSON');" +
"return v",
Collections.<Object>singletonList(getName()), index);
return get(f);
}
@Override
public void fastRemove(int index) {
get(fastRemoveAsync(index));
}
@Override
public RFuture<Void> fastRemoveAsync(int index) {
public RFuture<Void> fastRemoveAsync(long index) {
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID,
"redis.call('lset', KEYS[1], ARGV[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));
}
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),
"local key = KEYS[1] " +
"local obj = ARGV[1] " +
@ -415,13 +422,27 @@ public class RedissonList<V> extends RedissonExpirable implements RList<V> {
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
public void trim(int fromIndex, int toIndex) {
get(trimAsync(fromIndex, toIndex));
}
@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);
}

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

@ -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.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent;
/**
@ -121,7 +120,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
}
long threadId = Thread.currentThread().getId();
Future<RedissonLockEntry> future = subscribe(threadId);
RFuture<RedissonLockEntry> future = subscribe(threadId);
get(future);
try {
@ -171,11 +170,11 @@ public class RedissonLock extends RedissonExpirable implements RLock {
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) {
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>() {
@Override
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() {
@Override
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>() {
@Override
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();
Future<RedissonLockEntry> future = subscribe(threadId);
if (!await(future, time, TimeUnit.MILLISECONDS)) {
if (!future.cancel(false)) {
future.addListener(new FutureListener<RedissonLockEntry>() {
final RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
if (!await(subscribeFuture, time, TimeUnit.MILLISECONDS)) {
if (!subscribeFuture.cancel(false)) {
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (future.isSuccess()) {
unsubscribe(future, threadId);
if (subscribeFuture.isSuccess()) {
unsubscribe(subscribeFuture, threadId);
}
}
});
@ -304,7 +303,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
time -= elapsed;
}
} finally {
unsubscribe(future, threadId);
unsubscribe(subscribeFuture, threadId);
}
// return get(tryLockAsync(waitTime, leaseTime, unit));
}
@ -313,11 +312,11 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return PUBSUB.getEntry(getEntryName());
}
protected Future<RedissonLockEntry> subscribe(long threadId) {
protected RFuture<RedissonLockEntry> subscribe(long threadId) {
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());
}
@ -421,7 +420,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
public RFuture<Void> unlockAsync(final long threadId) {
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 " +
"redis.call('publish', KEYS[2], ARGV[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) {
final RPromise<Void> result = newPromise();
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
@ -494,7 +493,7 @@ public class RedissonLock extends RedissonExpirable implements RLock {
return;
}
final Future<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
final RFuture<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
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,
final Future<RedissonLockEntry> subscribeFuture, final Promise<Void> result, final long currentThreadId) {
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Void> result, final long currentThreadId) {
RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() {
@Override
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 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>() {
@Override
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 AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Future<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
final RFuture<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
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,
final Future<RedissonLockEntry> subscribeFuture, final Promise<Boolean> result, final long currentThreadId) {
Future<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<Boolean> result, final long currentThreadId) {
RFuture<Long> ttlFuture = tryAcquireAsync(leaseTime, unit, currentThreadId);
ttlFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {

@ -15,20 +15,22 @@
*/
package org.redisson;
import io.netty.util.concurrent.Promise;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Promise;
public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> {
private int counter;
private final Semaphore latch;
private final Promise<RedissonLockEntry> promise;
private final RPromise<RedissonLockEntry> promise;
private final ConcurrentLinkedQueue<Runnable> listeners = new ConcurrentLinkedQueue<Runnable>();
public RedissonLockEntry(Promise<RedissonLockEntry> promise) {
public RedissonLockEntry(RPromise<RedissonLockEntry> promise) {
super();
this.latch = new Semaphore(0);
this.promise = promise;
@ -42,7 +44,7 @@ public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> {
return --counter;
}
public Promise<RedissonLockEntry> getPromise() {
public RPromise<RedissonLockEntry> getPromise() {
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) {
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);
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 idleKeys = {}; "
+ "local res = redis.call('hscan', KEYS[1], ARGV[2]); "

@ -21,8 +21,8 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
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.Lock;
import org.redisson.api.RFuture;
import org.redisson.api.RLock;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonFuture;
import org.redisson.misc.RedissonPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
/**
* 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 {
Promise<Void> promise = ImmediateEventExecutor.INSTANCE.newPromise();
RPromise<Void> promise = new RedissonPromise<Void>(ImmediateEventExecutor.INSTANCE.<Void>newPromise());
long currentThreadId = Thread.currentThread().getId();
Queue<RLock> lockedLocks = new ConcurrentLinkedQueue<RLock>();
@ -94,7 +95,7 @@ public class RedissonMultiLock implements Lock {
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 AtomicInteger tryLockRequestsAmount = new AtomicInteger();
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 {
lockedLocks.clear();
if (failed.get() != null) {
@ -176,9 +177,9 @@ public class RedissonMultiLock implements Lock {
tryLockRequestsAmount.incrementAndGet();
Future<Boolean> future;
if (waitTime > 0 || leaseTime > 0) {
future = ((RedissonLock)lock).tryLockAsync(waitTime, leaseTime, unit, currentThreadId);
future = ((RedissonPromise)((RedissonLock)lock).tryLockAsync(waitTime, leaseTime, unit, currentThreadId)).getInnerPromise();
} else {
future = ((RedissonLock)lock).tryLockAsync(currentThreadId);
future = ((RedissonPromise)(((RedissonLock)lock).tryLockAsync(currentThreadId))).getInnerPromise();
}
if (future instanceof RedissonPromise) {
@ -197,7 +198,7 @@ public class RedissonMultiLock implements Lock {
@Override
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) {
tryLockFutures.put(lock, lock.tryLockAsync());
}
@ -205,10 +206,10 @@ public class RedissonMultiLock implements Lock {
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());
RuntimeException latestException = null;
for (Entry<RLock, Future<Boolean>> entry : tryLockFutures.entrySet()) {
for (Entry<RLock, RFuture<Boolean>> entry : tryLockFutures.entrySet()) {
try {
if (entry.getValue().syncUninterruptibly().getNow()) {
lockedLocks.add(entry.getKey());
@ -230,12 +231,12 @@ public class RedissonMultiLock implements Lock {
}
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) {
futures.add(lock.unlockAsync());
}
for (Future<Void> unlockFuture : futures) {
for (RFuture<Void> unlockFuture : futures) {
unlockFuture.awaitUninterruptibly();
}
}
@ -246,7 +247,7 @@ public class RedissonMultiLock implements Lock {
}
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) {
tryLockFutures.put(lock, lock.tryLockAsync(waitTime, leaseTime, unit));
}
@ -257,13 +258,13 @@ public class RedissonMultiLock implements Lock {
@Override
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) {
futures.add(lock.unlockAsync());
}
for (Future<Void> future : futures) {
for (RFuture<Void> future : futures) {
future.syncUninterruptibly();
}
}

@ -41,8 +41,6 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.Hash;
import io.netty.util.concurrent.Future;
/**
* @author Nikita Koksharov
*
@ -250,7 +248,7 @@ public abstract class RedissonMultimap<K, V> extends RedissonExpirable implement
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);
}

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

@ -25,9 +25,6 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
/**
* Base Redisson object
*
@ -50,11 +47,11 @@ abstract class RedissonObject implements RObject {
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);
}
protected <V> V get(Future<V> future) {
protected <V> V get(RFuture<V> 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.List;
import org.redisson.api.RFuture;
import org.redisson.api.RPatternTopic;
import org.redisson.api.listener.PatternMessageListener;
import org.redisson.api.listener.PatternStatusListener;
@ -27,8 +28,6 @@ import org.redisson.command.CommandExecutor;
import org.redisson.connection.PubSubConnectionEntry;
import org.redisson.pubsub.AsyncSemaphore;
import io.netty.util.concurrent.Future;
/**
* 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) {
Future<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().psubscribe(name, codec, pubSubListener);
RFuture<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().psubscribe(name, codec, pubSubListener);
future.syncUninterruptibly();
return System.identityHashCode(pubSubListener);
}

@ -28,6 +28,7 @@ import org.redisson.api.RBitSetReactive;
import org.redisson.api.RBlockingQueueReactive;
import org.redisson.api.RBucketReactive;
import org.redisson.api.RDequeReactive;
import org.redisson.api.RFuture;
import org.redisson.api.RHyperLogLogReactive;
import org.redisson.api.RKeysReactive;
import org.redisson.api.RLexSortedSetReactive;
@ -68,8 +69,6 @@ import org.redisson.reactive.RedissonSetCacheReactive;
import org.redisson.reactive.RedissonSetReactive;
import org.redisson.reactive.RedissonTopicReactive;
import io.netty.util.concurrent.Future;
/**
* Main infrastructure class allows to get access
* to all Redisson objects on top of Redis server.
@ -116,7 +115,7 @@ public class RedissonReactive implements RedissonReactiveClient {
@Override
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);
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.concurrent.atomic.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.api.RLock;
import io.netty.util.concurrent.Future;
@ -47,10 +48,10 @@ public class RedissonRedLock extends RedissonMultiLock {
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());
RuntimeException latestException = null;
for (Entry<RLock, Future<Boolean>> entry : tryLockFutures.entrySet()) {
for (Entry<RLock, RFuture<Boolean>> entry : tryLockFutures.entrySet()) {
try {
if (entry.getValue().syncUninterruptibly().getNow()) {
lockedLocks.add(entry.getKey());

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

@ -30,18 +30,16 @@ import java.util.Map.Entry;
import org.redisson.api.RFuture;
import org.redisson.api.RScoredSortedSet;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.DoubleCodec;
import org.redisson.client.codec.ScoredCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands;
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.decoder.ListScanResult;
import org.redisson.command.CommandAsyncExecutor;
import io.netty.util.concurrent.Future;
public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RScoredSortedSet<V> {
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) {
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);
}
@ -359,8 +357,8 @@ public class RedissonScoredSortedSet<V> extends RedissonExpirable implements RSc
@Override
public RFuture<Double> addScoreAsync(V object, Number value) {
return commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.ZINCRBY,
getName(), new BigDecimal(value.toString()).toPlainString(), object);
return commandExecutor.writeAsync(getName(), DoubleCodec.INSTANCE, RedisCommands.ZINCRBY,
getName(), new BigDecimal(value.toString()).toPlainString(), encode(object));
}
@Override

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

@ -323,7 +323,7 @@ public class RedissonSubList<V> extends RedissonList<V> implements RList<V> {
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),
"local items = redis.call('lrange', KEYS[1], tonumber(ARGV[2]), tonumber(ARGV[3])) " +
"for i=1,#items do " +
@ -470,7 +470,7 @@ public class RedissonSubList<V> extends RedissonList<V> implements RList<V> {
}
@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()) {
throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " toIndex: " + toIndex);
}

@ -29,8 +29,6 @@ import org.redisson.command.CommandAsyncExecutor;
import org.redisson.connection.PubSubConnectionEntry;
import org.redisson.pubsub.AsyncSemaphore;
import io.netty.util.concurrent.Future;
/**
* 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) {
Future<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().subscribe(codec, name, pubSubListener);
RFuture<PubSubConnectionEntry> future = commandExecutor.getConnectionManager().subscribe(codec, name, pubSubListener);
future.syncUninterruptibly();
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;
import io.netty.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import io.netty.util.concurrent.FutureListener;
/**
* Represents the result of an asynchronous computation
@ -24,6 +26,136 @@ import io.netty.util.concurrent.Future;
*
* @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
* @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);
/**
* 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.
*

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

@ -18,6 +18,7 @@ package org.redisson.client;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec;
import org.redisson.client.handler.CommandsQueue;
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.RedisCommands;
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.ChannelFuture;
@ -49,7 +53,7 @@ public class RedisConnection implements RedisCommands {
private ReconnectListener reconnectListener;
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) {
super();
@ -109,7 +113,7 @@ public class RedisConnection implements RedisCommands {
return redisClient;
}
public <R> R await(Future<R> future) {
public <R> R await(RFuture<R> future) {
final CountDownLatch l = new CountDownLatch(1);
future.addListener(new FutureListener<R>() {
@Override
@ -151,25 +155,25 @@ public class RedisConnection implements RedisCommands {
}
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));
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);
}
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);
}
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);
}
public <T, R> Future<R> async(long timeout, Codec encoder, RedisCommand<T> command, Object ... params) {
final Promise<R> promise = ImmediateEventExecutor.INSTANCE.newPromise();
public <T, R> RFuture<R> async(long timeout, Codec encoder, RedisCommand<T> command, Object ... params) {
final RPromise<R> promise = new RedissonPromise<R>(ImmediateEventExecutor.INSTANCE.<R>newPromise());
if (timeout == -1) {
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) {
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);
}
@ -237,7 +241,7 @@ public class RedisConnection implements RedisCommands {
return getClass().getSimpleName() + "@" + System.identityHashCode(this) + " [redisClient=" + redisClient + ", channel=" + channel + "]";
}
public Future<?> getAcquireFuture() {
public RFuture<?> getAcquireFuture() {
return acquireFuture;
}

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

@ -23,6 +23,11 @@ import org.redisson.client.protocol.Encoder;
import io.netty.buffer.ByteBuf;
/**
*
* @author Nikita Koksharov
*
*/
public class ByteArrayCodec implements Codec {
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.Unpooled;
/**
*
* @author Nikita Koksharov
*
*/
public class ScanCodec implements Codec {
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.PubSubPatternMessage;
import org.redisson.client.protocol.pubsub.PubSubStatusMessage;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -51,7 +52,6 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Promise;
import io.netty.util.internal.PlatformDependent;
/**
@ -192,7 +192,7 @@ public class CommandDecoder extends ReplayingDecoder<State> {
}
if (i == commandBatch.getCommands().size()) {
Promise<Void> promise = commandBatch.getPromise();
RPromise<Void> promise = commandBatch.getPromise();
if (error != null) {
if (!promise.tryFailure(error) && promise.cause() instanceof RedisTimeoutException) {
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.codec.Codec;
import org.redisson.client.protocol.CommandData;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,7 +41,6 @@ import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
public class ConnectionWatchdog extends ChannelInboundHandlerAdapter {
@ -125,7 +126,7 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter {
if (connection.getReconnectListener() != null) {
// new connection used only for channel init
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);
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override

@ -19,15 +19,14 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.client.RedisRedirectException;
import org.redisson.client.codec.Codec;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
public class BatchCommandData<T, R> extends CommandData<T, R> implements Comparable<BatchCommandData<T, R>> {
private final int index;
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);
this.index = index;
}

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

@ -18,20 +18,20 @@ package org.redisson.client.protocol;
import java.util.ArrayList;
import java.util.List;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
public class CommandsData implements QueueCommand {
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();
this.promise = promise;
this.commands = commands;
}
public Promise<Void> getPromise() {
public RPromise<Void> getPromise() {
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>>> 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);
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);
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.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
@ -46,13 +47,13 @@ import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import org.redisson.connection.MasterSlaveConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.SingleEntry;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.internal.PlatformDependent;
@ -77,7 +78,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Exception lastException = null;
for (URI addr : cfg.getNodeAddresses()) {
Future<RedisConnection> connectionFuture = connect(cfg, addr);
RFuture<RedisConnection> connectionFuture = connect(cfg, addr);
try {
RedisConnection connection = connectionFuture.syncUninterruptibly().getNow();
List<ClusterNodeInfo> nodes = connection.sync(RedisCommands.CLUSTER_NODES);
@ -93,21 +94,21 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
lastClusterNode = addr;
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) {
if (partition.isMasterFail()) {
continue;
}
Future<Collection<Future<Void>>> masterFuture = addMasterEntry(partition, cfg);
RFuture<Collection<RFuture<Void>>> masterFuture = addMasterEntry(partition, cfg);
futures.add(masterFuture);
}
for (Future<Collection<Future<Void>>> masterFuture : futures) {
for (RFuture<Collection<RFuture<Void>>> masterFuture : futures) {
masterFuture.awaitUninterruptibly();
if (!masterFuture.isSuccess()) {
continue;
}
for (Future<Void> future : masterFuture.getNow()) {
for (RFuture<Void> future : masterFuture.getNow()) {
future.awaitUninterruptibly();
if (!future.isSuccess()) {
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);
if (connection != null) {
return newSucceededFuture(connection);
}
RedisClient client = createClient(addr.getHost(), addr.getPort(), cfg.getConnectTimeout(), cfg.getRetryInterval() * cfg.getRetryAttempts());
final Promise<RedisConnection> result = newPromise();
Future<RedisConnection> future = client.connectAsync();
final RPromise<RedisConnection> result = newPromise();
RFuture<RedisConnection> future = client.connectAsync();
future.addListener(new FutureListener<RedisConnection>() {
@Override
public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -158,7 +159,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
}
RedisConnection connection = future.getNow();
Promise<RedisConnection> promise = newPromise();
RPromise<RedisConnection> promise = newPromise();
connectListener.onConnect(promise, connection, null, config);
promise.addListener(new FutureListener<RedisConnection>() {
@Override
@ -188,7 +189,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
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()) {
RedisException e = new RedisException("Failed to add master: " +
partition.getMasterAddress() + " for slot ranges: " +
@ -201,8 +202,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return newFailedFuture(e);
}
final Promise<Collection<Future<Void>>> result = newPromise();
Future<RedisConnection> connectionFuture = connect(cfg, partition.getMasterAddress());
final RPromise<Collection<RFuture<Void>>> result = newPromise();
RFuture<RedisConnection> connectionFuture = connect(cfg, partition.getMasterAddress());
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
public void operationComplete(Future<RedisConnection> future) throws Exception {
@ -213,7 +214,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
}
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>>() {
@Override
@ -238,7 +239,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
config.setMasterAddress(partition.getMasterAddress());
final MasterSlaveEntry e;
List<Future<Void>> futures = new ArrayList<Future<Void>>();
List<RFuture<Void>> futures = new ArrayList<RFuture<Void>>();
if (config.getReadMode() == ReadMode.MASTER) {
e = new SingleEntry(partition.getSlotRanges(), ClusterConnectionManager.this, config);
} else {
@ -246,7 +247,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
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);
if (!partition.getSlaveAddresses().isEmpty()) {
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());
final Promise<Void> initFuture = newPromise();
RFuture<Void> f = e.setupMasterEntry(config.getMasterAddress().getHost(), config.getMasterAddress().getPort());
final RPromise<Void> initFuture = newPromise();
futures.add(initFuture);
f.addListener(new FutureListener<Void>() {
@Override
@ -295,9 +296,6 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
if (nodesIterator == null) {
List<URI> nodes = new ArrayList<URI>();
List<URI> slaves = new ArrayList<URI>();
if (lastPartitions.isEmpty()) {
System.out.println("lastPartitions.isEmpty()");
}
for (ClusterPartition partition : getLastPartitions()) {
if (!partition.isMasterFail()) {
@ -327,7 +325,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return;
}
final URI uri = iterator.next();
Future<RedisConnection> connectionFuture = connect(cfg, uri);
RFuture<RedisConnection> connectionFuture = connect(cfg, uri);
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
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) {
Future<List<ClusterNodeInfo>> future = connection.async(RedisCommands.CLUSTER_NODES);
RFuture<List<ClusterNodeInfo>> future = connection.async(RedisCommands.CLUSTER_NODES);
future.addListener(new FutureListener<List<ClusterNodeInfo>>() {
@Override
public void operationComplete(Future<List<ClusterNodeInfo>> future) throws Exception {
@ -367,7 +365,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
}
final Collection<ClusterPartition> newPartitions = parsePartitions(nodes);
Future<Void> masterFuture = checkMasterNodesChange(cfg, newPartitions);
RFuture<Void> masterFuture = checkMasterNodesChange(cfg, newPartitions);
checkSlaveNodesChange(newPartitions);
masterFuture.addListener(new FutureListener<Void>() {
@Override
@ -390,17 +388,18 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
MasterSlaveEntry entry = getEntry(currentPart.getMasterAddr());
// should be invoked first in order to remove stale failedSlaveAddresses
addRemoveSlaves(entry, currentPart, newPart);
// Does some slaves change failed state to alive?
upDownSlaves(entry, currentPart, newPart);
Set<URI> addedSlaves = addRemoveSlaves(entry, currentPart, newPart);
// Do some slaves have changed state from failed to alive?
upDownSlaves(entry, currentPart, newPart, addedSlaves);
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());
aliveSlaves.removeAll(addedSlaves);
aliveSlaves.removeAll(newPart.getFailedSlaveAddresses());
for (URI uri : aliveSlaves) {
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());
removedSlaves.removeAll(newPart.getSlaveAddresses());
@ -434,7 +433,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
Set<URI> addedSlaves = new HashSet<URI>(newPart.getSlaveAddresses());
addedSlaves.removeAll(currentPart.getSlaveAddresses());
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>() {
@Override
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) {
@ -470,7 +470,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
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>();
for (final ClusterPartition newPart : newPartitions) {
boolean masterFound = false;
@ -509,21 +509,21 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
return newSucceededFuture(null);
}
final Promise<Void> result = newPromise();
final RPromise<Void> result = newPromise();
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) {
Future<Collection<Future<Void>>> future = addMasterEntry(newPart, cfg);
future.addListener(new FutureListener<Collection<Future<Void>>>() {
RFuture<Collection<RFuture<Void>>> future = addMasterEntry(newPart, cfg);
future.addListener(new FutureListener<Collection<RFuture<Void>>>() {
@Override
public void operationComplete(Future<Collection<Future<Void>>> future) throws Exception {
public void operationComplete(Future<Collection<RFuture<Void>>> future) throws Exception {
if (future.isSuccess()) {
futures.addAll(future.getNow());
}
if (masters.decrementAndGet() == 0) {
final AtomicInteger nodes = new AtomicInteger(futures.size());
for (Future<Void> nodeFuture : futures) {
for (RFuture<Void> nodeFuture : futures) {
nodeFuture.addListener(new FutureListener<Void>() {
@Override
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.ByteBufInputStream;
/**
*
* @author Nikita Koksharov
*
*/
public class KryoCodec implements Codec {
public interface KryoPool {

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

@ -42,11 +42,11 @@ public interface CommandAsyncExecutor {
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);

@ -95,7 +95,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}
@Override
public <V> V get(Future<V> future) {
public <V> V get(RFuture<V> future) {
final CountDownLatch l = new CountDownLatch(1);
future.addListener(new FutureListener<V>() {
@Override
@ -127,7 +127,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}
@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);
future.addListener(new FutureListener<Object>() {
@Override
@ -186,7 +186,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
};
for (MasterSlaveEntry entry : nodes) {
Promise<R> promise = connectionManager.newPromise();
RPromise<R> promise = connectionManager.newPromise();
promise.addListener(listener);
async(true, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0);
}
@ -203,7 +203,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
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 RPromise<R> attemptPromise = connectionManager.newPromise();
attemptPromise.addListener(new FutureListener<R>() {
@ -270,14 +270,14 @@ public class CommandAsyncService implements CommandAsyncExecutor {
};
for (MasterSlaveEntry entry : nodes) {
Promise<T> promise = connectionManager.newPromise();
RPromise<T> promise = connectionManager.newPromise();
promise.addListener(listener);
async(readOnlyMode, new NodeSource(entry), connectionManager.getCodec(), command, params, promise, 0);
}
return mainPromise;
}
public <V> RedisException convertException(Future<V> future) {
public <V> RedisException convertException(RFuture<V> future) {
return future.cause() instanceof RedisException ?
(RedisException) 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(Arrays.asList(params));
for (MasterSlaveEntry entry : entries) {
Promise<T> promise = connectionManager.newPromise();
RPromise<T> promise = connectionManager.newPromise();
promise.addListener(listener);
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,
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()) {
return;
}
@ -440,9 +440,9 @@ public class CommandAsyncService implements CommandAsyncExecutor {
return;
}
final Promise<R> attemptPromise = connectionManager.newPromise();
final RPromise<R> attemptPromise = connectionManager.newPromise();
final Future<RedisConnection> connectionFuture;
final RFuture<RedisConnection> connectionFuture;
if (readOnlyMode) {
connectionFuture = connectionManager.connectionReadOp(source, command);
} else {
@ -518,22 +518,22 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if (!connFuture.isSuccess()) {
connectionManager.getShutdownLatch().release();
details.setException(convertException(connFuture));
details.setException(convertException(connectionFuture));
return;
}
if (details.getAttemptPromise().isDone() || details.getMainPromise().isDone()) {
releaseConnection(source, connFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details);
releaseConnection(source, connectionFuture, details.isReadOnlyMode(), details.getAttemptPromise(), details);
return;
}
final RedisConnection connection = connFuture.getNow();
if (details.getSource().getRedirect() == Redirect.ASK) {
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<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));
details.setWriteFuture(future);
} 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,
final boolean isReadOnly, Promise<R> attemptPromise, final AsyncDetails<V, R> details) {
protected <V, R> void releaseConnection(final NodeSource source, final RFuture<RedisConnection> connectionFuture,
final boolean isReadOnly, RPromise<R> attemptPromise, final AsyncDetails<V, R> details) {
attemptPromise.addListener(new FutureListener<R>() {
@Override
public void operationComplete(Future<R> future) throws Exception {

@ -93,7 +93,7 @@ public class CommandBatchService extends CommandReactiveService {
@Override
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) {
throw new IllegalStateException("Batch already has been executed!");
}
@ -153,7 +153,7 @@ public class CommandBatchService extends CommandReactiveService {
}
executed = true;
Promise<Void> voidPromise = connectionManager.newPromise();
RPromise<Void> voidPromise = connectionManager.newPromise();
final RPromise<List<?>> promise = connectionManager.newPromise();
voidPromise.addListener(new FutureListener<Void>() {
@Override
@ -185,7 +185,7 @@ public class CommandBatchService extends CommandReactiveService {
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()) {
return;
}
@ -195,11 +195,11 @@ public class CommandBatchService extends CommandReactiveService {
return;
}
final Promise<Void> attemptPromise = connectionManager.newPromise();
final RPromise<Void> attemptPromise = connectionManager.newPromise();
final AsyncDetails details = new AsyncDetails();
final Future<RedisConnection> connectionFuture;
final RFuture<RedisConnection> connectionFuture;
if (entry.isReadOnlyMode()) {
connectionFuture = connectionManager.connectionReadOp(source, null);
} else {
@ -254,7 +254,7 @@ public class CommandBatchService extends CommandReactiveService {
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
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) {
if (attemptPromise.isDone() || future.isCancelled()) {
return;
@ -319,8 +319,8 @@ public class CommandBatchService extends CommandReactiveService {
}
private void checkConnectionFuture(final Entry entry, final NodeSource source,
final Promise<Void> mainPromise, final Promise<Void> attemptPromise, final AsyncDetails details,
Future<RedisConnection> connFuture) {
final RPromise<Void> mainPromise, final RPromise<Void> attemptPromise, final AsyncDetails details,
RFuture<RedisConnection> connFuture) {
if (attemptPromise.isDone() || mainPromise.isCancelled() || connFuture.isCancelled()) {
return;
}
@ -335,7 +335,7 @@ public class CommandBatchService extends CommandReactiveService {
List<CommandData<?, ?>> list = new ArrayList<CommandData<?, ?>>(entry.getCommands().size() + 1);
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[] {}));
}
for (BatchCommandData<?, ?> c : entry.getCommands()) {

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

@ -21,14 +21,13 @@ import java.util.List;
import org.reactivestreams.Publisher;
import org.redisson.SlotCallback;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.reactive.NettyFuturePublisher;
import io.netty.util.concurrent.Future;
/**
*
* @author Nikita Koksharov
@ -42,29 +41,29 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override
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);
}
public <R> Publisher<R> reactive(Future<R> future) {
public <R> Publisher<R> reactive(RFuture<R> future) {
return new NettyFuturePublisher<R>(future);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@ -75,13 +74,13 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override
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);
}
@Override
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);
}
@ -92,21 +91,21 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override
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);
}
@Override
public <T, R> Publisher<R> evalReadReactive(String key, Codec codec, RedisCommand<T> evalCommandType,
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);
}
@Override
public <T, R> Publisher<R> evalReadReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> evalCommandType,
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);
}
@ -114,19 +113,19 @@ public class CommandReactiveService extends CommandAsyncService implements Comma
@Override
public <T, R> Publisher<R> evalWriteReactive(String key, Codec codec, RedisCommand<T> evalCommandType,
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);
}
@Override
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);
}
@Override
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);
}

@ -18,12 +18,11 @@ package org.redisson.command;
import java.net.InetSocketAddress;
import java.util.List;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager;
import io.netty.util.concurrent.Future;
/**
*
* @author Nikita Koksharov
@ -31,7 +30,7 @@ import io.netty.util.concurrent.Future;
*/
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);

@ -18,14 +18,13 @@ package org.redisson.command;
import java.net.InetSocketAddress;
import java.util.List;
import org.redisson.api.RFuture;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.Future;
/**
*
* @author Nikita Koksharov
@ -46,19 +45,19 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override
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);
}
@Override
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);
}
@Override
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);
}
@ -69,7 +68,7 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override
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);
}
@ -80,25 +79,25 @@ public class CommandSyncService extends CommandAsyncService implements CommandEx
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}

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

@ -18,11 +18,10 @@ package org.redisson.connection;
import org.redisson.api.NodeType;
import org.redisson.client.RedisConnection;
import org.redisson.config.MasterSlaveServersConfig;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
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.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
/**
*
@ -59,9 +58,9 @@ public interface ConnectionManager {
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();
@ -89,9 +88,9 @@ public interface ConnectionManager {
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);
@ -101,9 +100,9 @@ public interface ConnectionManager {
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);
@ -123,6 +122,6 @@ public interface ConnectionManager {
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.protocol.RedisCommands;
import org.redisson.config.MasterSlaveServersConfig;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
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);
doConnect(config, nodeType, listener);
listener.executeCommands();

@ -30,11 +30,11 @@ import org.redisson.config.BaseMasterSlaveServersConfig;
import org.redisson.config.Config;
import org.redisson.config.ElasticacheServersConfig;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
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());
try {
connection = client.connect();
Promise<RedisConnection> future = newPromise();
RPromise<RedisConnection> future = newPromise();
connectListener.onConnect(future, connection, null, config);
future.syncUninterruptibly();
nodeConnections.put(addr, connection);

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

@ -70,7 +70,6 @@ import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
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 Promise<Boolean> shutdownPromise;
private final RPromise<Boolean> shutdownPromise;
private final InfinitySemaphoreLatch shutdownLatch = new InfinitySemaphoreLatch();
@ -245,7 +244,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
MasterSlaveEntry entry;
if (config.getReadMode() == ReadMode.MASTER) {
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();
} else {
entry = createMasterSlaveEntry(config, slots);
@ -259,11 +258,11 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config,
HashSet<ClusterSlotRange> slots) {
MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config);
List<Future<Void>> fs = entry.initSlaveBalancer(java.util.Collections.<URI>emptySet());
for (Future<Void> future : fs) {
List<RFuture<Void>> fs = entry.initSlaveBalancer(java.util.Collections.<URI>emptySet());
for (RFuture<Void> future : fs) {
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();
return entry;
}
@ -322,40 +321,40 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
@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 Promise<PubSubConnectionEntry> result = newPromise();
final RPromise<PubSubConnectionEntry> result = newPromise();
lock.acquire(new Runnable() {
@Override
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));
}
});
return result;
}
public Future<PubSubConnectionEntry> psubscribe(String channelName, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
Promise<PubSubConnectionEntry> promise = newPromise();
public RFuture<PubSubConnectionEntry> psubscribe(String channelName, Codec codec, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
RPromise<PubSubConnectionEntry> promise = newPromise();
subscribe(codec, channelName, listener, promise, PubSubType.PSUBSCRIBE, semaphore);
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 Promise<PubSubConnectionEntry> result = newPromise();
final RPromise<PubSubConnectionEntry> result = newPromise();
lock.acquire(new Runnable() {
@Override
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));
}
});
return result;
}
public Future<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
Promise<PubSubConnectionEntry> promise = newPromise();
public RFuture<PubSubConnectionEntry> subscribe(Codec codec, String channelName, RedisPubSubListener<?> listener, AsyncSemaphore semaphore) {
RPromise<PubSubConnectionEntry> promise = newPromise();
subscribe(codec, channelName, listener, promise, PubSubType.SUBSCRIBE, semaphore);
return promise;
}
@ -365,7 +364,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
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);
if (сonnEntry != null) {
с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,
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);
Future<RedisPubSubConnection> connFuture = nextPubSubConnection(slot);
RFuture<RedisPubSubConnection> connFuture = nextPubSubConnection(slot);
connFuture.addListener(new FutureListener<RedisPubSubConnection>() {
@Override
@ -614,7 +613,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
@Override
public Future<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command) {
public RFuture<RedisConnection> connectionWriteOp(NodeSource source, RedisCommand<?> command) {
MasterSlaveEntry entry = source.getEntry();
if (entry == null) {
entry = getEntry(source);
@ -640,7 +639,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
@Override
public Future<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command) {
public RFuture<RedisConnection> connectionReadOp(NodeSource source, RedisCommand<?> command) {
MasterSlaveEntry entry = source.getEntry();
if (entry == null && source.getSlot() != null) {
entry = getEntry(source.getSlot());
@ -651,7 +650,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
return entry.connectionReadOp();
}
Future<RedisPubSubConnection> nextPubSubConnection(int slot) {
RFuture<RedisPubSubConnection> nextPubSubConnection(int slot) {
return getEntry(slot).nextPubSubConnection();
}
@ -746,7 +745,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
@Override
public Future<Boolean> getShutdownPromise() {
public RFuture<Boolean> getShutdownPromise() {
return shutdownPromise;
}

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

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

@ -25,6 +25,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RFuture;
import org.redisson.client.BaseRedisPubSubListener;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
@ -115,13 +116,13 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
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()) {
Future<RedisPubSubConnection> future = registerSentinel(cfg, addr, c);
RFuture<RedisPubSubConnection> future = registerSentinel(cfg, addr, c);
connectionFutures.add(future);
}
for (Future<RedisPubSubConnection> future : connectionFutures) {
for (RFuture<RedisPubSubConnection> future : connectionFutures) {
future.awaitUninterruptibly();
}
}
@ -130,23 +131,23 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
protected MasterSlaveEntry createMasterSlaveEntry(MasterSlaveServersConfig config,
HashSet<ClusterSlotRange> slots) {
MasterSlaveEntry entry = new MasterSlaveEntry(slots, this, config);
List<Future<Void>> fs = entry.initSlaveBalancer(disconnectedSlaves);
for (Future<Void> future : fs) {
List<RFuture<Void>> fs = entry.initSlaveBalancer(disconnectedSlaves);
for (RFuture<Void> future : fs) {
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();
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 oldClient = sentinels.putIfAbsent(addr.getHost() + ":" + addr.getPort(), client);
if (oldClient != null) {
return newSucceededFuture(null);
}
Future<RedisPubSubConnection> pubsubFuture = client.connectPubSubAsync();
RFuture<RedisPubSubConnection> pubsubFuture = client.connectPubSubAsync();
pubsubFuture.addListener(new FutureListener<RedisPubSubConnection>() {
@Override
public void operationComplete(Future<RedisPubSubConnection> future) throws Exception {
@ -218,7 +219,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
// to avoid addition twice
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>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {

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

@ -17,16 +17,15 @@ package org.redisson.connection.balancer;
import java.net.InetSocketAddress;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import io.netty.util.concurrent.Future;
public interface LoadBalancerManager {
Future<RedisConnection> getConnection(InetSocketAddress addr);
RFuture<RedisConnection> getConnection(InetSocketAddress addr);
int getAvailableClients();
@ -40,11 +39,11 @@ public interface LoadBalancerManager {
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);

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

@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
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.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -38,7 +40,6 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
abstract class ConnectionPool<T extends RedisConnection> {
@ -58,8 +59,8 @@ abstract class ConnectionPool<T extends RedisConnection> {
this.connectionManager = connectionManager;
}
public Future<Void> add(final ClientConnectionsEntry entry) {
final Promise<Void> promise = connectionManager.newPromise();
public RFuture<Void> add(final ClientConnectionsEntry entry) {
final RPromise<Void> promise = connectionManager.newPromise();
promise.addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {
@ -70,7 +71,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
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);
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) {
if ((checkFreezed && entry.isFreezed()) || !tryAcquireConnection(entry)) {
@ -97,7 +98,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return;
}
Future<T> promise = createConnection(entry);
RFuture<T> promise = createConnection(entry);
promise.addListener(new FutureListener<T>() {
@Override
public void operationComplete(Future<T> future) throws Exception {
@ -135,7 +136,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return config.getLoadBalancer().getEntry(entries);
}
public Future<T> get() {
public RFuture<T> get() {
for (int j = entries.size() - 1; j >= 0; j--) {
ClientConnectionsEntry entry = getEntry();
if (!entry.isFreezed() && tryAcquireConnection(entry)) {
@ -165,7 +166,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
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())
&& tryAcquireConnection(entry)) {
return connectTo(entry);
@ -184,11 +185,11 @@ abstract class ConnectionPool<T extends RedisConnection> {
return (T) entry.pollConnection();
}
protected Future<T> connect(ClientConnectionsEntry entry) {
return (Future<T>) entry.connect();
protected RFuture<T> connect(ClientConnectionsEntry entry) {
return (RFuture<T>) entry.connect();
}
private Future<T> connectTo(ClientConnectionsEntry entry) {
private RFuture<T> connectTo(ClientConnectionsEntry entry) {
T conn = poll(entry);
if (conn != null) {
if (!conn.isActive()) {
@ -201,9 +202,9 @@ abstract class ConnectionPool<T extends RedisConnection> {
return createConnection(entry);
}
private Future<T> createConnection(final ClientConnectionsEntry entry) {
final Promise<T> promise = connectionManager.newPromise();
Future<T> connFuture = connect(entry);
private RFuture<T> createConnection(final ClientConnectionsEntry entry) {
final RPromise<T> promise = connectionManager.newPromise();
RFuture<T> connFuture = connect(entry);
connFuture.addListener(new FutureListener<T>() {
@Override
public void operationComplete(Future<T> future) throws Exception {
@ -226,7 +227,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return promise;
}
private void promiseSuccessful(ClientConnectionsEntry entry, Promise<T> promise, T conn) {
private void promiseSuccessful(ClientConnectionsEntry entry, RPromise<T> promise, T conn) {
entry.resetFailedAttempts();
if (!promise.trySuccess(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();
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()) {
checkForReconnect(entry);
}
@ -247,7 +248,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
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();
if (attempts == config.getFailedAttempts()) {
checkForReconnect(entry);
@ -261,7 +262,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
promise.tryFailure(cause);
}
private Future<T> promiseFailure(ClientConnectionsEntry entry, T conn) {
private RFuture<T> promiseFailure(ClientConnectionsEntry entry, T conn) {
int attempts = entry.incFailedAttempts();
if (attempts == config.getFailedAttempts()) {
checkForReconnect(entry);
@ -301,7 +302,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
return;
}
Future<RedisConnection> connectionFuture = entry.getClient().connectAsync();
RFuture<RedisConnection> connectionFuture = entry.getClient().connectAsync();
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
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())) {
entry.resetFailedAttempts();
Promise<Void> promise = connectionManager.newPromise();
RPromise<Void> promise = connectionManager.newPromise();
promise.addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future)
@ -362,10 +363,10 @@ abstract class ConnectionPool<T extends RedisConnection> {
};
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> () {
@Override public void operationComplete (Future < Void > future)throws Exception {
FutureListener<Void> listener = new FutureListener<Void>() {
@Override public void operationComplete(Future<Void> future)throws Exception {
ping(c, pingListener);
}
};
@ -381,7 +382,7 @@ abstract class ConnectionPool<T extends RedisConnection> {
}
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);
}

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

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

@ -19,7 +19,7 @@ import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
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>
*/
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 String taskId;

@ -15,10 +15,9 @@
*/
package org.redisson.executor;
import org.redisson.api.RFuture;
import org.redisson.misc.PromiseDelegator;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
/**
*
@ -28,9 +27,9 @@ import io.netty.util.concurrent.Promise;
public class RemotePromise<T> extends PromiseDelegator<T> {
private String requestId;
private Future<Boolean> addFuture;
private RFuture<Boolean> addFuture;
public RemotePromise(Promise<T> promise) {
public RemotePromise(RPromise<T> promise) {
super(promise);
}
@ -41,10 +40,10 @@ public class RemotePromise<T> extends PromiseDelegator<T> {
return requestId;
}
public void setAddFuture(Future<Boolean> addFuture) {
public void setAddFuture(RFuture<Boolean> addFuture) {
this.addFuture = addFuture;
}
public Future<Boolean> getAddFuture() {
public RFuture<Boolean> getAddFuture() {
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() {
}
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) {
long h1 = LongHashFunction.farmUo().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.TimeoutException;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
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();
this.promise = promise;
}
public Promise<T> getInnerPromise() {
public RPromise<T> getInnerPromise() {
return promise;
}
public Promise<T> setSuccess(T result) {
@Override
public RPromise<T> setSuccess(T result) {
return promise.setSuccess(result);
}
@Override
public boolean isSuccess() {
return promise.isSuccess();
}
@Override
public boolean trySuccess(T result) {
return promise.trySuccess(result);
}
public boolean isCancellable() {
return promise.isCancellable();
}
@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();
}
public Promise<T> addListener(GenericFutureListener<? extends Future<? super T>> listener) {
@Override
public RPromise<T> addListener(FutureListener<? super T> 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);
}
public Promise<T> removeListener(GenericFutureListener<? extends Future<? super T>> listener) {
@Override
public RPromise<T> removeListener(FutureListener<? super T> 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);
}
public Promise<T> await() throws InterruptedException {
@Override
public RPromise<T> await() throws InterruptedException {
return promise.await();
}
public Promise<T> awaitUninterruptibly() {
@Override
public RPromise<T> awaitUninterruptibly() {
return promise.awaitUninterruptibly();
}
public Promise<T> sync() throws InterruptedException {
@Override
public RPromise<T> sync() throws InterruptedException {
return promise.sync();
}
public Promise<T> syncUninterruptibly() {
@Override
public RPromise<T> syncUninterruptibly() {
return promise.syncUninterruptibly();
}
@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,6 +17,7 @@ package org.redisson.misc;
import org.redisson.api.RFuture;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.Promise;
/**
@ -25,6 +26,74 @@ import io.netty.util.concurrent.Promise;
*
* @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 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();
}
public Future<T> addListener(GenericFutureListener<? extends Future<? super T>> listener) {
return future.addListener(listener);
public RFuture<T> addListener(FutureListener<? super T> listener) {
future.addListener(listener);
return this;
}
public Future<T> addListeners(GenericFutureListener<? extends Future<? super T>>... listeners) {
return future.addListeners(listeners);
public RFuture<T> addListeners(FutureListener<? super T>... listeners) {
future.addListeners(listeners);
return this;
}
public Future<T> removeListener(GenericFutureListener<? extends Future<? super T>> listener) {
return future.removeListener(listener);
public RFuture<T> removeListener(FutureListener<? super T> listener) {
future.removeListener(listener);
return this;
}
public Future<T> removeListeners(GenericFutureListener<? extends Future<? super T>>... listeners) {
return future.removeListeners(listeners);
public RFuture<T> removeListeners(FutureListener<? super T>... listeners) {
future.removeListeners(listeners);
return this;
}
public Future<T> sync() throws InterruptedException {
return future.sync();
public RFuture<T> sync() throws InterruptedException {
future.sync();
return this;
}
public Future<T> syncUninterruptibly() {
return future.syncUninterruptibly();
public RFuture<T> syncUninterruptibly() {
future.syncUninterruptibly();
return this;
}
public Future<T> await() throws InterruptedException {
return future.await();
public RFuture<T> await() throws InterruptedException {
future.await();
return this;
}
public Future<T> awaitUninterruptibly() {
return future.awaitUninterruptibly();
public RFuture<T> awaitUninterruptibly() {
future.awaitUninterruptibly();
return this;
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {

@ -15,6 +15,11 @@
*/
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;
/**
@ -23,10 +28,150 @@ import io.netty.util.concurrent.Promise;
*
* @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) {
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.RedissonCountDownLatchEntry;
import io.netty.util.concurrent.Promise;
import org.redisson.misc.RPromise;
public class CountDownLatchPubSub extends PublishSubscribe<RedissonCountDownLatchEntry> {
@Override
protected RedissonCountDownLatchEntry createEntry(Promise<RedissonCountDownLatchEntry> newPromise) {
protected RedissonCountDownLatchEntry createEntry(RPromise<RedissonCountDownLatchEntry> newPromise) {
return new RedissonCountDownLatchEntry(newPromise);
}

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

@ -19,15 +19,15 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import org.redisson.PubSubEntry;
import org.redisson.api.RFuture;
import org.redisson.client.BaseRedisPubSubListener;
import org.redisson.client.RedisPubSubListener;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.pubsub.PubSubType;
import org.redisson.connection.ConnectionManager;
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;
abstract class PublishSubscribe<E extends PubSubEntry<E>> {
@ -58,10 +58,10 @@ abstract class PublishSubscribe<E extends PubSubEntry<E>> {
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 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
public boolean cancel(boolean mayInterruptIfRunning) {
return semaphore.remove(listenerHolder.get());
@ -101,7 +101,7 @@ abstract class PublishSubscribe<E extends PubSubEntry<E>> {
return newPromise;
}
protected abstract E createEntry(Promise<E> newPromise);
protected abstract E createEntry(RPromise<E> newPromise);
protected abstract void onMessage(E value, Long message);

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

@ -15,9 +15,10 @@
*/
package org.redisson.pubsub;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
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> {
private Promise<T> promise;
private RPromise<T> promise;
public TransferListener(Promise<T> promise) {
public TransferListener(RPromise<T> promise) {
super();
this.promise = promise;
}

@ -16,6 +16,7 @@
package org.redisson.reactive;
import org.reactivestreams.Subscriber;
import org.redisson.api.RFuture;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
@ -26,9 +27,9 @@ import reactor.rx.subscription.ReactiveSubscription;
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;
}

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

Loading…
Cancel
Save